Subdomain Delegation Takeover
Modifying tools to find vulnerable subdomain delegations.
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.
I will be using MassDNS to accomplish this. In my opinion, if you are not using MassDNS, you are doing it wrong.
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.
Therefore, the flow is as follows:
- Parse out SERVFAIL/REFUSED from our normal MassDNS logs
- Query the domain for their nameservers
- Set the authoritative nameserver as one of these nameservers
- Query the subdomain for its NS records using the domains nameservers
- If it responds with
subdomain.domain.com NS TTL othernameserver.comthen it has a subdomain delegation.
- 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:
- Run MassDNS on domain with a list of all subdomains to search for
- Do your normal DNS checks
- Grab subdomains that are NOERROR/REFUSED/SERVFAIL
- Get the domains nameservers to be used as an authoritative source
- Change your MassDNS resolvers.txt file to include these servers from step 4
- Try to resolve your subdomains from step 3 with the new resolvers.
- Find a NS record that has the subdomain pointing to a different nameserver
- Try to resolve the subdomain with the delegated nameservers.
- If it returns REFUSED/SERVFAIL it probably vulnerable.
- Try to get the right nameserver using the AWS Route53 api.
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.