GraphQL CSRF Demo
- Shone Pious
- Jul 3, 2024
- 3 min read
Updated: Jul 5, 2024

In this blog:
➡️ Find my blog on exposing private GraphQL endpoints here.
Exploring POST requests through Burpsuite
Open up Burpsuite and start the Chromium browser.
Load up the lab which will allow us to perform CSRF exploits over GraphQL.

Sign into the account using the given credentials (Wiener:Peter). We can now change the email address for this user.

Checking Burpsuite shows us the GraphQL requests being made to the database, to retrieve a blogpost from the website.

Let’s check another GraphQL request.
We see here a mutation request, allowing us to log into our account.

Playing with variables
Another mutation request allowing us to change our user email address.
This is the request which we will be using as part of our attack.

Right click the request and send to Repeater.

Inside the Repeater tab, if we go over into the GraphQL tab, we can see that the request simply uses variables to change the email address based on user input and inserts it into the ‘email’ variable.

It doesn’t matter whether we have “$input” or the actual value in the request body, as GraphQL will accept either method. Lets make it easier for ourselves, and modify the query to have no variables and take our updated email address as the value.
If we use this modified query and hit send, we will receive a 200 OK message. The email has been changed just like before, but with a variable-less query.

'Content-Type'
Going back to the raw request, we can see the content-Type is ‘application-json’. Application/json separates key value pairs using colons and commas.
We can change the content-Type and insert our own queries which we can then run to make the server do different things.

Right-click the left pane and click ‘change request method’.
The content-Type changes to application/x-www-form-urlencoded.

When running this request, we get a ‘Query not present’ message. This means that there is a GraphQL endpoint accepting queries but this isn’t a supported one. We must change the request to fit the ‘urlencoded’ format.

Copy and paste the modified GraphQL query from before, highlight it and click ‘control+U’ to url-encode the selection. When we run the request, we get a 200 OK. It works.

Crafting the payload
The server is accepting different content types and there is no CSRF token present. We know that it may be vulnerable to cross-site request forgery attacks. Let’s craft a malicious HTML script and send the request to the server to change anyone’s email address.
Start typing the HTML script. We need a ‘form action’ tag which holds the URL of the request page that we sent to the Repeater in Burpsuite, with the method ‘POST’. Inside this form tag we also need three input tags. I have named the first input tag ‘query’, and its value will be the mutation query from before. To encode it in HTML so that the server can understand it, we will use the decoder function in Burpsuite.
Go to the decoder tab and paste in the query. Encode it as html.
Copy and paste the encoded query into the value for the query input tag in our html script. Add ‘type=”hidden’ at the end.
inside the request variables, copy the variables and paste it into the decoder.

Encode this selection as html like before.

Copy and paste this into the value section of our third ‘variables’ input tag.
We also need to add an input tag named ‘OperationName’ which will be for our mutation query. The value for this will be ‘changeEmail’.
At the end of the value section of each input tag, add the ‘type=”hidden’ message.

Finally, add a script tag with ‘document.forms[0].submit():’ which basically just runs the script as soon as we send it to the victim’s server.

Deliver the exploit
Once you have finished the script, click ‘store’ at the bottom.
Now click ‘Deliver exploit to victim’.
If nothing happens, it may be because the email address you passed as the value for the variable is the same as before. You will need to change this to something else.
Simply go to the decoder again and change the email to anything else, encode it as html and paste It into the variables tag value in place of the old value.

Store and deliver exploit to victim again.
Lab complete!
Thank you for reading!
Comments