Takeshi Terada, Professional Service Div.
URL handling bugs have sometimes caused security problems. One example is the XSS bug of Safari I reported a year ago. This blog post describes the bug details.
Overview: The following are possible via a crafted redirection URL:
① Host header manipulation
② Origin Confusion XSS
Either leads to information theft or spoofing, if the target site meets certain conditions.
Recommendation: Upgrading Safari to the version released in July 18, 2016 or later.
Safari's fix: Improved validation. It now displays an error with invalid redirection URLs.
The bug can be reproduced when supplying a crafted Location response header with 302 or 307 status.
The URL's port is non-numeric. Safari, in reaction, connects to example.jp:80 and transmits a request message containing the header below:
The invalid port is set to the Host header. This means that it's possible to manipulate Host header being sent from someone's browser to somewhere, but there are two restrictions: the characters shouldn't occur in URL are percent-encoded, and only the portion after ":" can be altered.
Let's explore what sort of attacks are possible with this behavior.
(To reproduce the bug, you need to remove proxies like Burp, and use an old version of Safari)
Limited symbols such as "
'" and "&" are allowed as shown above.
I firstly tested a simple XSS attack in an apostrophe-enclosed value attribute.
Safari's XSS Filter works even with the Host's reflection, to my surprise. Of course, there is still a chance depending on the context like the one below.
However, this is too obvious. Let's further dig into the bug.
Host header can be reflected in the places like:
<script src="http://(HOST)/js/jquery.js"> <link href="http://(HOST)/css/style.css" rel="stylesheet" type="text/css">
You can find such apps in github's code search (sign-in required), and I myself have seen working examples in my security test job. They aren't very rare.
Let's consider the scenario of "<script src=" here. As an example, suppose the header is manipulated from "example.jp" to "example.jp:xyz".
In this case, Safari regards the src URL as malformed and doesn't load it (such URLs are accepted only in Location). Even if Safari loads the JS from example.jp:80, it's meaningless because Safari just loads the legitimate JS. The attacker's aim here is to make Safari load a JS from his server.
After some trial and error, I came up with the following idea.
Response from the attacker's server:
Request to the target server:
Upon receiving the Location, Safari connects to example.jp:80 and sends the Host header below:
The initial part, "a@" (containing basic authentication credentials) is stripped.
Response from the target server:
The target app reflects the Host header value in the hostname of "<script src=" URL.
The part before and including "@" is stripped again. Consequently, the JS is fetched from the "evil" host, and the XSS attack succeeds.
Note that the XSS Filter doesn't work in this attack, and neither does the phishing warning screen, which is usually displayed when a URL contains basic authentication credentials. Therefore the attacker won't be bothered by them in this attack.
The trick above can also be used for information theft attacks. Suppose that a web app, by design, redirects to a URL including some secret information.
In this case, the attacker can seize the token by manipulating the victim's Host header with the same "@" trick.
I think this scenario is relatively realistic because the Location header seems to be the most common place into which servers reflect the Host header value. This is probably not because web app developers are doing so, but because some web app platforms, when handling Location header, absolutize a given relative URL based on the request Host header value. A good example is Java's HttpServletResponse#sendRedirect().
Besides the Location header, HTML's URI attributes such as "<form action=", and "<a href=" can also be a target of information theft, if the header value is reflected in their hostnames.
An odd behavior caught my eyes when I was doing a test with "http://www.mbsd.jp/", our corporate website.
This is the normal screen of the site.
However, when redirecting to "http://www.mbsd.jp:xyz/", a dreary screen shows up.
The cause is that the relative-URL resources including images aren't loaded properly.
Let's examine what's happening on the browser.
The origin of the page is apparently corrupted. This should be why relative-URL resources weren't loaded. In addition, the access to the cookies is rejected with SecurityError, even though the cookies are normally included in the request message as below.
The limitaion caused by the corrupted origin, i.e. inaccessibility to the cookies, will also restrain the attacker's JS. The situation doesn't appear so favorable for attackers, but the stroy will be different if there is a way to take advantage of this corruption.
The best tool for the purpose should be iframe. Just see if a redirection inside an iframe makes any difference. The target and attacker's sites here are as follows.
Target site: http://test.mbsd.jp/ ("X-Frame-Options"-free version of our website)
Attacker's site: http://example7.jp/ (This iframe's a redirector to "http://test.mbsd.jp:xyz/")
The following is the result.
Look at the error in the JS console. The relative-URL resource (/js/jquery.js) of the iframe'd MBSD's page is causing 404 error, saying the URL is "http://example7.jp/js/jquery.js". What's happening here is that, because of the corrupted origin, the browser is trying to load the JS, which should normally be loaded from MBSD's site (test.mbsd.jp), from the iframe parent's site.
To be clear, "/js/jquery.js" on example7.jp is, if placed rightly, loaded with no 404 error.
Frankly, this result wasn't what I had expected; but anyway, this shows that, by ifram'ing the target, the attacker can now exploit the following hardcoded relative-URL scenario, too.
(Relative URLs with a hostname like "//example3.jp/a.js" aren't affected by the bug.)
Meanwhile, it can still access its own document's content. This means, the attacker can exfiltrate or alter the content of the exact Location URL. Cookie-authenticated pages can be a target, as the cookies are included in the request message as previously mentioned.
Some more details of the bug are listed here:
・Safari assumes the default port (80, or 443 in HTTPS) when an invalid port is given.
HTTP proxies, e.g. Burp and Squid, if present, hinder the attack, as they don't allow invalid port.
・A malformed Host header like "Host: hostname:xyz" is sent to the server.
Apache, WebLogic and Nginx accept them, while Tomcat and IIS don't.
・The HTTP method can be either GET or POST with 302 or 307 redirection.
The request body, however, is always empty due to the nature of redirection.
・The base URL is inherited from its parent if inside an iframe, null otherwise.
Oddly, "<base href=" is completely ignored, even if present.
・JS is executed in a blank origin, isolated even from the iframe parent.
DOM objects except for cookie and LocalStorage are accessible.
・CSP (or X-Frame-Options) may prevent the XSS attack.