Subdomain Delegation Takeover

Modifying tools to find vulnerable subdomain delegations.

Subdomain Delegation

If you have not watched the talk that Frans Rosen gave about DNS Hijacking, then you should probably watch it. In his talk, he mentions a problem that subdomain delegations have, and how they can also be taken over if the circumstances are correct. An interesting note is that any existing hijacking tooling was not checking for these problems (to my knowledge). Therefore, you must supplement your current DNS scanning and checks with a new method for complete coverage.

The tools

I will be using MassDNS to accomplish this. In my opinion, if you are not using MassDNS, you are doing it wrong.

The flow

We do our normal MassDNS scanning for subdomains, except now we are looking for subdomains that point to their own nameservers (instead of the apex pointing to nameservers). However, this is a bit trickier than stated.

In normal queries we will not get what nameserver is responsible for the subdomain, it happens behind the scenes. In order to get this information, using dig subdomain.site.com +trace is suggested. Run this dig command on any website and you will see that it is not scalable. The time that the trace takes is too long when you are hitting every open bug bounty.

A better solution

Read the man page on dig’s +trace option if you want. The important note is that it will keep querying incrementally, setting the authoritative server as it goes. An example looks like the following:

~ dig awsdns.offsecbyautomation.com +trace

; <<>> DiG 9.9.5-3ubuntu0.14-Ubuntu <<>> awsdns.offsecbyautomation.com +trace
;; global options: +cmd
.			85645	IN	NS	d.root-servers.net.
.			85645	IN	NS	k.root-servers.net.
.			85645	IN	NS	a.root-servers.net.
.			85645	IN	NS	i.root-servers.net.
.			85645	IN	NS	l.root-servers.net.
.			85645	IN	NS	c.root-servers.net.
.			85645	IN	NS	h.root-servers.net.
.			85645	IN	NS	f.root-servers.net.
.			85645	IN	NS	e.root-servers.net.
.			85645	IN	NS	j.root-servers.net.
.			85645	IN	NS	m.root-servers.net.
.			85645	IN	NS	b.root-servers.net.
.			85645	IN	NS	g.root-servers.net.

com.			172800	IN	NS	a.gtld-servers.net.
com.			172800	IN	NS	h.gtld-servers.net.
com.			172800	IN	NS	m.gtld-servers.net.
com.			172800	IN	NS	k.gtld-servers.net.
com.			172800	IN	NS	f.gtld-servers.net.
com.			172800	IN	NS	l.gtld-servers.net.
com.			172800	IN	NS	d.gtld-servers.net.
com.			172800	IN	NS	i.gtld-servers.net.
com.			172800	IN	NS	b.gtld-servers.net.
com.			172800	IN	NS	c.gtld-servers.net.
com.			172800	IN	NS	e.gtld-servers.net.
com.			172800	IN	NS	g.gtld-servers.net.
com.			172800	IN	NS	j.gtld-servers.net.

offsecbyautomation.com.	172800	IN	NS	a.dns.gandi.net.
offsecbyautomation.com.	172800	IN	NS	b.dns.gandi.net.
offsecbyautomation.com.	172800	IN	NS	c.dns.gandi.net.

awsdns.offsecbyautomation.com. 10800 IN	NS	ns-641.awddns-16.net.
awsdns.offsecbyautomation.com. 10800 IN	NS	ns-1474.awsdns-56.org.
awsdns.offsecbyautomation.com. 10800 IN	NS	ns-1606.awsdns-08.co.uk.
awsdns.offsecbyautomation.com. 10800 IN	NS	ns-78.awsdns-09.com.

Notice we can get the same end output (the good stuff) without the +trace flag slowing us down:

~ dig NS offsecbyautomation.com
...

;; ANSWER SECTION:
offsecbyautomation.com.	10799	IN	NS	a.dns.gandi.net.
offsecbyautomation.com.	10799	IN	NS	b.dns.gandi.net.
offsecbyautomation.com.	10799	IN	NS	c.dns.gandi.net.

...

~ dig @a.dns.gandi.net awsdns.offsecbyautomation.com

...

;; AUTHORITY SECTION:
awsdns.offsecbyautomation.com. 10800 IN	NS	ns-1474.awsdns-56.org.
awsdns.offsecbyautomation.com. 10800 IN	NS	ns-1606.awsdns-08.co.uk.
awsdns.offsecbyautomation.com. 10800 IN	NS	ns-641.awddns-16.net.
awsdns.offsecbyautomation.com. 10800 IN	NS	ns-78.awsdns-09.com.

The first command

 ~ dig NS offsecbyautomation.com

gets the NS servers responsible for the domain. With those nameservers ([a,b,c].dns.gandi.net), we can set the authoritative nameserver to check where the subdomain is pointing.

~ dig @[a,b,c].dns.gandi.net awsdns.offsecbyautomation.com

Therefore, we bypass using the trace flag, and get the same output.

The reason that we want to accomplish the task this way, is that we can actually leverage MassDNS and its ability to spread out the resolution for fast results – much faster than using +trace. In this method, you will bypass tracing the root DNS servers which do not matter for our task, and also not get extra information that we will not use.

New flow

Therefore, the flow is as follows:

  1. Parse out SERVFAIL/REFUSED from our normal MassDNS logs
  2. Query the domain for their nameservers
  3. Set the authoritative nameserver as one of these nameservers
  4. Query the subdomain for its NS records using the domains nameservers
  5. If it responds with subdomain.domain.com NS TTL othernameserver.com then it has a subdomain delegation.
  6. Check if those delegations are vulnerable

In the talk it is mentioned that Amazon Route53 could be vulnerable (a subdomain with NS to awsdns.com). To see if it is vulnerable, take each awsdns nameserver from step 4, and then check if the subdomain resolves using those as authoritative.

~ dig subdomain.domain.com @something.aws-dns.com

If it returns with a status SERVFAIL/REFUSED, it is probably vulnerable. At this point you will want to generate zone files from Route53 via their API. Since Route53 gives you random nameservers, you will keep regenerating the zone file until you get one of the nameservers that appear in step 4. Once you get it, you are able to set the DNS information for the subdomain.

In order to scale this solution, you take the domains nameservers from step 2, and use them as the resolver file for MassDNS. That way, you will get the authoritative answers for the domain and let MassDNS do the scaling for you.

A deeper flow is now as follows:

Final flow

  1. Run MassDNS on domain with a list of all subdomains to search for
  2. Do your normal DNS checks
  3. Grab subdomains that are NOERROR/REFUSED/SERVFAIL
  4. Get the domains nameservers to be used as an authoritative source
  5. Change your MassDNS resolvers.txt file to include these servers from step 4
  6. Try to resolve your subdomains from step 3 with the new resolvers.
  7. Find a NS record that has the subdomain pointing to a different nameserver
  8. Try to resolve the subdomain with the delegated nameservers.
  9. If it returns REFUSED/SERVFAIL it probably vulnerable.
  10. Try to get the right nameserver using the AWS Route53 api.
  11. ???
  12. Profit

Why should I check NOERRORs? Its possible the server that successfully answered your query is operating in round-robin. There could be another vulnerable nameserver that wasn’t responsible for serving your request. This could be overkill though.

In this post I intentionally did not give any code to do this. In order to truly understand the bug and this process I recommend that you code it yourself.

Good luck.

Written on June 14, 2017