Introduction

Recently, multiple vulnerabilities involving DNS rebinding were disclosed to the public. Starting with taviso’s (Tavis Ormandy) publication of a vulnerability in the Transmission BitTorrent client, and later in Blizzard’s Update Agent, other researchers started exploring applications of DNS rebinding attacks. One example is a research on attacking Ethereum wallets for stealing information or coins.

Update: Since we originally posted this article, the issues in this post have been assigned CVEs.
CVE-2018-1098 etcd: Cross-site request forgery via crafted local POST forms
CVE-2018-1099 etcd: DNS rebinding vulnerability in etcd server

DNS rebinding is not a new attack. It’s been demonstrated in security talks and discussions in the past, some of which I will mention here. Yet for various reasons, it has an history of being dismissed by developers and many times it is left as an unaddressed issue.

So what is a DNS rebinding attack? Simply put, it is a technique that allows an attacker to subvert the victim browser’s same-origin policy. First, the attacker needs the victim to access a domain under his control. The victim’s DNS resolver will accordingly send a DNS query for the attacker’s domain. The attacker controlled name server will respond with a completely legal DNS response, only with a very low TTL (time-to-live). This field determines how long the response is valid. DNS servers, the DNS resolver and the browser use it to decide how long to cache the response.

Inside the HTTP response, the attacker inserts an XHR or Fetch script to download another page under his domain after a timeout. This is completely accepted behavior and it happens all the time in modern websites. Only if the attacker tries this on another domain, same-origin policy would prevent him from reading or issuing the request.

If timed correctly, when this second request is sent, the victim’s browser and DNS resolver should have already forgotten the initial DNS response. Another DNS query would be sent to the attacker’s name server on his domain. However, this time the attacker responds with a different record and directs the browser to his desired IP. That IP could be of an internal network address (intranet) that the victim has access to or a networking service on the victim’s machine.

That way an attacker can theoretically access any resource in the victim’s local networks and localhost. For example, internal company websites, web management pages of networking entities such as firewalls or routers, or just local development services like databases or CI servers.

This is where authentication should fulfill its role and block access to anything the attacker should not reach. Unfortunately, it is commonly assumed that local networks are inherently safe, localhost even more so. While your local router almost certainly has some authentication scheme configured, it’s possible you haven’t considered protecting local development containers or such. Developers rarely set up authentication on services that are destined to run on localhost.

Nevertheless, as I’ve previously mentioned DNS rebinding is usually not taken as a real threat. The reason for that is that it is considered too unreliable to successfully execute. There are too many unpredictable layers involved, including the browser’s DNS caching algorithm, the operating system’s DNS cache, and the nameservers on the way. My first experiments with DNS rebinding succeeded only sporadically. While some attempts worked, sometimes the rebinding magic didn’t happen even after waiting a long time.

Thankfully some good effort was put into overcoming the unreliability of DNS rebinding. In a presentation in the recent DEFCON, researcher Luke Young discussed the problems and possible solutions to reliably executing this kind of attack. Eventually, in my experiments I found that forcing the cache eviction of my browser was enough for the rebinding to work at all times. I used the same code taviso used in his PoCs (example with Transmission).

Recent works

Besides the vulnerabilities I referenced above, the threat of DNS rebinding was brought up multiple times in recent years. An article on using this attack to steal data from local Redis, memcached and Elasticsearch databases was published back in 2016. The protocols of both Redis and memcached accept commands by line and ignore invalid lines, thus making it possible to command them even with HTTP1. Elasticsearch on the other hands is HTTP based, so the attacker can send HTTP requests directly and command the server as he desires. That is, of course, assuming no authentication scheme was configured.

Certainly DNS rebinding is a dangerous threat when there is an attacker trying to infiltrate your local network and has information regarding local domains or IPs. But this prerequisite makes the attack very targeted. With localhost, the attacker can directly attack known ports for specific services that are unauthenticated by default.

Etcd

I ran netstat to see what services I was running at the moment that may have been compromised by now. I went through some daemons and I found etcd listening on port 2379. To make things worse, it uses a RESTful, HTTP API.

DNS Rebinding with etcd

Etcd runs by default without authentication. In fact, when running etcd from the command line, etcd emits a warning message than it is listening to insecure client requests:

N | embed: serving insecure client requests on 127.0.0.1:2379, this is strongly discouraged!

Etcd’s uses a simple REST API for its v2 API. The v3 API uses gRPC, with an an HTTP/JSON gateway. In my experiments I used the v2 API, but the same should be possible with the new API when no authentication is configured.

Getting the value of all keys in an etcd cluster is as simple as firing an HTTP GET request:

Modifying keys is done with a PUT request, or a POST request for in-order keys. For the v3 API it seems only POST requests are used.

For the actual DNS rebinding, I used taviso’s rbndr server. I used his public server but I could easily launch a replicate server using his code. It alternates between two addresses based on given subdomains:

I used his work on Transmission and Blizzard as a base to my web server and modified the code a little to steal the data of an etcd server with the v2 API. I made the final PoC available publicly here.

When successful, the attack page looks like this:

A simpler attack with CSRF

I wasn’t too surprised to see the attack work. Though I did wonder if I was going too far with this kind of attack on a service that may not expect web attacks all. Why go all the way and try to deal with the mess of DNS rebinding when CSRF might just work?

I wrote a super simple CSRF PoC attacking etcd, and there were indeed no mitigations in place to prevent it:

<html>
    <body onload="document.forms[0].submit()">
        <h1>CSRF</h1>
        <form action="http://localhost:2379/v2/keys/bla" method="POST">
            <input type="hidden" name="value" value="MALICIOUS"/>
            <input type="submit" value="Send"/>
        </form>
    </body>
</html>

The v2 API uses PUT requests for writing keys and DELETE for deleting. With the CSRF it’s normally impossible to fire these HTTP requests, so this attack is limited to writing or modifying in-order keys with POST requests. However, the HTTP gateway for the beta v3 API accepts POST requests for all commands.

The new API is very rich and complicated attacks could rely on it. The problem is that it only accepts JSON. If we use the previous CSRF attack all form data would be URL encoded. The following form:

<input type="hidden" name="key" value="root_pass"/>
<input type="hidden" name="value" value="evil"/>

Would result in the browser sending the following in the request data:

key=root_pass&value=evil

The etcd server expects JSON and replies with the following error:

{"error":"invalid character 'k' looking for beginning of value","code":3}

To overcome this problem the attacker would have to cause the browser to issue the request in JSON form. This is easily possible with AJAX (XHR request) but then same-origin policy would then prevent the request.

The attacker would somehow have to change the form data type to JSON. There is currently no JSON form enctype. However, I found a nice hack that allows an attacker to produce valid JSON by using enctype=’text/plain’. With this encryption type, data is sent without URL encoding the values. The previous example would now produce the following request:

key=root_pass
value=evil

Using only one input element, the attacker inserts his JSON inside the name attribute and encloses the added “=” in an irrelevant field. For example:

<input type="hidden" name='{"key":"root_pass", "value": "evil", "fake":"' value='"}'/>

The browser would issue the following request accordingly:

{"key":"root_pass", "value": "evil", "fake":"="}

Finally, one more change is needed to this code before executing the attack. The API documentation mentions all values should be base64 encoded. So our example becomes:

<html>
    <body onload="document.forms[0].submit()">
      <h1>CSRF</h1>
        <form enctype='text/plain' action="http://localhost:2379/v3beta/kv/put" method="POST">
        <!-- The v3 API accepts base64 values -->
          <input type="hidden" name='{"key":"cm9vdF9wYXNz", "value": "ZXZpbA==", "fake":"' value='"}'/>
            <input type="submit" value="Send"/>
        </form>
    </body>
</html>

After opening this in the browser, the key was added to my localhost etcd3 cluster successfully:

Disclosure

I reported these issues to the CoreOS security mailing list. They were quick to response, and we determined it’s low enough in severity to discuss publicly. The reason for that is that etcd is not meant to be run locally in scale. Yet, rest assured it is a threat to any developer working on etcd locally with default configuration. This definitely applies to some of the readers.

The original report and fix progress can be found on GitHub.

Conclusion

The simplest precaution to DNS rebinding and other possible attacks would be to use authentication on all services you use, on your machine and on your local network. It is easy to dismiss security when working on your local network. Forcing secure defaults is always a good idea for any project you are involved in.

Follow @TwistlockLabs on Twitter for updates on issues we find and more interesting publications!


  1. Only browsers supporting HTTP/0.9 will actually allow the attacker to read all command responses. See discussion on chromium’s bug.
← Back to All Posts Next Post →