2

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?

schroeder
  • 125,553
  • 55
  • 289
  • 326
SaAtomic
  • 1,009
  • 2
  • 17
  • 28
  • 3
    Credentialed requests aren't permitted with wildcard values for the `Access-Control-Allow-Origin` header, regardless of what other headers are provided. See https://developer.mozilla.org/en-US/docs/Web/HTTP/CORS for the details of that. – Matthew Sep 21 '18 at 08:05
  • Right @Matthew, thanks for the comment! If the `Access-Control-Allow-Origin` would specify the attackers domain, this would fail anyways as the `Access-Control-Allow-Credentials` header isn't set in the OPTIONS response, correct? – SaAtomic Sep 21 '18 at 08:18

2 Answers2

2

I've identified the issue. The CORS settings don't allow "withCredentials" as the server doesn't respond with Access-Control-Allow-Credentials: true, which is why the POST request isn't made.

Furthermore, as stated by @Matthew, with a wildcard for Access-Control-Allow-Origin, the Authorization header can't be sent.

SaAtomic
  • 1,009
  • 2
  • 17
  • 28
  • 1
    One option might be to see if you can send a request with credentials that won’t get preflighted. – user18519 Sep 21 '18 at 11:55
  • @user18519 what do you mean? If I make an xhr with custom header a preflight request will be made. The point is that the page uses the authorization header, which requires the `Access-Control-Allow-Credentials` response header and a specific origin. – SaAtomic Sep 21 '18 at 12:29
  • I don’t believe Authorization counts as a custom header. I see that you’re setting the content-type though. Does the server require it? Often they parse it as json no matter what you put. – user18519 Sep 21 '18 at 12:31
  • @user18519 The Content-Type is fine. The browser sends the defined Content-Type after the preflight request, just not with `xhr.withCredentials = true;`. Which I'd require, as the Authorization header is used. – SaAtomic Sep 21 '18 at 12:33
  • I would reread the documentation on allow-credentials. I know it’s possible to send with credentials and without it preflighting. – user18519 Sep 21 '18 at 12:39
  • I'll go ahead and check it out. – SaAtomic Sep 21 '18 at 13:19
  • @user18519 right, sorry! I misunderstood you. The server doesn't check the content-type and no preflight request is made. However the authorization header is not sent with the POST request, even with the ` xhr.withCredentials = true;`. – SaAtomic Sep 21 '18 at 13:36
1

The attack is possible , you do not need CORS and you do not need XHR to exploit , try the tricky json CSRF via swf file.

https://www.geekboy.ninja/blog/tag/json-csrf/

Yasser Gersy
  • 173
  • 1
  • 5
  • Thanks for the response! I'm trying to create a PoC .swf for the application. The swf doesn't send the `Authorization` header, right? or am I missing something? – SaAtomic Sep 21 '18 at 09:53