Project: chromium Issues People Development process History Sign in
New issue
Advanced search Search tips
Note: Color blocks (like or ) mean that a user may not be available. Tooltip shows the reason.
Issue 600352 Security: Cross-Protocol Theft from non-HTTP services via DNS rebinding + HTTP/0.9
Starred by 10 users Reported by jor...@jordanmilne.com, Apr 4 2016 Back to list
Status: Fixed
Owner:
Closed: Aug 2016
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: All
Pri: 1
Type: Bug-Security

Blocked on:
issue 624462



Sign in to add a comment
VULNERABILITY DETAILS

DNS rebinding attacks can be mounted against non-HTTP services to steal their responses cross-protocol. Non-HTTP services' responses can be read via XHR as their response streams will be interpreted by Chrome as `HTTP/0.9`.

This is an issue because, HFPA attacks[0] aside, many services that bind to localhost don't require authentication, and haven't factored browsers being able to read their responses into their threat model. 

For example: MySQL *cannot* be attacked via a standard HFPA attack, as it closes the connection due to the handshake failing while the browser is still writing the HTTP headers; however, being able to read the server's half of the handshake tells us a lot about the server itself[1]. 

Memcached *can* have its contents manipulated via a standard HFPA attack, but this behaviour allows actually leaking the database as well.

Likely all services not bound to blacklisted ports that have "fault tolerant" parsers, or that leak sensitive data before or during the handshake are vulnerable.

VERSION

Chrome Version: 49.0.2623.110 (64-bit) stable
Operating System: Ubuntu 15.10 as well as OS X / Windows 10

REPRODUCTION CASE

* To simulate a non-HTTP service bound to the loopback run `python -c 'print("\x00\x01I am not an HTTP response\r\n\r\nfoo\x00")' | nc -l 127.0.0.1 11212` on the same machine as your browser
* Start up a webserver on another host on port `11212` and have it serve the following document:

		<pre id="output"></pre>
		<script>
		var outputElem = document.getElementById("output");
		outputElem.textContent = "Waiting 120s to fetch";
		setTimeout(function() {
		  var xhr = new XMLHttpRequest();
		  xhr.open("GET", "http://" + window.location.host + "/?a=" + (new Date()).getTime());
		  xhr.onload = function() {
			outputElem.textContent = xhr.responseText;
		  };
		  xhr.send();
		}, 120000);
		</script>

* Create an entry for "rebinding.example.com" in your `/etc/hosts` file that points to the host running your webserver
* Load "http://rebinding.example.com:11212/" in your browser
* To simulate DNS rebinding, edit the "rebinding.example.com" entry in your `/etc/hosts` file and make it point to `127.0.0.1`
* After 120 seconds the `<pre>` should contain `\x00\x01I am not an HTTP response\r\n\r\nfoo\x00`.

A hosted version of this PoC that uses a custom DNS server[2] to swap the records after the first resolution is at <http://(unique_string).bondage.computersareca.ca:11212/tests/simplest_rebinding.html>.

I've also made PoCs that abuse this behaviour to dump local Memcached[3] and Redis[4] databases, as well as the MySQL[5] server handshake. Screenshots for all of these are attached.

Note that this rebinding method requires waiting longer than 60 seconds so the entry in Chrome's resolver cache gets evicted, but a more efficient method may exist. I didn't spend much time on that.

REMEDIATION

Mitigations for DNS rebinding attacks on HTTP services are well understood, the server forcing the use of HTTPS or verifying the `Host` header[6] in the request mitigates the worst issues. What's less clear is how non-HTTP services bound to non-blacklisted[7] ports should protect themselves.

Previous attacks on non-HTTP services via DNS rebinding relied on now-fixed vulnerabilities in plugins and their TCP socket APIs[8]. This is still an issue due to browsers interpreting anything that doesn't specifically declare itself as HTTP to be `HTTP/0.9`.

I think the best thing would be for DNS servers to filter responses containing "private" addresses, including loopback addresses; however, these filters are not commonly enabled, and are generally insufficient. Many that I've audited do not block loopback addresses, ignore IPv6 or improperly handle its edge cases, etc.

With that in mind, I think the *most reasonable* place to mitigate DNS rebinding attacks on non-HTTP services is in the browser. Since updating the port blacklist for every new service that comes out isn't feasible, we should instead restrict where `HTTP/0.9` is allowed.

The easiest fix would be to disallow HTTP/0.9 on "unusual" ports. If that was too restrictive, we could disallow HTTP/0.9 only if the request was for a subresource or subdocument over an "unusual" port. Loading `HTTP/0.9` at the top level should still be safe.

I'd be interested to hear your thoughts on how this should be mitigated, or whether mitigation is the browser's responsibility at all, as this behaviour is present in multiple browsers and I couldn't find any previous mentions of DNS rebinding + HTTP/0.9 attacks.

[0]: https://www.jochentopf.com/hfpa/hfpa.pdf
[1]: https://dev.mysql.com/doc/internals/en/connection-phase-packets.html#packet-Protocol::Handshake
[2]: https://github.com/JordanMilne/FakeDns
[3]: http://computersareca.ca/tests/rebinding_frame.html?memcached
[4]: http://computersareca.ca/tests/rebinding_frame.html?redis
[5]: http://computersareca.ca/tests/rebinding_frame.html?mysql
[6]: https://bugs.chromium.org/p/chromium/issues/detail?id=98357#c2
[7]: https://code.google.com/p/chromium/codesearch#chromium/src/net/base/port_util.cc&q=remotefs&sq=package:chromium&type=cs&l=71
[8]: http://www.adambarth.com/papers/2009/jackson-barth-bortz-shao-boneh-tweb.pdf

 
rebinding-chrome-memcached.png
412 KB View Download
rebinding-chrome-mysql.png
345 KB View Download
rebinding-chrome-redis.png
414 KB View Download
Cc: cbentzel@chromium.org taviso@chromium.org
Components: Internals>Network>DNS Internals>Network>HTTP
Labels: Security_Impact-Stable OS-All Pri-1
+taviso as this may be relevant to your interests
+cbentzel for network triage
I just updated my tests and confirmed that <http://computersareca.ca/tests/rebinding_frame.html?memcached> and friends also repro in Firefox, OS X Safari, and MS Edge. I haven't figured out how to perform rebinding attacks on IE<=11 yet, as its pinning behaviour is even harder to understand than Edge's, but it appears that this issue is pervasive.
Comment 3 by kenrb@chromium.org, Apr 5 2016
Cc: -cbentzel@chromium.org
Labels: Security_Severity-Low Pri-2
Owner: cbentzel@chromium.org
Status: Assigned
cbentzel, do the proposed fixes in the report look feasible?
Cc: palmer@chromium.org
adding palmer as I think he's chimed in on previous rebinding attacks.
Comment 5 by kenrb@chromium.org, Apr 5 2016
Labels: -Pri-2
I'd actually love to look at HTTP/0.9 usage and see whether that could be removed. If not restricting it to a whitelist of ports is probably a good mitigation.
Cc: mkwst@chromium.org
+mkwst due to internet sites being able to reach intranet/localhost addresses.
This now being tracked on Moz's Bugzilla as well, #1262128. I'm waiting until I have more stable repros for Edge and Safari before reporting to them. Since this is a cross-browser issue we should probably coordinate disclosure.
RE #6: Do we have any telemetry on this?

Edge was hesitant to remove HTTP/0.9 support because Chrome had it. Chrome appears to have had it from the original Firefox stack. Firefox supported 0.9 due to buggy servers of the era (e.g. see https://bugzilla.mozilla.org/show_bug.cgi?id=193921) 

The only *common* occurrence of HTTP/0.9 I'd ever seen were some buggy/misconfigured CDN servers used by Yahoo circa 2006 that would occasionally send images without headers, and these worked fine with IE but blew up Fiddler, so I had to write code to accommodate such responses. Those servers have been long fixed, as I haven’t seen an error like this on the public internet for a long time. The last time I saw a site with this issue was 2014:

http://patft.uspto.gov/netacgi/nph-Parser?Sect1=PTO2&Sect2=HITOFF&u=%2Fnetahtml%2FPTO%2Fsearch-adv.htm&r=0&p=1&f=S&l=50&Query=IN%2FEric+Lawrence%0D%0A&d=PTXT

Based on all of the browsing I do these days (virtually all of which is through Fiddler) I don’t believe that there’s any public-facing webserver still relying on this support. It’s possible that there’s some legacy device somewhere that was “getting lucky” but it seems low-risk to disable this by default for the browser. But it's entirely possible that there's 0.9 coming from some IoT or other device that's not globally exposed...
Cc: mmenke@chromium.org
#9: I asked mmenke if we had numbers about this - it sounds like there was UMA from before where we would guess that HTTP/0.9 exists but it's not in place any more. I'd be interested in what it would take to get back in as it's possible we could just get by with removing HTTP/0.9
The histogram is still around:  Net.HttpHeaderParserEvent.  ~0.01% of HTTP 0.9/1.x (i.e. not including H2/QUIC) responses are HTTP/0.9 on stable (Closer to 0.02% on canary), and 0.025% of those 0.01% are over HTTPS.  Worth noting that that's how often we interpret the response as HTTP/0.9, not how often it actually is HTTP/0.9.  Responses from broken servers can be interpreted as HTTP/0.9 as long as they don't seem to have an HTTP/1.x status line.
I'd support removing HTTP/0.9.  Its continued existence has bugged me since before I started working for Google, I'd love to see it go.  My only concern is about breaking stuff that depends on it.  Guess we can't really know how bad the fallout will be without just trying it.
Mozilla has some stats on HTTP/0.9 usage in Firefox's beta channel as well:

https://telemetry.mozilla.org/new-pipeline/dist.html#!cumulative=0&end_date=2016-05-12&keys=__none__!__none__!__none__&max_channel_version=beta%252F47&measure=HTTP_09_INFO&min_channel_version=null&product=Firefox&sanitize=1&sort_keys=submissions&start_date=2016-04-25&table=0&trim=1&use_submission_date=0

I feel like Firefox might be interpreting completely empty responses with no status line as HTTP/0.9 to end up with those numbers for sub-resources over non-standard ports, but I'd need to double-check.
Only thing that concerns is me about killing off HTTP/0.9 is about 1% of
users seem to hit this over the course of the week. Per-request basis is
below reasonable threshold. It does seem like it's hard to tell if it's
actual HTTP/0.9 responses or just garbage being interpreted as HTTP/0.9
There are other less aggressive mitigations we could consider.  We could  only allow HTTP/0.9 for main frame requests, or disallow it for cross-site requests, for some definition of cross-site.
I remain convinced that disabling HTTP/0.9 globally is low-risk. 

Unfortunately, DNS rebinding means that a lot of other mitigations we could take (e.g. only allow for main frame requests, disallow for cross-site requests) probably wouldn't help much.

The proposal in the original issue ("disallow HTTP/0.9 on "unusual" ports") does indeed seem likely to be the easiest mitigation if we wanted to maintain support for HTTP/0.9. 
Hi Folks, just wanted to give you a heads-up that I intend to publicly disclose this as part of some related inter-protocol exploitation research in 3 months (August 31st.)

If you wish to co-ordinate with the other vendors then the updated bug references are: Mozilla Bugzilla #1262128, Apple ProdSec Followup #639367943, MSRC Case 33254.
Thanks for the update, Jordan.

So, Chris:  Should we disable it an hope for the best, or just disable it on unusual ports?
This was rediscovered and publicly disclosed at http://bouk.co/blog/hacking-developers/ , can probably remove the view restriction.
Labels: -Restrict-View-SecurityTeam
Removing the restriction.  Given its low severity classification, and that it's already been publicly disclosed, seem reasonable to open up the bug.
Blockedon: 624462
Worth noting that we did indeed decide we'd try to remove HTTP/0.9 support (Which has been removed in M54 - still a ways off from deployment).
Cc: cbentzel@chromium.org
Labels: M-54
Owner: mmenke@chromium.org
Status: Fixed
Assigning to mmenke due to the HTTP/0.9 support.

Should this 
the POC site http://extractdata.club from http://bouk.co/blog/hacking-developers still can get information from a local running redis instance.

55.0.2846.4 canary (64-bit)
OS X 10.11.6

Maybe HTTP/0.9 removing is not enough to prevent this kind of attacks.
Follow 624462 for status of the change, which has been landing and reverting as the compat story is nailed down.
therealmarv:  Also seems like if a NAT router is using a default login/password, and doesn't have any defense against this sort of thing (Force being accessed by a certain hostname or something), an attacker may also be able to reconfigure your router by similar means, unless I'm missing something.
mmenke: Yes, that's the classical DNS rebinding attack. Using HTTPS is the best defense (due to enforced hostname verification) but there are other defenses being explored; see e.g. https://mikewest.github.io/cors-rfc1918/
Project Member Comment 27 by sheriffbot@chromium.org, Oct 1 2016
Labels: Restrict-View-SecurityNotify
Labels: -M-54 M-55
Project Member Comment 29 by sheriffbot@chromium.org, Nov 15 2016
Labels: -Restrict-View-SecurityNotify allpublic
This bug has been closed for more than 14 weeks. Removing security view restrictions.

For more details visit https://www.chromium.org/issue-tracking/autotriage - Your friendly Sheriffbot
Sign in to add a comment