Chaining Vulnerabilities to Exploit POST Based Reflected XSS
Cross-Site Scripting (XSS) vulnerabilities are quite common in web applications. These vulnerabilities allow attackers to inject their own JavaScript into the application which can have devastating impacts. TrustedSec regularly creates weaponized XSS payloads on engagements to perform malicious actions such as stealing documents we shouldn't have access to. One specific form of XSS vulnerability that is particularly difficult to exploit is a reflected POST based XSS vulnerability.
For many XSS vulnerabilities we can craft a malicious URL that will run our payload if a user clicks the link, say in a phishing email. Sometimes we can inject our payload into the application and it is stored in the database before being served up to other users later when they access specific areas of the application. But with a reflected POST based XSS vulnerability, the payload has to be typed into a form or field on the webpage, submitted, and the payload runs in the response to that POST.
We would need to convince a user to manually type in our malicious payload into the application and submit it in order to get our payload to run in their browser, which is a scenario even the best of social engineers would consider unlikely. Due to how difficult the vulnerability is to exploit, reflected POST based XSS vulnerabilities are often relegated to the lower severity findings in penetration test reports.
There are a few scenarios however where these vulnerabilities are perfectly exploitable. Reflected POST based XSS just needs to be chained with other vulnerabilities. There are three scenarios I'd like to illustrate:
- Method Tampering
- Cross-Site Request Forgery (CSRF)
- Spoofed JSON with CSRF
I've created a lab that implements these three scenarios that will let you practice chaining these vulnerabilities to achieve a working XSS payload. The content of this blog can be found in the tutorials built into the lab. The lab project is hosted here:
https://github.com/hoodoer/postBasedXSS
This lab is a simple python flask webserver. You can get the lab server running with the following commands:
git clone https://github.com/hoodoer/postBasedXSS cd postBasedXSS pip install -r requirements.txt python postXssServer.py
Ideally, you should have a browser configured to proxy through Burp Suite Pro, which can help develop the proof-of-concept attacks to exploit these vulnerabilities. Once you have the lab server running, you'll find it running HTTP on port 80.
http://localhost
When you launch a particular lab, you'll see an "Open Tutorial" link. Opening this shows a walkthrough of how the chained attack works for that particular lab. The First name and Last name fields at the bottom of the lab page are vulnerable to both the reflected POST based XSS and the particular lab precursor vulnerability that can be chained with it. Let's review the three chained techniques.
Method Tampering
The first (and simplest) method is using Method Tampering.
When you fill out and submit the form, it is submitted using a POST request.
The inputs are reflected in the response, so you can submit a name such as
Joe<script>alert(1)</script>
and the page will trigger an alert box, indicating an XSS vulnerability.
While developers often code up client-side forms to use a POST to send data to the server,
sometimes the actual endpoint in the server is more agnostic to the method used.
If you get the POST request into Burp Suite Pro, you'll see that it looks like this:
If you send this specific POST request to your Burp Suite Repeater, you can modify the
request before sending it. One of the first things to try with a POST based reflected XSS
vulnerability is to see if you can convert it to a GET request. If the backend accepts the
request as a GET and still executes the XSS payload, you can treat this as a normal XSS
vulnerability, and you can craft a malicious URL to trigger the XSS vulnerability. Burp Suite Pro provides an option in the context menu to convert between POST and GET requests:
Once the request is changed to a GET, you can resend the request in repeater, and see that the response is precisely the same.
This means you can provide a malicious link to users, and if they click the link
the payload will run in their browser. This is a much easier path to exploitation than a POST based
XSS vulnerability. Note that not all endpoints will accept POST or GET requests, but this is an
easy first thing to try. An example URL would be:
http://localhost/postForm?fname=Joe<script>alert(1)</script>&lname=Smith
Cross-Site Request Forgery (CSRF)
Let's see how to trigger the reflected POST based XSS using a CSRF attack. Unlike Method Tampering, this endpoint in the lab specifically requires the submission to be a POST request. We can still exploit this POST XSS vulnerability by crafting a CSRF attack to submit our payload. The form POST in question does not implement anti-CSRF tokens so it is vulnerable to traditional CSRF attacks. We can use a CSRF attack to submit our XSS payload. The easiest way to craft this attack is getting our form POST request into Burp Suite Pro.
Burp Suite Pro can generate the CSRF attack proof-of-concept for us. Right click on the request, select Engagement tools and then Generate CSRF PoC
This creates a proof-of-concept third-party webpage that can submit a form POST, including any XSS payload you need.
While the Burp Suite Pro proof-of-concept requires you to click a button to submit the malicious POST request, this could easily be rewritten to automatically submit the request using JavaScript.
Spoofed JSON using CSRF
For the last technique, we're looking at a variation on the CSRF attack. Unlike the prior two tutorials where a form POST allowed us to send our XSS payload, many applications send user inputs to the server in JSON. An HTML form cannot generate JSON, so form-based attacks will not work here. To create valid JSON we need JavaScript. We have quite the chicken and egg problem here: we can't inject our malicious JavaScript without JSON, which we can't generate without… JavaScript. Or maybe we can come close enough to fool the server. For this attack to work, the server endpoint receiving the JSON POST should not be enforcing the content-type as it should.
In a typical JSON POST, the JavaScript creating that POST will set the content-type to
application/json
We can use a traditional form based CSRF attack to create JSON-ish looking inputs, but we can't change the content-type to application/json without JavaScript. However, we're not allowed to run JavaScript on our third-party CSRF attack website in anyway that will interact with another site. So, this attack will only work against a JSON POST endpoint that processes the JSON input even if the content-type is wrong, specifically using the content-type of
application/x-www-form-urlencoded
or
text/plain
It's pretty rare to find such a configuration, but when you do, you can then configure your form post so that it sends almost JSON. Let's look at a normal HTML form POST:
Now, here's what a JSON formatted POST looks like:
We can see the formatting of the parameters is quite different from a traditional HTML form POST. However, we can almost perfectly reproduce this in a form POST. We can do this by putting the entire content of our desired JSON in the parameter name, leaving the value field empty, and only sending a single parameter. This attack proof-of-concept looks similar to the following:
Let's see what the request made from this page looks like.
This is pretty close to a valid JSON POST, but we have the wrong content-type and a random trailing '=', but it's close. You can create a CSRF attack that includes an XSS payload in the fake JSON data.
Running this CSRF attack will pop open the alert box in the lab.
If you have issues or ideas how this can be improved, or better methods of triggering reflected POST based XSS vulnerabilities, my DMs are always open! @hoodoer.
- https://github.com/hoodoer/postBasedXSS (Lab Repository)