Hacker News new | ask | show | jobs
by dooglius 3076 days ago
> Any website can simply create a dns name that they are authorized to communicate with, and then make it resolve to localhost.

So if I understand this correctly, websites can now bypass all firewalls and send traffic to any _local_ port at will? It also seems that this same trick would apply to local/intranet IPs (e.g. have domains that redirect to 192.168.0.x) allowing interaction with things like printers. While Blizzard has a bug, it seems to be the browser that has the real vulnerability here.

Edit: The replies have good explanations with more detail why this would be difficult to fix -- the host doesn't have enough context to differentiate between "intended" and "unintended" IPs without a bunch of pernicious edge cases.

4 comments

Lots of routers are vulnerable to this. One of my favorite DefCon talks [1] (favorite talks in general, actually) goes over this vulnerability.

Generally, I think browsers handle this as well as they can. DNS rebinding preys on a feature that's useful for being able to fall back on redundant servers if a primary fails, which is important.

IIRC from the talk, browsers have implemented policies that prevent rebinding to non-public IP ranges. The talk below touches on how that's not quite sufficient for routers, because they also happen to have a valid public IP, but often don't properly filter or NAT packets from the LAN NIC, leaving them vulnerable because the packets still come from a private IP, so the source-IP-based security lets them through.

[1] https://www.youtube.com/watch?v=FV7SQd-3Ytk

Yes.

They can't send arbitrary traffic, though; they can only send valid HTTP requests, and they don't get access to your cookies (because the hostname doesn't match), so the "only" thing they can do is get access to things that an unauthenticated HTTP client running as you could get access to.

This has been true since almost the first web browsers - XHR wasn't a thing, but you could send GET requests with <img src="http://192.168.0.1/reboot-everything"> or even POST requests with forms (a little easier once JS let you create and submit forms from JS, but certainly doable in pure HTML).

And the problem is there's no way to tell what IP addresses to block. Special-casing 127.0.0.1 is at least a clear enough solution to articulate (though it breaks all sorts of use cases where HTTP to localhost on a custom domain name is intended), but should you also block all the RFC 1918 space? Doesn't that break the vast majorities of companies that have internal websites named wiki.example.com or wiki.corp.example.com? And some companies don't even use RFC 1918 space, they use public IPv4 ranges they own for internal routing.

It gets worse - the other problem here is that IP-based access to resources on the public internet is also vulnerable. If you're at, say, a university which has IP-based access to some journals, any website can send HTTP requests to those journals from the university.

The real right solution here is to avoid IP-based access controls, either on the public internet or on your private network - preferably by not having a private network or at least not trusting it, BeyondCorp style. Every HTTP request that does stuff on your behalf needs to be explicitly authenticated, even if it comes from the private network.

This makes sense, thanks for the explanation. The unfortunate thing is that setting up a local HTTP server is easy, while proper authentication takes more work. Based on the nature of their fix, it seems Blizzard doesn't really want to expend effort on proper authentication. I wonder if browsers could send a special HTTP header indicating the host that initiated the request?
Browsers (and most other HTTP clients) already send the Host: header, and that appears to be a pretty good way to mitigate DNS rebinidng attacks. It does not save you from things like <img src> attacks.

One common use of local HTTP servers is with the express intent of hosting web pages (not just an API endpoint) that's rendered in an embedded web browser widget, or perhaps even in a real web browser, because the web is a pretty good way of showing UIs. A common example is CUPS - if you're on macOS or most desktop Linuxes, http://localhost:631 is likely to bring up the CUPS admin interface. So browsers saying "I'm a browser" is not really the (un)authorization you want - many times you want browsers, or embedded widgets made from browser code, to access them. So if the Host header isn't enough, there isn't really a better answer than proper authentication. (CUPS is pretty hardened now, but one good solution for CUPS would be a command-line utility that generated a session key and printed out a URL like http://localhost:631/?auth=a1b2c3d4.)

I know about the Host header, my thought was more about something like a Redirected-From header which would be set based on things like the host the <img src> or XHR came from. A simple sanity check on that (anything other than localhost is blocked) should suffice.
Agreed. Not that lost ago, there was a post about how a BitTorrent client had a similar issue. Just like in that case, the real vulnerability was in browsers. I wonder how many programs are going to be discovered to be “vulnerable” before people realize that they are missing the point.
What do you think browsers should do instead?
There are a few options. IMO the best is saving ip address that each DNS name is resolved to for every connection for the duration of a windows existence.
That doesn't save you from this attack - you can send the index page and some JS over with a long Cache-Control header, and then trigger the site to get loaded some days later when DNS has been changed to point to localhost. The JS will trigger the same XHR and it will succeed this time.

(.. and now that I think about caching, the various "within the same tab" solutions elsewhere in the comments don't work, because they'd force Gmail / OWA / Slack / etc. to get reloaded with a full cache flush when they change IP addresses, which everyone would hate.)

Can you really reload a website just even if it is rejecting connections just using a long Cache-Control header? I find that hard to believe.

> because they'd force Gmail / OWA / Slack / etc. to get reloaded with a full cache flush when they change IP addresses

I think security issues should be fixed even if the fix imposes an inconvenience. Especially since the inconvenience is basically just a performance issue.

Side note: I don't find the idea that this attack is hard to fix a particularly strong justification for not fixing it. Not being able to connect to arbitrary hosts is deliberately not part of the API exposed to javascript so I think it would be hard to argue that DNS rebinding isn't a bug.

Side note 2: The workaround of "don't trust" localhost doesn't prevent all DNS rebinding based attacks. For instance, if you took out an ad, you could then have a botnet to bypass any ratelimiter.

I call BS, it's the responsibility of the server to check Host headers and implement CORS. All browser provide these security measurements. There are valid use cases for having domain aliases for local ips.
> There are valid use cases for having domain aliases for local ips.

My preferred solution doesn't prevent this, and in fact it is preferred partially because some of the other solutions do.

The vulun is in the fact that the program blindly trusts incoming HTTP based only on a nonce being in both the body and a header.
No, the "vuln" is assuming that only users on the machine can access localhost. This is a completely reasonable assumption, and it is on the browsers for invalidating it.
Yes. This same thing can be used to attack web crawlers: you can cajole the crawler into making web requests to localhost or private networks.