Exploiting Misconfigured CORS

Hi folks, 

This post is about some of the CORS misconfiguration which I see frequently, mostly in Django applications.

Let’s assume all the test cases have been performed on the domain example.com

Following are the most common CORS configurations 

• Access-Control-Allow-Origin: *
       • Remark: In this case we can fetch unauthenticated resources only.

• Access-Control-Allow-Origin: *
          Access-Control-Allow-Credentials: true
      • Remark: In this case we can fetch unauthenticated resources only.

• Access-Control-Allow-Origin: null
          Access-Control-Allow-Credentials: true
      • Remark: In this case we can fetch authenticated    resources as well.

• Access-Control-Allow-Origin: https://attacker.com
          Access-Control-Allow-Credentials: true
     • Remark: In this case we can fetch authenticated resources as well.

• Access-Control-Allow-Origin: https://example.com
          Access-Control-Allow-Credentials: true
    • Remark: Properly implemented

So we usually see these type of CORS configuration in response headers and most of us don’t try to exploit it because we think it’s properly implemented. But that’s not true. 

Let’s study some of the weird CORS misconfiguration cases.


• I have found this vulnerability in one of most popular python web hosting site which has following request and response headers shown below -

Original Request and response headers

GET /<redacted> HTTP/1.1
Host: dummy.example.com
User-Agent: <redacted>
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer:  <redacted>
Origin: https://www.example.com
Connection: close

HTTP/1.1 200 OK
Server: <redacted>
Date: <redacted>
Content-Type: application/json; charset=UTF-8
Content-Length: 87
Connection: close
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://www.example.com
Strict-Transport-Security: max-age=31536000;

So looking at the response headers, you can see CORS is  implemented correctly and most of us don’t test it further. At this point most of time I have seen that by changing the value of origin header would reflect back in response headers as following.

Edited Request and response headers

GET /<redacted>HTTP/1.1
Host: dummy.example.com
User-Agent: <redacted>
Accept: */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate
Referer: <redacted>
Origin: https://attacker.com
Connection: close 

HTTP/1.1 200 OK
Server: <redacted>
Date: <redacted>
Content-Type: application/json; charset=UTF-8
Content-Length: 87
Connection: close
Cache-Control: no-store, no-cache, must-revalidate, max-age=0
Access-Control-Allow-Credentials: true
Access-Control-Allow-Origin: https://attacker.com
Strict-Transport-Security: max-age=31536000;

• I have found this vulnerability in one of the bitcoin website which has the following request and response headers.

Original Request and response headers

POST /<redacted> HTTP/1.1
Host: <redacted>
User-Agent: <redacted>
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded;charset=utf-8
Referer: <redacted>
Content-Length: 270
Cookie: <redacted>
Connection: close

 HTTP/1.1 200 OK
 Server: nginx
 Date: <redacted>
 Content-Type: application/json
 Connection: close
 Access-Control-Allow-Credentials: true
 Content-Length: 128

Looking at the response you can see Access-Control-Allow-Origin header is missing so I added origin header in http request which makes it vulnerable as following.

Edited Request and response headers

POST /<redacted>HTTP/1.1
Host: <redacted>
User-Agent: <redacted>
Accept: application/json, text/plain, */*
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded;charset=utf-8
Origin: https://attacker.com
Referer: <redacted>
Content-Length: 270
Cookie: <redacted>
Connection: close

HTTP/1.1 200 OK
Server: nginx
Date: <redacted>
Content-Type: application/json
Connection: close
Access-Control-Allow-Origin: https://attacker.com
Access-Control-Allow-Credentials: true
Content-Length: 128

Thanks for reading :)





Comments

Popular posts from this blog

How I bypassed 2-Factor Authentication in a bug bounty program

Story of a JSON XSS