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 :)
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
Post a Comment