During a recent penetration test we stumbled upon a couple of issues which independently might not have warranted any attention, but when combined allowed to compromise other users by injecting arbitrary JavaScript into their browsers. It goes to show that even certain issues which might not always seem particularly interesting (such as self-XSS) can sometimes be exploited in meaningful ways. I’ll keep this mostly theoretical so as not to divulge any information on the actual targeted system.
The first interesting behaviour we noticed during the assessment was related to the authentication mechanism. When logging in with a valid user account, the application would generate a base64-encoded session cookie which always started with the same values but had differing endings. This often happens when the cookie contains some kind of encrypted information related to the account and a timestamp to define how long the cookie is valid. Given the fact that the start of the cookie was always the same, it pointed to the fact that the encryption mode was either ECB or CBC with a static IV.
The web application actually decrypts the content of the cookie to display the username on the main page. The latter was discovered by attempting a CBC byte-flipping attack which allowed us to see certain blocks of scrambled text in the resulting page.
In this particular case, we weren’t able to generate arbitrary accounts to force the creation of arbitrary cookies, but we did notice a particularly strange behaviour in the authentication mechanism which allowed us to generate semi-arbitrary cookies anyways, which would in turn allow us to generate encrypted blocks for values we could use to inject JavaScript into the page.
It turns out that if we could login with an account named test, it was also possible to login with an account named ./toto/titi/../../test. This username was accepted with the same password as the original one. There is most certainly some other vulnerability here (path traversal or XPath injection maybe?), but given the limited time of the assessment, we weren’t able to exploit it in any other way than the one detailed below.
Given the “name traversal” issue, we could essentially generate encrypted cookies with arbitrary blocks. Since some of these blocks are then decrypted and shown in the web page, we were then able to force the generation of blocks which would result in a self-XSS. Obviously when we first noticed that the username was reflected in the page we attempted to inject JavaScript code directly into the username, but this was actually rejected by the application, so the only way of exploiting the issue was through the manipulation of the encrypted cookie, as its decrypted value was not sanitized. Unfortunately, this would only impact ourselves, unless we found a way to set another browser’s cookie to our malicious value.
This is where Burp’s request smuggler plugin came in handy, as while we were busy encrypting cookies, it also revealed that the web application was vulnerable to a request smuggling vulnerability. This type of vulnerability gives an attacker the ability to prepend another user’s HTTP request to the web application. This is where our previous discoveries related to the cookie parsing came in handy, as the request smuggling issue allowed us to specify the URL and headers of a subsequent request from another browser. In essence, this allows us to specify the cookie used by another browser for one request (although it could be repeated multiple times).
So, by exploiting this issue, we can send our malicious cookie to another user’s browser and therefore have our decrypted malicious javaScript code executed in his browser. That particular page would be rendered with our own cookie and privileges, but any further request would keep the browser’s original cookie and privileges (as long as we don’t perform another smuggling attack…). This would therefore allow our script to interact with the affected domain in any way the legitimate user could. Our Self-XSS was therefore transformed into a stored-XSS! A very restrictive CSP could have made our life harder, but in this case there was none.
I hope this quick post can give you other ideas to exploit weird and seemingly unrelated issues such as these in your own assessments!