Often a combination of security flaws come together to produce a unique attack vector. Individually the flaws may not amount to much but together they make an interesting combo. This is invariably more interesting from a pentesting point of view because you know that a tool couldn’t positively find it. Session fixation is one such scenario because usually a few requirements must be met for the attack to work. I thought I’d write up a recent session fixation flaw because the act of forcing the cookie onto the victim involved a little twist on overwriting session cookies that made a reflective XSS attack last a lot longer while also laughing in the face of httponly
.
As long as an attacker can remotely force the victim to use a known session cookie that becomes authenticated, you’ve found session fixation, but it’s one of those flaws that can be achieved in multiple ways that are subtly different from one another. In this particular instance the session fixation attack ran like this:
1. The attacker makes up a session cookie
Yes, the application accepted client-generated cookies.
2. The attacker makes a specific request using the fabricated cookie
This was a bit odd but if the session cookie from a request was not recognised by the application (whether it was made up or, more usually, it had just been set by the previous response page) then a background XHR request was made that effectively “authorised” the cookie. Okay, whatever, so the attacker does this.
3. The login page suffered from XSS so the attacker crafts a malicious link to set the known cookie on the victim.
The malicious link was something like this (I’ve removed the URL-encoding to make it easier to read):
https://www.example.com/login?param="><script>document.cookie="PHPSESSID=attackerCookie; path=/login; expires=Tue, 06-Aug-2024 00:00:01 GMT"</script>
In more “traditional” session fixation the attacker’s cookie is a parameter in the request that the attacker tricks the victim into making, so using XSS seems a bit like cheating. Unfortunately (for me) the application didn’t accept a session cookie in the “traditional” way and XSS was my only option. OWASP does credit XSS in its description of session fixation but, that aside, not only did XSS help the session fixation attack but the session fixation flaw helped the XSS attack…One reason for this was that a simple document.cookie
session hijack through XSS was restricted by the response to the above request:
Set-Cookie: PHPSESSID=serverCookie; path=/; secure; HttpOnly
Because of the httponly
flag, the XSS payload could not pull out the session cookie and send it to the attacker. Of course, many other interesting XSS options are still possible, such as rewriting the form’s action
attribute so that the login credentials would be sent to the attacker. However, one advantage of the session fixation approach (apart from the interest of seeing it working) is that nothing is sent to the attacker. Furthermore, as I’ll explain later (and you may have already spotted from the XSS payload) this attack has the potential to be more long-term than knowing the username and password.
The httponly
flag has another effect: the XSS payload can neither read it nor overwrite it. This behaviour isn’t standardised, it’s one of those grey areas that Michal Zalewski covers so well but in this case it’s not so grey. IE 10, Chrome 37 and Firefox 30 all behaved in the same way. But you might have noticed that the XSS payload included a path
of /login when it set the session cookie. This is where the attacker wins as now the browser doesn’t see this as an overwrite but as a different cookie altogether…
4. The victim logs in and the session cookie becomes authenticated
The server-generated session cookie included a path=/
directive so when the victim logs in to /login the attacker’s cookie has precedence (in that it’s listed first) because the path is a more specific match to the target page:
Cookie: PHPSESSID=attackerCookie; PHPSESSID=serverCookie
The application processed the first cookie with the login, thus the attacker’s fabricated cookie became authenticated and was associated with the victim’s account. Of course if the session cookie had been changed after authentication, which is best practice, the attack would have failed. Note that the attacker can also set the domain
attribute of the cookie to .example.com to try to widen the impact of the attack.
5. The attacker uses the known session cookie to masquerade as the victim
The last thing to mention is the long-term nature of this attack. Although logging off did detach the session cookie from the victim’s account, leaving it unauthenticated, the application did not clear it (again, best practice). So the next time the website is visited, the attacker’s session cookie will again be offered, accepted and authenticated. Because the XSS payload effectively makes the cookie permanent by setting a long expiry date, the attacker has access to the account of anyone that logs in using the compromised browser in the future. Of course, the persistence of the attack dies as soon as the browser’s cookie cache is cleared – but how often does that happen? For what is, after all, a reflected XSS attack, you’d be certain to get a good return. Indeed, if the browser is shared among users (e.g. at home or at internet kiosks), a single XSS attack can exploit multiple users of the website, making it a one-to-many attack, which you don’t tend to associate with reflective XSS.
I’m not claiming any of this is particularly novel, by the way. I just enjoyed finding the XSS path trick for myself and using it with session fixation to poke fun at httponly
and to create a more persistent version of a reflective XSS attack. It also demonstrated that best practice points, although seemingly trivial when taken alone, can help to stop or mitigate more complex attacks.