Skip to Main Content
July 06, 2023

Chaining Vulnerabilities to Exploit POST Based Reflected XSS

Written by Drew Kirkpatrick

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:

  1. Method Tampering
  2. Cross-Site Request Forgery (CSRF)
  3. 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
Figure 1 - XSS Lab Landing Page

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:

Figure 2 - Form POST Request in Burp Suite

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:

Figure 3 - Changing Request Method in Burp Suite

Once the request is changed to a GET, you can resend the request in repeater, and see that the response is precisely the same.

Figure 4 - GET Request Works

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.

Figure 5 - CSRF Form POST

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

Figure 6 - Burp Suite Pro Generating CSRF Proof-of-Concept

This creates a proof-of-concept third-party webpage that can submit a form POST, including any XSS payload you need.

Figure 7 - CSRF Proof-of-Concept

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:

Figure 8 - Normal Form POST

Now, here's what a JSON formatted POST looks like:

Figure 9 - JSON POST

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:

Figure 10 - Proof-of-Concept to Spoof JSON

Let's see what the request made from this page looks like.

Figure 11 - Spoofed JSON Request

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.

Figure 12 - Proof-of-Concept With JavaScript Payload

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.