Published by Security Testing and Assurance on 3 February 2023
This blog post discusses how the NSEC and NSEC3 DNSSEC records can be abused by attackers to identify valid DNS entries. We introduce a tool to allow penetration testers to carry out these attacks. We also present a whitepaper that examines attacks against NSEC3 in detail and demonstrates these attacks against top-trafficked Internet domains.
The Domain Name System (DNS) is the method by which domain names are resolved to IP addresses and other resources. Public (Internet-facing) DNS entries were never intended to be confidential, however entries that may be useful to attackers are routinely found in DNS records. If an attacker knows that a domain like 𝚝𝚎𝚖𝚙-𝚌𝚘𝚙𝚢-𝚘𝚏-𝚙𝚛𝚘𝚍-𝚍𝚊𝚝𝚊𝚋𝚊𝚜𝚎𝟹𝟾𝟺𝟿𝟸𝟺𝟾𝟹𝟿𝟸𝟺𝟸𝟹.𝚎𝚡𝚊𝚖𝚙𝚕𝚎.𝚌𝚘𝚖 exists, this is invaluable for them to target their attacks.
In the earlier days of the Internet, it was common to be able to get a list of all valid domains in a zone using a DNS query known as a Zone Transfer. To prevent leaking information about valid domains to attackers, it now commonplace for DNS servers to prevent zone transfers from unauthorised sources.
Even without the ability to perform zone transfers, attackers have several mechanisms available to identify valid DNS records, such as:
- Brute-forcing DNS queries (using wordlists of likely domains to assist)
- Certificate transparency logs
- Domains embedded in code, leaked from APIs etc.
While these mechanisms may recover many records:
- They can be very noisy (brute-forcing / wordlists)
- There is no guarantee the results are complete
- It is difficult to find complex records e.g 𝚢𝚘𝚞-𝚠𝚒𝚕𝚕.𝚗𝚎𝚟𝚎𝚛.𝚏𝚒𝚗𝚍-𝚖𝚎-𝟹𝟾𝟺𝟿𝟸𝟺𝟾𝟹𝟿𝟸𝟺𝟸𝟹.𝚎𝚡𝚊𝚖𝚙𝚕𝚎.𝚌𝚘𝚖 if there is no associated PKI TLS certificate that will identify the domain in certificate transparency logs.
If DNS servers make use of DNSSEC, this adds an additional mechanism that attackers can use to retrieve DNS records – in some cases entire zones.
DNSSEC is a suite of extension specifications to DNS that provides authentication and data integrity to the DNS protocol (but importantly, does not provide availability or confidentiality protections). DNSSEC does this by signing DNS records in a way that is verifiable through a chain of trust. One issue the implementors of DNSSEC grappled with is how do you a sign the response to a query for a record that doesn’t exist?
In traditional DNS without DNSSEC, if you were to lookup a non-existent record, you’d get a DNS NXDOMAIN (non-existent domain) error:
$ 𝚍𝚒𝚐 𝚊 𝚗𝚘𝚗-𝚎𝚡𝚒𝚜𝚝𝚎𝚗𝚝.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖 @𝚗𝚜𝟷.𝚙𝟻𝟽.𝚍𝚢𝚗𝚎𝚌𝚝.𝚗𝚎𝚝.
With a DNSSEC-aware resolver, if you were to lookup an existing record you will get the answer, and the RRSIG (record set signature) to authenticate the answer and make sure it wasn’t tampered with:
$ 𝚍𝚒𝚐 𝚊 𝚠𝚠𝚠.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚗𝚜𝟷.𝚙𝟻𝟽.𝚍𝚢𝚗𝚎𝚌𝚝.𝚗𝚎𝚝.
𝚁𝚁𝚂𝙸𝙶 𝙲𝙽𝙰𝙼𝙴 𝙶𝚝…𝚂𝙸𝙶𝙽𝙰𝚃𝚄𝚁𝙴…𝟹𝚈=
Combining the two, what happens if you look up a non-existent record with a DNSSEC-aware resolver?
$ 𝚍𝚒𝚐 𝚗𝚘𝚗-𝚎𝚡𝚒𝚜𝚝𝚎𝚗𝚝.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚗𝚜𝟷.𝚙𝟻𝟽.𝚍𝚢𝚗𝚎𝚌𝚝.𝚗𝚎𝚝.
𝚗𝚍𝚖-𝚜𝚜𝚙.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖. 𝙽𝚂𝙴𝙲 𝚗𝚘𝚝𝚒𝚏𝚒𝚌𝚊𝚝𝚒𝚘𝚗𝚜.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖. 𝙲𝙽𝙰𝙼𝙴 𝚁𝚁𝚂𝙸𝙶 𝙽𝚂𝙴𝙲
NSEC (Next Secure) Records
What happened in the response above? The server can’t sign an empty record, but it also can’t not authenticate the empty response, because while a Person-in-the-Middle might not be able to tamper with DNS responses, they could respond with NXDOMAIN to all requests in a “denial of existence” attack.
DNSSEC’s first solution to authenticate non-existent records, known as NSEC (Next Secure), is to return a range for which there are no records. In the example above, we looked up non-existent and the Paypal DNS resolver responded with “𝙸 𝚍𝚘𝚗’𝚝 𝚑𝚊𝚟𝚎 𝚊𝚗𝚢 𝚛𝚎𝚌𝚘𝚛𝚍𝚜 𝚋𝚎𝚝𝚠𝚎𝚎𝚗 𝚗𝚍𝚖-𝚜𝚜𝚙 𝚊𝚗𝚍 𝚗𝚘𝚝𝚒𝚏𝚒𝚌𝚊𝚝𝚒𝚘𝚗𝚜”. The RFC requires these ranges are returned in alphabetical order, and that they wrap. As a bonus, it also gives all the record types for the start of the range, now we 𝚔𝚗𝚘𝚠 𝚝𝚑𝚊𝚝 𝚗𝚍𝚖-𝚜𝚜𝚙 𝚘𝚗𝚕𝚢 has a CNAME record (ignoring the RRSIG and NSEC records).
The fact that looking up a non-existent domain reveals existent domains in the response is extremely useful to an attacker trying to identify valid domains. In fact, it is possible to iteratively look up non-existent domains, collect the ranges, then look up the records to retrieve every record for a domain:
$ 𝚍𝚒𝚐 𝚊 𝟶.𝚍𝚎𝚟𝚋𝚕𝚘𝚐.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚗𝚜𝟷.𝚙𝟻𝟽.𝚍𝚢𝚗𝚎𝚌𝚝.𝚗𝚎𝚝.
𝚍𝚎𝚟𝚋𝚕𝚘𝚐.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖. 𝙽𝚂𝙴𝙲 𝚍𝚎𝚟𝚎𝚕𝚘𝚙𝚎𝚛.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖. 𝙰 𝚁𝚁𝚂𝙸𝙶 𝙽𝚂𝙴𝙲
$ 𝚍𝚒𝚐 𝚊 𝟶.𝚍𝚎𝚟𝚎𝚕𝚘𝚙𝚎𝚛.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚗𝚜𝟷.𝚙𝟻𝟽.𝚍𝚢𝚗𝚎𝚌𝚝.𝚗𝚎𝚝.
𝚍𝚎𝚟𝚎𝚕𝚘𝚙𝚎𝚛.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖. 𝙽𝚂𝙴𝙲 𝚍𝚒𝚜𝚙𝚞𝚝𝚎𝚜.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖. 𝙲𝙽𝙰𝙼𝙴 𝚁𝚁𝚂𝙸𝙶 𝙽𝚂𝙴𝙲
$ 𝚍𝚒𝚐 𝚊 𝟶.𝚍𝚒𝚜𝚙𝚞𝚝𝚎𝚜.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚗𝚜𝟷.𝚙𝟻𝟽.𝚍𝚢𝚗𝚎𝚌𝚝.𝚗𝚎𝚝.
𝚍𝚒𝚜𝚙𝚞𝚝𝚎𝚜.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖. 𝙽𝚂𝙴𝙲 𝚍𝚕.𝚙𝚊𝚢𝚙𝚊𝚕.𝚌𝚘𝚖. 𝙲𝙽𝙰𝙼𝙴 𝚁𝚁𝚂𝙸𝙶 𝙽𝚂𝙴𝙲
To address these obvious shortcomings with NSEC, DNSSEC offers an alternative mechanism known as NSEC3. NSEC3 attempts to prevent the leaking of valid records by hashing returned ranges. Importantly, the ranges still correspond to valid domain records.
$ 𝚍𝚒𝚐 𝚊 𝚗𝚘𝚗-𝚎𝚡𝚒𝚜𝚝𝚎𝚗𝚝.𝚍𝚒𝚜𝚌𝚘𝚟𝚎𝚛.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚊𝟹-𝟼𝟺.𝚊𝚔𝚊𝚖.𝚗𝚎𝚝.
𝟽𝚚𝚖𝚎𝚊𝚚𝚘𝚖… 𝙽𝚂𝙴𝙲𝟹 𝟽𝚃𝟽𝟼𝟹𝚁𝚃𝙷… 𝙲𝙽𝙰𝙼𝙴 𝚁𝚁𝚂𝙸𝙶
Because results are hashed, it is no longer possible for an attacker to simply enumerate valid domains. However, the hashes are still hashes of valid domains. The hashing algorithm, salt, iterations, and plaintext are all known, so it is possible for an attacker to hash candidates locally. Recovering valid domains becomes a two-step process:
- The attacker can enumerate all range hashes by iteratively generating hashes locally. Once a hash is generated that falls within a range that is yet to be observed in a response, that request is sent to the nameserver to get new hashed ranges. This process is repeated until all hashed ranges have been retrieved.
- The retrieved hashes can be cracked offline
An example showing the retrieval of multiple hashed ranges is shown below:
$ 𝚍𝚒𝚐 𝚊 𝟶𝟶𝟶𝟶.𝚍𝚒𝚜𝚌𝚘𝚟𝚎𝚛.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚊𝟹-𝟼𝟺.𝚊𝚔𝚊𝚖.𝚗𝚎𝚝.
𝚜𝚋𝟶𝟷𝟷𝟾𝚝𝚜… 𝙽𝚂𝙴𝙲𝟹 𝚂𝙱𝙱𝙻𝚃𝙰𝟽𝟶… 𝙲𝙽𝙰𝙼𝙴
$ 𝚍𝚒𝚐 𝚊 𝟻𝟺𝟹𝟷.𝚍𝚒𝚜𝚌𝚘𝚟𝚎𝚛.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚊𝟹-𝟼𝟺.𝚊𝚔𝚊𝚖.𝚗𝚎𝚝.
𝚋𝚑𝟾𝚙𝟷𝚙𝟸𝚋… 𝙽𝚂𝙴𝙲𝟹 𝙱𝙸𝙽𝙺𝙰𝟽𝙶𝙾… 𝙲𝙽𝙰𝙼𝙴
$ 𝚍𝚒𝚐 𝚊 𝚏𝚍𝟾𝚎.𝚍𝚒𝚜𝚌𝚘𝚟𝚎𝚛.𝚌𝚘𝚖 +𝚍𝚗𝚜𝚜𝚎𝚌 @𝚊𝟹-𝟼𝟺.𝚊𝚔𝚊𝚖.𝚗𝚎𝚝.
𝚞𝟹𝚊𝚋𝟸𝚌𝚍𝚞… 𝙽𝚂𝙴𝙲𝟹 𝚄𝟺𝙼𝚅𝟶𝟿𝚀𝟸… 𝙰 𝙼𝚇 𝚃𝚇𝚃
There are a few items to note about attacking NSEC3:
- Hashes are salted with a salt and the domain, so rainbow tables are of no use
- NSEC3 uses the SHA-1 hashing algorithm, so cracking is fast compared with more modern cryptographic hashing algorithms
- It is possible to estimate the number of valid records in a DNS zone from the hash range returned in NSEC3 responses. For example, if a returned hash range covers 5% of the possible hashes, it can be deduced that there will be roughly 20 records in the domain. The more hash ranges that are observed, the greater the certainty of this calculation.
Tooling to attack NSEC3
To allow security testers to more easily validate issues with NSEC and NSEC3 configuration, we are releasing a tool to automate these attacks – “NSEC(3) Walker 🚶♂️“. It has 3 modes (the README has far more detail):
- NSEC walking + dumping
- NSEC3 walking
- NSEC3 post-crack dumping
In the associated Whitepaper Taking the DNS for a Walk; NSEC3 Prevalence and Recoverability, we also take a deeper dive into the theory behind attacking NSEC3 and demonstrate practical use of these methods against real-world targets. It demonstrates a GPU-based attack on NSEC3 that recovered 44% of names for the internet’s top 20,000 NSEC3-protected DNS zones, partially invalidating NSEC3’s privacy and security goals.
This blog post, associated whitepaper, and tool are the work of Harrison Mitchell of CyberCX. The research builds on previous attacks against DNSSEC. For a full list of references, please see the associated Whitepaper.