Escalating subdomain takeovers to steal cookies by abusing document.domain
Hi everyone,
It's been a really long time since I've blogged about anything. Mainly because I got a job as security analyst- therefore I've been very busy. And I also got into Synack!
This blog post focuses on one of my recent findings, how I was able to escalate an out of scope subdomain takeover to steal the session cookies. And how I also thought of a few more methods to escalate it, affecting the main domain.
Before I get started with the bug, I would like to talk a little about same-origin policy. If 2 websites want to communicate with each other, or perhaps if 2 hosts want to interact with each other, there could be mainly 2 ways to go around this. The book "Tangled Web" (a great book, do read it) states the following:
"Attempts to broaden origins or facilitate cross-domain interactions are more common. The two broadly sup- ported ways of achieving these goals are document.domain and postMessage(...)"
It's been a really long time since I've blogged about anything. Mainly because I got a job as security analyst- therefore I've been very busy. And I also got into Synack!
This blog post focuses on one of my recent findings, how I was able to escalate an out of scope subdomain takeover to steal the session cookies. And how I also thought of a few more methods to escalate it, affecting the main domain.
Before I get started with the bug, I would like to talk a little about same-origin policy. If 2 websites want to communicate with each other, or perhaps if 2 hosts want to interact with each other, there could be mainly 2 ways to go around this. The book "Tangled Web" (a great book, do read it) states the following:
"Attempts to broaden origins or facilitate cross-domain interactions are more common. The two broadly sup- ported ways of achieving these goals are document.domain and postMessage(...)"
DOCUMENT.DOMAIN
This JavaScript property permits any two cooperating websites that share a common top-level domain (such as example.com, or even just .com) to agree that for the purpose of future same-origin checks, they want to be considered equivalent.
So basically, if login.example.com and www.example.com both explicitly set their document.domain to example.com, this will lax the same-origin policy checks thereafter.
https://raster-static.postmates.com/?url=
Now this endpoint was only was only accepting image links coming from subdomains of postmates.com. I thought, if somehow I can find a subdomain takeover, maybe I can find an SSRF or perhaps serve my own malicious content to the victim. So I went ahead and fired up some subdomain discovery tools and started sifting through them. I found one subdomain, impact.postmates.com, which was prone to a Github subdomain takeover. I went ahead and added the custom domain name to my test repo and the subdomain was mine.
However, I couldn't have access to any backend, so an SSRF was impossible in this case. The max I could do was serve random JPEG's. Bummer.
After a lot of time of thinking, something struck my mind. The main domain for users in Postmates is, postmates.com.
Now, "Tangled Web" also states:
"Simply because login.example.com has set its document.domain to example.com does not mean that it will be allowed to access content originating from the website hosted at http://example.com/. That website needs to perform such an assignment, too, even if common sense would indicate that it is a no-op."
So, if and only if, postmates.com has explicitly set it's document.domain, maybe I could set impact.postmates.com's document.domain to postmates.com and access it's cookies somehow?
Precursor: a.xyz.com can NOT set it's document.domain to a.a.xyz.com or b.xyz.com, but it CAN set it's document.domain to xyz.com. An example of changing the values of blog.takemyhand.xyz to other settings:
So basically, if login.example.com and www.example.com both explicitly set their document.domain to example.com, this will lax the same-origin policy checks thereafter.
Exploitation
I was hunting on the Postmates bug bounty program from H1. Now this program has a limited scope. I came across an [[in-scope]] endpoint like the following:https://raster-static.postmates.com/?url=
Now this endpoint was only was only accepting image links coming from subdomains of postmates.com. I thought, if somehow I can find a subdomain takeover, maybe I can find an SSRF or perhaps serve my own malicious content to the victim. So I went ahead and fired up some subdomain discovery tools and started sifting through them. I found one subdomain, impact.postmates.com, which was prone to a Github subdomain takeover. I went ahead and added the custom domain name to my test repo and the subdomain was mine.
However, I couldn't have access to any backend, so an SSRF was impossible in this case. The max I could do was serve random JPEG's. Bummer.
After a lot of time of thinking, something struck my mind. The main domain for users in Postmates is, postmates.com.
Now, "Tangled Web" also states:
"Simply because login.example.com has set its document.domain to example.com does not mean that it will be allowed to access content originating from the website hosted at http://example.com/. That website needs to perform such an assignment, too, even if common sense would indicate that it is a no-op."
So, if and only if, postmates.com has explicitly set it's document.domain, maybe I could set impact.postmates.com's document.domain to postmates.com and access it's cookies somehow?
Precursor: a.xyz.com can NOT set it's document.domain to a.a.xyz.com or b.xyz.com, but it CAN set it's document.domain to xyz.com. An example of changing the values of blog.takemyhand.xyz to other settings:
That being said, I went ahead to check if postmates.com had explicitly set their document.domain. They had! Now, you have to keep in mind, that this attack worked only because the main domain of the program was postmates.com (that is, document.domain = postmates.com) and not something like www.postmates.com (document.domain possibly set to www.postmates.com, because then I could not set the document.domain of impact.postmates.com to www.postmates.com). So now all I had to do was, using JS, set the document.domain to postmates.com, and add the following code in my javascript to steal the cookies from the main account:
While working on this, I even thought of a few other creative ways to escalate an subdomain takeover to increase it's impact:
- Bypassing X-Frame-Options : SAMEORIGIN
- Bypassing CORS validation where the Access-Control-Allow-Origin is set to *.example.com (* being any subdomain)
- Bypassing URL validation wherever applicable (eg. open redirects to steal OAuth login tokens etc.
Regards,
t4kemyh4nd