How your ethereum can be stolen through DNS rebinding

With the new buzz around exploiting unauthenticated JSON-RPC services on localhost ignited by Tavis Ormandy,  The first thing that came to my mind was ethereum clients(Geth, Mist and Parity).

Most of the ethereum clients run a JSON-RPC service on port 8545 on localhost, but since it’s on localhost, we can’t access it directly from user’s browser due to SOP.
This issue in the electrum wallet exploited the CORS headers to take control over the user’s electrum wallet through JSON-RPC on localhost.

Geth’s JSON-RPC looked pretty secure as it didn’t return any CORS header, but then cpacia commented something on the half-patch of the electrum wallet which sparked my interest. Here are the exact words

Just disabling CORS is still vulnerable to a DNS rebinding attack. It needs to be authenticated.   ~ cpacia

I had heard about DNS rebinding but never tried to look into it much. Since Geth’s JSON-RPC is also unauthenticated, it might be vulnerable to DNS rebinding attacks too?

Here is basic definition of DNS rebinding.

I started looking into DNS Rebinding, but all the articles were mainly pretty old. Then I asked about it in Bug Bounty Forum and Luke Young linked me his awesome Defcon talk about modern DNS rebinding exploitation. It also included an automated tool to make DNS rebinding achievable on most of the modern browsers.

But I was more curious and I didn’t want to use any pre-made tool, So I began writing my own DNS server. Python has a pretty nice library called dnslib which handled most of the stuff for me. I registered a domain, setup some glue records pointing towards my server and used them as the nameservers.

I wanted to see how different browsers behaved with very low TTLs, so I made my DNS server return TTLs < 5. Chrome, Firefox and Safari cached the DNS responses for 60 seconds, even though the TTL was less than 5.

60 seconds isn’t such a long time, and I think I can make a user stay on my webpage for at least 60 seconds. Now the only thing left was to actually try it.

I ran geth with the --rpc flag(in testnet of-course)

geth –rpc –testnet

Now was the time for some javascript, and this was the hardest part. I’m not a good web-dev and it was pretty hard for me to wrap my head around the every time Javascript behaviour. I hacked together a pretty bad but working javascript in 3 hours. The initial results were successful.

Now to make it work with geth, I had to run my web server and domain on port 8545 as SOP also follows the port. But this would look kinda sketchy if I sent the link to anyone with port 8545 in it.

The solution was iframes. I made apache listen on both 8545 and 80, and set up a virtual host for each port. Now I could iframe the port 8545 and run all the javascript in the hidden iframe.

Another issue was about multiple users, what if multiple users at the same time visited my domain? The DNS server would get confused as I was using a counter based system and there was no way to differentiate between requests from individual users. This had me stumped for a while until I remembered subdomains.

I could iframe a random subdomain each time a user visits the main domain and use it as an identification. I know I may not be explaining it well but here’s an example.

Let’s assume that my domain is attacker.com and my server’s IP is 87.87.87.87 Here is how the flow goes.

  • The victim opens attacker.com in his browser.
  • First, a DNS request for attacker.com is sent to my server and it responds with the real IP 87.87.87.87
  • Next,  attacker.com is loaded into the user’s browser, which then creates a hidden iframe with a random subdomain randomrsub.attacker.com:8545 and appends it to the body
  • Now, a DNS request is sent to my server for the subdomain randomrsub.attacker.com, and the DNS server again responds with the real IP 87.87.87.87. But this time, since it’s on port 8545, the apache responds with a different virtual host, which begins the DNS rebinding.
  • The javascript on randomrsub.attacker.com:8545 waits 60 seconds, and then sends an XmlHttpRequest to randomrr.attacker.com:8545/test.
  • Since the DNS cache has expired, the browser resolves the DNS again. This time, my server responds with an IP of 127.0.0.1.
  • Now the request is actually sent to 127.0.0.1:8545/test instead of my server, and since it’s under the origin of randomrr.attacker.com:8545, we are able to read the response.
  • Since we are generating a random subdomain everytime, we can now even accommodate multiple users as the subdomain can act their identification token.

I also had to optimize the javascript a little to make sure it works 95% of the time. I added some fake DNS lookups before the real ones so that it doesn’t respond with the wrong IP at the wrong time.

This could basically be exploited with a stored XSS too. Just point a script src to the js file which adds the iframe and TADA!!

So now we can read responses from JSON-RPC service, which means we can read their ethereum addresses, their balance and potentially steal their ether if their account is unlocked. The JSON-RPC API has pretty decent method called eth_sendTransaction which can be basically used to send ethereum from the user’s account.

I have set up a Proof-of-Concept on http://rebinddns.ml. If you stay on it for more than 60 seconds and you’re running Geth(or any other ethereum client) with JSON-RPC, you will see an alert() which will contain your ethereum addresses and their balance.

H

 

All the files used in the PoC can be found on my github.

  • min.js – The Js file which generates a hidden iframe of a subdomain on port 8545
  • main.js – The Js file which executes the DNS Rebinding
  • server.py – The DNS server written in python

I have verified that Geth, the C++ ethereum client and the python client are vulnerable. The PoC has been tested on Firefox, Chrome and Safari.


PS: This has been reported to the ethereum foundation but they don’t consider it a valid vulnerability.

For any questions, you can hit me up on my twitter @ret2got

Advertisements

40 thoughts on “How your ethereum can be stolen through DNS rebinding

  1. I’m not an expert, but why not always make the XmlHttpRequest request 127.0.0.1/test directly? Also, why not create a domain, eg., localhost.rebinddns.ml, which always resolves to 127.0.0.1? I think this would not cause the 60 second delay for your browser to invalidate the old DNS response.

    Like

  2. I feel this is one of the such a lot significant info for me.
    And i’m happy reading your article. But should
    observation on some normal things, The web site taste is great, the articles is truly great :
    D. Excellent job, cheers

    Like

  3. From what I remember, a subdomain sending requests to its parent domain doesn’t count as cross origin. So couldn’t you just bind `sub.example.com` to 127.0.0.1 and `attack.sub.example.com` to your server?

    Like

  4. It’s a pity you don’t have a donate button! I’d most certainly
    donate to this superb blog! I suppose for now i’ll settle for bookmarking and adding your RSS feed to
    my Google account. I look forward to brand new updates
    and will talk about this blog with my Facebook group.
    Talk soon!

    Like

  5. El valor del activo digital ethereum muestra signos de que es algo que está en constante auge, solo hay que ver que su mercado se trabaja 24h/365 dias al año. Al tener esta propiedad, existen muchas plataformas, foros, blog, etc… trabajando sobre ello.

    Like

  6. Greate post. Keep posting such kind of information on your blog.

    Im really impressed by it.
    Hey there, You’ve performed a fantastic job. I will certainly digg it and personally recommend to my
    friends. I am confident they will be benefited from this web site.

    Like

  7. I loved as much as you’ll receive carried
    out right here. The sketch is attractive, your authored material stylish.
    nonetheless, you command get bought an shakiness over that you wish
    be delivering the following. unwell unquestionably come further formerly again since exactly the same nearly a lot often inside case you shield this
    increase.

    Like

  8. Ah meu Deus! Incrível ! Obrigado , no entanto estou encontrando problemas ⅽom sеu RSS.
    Nãο entender pοr ԛue Eս não posso junçãⲟ isso.
    Há ninguém ficando semelhante RSS problemas ?

    Alguém ԛuem ѕabe a soluçãօ Sim gentilmente responder?
    Тhanx !

    Like

  9. Hey! Do you use Twitter? I’d like to follow you if that would be ok.

    I’m absolutely enjoying your blog and look forward to new updates.

    Like

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Google+ photo

You are commenting using your Google+ account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

w

Connecting to %s