WebApp Sec mailing list archives
Technical Note by Amit Klein: "Path Insecurity"
From: "Amit Klein (AKsecurity)" <aksecurity () hotpop com>
Date: Wed, 01 Mar 2006 06:54:05 +0000 (GMT)
Path Insecurity Amit Klein, March 2006 Preface ======= This technical note was written as a result of a private discussion between Ivan Ristic and the author. It all began when Ivan made a comment about path insecurity, which made me spend some time on these issues and reach the sad conclusion summarized in the write-up's title. Anyway, I owe Ivan my interest in the problem, as well as some of the technical details presented below - so thank you Ivan! Introduction ============ The problem at hand is as following: assuming two entities, "Foo" and "Bar", which reside on the same host (same hostname, to be more precise), is it at all possible to provide ANY kind of security to them, given that they're "hostile" to each other? Foo and Bar may be applications, users, partners, etc., and the URLs used throughout this document are http://www.some.site/foo/... and http://www.some.site/bar/... respectively (it seems that using HTTPS instead of HTTP has no significance to this problem, hence HTTP will be assumed for simplicity). Without loss of generality, we assume that Foo wants to attack Bar. The trivial attacks =================== Hopefully this is obvious, but in order to focus the discussion, it is first needed to observe that a window loaded with URL http://www.some.site/bar/page1.html can be both fully read and fully written by a window opened with http://www.some.site/foo/attack1.html, by means of the latter incorporating a Javacript code that obtains a handle H for the Bar window, and then reads or assigns to H.document.body.innerHTML. Likewise the document URL (H.document.URL), the history collection of this window (H.history - actually, the way to exploit this is to traverse the history list via iterative application of the prev() and next() operations, each time reading the URL via H.document.URL) and the document referrer (H.document.referrer) can be accessed. It should be very clear that this is a fundamental security issue, enabling Foo to attack Bar and to fool Bar's user easily by changing data/events in Bar's page and reading sensitive data off the page. To be explicit: everything that can be typically achieved with cross site scripting and cross site request forgery [1] can be done so in this situation, and with much greater convenience, since the attacker is already on the same domain (and host) with the target, and has full access to the windows of the target application. Let us assume then that we only need to protect Bar's credentials, be they in cookies or in HTTP basic authentication. Of course, resorting to this means that we give up most of the security we can hope for, but still, for academic purposes (and for some practical purposes too) let's only focus on credentials security. Note that if Bar is careful enough with the way it assigns cookies, i.e. by setting the cookie path to /bar/, Bar can prevent Foo to access the cookies directly. The HTTP authentication credentials provided for /bar/ will not be transmitted automatically to pages outside the /bar/ folder. A practical justification for researching this could be as following: obtaining the credentials themselves may sometimes be more important than attacking any other part of the application. Consider "single sign-on" situation, in which the same credentials are used in many applications - attacking the application at hand may be not interesting (it may be a "read only" application), yet obtaining the credentials and using them in another application may be very rewarding. Now, again an obvious attack is to read the cookies from H.document.cookie. If no such handle can be obtained, then it's still possible for http://www.some.site/foo/attack1.html to open a window to some page in /bar/, e.g. http://www.some.site/bar/page2.html, and now that a handle exists, to use it to read the cookies in /bar/ folder. If it is totally impossible to open a window, then perhaps the "voluntary" HTTP Response Splitting method described in [2] (p. 26) can be used. HTTP Basic Authentication ========================= A less obvious attack (described in [3]) is against HTTP basic authentication (RFC 2617 [4]). Assume that the user browsed to /bar/somewhere, and authenticated to that page via HTTP basic authentication. A browser is allowed to automatically send the credentials only for pages outside /bar/, as stated in [4] section 2: A client SHOULD assume that all paths at or deeper than the depth of the last symbolic element in the path field of the Request-URI also are within the protection space specified by the Basic realm value of the current challenge. A client MAY preemptively send the corresponding Authorization header with requests for resources in that space without receipt of another challenge from the server. IE 6.0 SP2 and Mozilla Firefox 1.5 comply with the above, and will send credentials automatically just for resources under /bar/. However, the same RFC, section 1.2 also states: The realm directive (case-insensitive) is required for all authentication schemes that issue a challenge. The realm value (case-sensitive), in combination with the canonical root URL [...] of the server being accessed, defines the protection space. [...] The protection space determines the domain over which credentials can be automatically applied. If a prior request has been authorized, the same credentials MAY be reused for all other requests within that protection space [...]. Meaning that a browser is allowed to send the credentials for resources that require authentication (i.e. return a 401 response), with the same realm (and host, of course) as the one used by Bar (note that the canonical root URL for both http://www.some.site/bar/someplace and http://www.some.site/foo/... is http://www.some.site/). So Foo needs simply to know the realm string used by Bar, set up a resource http://www.some.site/foo/attack2.cgi that requires authentication, and that declares the same realm as Bar. Foo then sends this link (http://www.some.site/foo/attack2.cgi) to the user after he/she authenticates with Bar. This attack works both with Microsoft IE 6.0 SP2 and Mozilla Firefox 1.5. A defense against this attack can be as following: Bar needs to send out a cryptographically strong random realm string for every hit to a resource that requires authentication, where the hit is without valid credentials. This solution is practical because (as mentioned above) the browsers do send the credentials preemptively for any resource under /bar/ once credentials were provided for a resource directly under /bar/. So the user will asked for Bar's credentials only once, and won't be bugged each and every time a Bar resource is requested. Since Foo cannot predict the realm string, and since there's no way to get hold of the realm (by means of a Javascript code, for example), Foo cannot craft a resource with the same realm string. Apparently, using randomized realms (albeit for other purposes - e.g. for a simulated session expiration and log-out) was experimented by Ivan Ristic (and perhaps others). The fundamental flaw ==================== It may seem at this point that HTTP Basic authentication credentials are safe (using the random realm string technique), and likewise, that HttpOnly cookies are safe. Unfortunately, this is nowhere near reality. You see, at the end of the day, the "security" provided by cookies and HTTP Basic Authentication for two co-hosted entities relies solely on the separation by path of those entities. And we trust the browser to perform this separation in a trustworthy manner. Yet there are too many ways to bypass this separation, i.e. to make the browser send a request to Foo while it thinks it sends this request to Bar. This is, of course, a fundamental flaw, since if the browser thinks it sends the request to Bar, it will accompany the request with Bar's credentials, and these will in fact be forwarded to Foo. Again, this pertains to both HTTP Basic Authentication and to cookies. Attack 1 - using the classic tricks ----------------------------------- Many web servers can be tricked to invoke a resource (script) at /foo/ even though the URL appears to be for a resource at /bar/, the below is a partial list of the most common (and well known) such tricks. * The URL encoding trick (works with most web servers) http://www.some.site/bar/%2e%2e/foo/collect.cgi IE 6.0 SP2 will send this link to Foo with Bar's credentials. Firefox 1.5 will canonicalize into http://www.some.site/foo/collect.cgi * Backslashes (works in many Windows-based servers, particularly IIS) http://www.some.site/bar/baz\..\../foo/collect.cgi Firefox will send this link to Foo with Bar's credentials. IE 6.0 SP2 will canonicalize into http://www.some.site/foo/collect.cgi * %uHHHH (IIS specific extension) http://www.some.site/bar/%u002e%u002e/foo/collect.cgi Both browsers will send this to Foo with Bar's credentials. * Overlong UTF-8 encoding of a dot (may work with some servers, works with old IIS) http://www.some.site/bar/%c0%ae%c0%ae/foo/collect.cgi Both browsers will send this to Foo with Bar's credentials. * Double-encoded dot (may work with some servers, works with old IIS) http://www.some.site/bar/%252e%252e/foo/collect.cgi Both browsers will send this to Foo with Bar's credentials. Attack 2 - using XmlHttpRequest (XHR) ------------------------------------- Since both Foo and Bar reside on the same host, XHR can be used by Foo to access Bar's credentials, using the notorious TRACE HTTP method (see [5] and [6]). The following works with IE 6.0 SP2 (notice the need to prefix the TRACE with CRLF, and the Max- Forwards header - both explained in [6]): var x = new ActiveXObject("Microsoft.XMLHTTP"); x.open("\r\nTRACE","/bar/someplace",false); x.setRequestHeader("Max-Forwards","0"); x.send(); alert(x.responseText); The following works with Firefox v<=1.0.6 var x = new XMLHttpRequest(); x.open("TRACE","/bar/someplace",false); x.setRequestHeader("Max-Forwards","0"); x.send(""); alert(x.responseText); Moreover, the following Javascript code uses XHR differently to fool the browser into sending the request with Bar's credentials directly to Foo, as explained in [7] and [8] (works with IE 6.0 SP2, may not work with some web servers): var x = new ActiveXObject("Microsoft.XMLHTTP"); x.open("GET\t/foo/collect.cgi\tHTTP/1.0\r\nDummyHeader:", "/bar/someplace",false); x.send(); Note that the TRACE-based attacks can be used not only when Foo is a malicious application (or is fully owned by the attacker), but also when a cross site scripting condition is present at Foo, because they do not rely on a server-based resource (script) to collect the credentials - the credentials can be collected at the client side. HTTP Digest authentication ========================== [3] suggests using HTTP Digest Authentication [4]. It is more secure than basic authentication (or cookies) because the shared secret (password, and possibly the username too) is always transmitted in a one-way hashed (based on MD5) form. However, it is not 100% secure because the MD5-hashed credentials can be obtained in the ways described above, and then attacked (using a dictionary) off-line. This (brute force/dictionary weakness) is mentioned in [4] section 4.7. Note also that there are other methods in which the credentials can be obtained, such as fooling the user to provide the details to a rogue site using a similar interface. In fact, the same realm trick and the path tricks still work with digest authentication (verified with Microsoft IE 6.0 SP2 and Mozilla Firefox 1.5). The XHR based attacks do not work with Firefox 1.5 in the first place, and they also do not work with IE 6.0 SP2 because it seems that IE 6.0 SP2 will only send the digest Authorization with requests that make use of a close set of HTTP methods (such as GET and POST). Moreover, the Host header modification technique described in [8] for IE 6.0 SP1 apparently have been fixed in SP2, so this XHR trick cannot be used as well. Conclusions =========== There is no such thing as path security. Two entities that share the same host cannot be defended from each other. At best, the username and password can be kept secret using HTTP digest authentication, but even that is not too secure (due to the ability to brute force the data in offline). References ========== [1] "Cross Site Request Forgery", Peter Watkins, BugTraq posting, June 13th, 2001 http://www.tux.org/~peterw/csrf.txt [2] "Divide and Conquer - HTTP Response Splitting, Web Cache Poisoning Attacks, and Related Topics", Amit Klein, March 4th 2004 http://www.packetstormsecurity.org/papers/general/whitepaper_httpresponse.pdf [3] "Apache Security", Ivan Ristic, O'reilly Media, March 2005. pp. 132-133. [4] "HTTP Authentication: Basic and Digest Access Authentication", RFC 2617, June 1999 http://www.ietf.org/rfc/rfc2617.txt [5] "Cross Site Tracing", Jeremiah Grossman, WhiteHat Security whitepaper, January 20th, 2003 http://www.cgisecurity.com/whitehat-mirror/WhitePaper_screen.pdf [6] "XST Strikes Back", Amit Klein, BugTraq posting, January 25th, 2006 http://www.securityfocus.com/archive/1/423028 [7] "Exploiting the XmlHttpRequest object in IE - Referrer spoofing, and a lot more...", Amit Klein, BugTraq posting, September 24th, 2005 http://www.securityfocus.com/archive/1/411585 [8] "XS(T) attack variants which can, in some cases, eliminate the need for TRACE", Amit Klein, WebAppSec posting, January 26th, 2003 http://www.securityfocus.com/archive/107/308433
Current thread:
- Technical Note by Amit Klein: "Path Insecurity" Amit Klein (AKsecurity) (Mar 01)