CTF WriteUp: 0CTF 2016 / Monkey / web / 4 points
We are presented with a simple page that allows us to submit a URL which some monkey will browse for two minutes. In addition, the page says that we can find the flag at
127.0.0.1:8080/secret. The challenge page also asks what the same-origin policy is. Let’s start by answering that question.
The same-origin policy regulates that scripts shall only be allowed to access or request data from the origin from which they were loaded. An origin is defined by the URI scheme, the hostname and port.
As such, if we load our page from
http://foo.dollberg.xyz:8080 we are not allowed to do an XHR request to
http://127.0.0.1:8080 because the hostname is different.
The task of the challenge is now to circumvent this policy. While there exist several possibilities to circumvent the same-origin policy, such as explicitly allowing it using CORS, most of them require active help from the target domain.
My initial idea was to load the page via an image and then extract the data via html canvas elements. Second, was to load the flag page in an iframe and try to access it via some hacks of the
document.domain property. However, both of those failed.
At that point, two things came to my mind. First, I got suspicious of the hint which mentioned that the monkey will surf for two minutes on the page. Second, I remembered attacks on smart home devices in local home networks that used DNS to circumvent the same-origin policy. At this point, I was totally sure that this must be the way to solve it.
Specifically, the attack works like this. The victim browses a page that you control (e.g.:
/secret) after a certain amount time (110 seconds). If the DNS entry of
foo.dollberg.xyz has a very short TTL (60 seconds), the delayed request has to do an additional DNS request. However, by changing the DNS record in the meantime, the domain will resolve to the victim page (
There is only one last hurdle before we can make this happen. I use Cloudflare as a DNS provider for this page/domain. Unfortunately, Cloudflare only supports TTLs of two minutes. As a consequence, we first have to submit a different dummy link and wait some time so that the DNS record gets cached. The final procedure looks like this.
We create a DNS record for
foo.dollberg.xyz with the IP of our server (e.g.:
After that, we submit the dummy URL
http://foo.dollberg.xyz:8080/dummy. This causes the DNS query and the caching of the real IP. Then, we change the DNS record to point to localhost.
Now, we wait for a small amount of time, e.g.: 30 seconds. Then we submit a second link that contains our webpage
As the DNS record for
foo.dollberg.xyz is still cached it is loaded from the correct server and the page is being browsed for another 120 seconds. After 110 seconds the timeout fires. As the TTL has expired an additional DNS request is being made which resolves to
127.0.0.1. As a result, the request successfully accesses the
/secret page of
127.0.0.1:8080. Finally, we use an image tag to send the flag/data to another IP/domain of ours:
For a change, this was a really cool web challenge and not the usual PHP crap. In the meantime, I have learned from other write-ups that the attack is generally known as DNS rebinding.