Recon Wave

Enumerating DNS zones using NSEC

Recon Wave helps organizations protect their external attack surfaces. While enumerating all DNS records isn't inherently a security risk, it can reveal unnecessary information to adversaries. This information might lead to unpatched services, shadow IT, supply chain details, or generally to insights of the organization's infrastructure.

In this post, we want to raise awareness about a technique that's less commonly supported nowadays but still relevant in some cases: DNS zone enumeration using NSEC (and occasionally NSEC3) records.

Recon Wave Logo

When it comes to DNS zone enumeration, people usually think about DNS zone transfers using AXFR type, gathering domains from various OSINT sources, or brute-forcing. However, fewer people are aware of the technique involving NSEC records.

What is NSEC?

NSEC, introduced in RFC4033 in 2005, stands for NextSECure and is part of the DNSSEC extension. It provides a secure proof of non-existence for DNS records. In DNSSEC, all records are cryptographically signed to ensure data authenticity and integrity. But when a queried record doesn't exist, there's nothing to sign. NSEC solves this by providing signed records for the first lexicographically smaller and larger records of the queried domain.

Consider the following A records in a DNS zone:

example.com.		3600	IN	SOA	ns1.example.com. hostmaster.example.com. 1 10800 3600 604800 3600
admin.example.com.		3600	IN	A	192.168.0.1
dev.example.com.		3600	IN	A	192.168.0.2
grafana.example.com.		3600	IN	A	192.168.0.3
internal.example.com.		3600	IN	A	192.168.0.4
login.example.com.		3600	IN	A	192.168.0.5
secret.example.com.		3600	IN	A	192.168.0.6
www.example.com.		3600	IN	A	192.168.0.7

If the zone supports NSEC records and we query for example monitoring.example.com, the authoritative server might respond with:

login.example.com.		3600	IN	NSEC	secret.example.com. A RRSIG NSEC

Translated to human readable form, this effectively says:

There is no record monitoring.example.com but the previous and next records are login.example.com and secret.example.com.

As you already probably think, this technique (known as Zone Walking) allows us to enumerate all records in a DNS zone. There are many open-source tools exploiting this functionality, such as the for example dns-nsec3-enum script in nmap.

Real World Example

Despite the limited support for the original NSEC feature, we still encounter exceptions. For example, the .se zone (TLD of Sweden) supports NSEC. The Internet Foundation in Sweden states that: “there is no confidential information in zone files“, and they publish the entire DNS zone records hourly. That's why in this case, adversaries do not need Zone Walking to obtain all zone records.

> dig doesnotexist.se nsec
...

;; AUTHORITY SECTION:
se.			7200	IN	SOA	catcher-in-the-rye.nic.se. registry-default.nic.se. 2024080612 1800 1800 864000 7200
se.			7200	IN	NSEC	0.se. NS SOA TXT RRSIG NSEC DNSKEY
doesnotcompute.se.	7200	IN	NSEC	doesntsuckbutyoudo.se. NS DS RRSIG NSEC

...

Here, querying non-existent domain doesnotexist.se reveals information about two existing domains - doesnotcompute.se and doesntsuckbutyoudo.se.

Due to criticism, NSEC3 was introduced as an improvement over NSEC. Unlike NSEC, NSEC3 does not reveal existing records in plaintext but returns them as salted hashes. Let's see an example by querying the same domain under a different TLD.

> dig +dnssec doesnotexist.cz
...

;; AUTHORITY SECTION:
jsjplp2o5mj1jcdn19in7a7s69gpfc9k.cz. 900 IN NSEC3 1 0 0 58CE8A3BC93CDA95 JSJR2C25GAQ26ED7S3LL3LSGQU8J6UMD NS DS RRSIG
jsjplp2o5mj1jcdn19in7a7s69gpfc9k.cz. 900 IN RRSIG NSEC3 13 2 900 20240817082134 20240803065134 51492 cz. Bg6MhdU8IAwTzhe82J374302Kndiq1HqcfAp8F+nQiBGds1VpUPeMMIj xtMzUbtE/VTdoUDvtnuenKvKJwFkDg==
huplsheg7b0rac930a2ff0hsvqreaf42.cz. 900 IN NSEC3 1 0 0 58CE8A3BC93CDA95 HUPLTPT925LJTTP5DPU5U68591HFLDTB NS SOA RRSIG DNSKEY NSEC3PARAM
huplsheg7b0rac930a2ff0hsvqreaf42.cz. 900 IN RRSIG NSEC3 13 2 900 20240817082134 20240803065134 51492 cz. 29slOMnd+be1YRA/onH5r5LlteRTj7onxcbfRsJnx9Khr1tgMn4mFdmX vBX6qiinLZG7D4JltaJBjyr15C5BIQ==
dvg522s7d6l85618g28ajlb3v2siheh6.cz. 900 IN NSEC3 1 0 0 58CE8A3BC93CDA95 DVG70GDR6DTIML48DKTMUH5QP7JSBE52 NS
dvg522s7d6l85618g28ajlb3v2siheh6.cz. 900 IN RRSIG NSEC3 13 2 900 20240817082134 20240803065134 51492 cz. u2x4rTi8iZwNso0fvbq8wdttDanY6Un5TlM/wc+fIdjSRFQ0cjQFC+J0 ZrFmw07XryT/bZDXEmgriXdX04eBpg==
cz.			900	IN	SOA	a.ns.nic.cz. hostmaster.nic.cz. 1722941318 900 300 604800 900
cz.			900	IN	RRSIG	SOA 13 1 3600 20240820104840 20240806091840 51492 cz. 8XVMnY1zpmxOCzfiAwWogOQxoPAxYXBsXJO7N9yOoBLpX9fvK19UV2k6 1PJWSQQbxI8Yo9oDoApFHz1Neti3+Q==

...

Conclusion

While NSEC3 mitigates some of the issues with NSEC, it's not a perfect solution. Using a smart algorithm, NSEC3 can still be exploited to disclose the total number of records in a zone. If the domains are guessable, attackers can attempt to brute-force the hashes offline. We'll cover NSEC3 and the latest countermeasures, including “black and white lies,“ in a future post. Stay tuned!

Ready to be more secure?