Last Updated: 2015-06-25 08:56:25 UTC
by Bojan Zdrnja (Version: 1)
The goal of a penetration test is to report all identified vulnerabilities to the customer. Of course, every penetration tester puts most of his effort into finding critical security vulnerabilities: SQL injection, XSS and similar, which have the most impact for the tested web application (and, indeed, it does not hurt a penetration tester’s ego when such a vulnerability is identified :)
However, I strongly push towards reporting of every single vulnerability, no matter how harmless it might appear (and my penetration team coworkers sometimes complain about this, but let’s prove them wrong).
Here we’ll take a look at how two seemingly low risk vulnerabilities can be combined into a more dangerous one.
Accepting parameters in GET and POST requests
When processing parameters/responses received from the client, most of the today’s web applications rely on POST HTTP requests. This is a preferred way of sending client-related input/output from the browser since it will not be visible in web server’s (or proxy’s) logs. One of the tests I normally do is to check if the application accepts same parameters in GET HTTP requests. Let’s take a look at this.
The “official” request looks like this:
POST /page HTTP/1.1
… (other headers)
Now we can try to issue the same request as a GET HTTP request:
GET /page?parameter=value&secret=secret_value HTTP/1.1
… (other headers)
If this worked it means that the tested web application (the tested page/script) accepts parameters from any request. While this by itself is not really a security vulnerability, it is not a perfect way for receiving and processing parameters as we will see below. Additionally, keep in mind that this makes an attacker’s job a bit easier – instead of working with POST HTTP requests he can simply put everything into GET HTTP request (yeah, it works for the defenders as well since we’ll see what he put into the request).
A seemingly harmless XSS vulnerability
While further testing this application we found an XSS vulnerability. For sake of simplicity let’s say it’s an anonymous application that has no login forms. However, since the application depends on a certain workflow, and since the XSS vulnerability was found in the 3rd step of the workflow, it does require a valid session cookie (a JSESSIONID cookie).
What does this mean? It means that the attacker cannot exploit the XSS vulnerability: if the request to the vulnerable page is made without a valid JSESSIONID cookie, the application simply redirects the user to the front page (the first step of the workflow). Even if the victim now again clicked on the malicious link, it still wouldn’t work because the tested application checks the workflow phase/step and if it is not correct again simply redirects the user to the front page.
Ahh, such a disappointment after finding a very nice XSS vulnerability: the attacker can really exploit only himself and that’s no fun at all. Or is there another way?
Taking this a bit further
Remember how we figured out that the application accepts parameters in both GET and POST HTTP requests above?
Let’s see what else can be submitted through such requests. The cookie, which is crucial to the behavior of the tested application is a simple JSESSIONID cookie that looks like this:
Since the cookie is normally sent as part of a header, the attacker cannot get the victim’s browser to set the cookie for the target web application, at least not without exploiting another vulnerability – such as an XSS vulnerability – but remember that we cannot exploit it without a valid cookie. Catch 22 isn’t it?
But, let’s not lose hope. What if we try to submit the cookie as a parameter in a GET or POST HTTP request? Such a request would look like this:
GET /page?JSESSIONID=560308266F93351159D8D20732C637FA¶meter=value&secret=secret_value HTTP/1.1
… (other headers)
Bingo! This worked – the tested web application happily took and parsed all submitted parameters, even the JSESSIONID parameter that should be normally delivered as a cookie. The developers probably wanted to be as flexible as possible.
Combining the vulnerabilities into an exploit
So, the attacker can now deploy the following attack:
- Create a new session where he navigates to the required screen. The application now “knows” that the JSESSIONID cookie that was given to the attacker relates to a session that is at the vulnerable screen.
- Create a malicious URL that exploits the XSS vulnerability. Append the JSESSIONID parameter that contains the attacker’s cookie value to the malicious URL. This URL will work because the vulnerable web application will verify the session state and see that the user is accessing a valid screen in the workflow.
- Send the malicious URL to the victim, wait and profit.
Finally, last thing to discuss is maybe what we exploit with the XSS vulnerability in the first place: typically the attacker tries to steal cookies in order to gain access to the victim’s session. Since here sessions are irrelevant, the attacker will not use XSS to steal cookies but instead to change what the web page displays to the victim. This can be used for all sorts of phishing exploits and, depending on the URL and context of the attack, can be even more devastating than stealing the sessions.