Thursday, February 04, 2010

Converting unimplementable Cookie-based XSS to a persistent attack

If you spend enough time looking for Cross-Site Scripting (XSS) vulnerabilities, you are bound to come across a cookie-based version eventually -- where the script injection is located in the Cookie header. The problem is there’s no good way (in a modern browser) to force a victims browser to send an HTTP request with a modified Cookie value (to include HTML/JS). While the website or Web application is still technically vulnerable to XSS this is usually considered unimplementable since no PoC code can be created and the risk/threat is therefore lowered.

I was having this conversation with Rob Tate, a member of WhiteHat’s Engineering team, who enlightened to something I hadn’t previously considered. Cookie-based XSS can be made very useful after all!

Consider an online bank with an XSS through a username Cookie parameter. After successful login the resulting page would read something like, "Hello ."

Cookie: username=

Setting the Cookie will most likely require another (non-persistent) XSS vulnerability, which as we know is extremely common. By combining these two vulnerabilities, an unimplementable and non-persistent XSS, you could create a persistent XSS scenario.

What the attacker could do is use the non-persistent XSS to inject a data mining JavaScript function into the browser’s Cookie username parameter via document.cookie. Afterwards every time the victim logs-in the JavaScript will execute in the DOM. Now you have an a persistent XSS attack sticking with the browser over multiple sessions.

After I read this, my initial response was to suggest using DNS Rebinding to set up the XSS attack through the cookie - but after giving it further thought I realized that this wouldn't work because of the problem of switching domains.

This may all depend on the specific architecture of the application tho. By persistent do you mean that the XSS payload in the cookie will remain in the user's browser across multiple sessions or is the XSS payload actually being stored in the application itself?

If the XSS payload in the cookie became stored by the application and let to a persistent XSS, then DNS Rebinding might actually work to set this up.

Anyways, RSnake covered some cookie-based XSS attacks using DNS Rebinding that you might find interesting if you haven't seen them already: http://ha.ckers.org/blog/20090120/persistent-cookies-and-dns-rebinding-redux/

@nickhacks in this case the persistence comes in because the victims browser would be storing the payload in the cookies across multiple sessions. Unless the Web application steps on the username parameter in the cookie at some later point, you are golden.

I also think your inclination about DNS rebinding here is correct. You could use such an attack to load the JavaScript into the cookie.

The DNS Rebinding attack would work to exploit the cookie-based XSS, but I'm not sure about it remaining persistent (in the manner you describe) due to the nature of DNS Rebinding. The cookie containing the XSS payload will be bound to the domain used to perform the DNS Rebinding attack (evil.com) but can't be bound to the domain that corresponds to the vulnerable site (victim.com). So if the user directly loads victim.com our cookie with the XSS payload won't be sent :(

In any case, all these methods show that cookie-based XSS issues need to be dealt with just like any other XSS.

One other tiny thing to keep in mind: Whenever there's a cookie-based XSS, don't forget to try just sticking the cookie name/value as a query-string parameter instead. Lots of lazy coders do things like Request["username"] (in ASP.NET, for instance), which will pull the data no matter whether it's coming from from a cookie, or from a query-string parameter, or from a form variable, or...

By inserting your sessionID into someone else's cookie you can log them into your own account, which is useful if the site uses CSRF tokens has persistent XSS on a page only the account owner can see. Blogger had this flaw quite recently.