Giter VIP home page Giter VIP logo

nsec3map's Introduction

nsec3map - DNSSEC Zone Enumerator

n3map is a tool that can enumerate DNS zone entries based on DNSSEC NSEC or NSEC3 record chains. It can be used to discover hosts in a DNS zone quickly and with a minimum amount of queries if said zone is DNSSEC-enabled.

n3map was written primarily to show that NSEC3 does not offer meaningful protection against zone enumeration. Although originally only intended as a PoC and written in Python, it is actually quite fast and able to enumerate even large zones (with a million or more entries) in a short time given adequate hardware.

It also includes a simple John the Ripper plugin that can be used to crack the obtained NSEC3 hashes.

n3map screenshot

Usage Examples

Some typical usage examples are shown below. For a more detailed documentation, refer to the man pages or the output of n3map --help.

NSEC Zone Walking

The most basic example is to enumerate a particular zone (e.g. example.com) and store the retrieved NSEC/NSEC3 records in a file example.com.zone:

$ n3map -v -o example.com.zone example.com
n3map 0.4.0: starting mapping of example.com
looking up nameservers for zone example.com.
using nameserver: 199.43.133.53:53 (b.iana-servers.net.)
using nameserver: 199.43.132.53:53 (a.iana-servers.net.)
checking SOA...
detecting zone type...
zone uses NSEC records
starting enumeration in mixed query mode...
discovered owner: example.com.	A NS SOA TXT AAAA RRSIG NSEC DNSKEY
discovered owner: www.example.com.	A TXT AAAA RRSIG NSEC
;; walking example.com.: records =   2; queries =   4; ............. q/s = 11 ;;
finished mapping of example.com. in 0:00:00.196471

The -v switch is only used for more verbosity and not generally needed. With no further arguments, nsec3map detects automatically whether the zone uses NSEC or NSEC3 and uses the corresponding enumeration method. It also looks up the zone's nameservers by itself.

Some nameservers do not accept NSEC queries. In such a case, --query-mode A (short -A) can be used instead. For example, to enumerate the root zone, one could run the command:

n3map -v -A --output root.zone  .

Avoiding Sub-Zones

Note that the above command will likely print a lot of warnings about sub-zones (children of the zone that we want to enumerate). n3map tries its best to avoid descending into sub-zones and instead tries to jump over them automatically. If you wish to avoid most of these warnings, you can tell n3map to never add prefix labels to the queries it sends using the --no-prefix-labels option. For example:

n3map -vA --no-prefix-labels -o root.zone .

This option is particularly useful to enumerate top-level domain (TLD) zones. Note however that using it can sometimes lead to a less complete enumeration for zones with nested subdomains.

Alternatively, you can try to find nameservers that respond to direct NSEC queries (find them e.g. by trying --query-mode=NSEC) and tell n3map to only use those:

n3map -vo example.com.zone goodns{1,2}.example.com example.com

NSEC3 Zone Enumeration

The following example shows the enumeration of a NSEC3 chain at example.com using a nameserver at 192.168.1.37. It also shows the NSEC3 zone size prediction and progress indicator (enabled using the -p switch).

$ n3map -3po example.com.zone 192.168.1.37 example.com
;; mapping example.com.: 79% [===========================================================================                   ] ;;
;; records = 797; queries = 802; hashes = 3840; predicted zone size = 1003; ............... q/s = 513; coverage =  95.677595% ;;

received SIGINT, terminating

Note that the enumeration will proceed slower towards the end as it becomes harder to find domain names that are not covered by any retrieved NSEC3 records. Therefore, finishing the enumeration of a large zone can take quite some time and computing resources. It is advisable to manually cancel the enumeration once the query rate drops under a certain limit.

You should also make use of the --limit-rate option to reduce stress on the nameservers. If you think the enumeration is too slow because of a high round-trip time to the nameservers, you can also use a more aggressive mode which sends multiple queries simultaneously (--aggressive option). The following example shows how to use these options:

n3map -3pvo example.com.zone --aggressive 16 --limit-rate 100/s example.com

This will cause nsec3map to send a maximum of 16 queries in parallel while at the same time keeping the query rate at or below roughly 100 queries per second.

It is also possible to continue the enumeration from a partially obtained NSEC3 (or NSEC) chain, as long as the zone's NSEC3 parameters (salt, iteration count) have not been changed:

n3map -3pv --input example.com.partial --output example.com.zone --ignore-overlapping example.com

This will first read the NSEC3 records from example.com.partial and then continue the enumeration, saving the NSEC3 chain to example.com.zone. The --ignore-overlapping option should be used for large zones, or if it is otherwise likely that changes are made to the zone during the enumeration. If specified, nsec3map will not abort the enumeration when it receives an NSEC3 record which overlaps with another record that was received earlier. Note however that you will not get a completely consistent view of the NSEC3 chain if you use this option.

Cracking NSEC3 Hashes

Once you obtained some NSEC3 records from a particular zone, you can (try to) crack them using John the Ripper and the supplied NSEC3 patch (see John the Ripper Plugin below on how to install it).

First, the NSEC3 records need to be converted to a different format used by the JtR patch:

n3map-johnify example.com.zone example.com.john

The records can then be cracked simply by running john on the resulting file:

john example.com.john

Refer to the JtR documentation for more information on how to make use of john's different cracking modes, wordlist rules and so on. It is probably a good idea to adapt the wordlist and mangling rules to the kind of zone you are trying to map.

You can also try to crack NSEC3 records using hashcat, using hashes converted to a slightly different format:

n3map-hashcatify example.com.zone example.com.hashcat

The records can then be cracked simply by running hashcat on the resulting file:

hashcat -m 8300 example.com.hashcat

Installation

From PyPI

The PyPI package still needs to compile the C extension module for faster hashing, which means you need a C compiler as well as the necessary header files for Python and libcrypto (OpenSSL) installed.

For Debian-based systems:

sudo apt-get install python3 python3-pip python3-dev gcc libssl3 libssl-dev

To then install nsec3map from PyPI, simply run:

python3 -m pip install n3map[predict]

If you do not care about NSEC3 zone size prediction and don't want numpy and scipy installed, you can use:

python3 -m pip install n3map

Installing into a Virtual Environment

It may be advisable to install n3map into a Python venv, especially if you are faced with any dependency problems:

mkdir venv
python3 -m venv venv
source venv/bin/activate
python3 -m pip install n3map[predict]

More conveniently, you can also use pipx:

pipx install n3map[predict]

Note that you still need libssl, libssl-dev, gcc and python3-dev.

From Git Repository

Dependencies:

  • Python >= 3.9
  • dnspython >= 2.0
  • OpenSSL (libcrypto) >= 3.0.0
  • Optionally numpy and scipy for zone size prediction (recommended)

Additionally, pip, setuptools and GCC (for the extension module) are required during setup.

On a Debian system, just run

sudo apt-get install python3 python3-dev gcc python3-pip \
     python3-setuptools python3-dnspython libssl3 libssl-dev \
     python3-numpy python3-scipy

Installation:

After cloning the repositry / unpacking the tarball, cd into the project directory and run:

python3 -m pip install .[predict]

This will compile the extension modules(s) and install the scripts, python modules as well as the man pages. It will make a user install if you are not root.

If you do not care about NSEC3 zone size prediction and don't want numpy and scipy installed, you can use:

python3 -m pip install .

Alternatively, you can install it w/o pip:

sudo python3 setup.py install

Running directly from Source Directory

Alternatively, you can also run nsec3map directly from the source directory without installing it:

./map.py [options]

If you want to use OpenSSL accelerated hashing however, you still need to build the extension module:

python3 setup.py build_ext

This should compile a shared object nsec3hash.so in the build/ directory. You can then copy this file to the n3map/ directory.

John the Ripper Plugin

Update: The latest version of John the Ripper jumbo includes the NSEC3 cracking patch from this project. There is no need to install it separately, just follow the build instructions for JtR-Jumbo. Using the latest source version is recommended.

Alternatively, you can also use hashcat.

Docker

Building the docker container.

docker build -t nsec3map .

Running n3map or e.g. n3map-hashcatify:

docker run -it --rm -v "${PWD}:/host" nsec3map -v -o example.com.zone example.com
docker run -it --entrypoint n3map-hashcatify --rm -v "${PWD}:/host" nsec3map example.com.zone example.com.hashcat

Limitations

  • Many DNS errors are not handled correctly
  • No automatic parallelization of NSEC walking (though it is possible to do this manually by partitioning the namespace)
  • High memory usage (mostly as a result of using CPython)
  • ...

(remember that nsec3map is still mostly a PoC tool...)

nsec3map's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

nsec3map's Issues

Allow to auto-stop after N hashes generated

A small (and likely easy to implement) idea I was recently missing was a command line flag where I can tell n3map to generate at most a given number of hashes (like 2^30) and terminate at the time latest even if the zone hasn't been fully enumerated yet.

This feature can be interesting if you are enumerating several zones in a batch run and want a somewhat "guaranteed" runtime for each zone.

NSEC zone reading fails for wildcards in next owner field

When calling n3map with an input file of previously obtained NSEC RR of a zone, where one entry contains a next owner field denoting a wildcard, this record is marked as invalid. To reproduce you can enumerate the zones audio. and auto. which contain such offending NSEC RR:

$ n3map -v -p -f4 -c reproducer.zone auto.
n3map 0.7.0: starting mapping of auto.
looking up nameservers for zone auto.
using nameserver: 185.24.64.131 (b.nic.auto.)
using nameserver: 194.169.218.131 (a.nic.auto.)
using nameserver: 212.18.248.131 (c.nic.auto.)
using nameserver: 212.18.249.131 (d.nic.auto.)
checking SOA...
checking DNSKEY...
detecting zone type...
zone uses NSEC records
zone file reproducer.zone does not exist yet, creating it
starting enumeration in mixed query mode...

Interrupt somewhere in the middle, after the offending NSEC RR was recorded …

$ n3map -v -p -f4 -c reproducer.zone auto.
n3map 0.7.0: starting mapping of auto.
looking up nameservers for zone auto.
using nameserver: 212.18.249.131 (d.nic.auto.)
using nameserver: 194.169.218.131 (a.nic.auto.)
using nameserver: 212.18.248.131 (c.nic.auto.)
using nameserver: 185.24.64.131 (b.nic.auto.)
checking SOA...
checking DNSKEY...
detecting zone type...
zone uses NSEC records
reading NSEC RRs from reproducer.zone
n3map: fatal: unable to parse input file: 
reproducer.zone:314: invalid file format                                                                                                                                        
$ grep -n \*\. reproducer.zone 
314:nic.auto.   3600    IN      NSEC    *.nic.auto.     A NS SOA MX TXT RRSIG NSEC DNSKEY

Expected behavior would be to just import this record as normal or ignore it and carry on, where a previous run had left off

some zones/servers "hit an existing owner name" loop

Some zones/servers trigger a "hit an existing owner name" loop. I am pretty sure that this is because of how the zone behaves, not a direct problem with n3map, but if the condition can be detected early and skipped/aborted, that would be an improvement.

Examples:

looking up nameservers for zone 0172.nl.
using nameserver: 85.17.41.33:53 (ns2.flexwebhosting.nl.)
using nameserver: 82.192.67.204:53 (ns1.flexwebhosting.nl.)
using nameserver: 85.92.140.133:53 (ns3.flexwebhosting.com.)
checking SOA...
detecting zone type...
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
[...]


looking up nameservers for zone 010buurt.info.
using nameserver: 80.69.67.67:53 (ns0.transip.nl.)
using nameserver: 37.97.255.53:53 (ns2.transip.eu.)
using nameserver: 80.69.69.69:53 (ns1.transip.net.)
checking SOA...
detecting zone type...
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
[...]

Do not fail on missing GLUE records

Let's consider enumerating arpa.:

# n3map -v -v -v -p arpa.
n3map 0.6.5: starting mapping of arpa.
looking up nameservers for zone arpa.
n3map: fatal: could not resolve host 'm.ns.arpa.': [Errno -2] Name or service not known

Running dig ns arpa. shows the full GLUE records, though asking for the A records directly does not yield a result:

$ dig ns arpa.
; <<>> DiG 9.18 <<>> ns arpa.
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 40937
;; flags: qr aa rd ra; QUERY: 1, ANSWER: 12, AUTHORITY: 0, ADDITIONAL: 25

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;arpa.                          IN      NS

;; ANSWER SECTION:
arpa.                   518400  IN      NS      a.ns.arpa.
arpa.                   518400  IN      NS      b.ns.arpa.
arpa.                   518400  IN      NS      c.ns.arpa.
arpa.                   518400  IN      NS      d.ns.arpa.
arpa.                   518400  IN      NS      e.ns.arpa.
arpa.                   518400  IN      NS      f.ns.arpa.
arpa.                   518400  IN      NS      g.ns.arpa.
arpa.                   518400  IN      NS      h.ns.arpa.
arpa.                   518400  IN      NS      i.ns.arpa.
arpa.                   518400  IN      NS      k.ns.arpa.
arpa.                   518400  IN      NS      l.ns.arpa.
arpa.                   518400  IN      NS      m.ns.arpa.

;; ADDITIONAL SECTION:
a.ns.arpa.              518400  IN      A       198.41.0.4
a.ns.arpa.              518400  IN      AAAA    2001:503:ba3e::2:30
b.ns.arpa.              518400  IN      A       199.9.14.201
b.ns.arpa.              518400  IN      AAAA    2001:500:200::b
c.ns.arpa.              518400  IN      A       192.33.4.12
c.ns.arpa.              518400  IN      AAAA    2001:500:2::c
d.ns.arpa.              518400  IN      A       199.7.91.13
d.ns.arpa.              518400  IN      AAAA    2001:500:2d::d
e.ns.arpa.              518400  IN      A       192.203.230.10
e.ns.arpa.              518400  IN      AAAA    2001:500:a8::e
f.ns.arpa.              518400  IN      A       192.5.5.241
f.ns.arpa.              518400  IN      AAAA    2001:500:2f::f
g.ns.arpa.              518400  IN      A       192.112.36.4
g.ns.arpa.              518400  IN      AAAA    2001:500:12::d0d
h.ns.arpa.              518400  IN      A       198.97.190.53
h.ns.arpa.              518400  IN      AAAA    2001:500:1::53
i.ns.arpa.              518400  IN      A       192.36.148.17
i.ns.arpa.              518400  IN      AAAA    2001:7fe::53
k.ns.arpa.              518400  IN      A       193.0.14.129
k.ns.arpa.              518400  IN      AAAA    2001:7fd::1
l.ns.arpa.              518400  IN      A       199.7.83.42
l.ns.arpa.              518400  IN      AAAA    2001:500:9f::42
m.ns.arpa.              518400  IN      A       202.12.27.33
m.ns.arpa.              518400  IN      AAAA    2001:dc3::35

$ dig a a.ns.arpa.
; <<>> DiG 9.18 <<>> a a.ns.arpa.
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 63802
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 1232
;; QUESTION SECTION:
;a.ns.arpa.                     IN      A

;; AUTHORITY SECTION:
arpa.                   86400   IN      SOA     a.root-servers.net. nstld.verisign-grs.com. 2023021200 1800 900 604800 86400

If you provide an authoritive nameserver, in this case both . and arpa. are served by essentially the same servers from root-servers.net., there is two issues further arising:

Number one is: Some server's won't respond properly to queries (as can be seen with a.root-servers.net.):

$ n3map -v -v -v -p a.root-servers.net. arpa.
n3map -v -v -v -p a.root-servers.net. arpa.
n3map 0.6.5: starting mapping of arpa.
checking SOA...
query: arpa.; ns = 198.41.0.4 (a.root-servers.net.); rrtype = SOA
warning: timeout reached when waiting for response from 198.41.0.4 (a.root-servers.net.), 4 retries left
query: arpa.; ns = 198.41.0.4 (a.root-servers.net.); rrtype = SOA
warning: timeout reached when waiting for response from 198.41.0.4 (a.root-servers.net.), 3 retries left
query: arpa.; ns = 198.41.0.4 (a.root-servers.net.); rrtype = SOA
warning: timeout reached when waiting for response from 198.41.0.4 (a.root-servers.net.), 2 retries left
query: arpa.; ns = 198.41.0.4 (a.root-servers.net.); rrtype = SOA
warning: timeout reached when waiting for response from 198.41.0.4 (a.root-servers.net.), 1 retries left
query: arpa.; ns = 198.41.0.4 (a.root-servers.net.); rrtype = SOA
warning: timeout reached when waiting for response from 198.41.0.4 (a.root-servers.net.), 0 retries left
warning: removed misbehaving/unresponsive nameserver 198.41.0.4 (a.root-servers.net.)
n3map: fatal: ran out of working nameservers!

Number two can be seen with b.root-servers.net.:

$ n3map -v -v -v -p b.root-servers.net. arpa.
n3map 0.6.5: starting mapping of arpa.
checking SOA...
query: arpa.; ns = 199.9.14.201 (b.root-servers.net.); rrtype = SOA
checking DNSKEY...
query: arpa.; ns = 199.9.14.201 (b.root-servers.net.); rrtype = DNSKEY
detecting zone type...
query: c2ddce000b916320.arpa.; ns = 199.9.14.201 (b.root-servers.net.); rrtype = A
zone uses NSEC records
starting enumeration in mixed query mode...
query: arpa.; ns = 199.9.14.201 (b.root-servers.net.); rrtype = NSEC
received NSEC RR: arpa. 86400   IN      NSEC    as112.arpa.     NS SOA RRSIG NSEC DNSKEY
covering NSEC RR found: arpa.   86400   IN      NSEC    as112.arpa.     NS SOA RRSIG NSEC DNSKEY
discovered owner: arpa. NS SOA RRSIG NSEC DNSKEY
query: as112.arpa.; ns = 199.9.14.201 (b.root-servers.net.); rrtype = NSEC
error: no NSEC RR received
Maybe the zone doesn't support DNSSEC or uses NSEC3 RRs                                                                                                                                      
or the server 199.9.14.201 (b.root-servers.net.) does not allow NSEC queries.                                                                                                                
Perhaps try using --query-mode=A                                                                                                                                                             
warning: 0 errors left for 199.9.14.201 (b.root-servers.net.)
warning: removed misbehaving/unresponsive nameserver 199.9.14.201 (b.root-servers.net.)
;; walking arpa.: records =   1; queries =   5; ................................................................................................................................. q/s = 39 ;;
n3map: fatal: ran out of working nameservers!

Only with c.root-servers.net. (and the others in the NS RRset), the enumeration succeeds:

$ n3map -v -v -v -p c.root-servers.net. arpa.
n3map 0.6.5: starting mapping of arpa.
checking SOA...
query: arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = SOA
checking DNSKEY...
query: arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = DNSKEY
detecting zone type...
query: 2dde43efde20eedf.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = A
zone uses NSEC records
starting enumeration in mixed query mode...
query: arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: arpa. 86400   IN      NSEC    as112.arpa.     NS SOA RRSIG NSEC DNSKEY
covering NSEC RR found: arpa.   86400   IN      NSEC    as112.arpa.     NS SOA RRSIG NSEC DNSKEY
discovered owner: arpa. NS SOA RRSIG NSEC DNSKEY
query: as112.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: as112.arpa.   86400   IN      NSEC    e164.arpa.      NS DS RRSIG NSEC
covering NSEC RR found: as112.arpa.     86400   IN      NSEC    e164.arpa.      NS DS RRSIG NSEC
discovered owner: as112.arpa.   NS DS RRSIG NSEC
query: e164.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: e164.arpa.    86400   IN      NSEC    home.arpa.      NS DS RRSIG NSEC
covering NSEC RR found: e164.arpa.      86400   IN      NSEC    home.arpa.      NS DS RRSIG NSEC
discovered owner: e164.arpa.    NS DS RRSIG NSEC
query: home.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: home.arpa.    86400   IN      NSEC    in-addr.arpa.   NS RRSIG NSEC
covering NSEC RR found: home.arpa.      86400   IN      NSEC    in-addr.arpa.   NS RRSIG NSEC
discovered owner: home.arpa.    NS RRSIG NSEC
query: in-addr.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: in-addr.arpa. 86400   IN      NSEC    in-addr-servers.arpa.   NS DS RRSIG NSEC
covering NSEC RR found: in-addr.arpa.   86400   IN      NSEC    in-addr-servers.arpa.   NS DS RRSIG NSEC
discovered owner: in-addr.arpa. NS DS RRSIG NSEC
query: in-addr-servers.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: in-addr-servers.arpa. 86400   IN      NSEC    ip6.arpa.       NS DS RRSIG NSEC
covering NSEC RR found: in-addr-servers.arpa.   86400   IN      NSEC    ip6.arpa.       NS DS RRSIG NSEC
discovered owner: in-addr-servers.arpa. NS DS RRSIG NSEC
query: ip6.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: ip6.arpa.     86400   IN      NSEC    ip6-servers.arpa.       NS DS RRSIG NSEC
covering NSEC RR found: ip6.arpa.       86400   IN      NSEC    ip6-servers.arpa.       NS DS RRSIG NSEC
discovered owner: ip6.arpa.     NS DS RRSIG NSEC
query: ip6-servers.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: ip6-servers.arpa.     86400   IN      NSEC    ipv4only.arpa.  NS DS RRSIG NSEC
covering NSEC RR found: ip6-servers.arpa.       86400   IN      NSEC    ipv4only.arpa.  NS DS RRSIG NSEC
discovered owner: ip6-servers.arpa.     NS DS RRSIG NSEC
query: ipv4only.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: ipv4only.arpa.        86400   IN      NSEC    iris.arpa.      NS RRSIG NSEC
covering NSEC RR found: ipv4only.arpa.  86400   IN      NSEC    iris.arpa.      NS RRSIG NSEC
discovered owner: ipv4only.arpa.        NS RRSIG NSEC
query: iris.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: iris.arpa.    86400   IN      NSEC    a.ns.arpa.      NS DS RRSIG NSEC
covering NSEC RR found: iris.arpa.      86400   IN      NSEC    a.ns.arpa.      NS DS RRSIG NSEC
discovered owner: iris.arpa.    NS DS RRSIG NSEC
query: a.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: a.ns.arpa.    86400   IN      NSEC    b.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: a.ns.arpa.      86400   IN      NSEC    b.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: a.ns.arpa.    A AAAA RRSIG NSEC
query: b.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: b.ns.arpa.    86400   IN      NSEC    c.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: b.ns.arpa.      86400   IN      NSEC    c.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: b.ns.arpa.    A AAAA RRSIG NSEC
query: c.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: c.ns.arpa.    86400   IN      NSEC    d.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: c.ns.arpa.      86400   IN      NSEC    d.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: c.ns.arpa.    A AAAA RRSIG NSEC
query: d.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: d.ns.arpa.    86400   IN      NSEC    e.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: d.ns.arpa.      86400   IN      NSEC    e.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: d.ns.arpa.    A AAAA RRSIG NSEC
query: e.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: e.ns.arpa.    86400   IN      NSEC    f.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: e.ns.arpa.      86400   IN      NSEC    f.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: e.ns.arpa.    A AAAA RRSIG NSEC
query: f.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: f.ns.arpa.    86400   IN      NSEC    g.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: f.ns.arpa.      86400   IN      NSEC    g.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: f.ns.arpa.    A AAAA RRSIG NSEC
query: g.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: g.ns.arpa.    86400   IN      NSEC    h.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: g.ns.arpa.      86400   IN      NSEC    h.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: g.ns.arpa.    A AAAA RRSIG NSEC
query: h.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: h.ns.arpa.    86400   IN      NSEC    i.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: h.ns.arpa.      86400   IN      NSEC    i.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: h.ns.arpa.    A AAAA RRSIG NSEC
query: i.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: i.ns.arpa.    86400   IN      NSEC    k.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: i.ns.arpa.      86400   IN      NSEC    k.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: i.ns.arpa.    A AAAA RRSIG NSEC
query: k.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: k.ns.arpa.    86400   IN      NSEC    l.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: k.ns.arpa.      86400   IN      NSEC    l.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: k.ns.arpa.    A AAAA RRSIG NSEC
query: l.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: l.ns.arpa.    86400   IN      NSEC    m.ns.arpa.      A AAAA RRSIG NSEC
covering NSEC RR found: l.ns.arpa.      86400   IN      NSEC    m.ns.arpa.      A AAAA RRSIG NSEC
discovered owner: l.ns.arpa.    A AAAA RRSIG NSEC
query: m.ns.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: m.ns.arpa.    86400   IN      NSEC    uri.arpa.       A AAAA RRSIG NSEC
covering NSEC RR found: m.ns.arpa.      86400   IN      NSEC    uri.arpa.       A AAAA RRSIG NSEC
discovered owner: m.ns.arpa.    A AAAA RRSIG NSEC
query: uri.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: uri.arpa.     86400   IN      NSEC    urn.arpa.       NS DS RRSIG NSEC
covering NSEC RR found: uri.arpa.       86400   IN      NSEC    urn.arpa.       NS DS RRSIG NSEC
discovered owner: uri.arpa.     NS DS RRSIG NSEC
query: urn.arpa.; ns = 192.33.4.12 (c.root-servers.net.); rrtype = NSEC
received NSEC RR: urn.arpa.     86400   IN      NSEC    arpa.   NS DS RRSIG NSEC
covering NSEC RR found: urn.arpa.       86400   IN      NSEC    arpa.   NS DS RRSIG NSEC
discovered owner: urn.arpa.     NS DS RRSIG NSEC
;; walking arpa.: records =  24; queries =  28; ................................................................................................................................. q/s = 30 ;;
finished mapping of arpa. in 0:00:03.463583

Would be nice if the resolution of (working) nameservers could be made more robust for cases like this.

Hashcatify and Johnify fail if there is no salt.

If there is no salt in the NSEC3 hash, the commands fail.
Unfortunately i cannot provide you with example domains, due to customer NDAs.

$ ./hashcatify.py all.nsec3.zone.hash
...
Traceback (most recent call last):
  File "/home/user/gits_public/nsec3map/./hashcatify.py", line 6, in <module>
    n3map.hashcatify.main()
  File "/home/user/gits_public/nsec3map/n3map/hashcatify.py", line 41, in main
    sys.exit(hashcatify_main(sys.argv))
  File "/home/user/gits_public/nsec3map/n3map/hashcatify.py", line 32, in hashcatify_main
    salt = util.str_to_hex(nsec3.salt)
  File "/home/user/gits_public/nsec3map/n3map/util.py", line 18, in str_to_hex
    hex_list = ["{0:02x}".format(b) for b in struct.unpack('B'*len(s), s)]
TypeError: a bytes-like object is required, not 'str'

What made the error go away was the following change:

In the original hashcatify.py in line 32, we have

 32             salt = util.str_to_hex(nsec3.salt)

However, that fails if the nsec3.salt is empty. Therefore i changed it to:

            if nsec3.salt == '': 
                salt = ''
            else:
                salt = util.str_to_hex(nsec3.salt)

I do not know if this fixes the issue completely, i.e., if the hashes are valid, as i am no expert in the format of hashcat. Same with johnify.
If you would like me to submit a merge request, I can do so.

feature request: save/resume state on late server timeout

As a nice-to-have:

If zone enumeration successfully started, and some records have been acquired, but the server then times out, it may be due to temporary throttling. If current state could be saved to a specified file, and then a flag added to resume if the specified file exists (so two different new command-line options), then zones could be eventually fully enumerated (or at least moreso).

Edit: On the next run, the user could potentially adjust the query rate downwards to compensate (if that was the issue).

optionally skip zones using commonly-used 'ab' salt

The "white lies" technique of preventing NSEC3 enumeration appears to be strongly correlated with zones that use a simple 'ab' as the salt. From my testing across quite a few zones, no 'ab'-salted domains can be properly enumerated using nsec3map.

Recommendation: As a user-configurable option, perform a NSEC3PARAM lookup to query the salt in advance, and if it is 'ab', skip the zone.

$ host -t nsec3param geoguessr.com
geoguessr.com has NSEC3PARAM record 1 0 1 AB

Obviously, someone could simply use 'ab' as their salt to avoid enumeration. But this would also make their zone more easily bruteforced, as their salt would be short and static.

Edit: it's also possible that I'm totally wrong about it being "white lies". The static salt might instead just the sign of a front-end device with an unchanging salt that also happens to detect and block enumeration. For example, Infoblox may have done this at some point.

Type error when converting to hashcat/john

Hi,
i sometimes get an error when using hashcatify and johnify. I fixed it for me and will submit a merge request shortly.
The problem seems to be that the files for writing the hashes in hashcat, respectively john format are opened in binary mode, but we do not write binary in there.

NSEC3: NextOwner==CurrentOwner handling suggestion

At the moment an NSEC3 (and possibly NSEC RR too?) that has it's NextOwner set to itself is handled as invalid.

While this is correct for the common case, there is one exception, which is if the Owner name points to the zone's SOA name, in which case such an RR indicates an empty zone.

It would be nice if n3map could handle this situation in such a way, that the zone is simply "finished" with this NSEC3/NSEC RR as it's only owner name in the NSEC3/NSEC chain (i.e. no exception IFF the Owner belongs to the zone entry).

Example:

$ dig +dnssec CNAME airtel.

; <<>> DiG 9.18 <<>> +dnssec CNAME airtel.
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 65372
;; flags: qr rd ra; QUERY: 1, ANSWER: 0, AUTHORITY: 4, ADDITIONAL: 1

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 1232
;; QUESTION SECTION:
;airtel.                                IN      CNAME

;; AUTHORITY SECTION:
airtel.                 86400   IN      SOA     ac1.nstld.com. info.verisign-grs.com. 1676332990 1800 900 604800 86400
airtel.                 86400   IN      RRSIG   SOA 8 1 86400 20230220215310 20230213215310 5023 airtel. kmR8WQ6M8aXAMgSX1Ez10M5GPKmZyyTp/6KN1mxLOd/dWrYBowEw9SW8 ZykPpNNN7Yxr/1S+0B3ywGXVmJFhBO+IMP3DtN++nYEXPfMQPfbRQYnM SfdHQpHwJw6Q0kbWL2o9mGpZYZKmOmJXIzsA3ycZZbJaK3+ClBfKRdMm gy0mxuxS6GQ8NyYyJ1l0WAzz4bM0Ray0W9pXfO+aPrJ6GA==
SUKRVK4IEDLPQC37JR5200NRLPOAJIBS.airtel. 86400 IN NSEC3 1 1 0 - SUKRVK4IEDLPQC37JR5200NRLPOAJIBS NS SOA RRSIG DNSKEY NSEC3PARAM
SUKRVK4IEDLPQC37JR5200NRLPOAJIBS.airtel. 86400 IN RRSIG NSEC3 8 2 86400 20230218222412 20230211222412 5023 airtel. XKAmXeswtninpnsrTrwwCrkow67nIv60qKBO6QvvzD857Zvrmi87jm+b V+Epw9AUdf9d+PQ3F21Pd7DLtUQ8/NpX2dJaz8fPQGxjgtZcd0aGeqjs 0CuAGGGYbOwC+gBgC6VGRv73xBVd1BPWIwIop35o90Fy7F/SgSj2WqBm d5nT7qrkcSvlS8201eerMqpPxEBjPa7nYOQfY/ZFZDKY7g==

;; Query time: 116 msec
;; SERVER: 1.1.1.1#53(1.1.1.1) (UDP)
;; WHEN: Tue Feb 14 01:03:33 CET 2023
;; MSG SIZE  rcvd: 578

hashcatify.py seems broken on Python 3.10

Versions:

Input: example.zone.txt

Reproducer:

$ ./hashcatify.py example.zone example.hashcat
 File "/home/pspacek/w/pkg/nsec3map/git/hashcatify.py", line 6, in <module>
    n3map.hashcatify.main()
  File "/home/pspacek/w/pkg/nsec3map/git/n3map/hashcatify.py", line 41, in main
    sys.exit(hashcatify_main(sys.argv))
  File "/home/pspacek/w/pkg/nsec3map/git/n3map/hashcatify.py", line 33, in hashcatify_main
    out.write(":".join((nsec3_hash, "." + zone, salt, iterations)) 
TypeError: a bytes-like object is required, not 'str'

Help with installation and usage

I was wandering if someone can make just a short video on how to set it up and run it. I did as the installation Guide said but nothing, i also think, the installation Guide and usage is not detailed enough there need to be some updates to make things a little clear for be people who are not experts in DNS enumeration and all that. Thanks

Indicate the number of known gaps for NSEC3

It would be nice if the status line could indicate the number of still open gaps in the zone coverage (their total size is indirectly given by the coverage percentage).

;; mapping tld. 100% [===================================================================================================================================================================] ;;
;; records = 999999; queries =  42; hashes = 1234567890; predicted zone size = 999999; ................................................................... q/s = 0; coverage =  99.999997% ;;

The second line could additionally include some indication like gaps = 5; or similar, to let the user know if n3map is just working on one gap or possibly many small ones.

excessive(?) "hit an existing owner name" output?

Using this syntax:

n3map -v --ignore-overlapping --ldh --max-retries=1 --timeout=30000 --limit-rate 50/s -o [domain].out [domain]

... (and using the latest n3map / map.py from Github), a couple of domains (for example, ladiada.com and karmelak.pl) go through a pretty extensive number of "hit an existing owner name" output lines:

$ head -20 karmelak.pl.debug
looking up nameservers for zone karmelak.pl.
using nameserver: 46.242.149.31:53 (dns3.home.pl.)
using nameserver: 46.242.149.30:53 (dns3.home.pl.)
using nameserver: 46.242.149.10:53 (dns.home.pl.)
using nameserver: 46.242.149.11:53 (dns.home.pl.)
using nameserver: 46.242.149.20:53 (dns2.home.pl.)
using nameserver: 46.242.149.21:53 (dns2.home.pl.)
checking SOA...
detecting zone type...
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name
hit an existing owner name

$ wc -l karmelak.pl.debug
26877 karmelak.pl.debug

$ wc -l ladiada.com.debug
4341 ladiada.com.debug

Zone Refresh Mode

Given that most zones usually only change slightly when they are updated, it could be interesting to record the query that yielded any given NSEC3 record, so when restarting a zone walk you could simply re-query those records and record any changes to the NSEC3 coverage. That way most of the progress can be used to refresh the NSEC3 chain in the zone without wasting too many cycles on finding candidate domain names that previously already found records.

If a zone did not change this basically confirms the prior knowledge from the previous scan.

If an entry in the zone was removed, this potentially wastes a query (though you can skip querying for records, where you know from the new state that they are already covered).

If a new entry was added, this basically shrinks the coverage of one existing NSEC3 record, thus leaving a small gap, which the actual zone walk could then go on to fill just as normal.

While mostly intended for NSEC3, the same should work just as well for NSEC, although it likely won't speed things up over normal re-enumeration.

Ignore mis-behaving authoritative servers

Some DNS servers (e.g. in the nl. or fail. zones) sometimes omit DNSSEC-relevant records causing nsec3map to hard-fail on the zone although asking one of the other servers for the same record would work just fine. This is especially annoying as this causes the reload of a large state file when iterating such zones.

Currently binding nsec3map to one of the servers will usually solve the issue.

Intended behaviour: Retry with different server and only fail if all lack DNSSEC RR and no particular "brute-force-anyway" option is given.

Error building john

Hi

When I run make I get the following error (I am trying to build john-1.8.0-jumbo-1 since I can not find john-1.7.9-jumbo8 on the homepage).

nsec3_gen_fmt_plug.c:314:2: warning: initialization makes integer from pointer without a cast [enabled by default]
nsec3_gen_fmt_plug.c:314:2: warning: (near initialization for ‘fmt_nsec3_gen.params.max_keys_per_crypt’) [enabled by default]
nsec3_gen_fmt_plug.c:314:2: error: initializer element is not computable at load time
nsec3_gen_fmt_plug.c:314:2: error: (near initialization for ‘fmt_nsec3_gen.params.max_keys_per_crypt’)
nsec3_gen_fmt_plug.c:316:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:316:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.done’) [enabled by default]
nsec3_gen_fmt_plug.c:317:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:317:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.reset’) [enabled by default]
nsec3_gen_fmt_plug.c:318:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:318:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.prepare’) [enabled by default]
nsec3_gen_fmt_plug.c:319:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:319:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.valid’) [enabled by default]
nsec3_gen_fmt_plug.c:320:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:320:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.split’) [enabled by default]
nsec3_gen_fmt_plug.c:321:3: warning: braces around scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:321:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary’) [enabled by default]
nsec3_gen_fmt_plug.c:322:4: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:322:4: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary’) [enabled by default]
nsec3_gen_fmt_plug.c:323:4: warning: excess elements in scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:323:4: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary’) [enabled by default]
nsec3_gen_fmt_plug.c:324:4: warning: excess elements in scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:324:4: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary’) [enabled by default]
nsec3_gen_fmt_plug.c:325:4: warning: excess elements in scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:325:4: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary’) [enabled by default]
nsec3_gen_fmt_plug.c:327:3: warning: excess elements in scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:327:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary’) [enabled by default]
nsec3_gen_fmt_plug.c:328:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:328:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.salt’) [enabled by default]
nsec3_gen_fmt_plug.c:329:3: warning: missing braces around initializer [-Wmissing-braces]
nsec3_gen_fmt_plug.c:329:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.tunable_cost_value’) [-Wmissing-braces]
nsec3_gen_fmt_plug.c:329:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:329:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.tunable_cost_value[0]’) [enabled by default]
nsec3_gen_fmt_plug.c:330:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:330:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.tunable_cost_value[1]’) [enabled by default]
nsec3_gen_fmt_plug.c:331:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:331:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.tunable_cost_value[2]’) [enabled by default]
nsec3_gen_fmt_plug.c:332:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:332:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.source’) [enabled by default]
nsec3_gen_fmt_plug.c:333:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:333:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[0]’) [enabled by default]
nsec3_gen_fmt_plug.c:334:3: warning: braces around scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:334:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[1]’) [enabled by default]
nsec3_gen_fmt_plug.c:335:4: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:335:4: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[1]’) [enabled by default]
nsec3_gen_fmt_plug.c:336:4: warning: excess elements in scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:336:4: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[1]’) [enabled by default]
nsec3_gen_fmt_plug.c:337:4: warning: excess elements in scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:337:4: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[1]’) [enabled by default]
nsec3_gen_fmt_plug.c:338:4: warning: excess elements in scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:338:4: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[1]’) [enabled by default]
nsec3_gen_fmt_plug.c:340:3: warning: excess elements in scalar initializer [enabled by default]
nsec3_gen_fmt_plug.c:340:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[1]’) [enabled by default]
nsec3_gen_fmt_plug.c:341:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:341:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[2]’) [enabled by default]
nsec3_gen_fmt_plug.c:342:3: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:342:3: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[3]’) [enabled by default]
nsec3_gen_fmt_plug.c:344:2: warning: initialization from incompatible pointer type [enabled by default]
nsec3_gen_fmt_plug.c:344:2: warning: (near initialization for ‘fmt_nsec3_gen.methods.binary_hash[4]’) [enabled by default]
make[1]: *** [nsec3_gen_fmt_plug.o] Error 1
make[1]: Leaving directory `/tmp/john-1.8.0-jumbo-1/src'
make: *** [default] Error 2

NSEC enumeration fails for ax.

Enumeration of the TLD ax. fails after a few records are found.

To reproduce:

$ n3map -v -v -n --ldh -p -f4 --ignore-overlapping -A -a ax.
n3map 0.7.0: starting mapping of ax.
looking up nameservers for zone ax.
using nameserver: 194.112.0.5 (ns2.aland.net.)
using nameserver: 2a00:5500:1:6::130 (ns3.alcom.fi.)
using nameserver: 194.112.0.1 (ns1.aland.net.)
using nameserver: 2a00:5500:1:7::194 (ns4.alcom.fi.)
checking SOA...
checking DNSKEY...
detecting zone type...
zone uses NSEC records
starting enumeration in A query mode...
discovered owner: ax.   NS SOA RRSIG NSEC DNSKEY TYPE65534
discovered owner: 00.ax.        NS RRSIG NSEC
discovered owner: 007.ax.       NS RRSIG NSEC
discovered owner: 0244a.ax.     NS RRSIG NSEC
discovered owner: 04.ax.        NS RRSIG NSEC
discovered owner: 07.ax.        NS RRSIG NSEC
discovered owner: 08.ax.        NS RRSIG NSEC
discovered owner: 089.ax.       NS RRSIG NSEC
discovered owner: 09.ax.        NS RRSIG NSEC
discovered owner: 0a.ax.        NS RRSIG NSEC
discovered owner: 0h.ax.        NS RRSIG NSEC
discovered owner: 0m.ax.        NS RRSIG NSEC
discovered owner: 0x.ax.        NS RRSIG NSEC
discovered owner: 10.ax.        NS RRSIG NSEC
discovered owner: 100.ax.       NS RRSIG NSEC
discovered owner: 1001.ax.      NS RRSIG NSEC
discovered owner: 100kvinnor.ax.        NS RRSIG NSEC
discovered owner: 1040t.ax.     NS RRSIG NSEC
discovered owner: 10mm.ax.      NS RRSIG NSEC
discovered owner: 11.ax.        NS RRSIG NSEC
discovered owner: 111.ax.       NS RRSIG NSEC
discovered owner: 112.ax.       NS RRSIG NSEC
discovered owner: 12.ax.        NS RRSIG NSEC
discovered owner: 123.ax.       NS RRSIG NSEC
discovered owner: 123domain.ax. NS RRSIG NSEC
discovered owner: 13.ax.        NS RRSIG NSEC
discovered owner: 1337.ax.      NS RRSIG NSEC
discovered owner: 1337h.ax.     NS RRSIG NSEC
discovered owner: 138.ax.       NS RRSIG NSEC
discovered owner: 15.ax.        NS RRSIG NSEC
discovered owner: 16.ax.        NS RRSIG NSEC
discovered owner: 17.ax.        NS RRSIG NSEC
discovered owner: 18.ax.        NS RRSIG NSEC
discovered owner: 19.ax.        NS RRSIG NSEC
discovered owner: 1963.ax.      NS RRSIG NSEC
discovered owner: 1fairf.ax.    NS RRSIG NSEC
discovered owner: 1h.ax.        NS RRSIG NSEC
discovered owner: 1n.ax.        NS RRSIG NSEC
discovered owner: 20.ax.        NS RRSIG NSEC
discovered owner: 2022.ax.      NS RRSIG NSEC
discovered owner: 21.ax.        NS RRSIG NSEC
discovered owner: 2138.ax.      NS RRSIG NSEC
discovered owner: 22.ax.        NS RRSIG NSEC
discovered owner: 23.ax.        NS RRSIG NSEC
discovered owner: 24.ax.        NS RRSIG NSEC
discovered owner: 240.ax.       NS RRSIG NSEC
discovered owner: 25.ax.        NS RRSIG NSEC
discovered owner: 26.ax.        NS RRSIG NSEC
discovered owner: 27.ax.        NS RRSIG NSEC
discovered owner: 28.ax.        NS RRSIG NSEC
discovered owner: 29.ax.        NS RRSIG NSEC
discovered owner: 297.ax.       NS RRSIG NSEC
discovered owner: 2d.ax.        NS RRSIG NSEC
discovered owner: 2m.ax.        NS RRSIG NSEC
discovered owner: 2ndtrip.ax.   NS RRSIG NSEC
discovered owner: 2x.ax.        NS RRSIG NSEC
discovered owner: 301.ax.       NS RRSIG NSEC
discovered owner: 31.ax.        NS RRSIG NSEC
discovered owner: 3152.ax.      NS RRSIG NSEC
discovered owner: 317.ax.       NS RRSIG NSEC
discovered owner: 32.ax.        NS RRSIG NSEC
discovered owner: 33.ax.        NS RRSIG NSEC
discovered owner: 35.ax.        NS RRSIG NSEC
discovered owner: 36.ax.        NS RRSIG NSEC
discovered owner: 365.ax.       NS RRSIG NSEC
discovered owner: 37.ax.        NS RRSIG NSEC
discovered owner: 38.ax.        NS RRSIG NSEC
discovered owner: 39.ax.        NS RRSIG NSEC
discovered owner: 3d.ax.        NS RRSIG NSEC
discovered owner: 3partners.ax. NS RRSIG NSEC
discovered owner: 42.ax.        NS RRSIG NSEC
discovered owner: 43.ax.        NS RRSIG NSEC
discovered owner: 44.ax.        NS RRSIG NSEC
discovered owner: 45.ax.        NS RRSIG NSEC
discovered owner: 46.ax.        NS RRSIG NSEC
discovered owner: 47.ax.        NS RRSIG NSEC
discovered owner: 48.ax.        NS RRSIG NSEC
error: no NSEC RR received
Maybe the zone doesn't support DNSSEC or uses NSEC3 RRs
                                                                                                                                                                                             
warning: 0 errors left for 194.112.0.5 (ns2.aland.net.)
warning: removed misbehaving/unresponsive nameserver 194.112.0.5 (ns2.aland.net.)
error: no NSEC RR received
Maybe the zone doesn't support DNSSEC or uses NSEC3 RRs
                                                                                                                                                                                             
warning: 0 errors left for 2a00:5500:1:6::130 (ns3.alcom.fi.)
warning: removed misbehaving/unresponsive nameserver 2a00:5500:1:6::130 (ns3.alcom.fi.)
error: no NSEC RR received
Maybe the zone doesn't support DNSSEC or uses NSEC3 RRs
                                                                                                                                                                                             
warning: 0 errors left for 194.112.0.1 (ns1.aland.net.)
warning: removed misbehaving/unresponsive nameserver 194.112.0.1 (ns1.aland.net.)
error: no NSEC RR received
Maybe the zone doesn't support DNSSEC or uses NSEC3 RRs
                                                                                                                                                                                             
warning: 0 errors left for 2a00:5500:1:7::194 (ns4.alcom.fi.)
warning: removed misbehaving/unresponsive nameserver 2a00:5500:1:7::194 (ns4.alcom.fi.)
;; walking ax.: records =  77; queries =  84; ................................................................................................................................... q/s = 16 ;;
n3map: fatal: ran out of working nameservers!

Given that 4h.ax. seems to b served also by the same nameservers as ax. itself, querying for the A DNS RR does not produce a NSEC record:

$ dig +dnssec @194.112.0.1 A 4h.ax.

; <<>> DiG 9.18 <<>> +dnssec @194.112.0.1 A 4h.ax.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NOERROR, id: 29925
;; flags: qr aa rd; QUERY: 1, ANSWER: 1, AUTHORITY: 3, ADDITIONAL: 7
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;4h.ax.                         IN      A

;; ANSWER SECTION:
4h.ax.                  86400   IN      A       194.136.187.240

;; AUTHORITY SECTION:
4h.ax.                  86400   IN      NS      ns1.aland.net.
4h.ax.                  86400   IN      NS      ns2.aland.net.
4h.ax.                  86400   IN      NS      ns3.alcom.fi.

;; ADDITIONAL SECTION:
ns2.aland.net.          86400   IN      A       194.112.0.5
ns3.alcom.fi.           86400   IN      A       82.199.186.130
ns3.alcom.fi.           86400   IN      AAAA    2a00:5500:1:6::130
ns1.aland.net.          86400   IN      A       194.112.0.1
ns3.alcom.fi.           86400   IN      RRSIG   A 8 3 86400 20230317104514 20230215103424 18504 alcom.fi. Nf3S3eNg/kylFkuDNvjydN3H5NWQfvX2Olrdqn58Z3jffQISM5ZJXfKa g2JSh/wcckUF9c9+qlfscSWIiGBPULvaX8BanEDuTu/2wEFgFP/jfaUA G4DOPiwuxi4paoVCW9Y+Y9EhbG1rmLiIadMkWsZMJoe5IRibS/PnZ1Uy l54=
ns3.alcom.fi.           86400   IN      RRSIG   AAAA 8 3 86400 20230317104514 20230215103424 18504 alcom.fi. j52jup0dwEXH2wiyVkgadogO4v7gnL7QOnShCrEkL3klEXHvaxCMeeGK Huvr5Yd6UBUZEKqRnIqjkq+8NRsx7U4u2UNsQdxzm7y0NZzEB9L03V6M ZgoUXK0U4Stc1gNXmosJk31KPP4671cHRr4i3Z1BSZw1G07NzPmFy5HQ UOU=

;; Query time: 44 msec
;; SERVER: 194.112.0.1#53(194.112.0.1) (UDP)
;; WHEN: Thu Feb 16 19:46:27 CET 2023
;; MSG SIZE  rcvd: 533

Instead to produce the next NSEC record, we need to manually increment the left-most label from our previous response; similar to what NSEC White Lies does, e.g. 4h0.ax.. This gives the following (proper) reply:

$ dig +dnssec @194.112.0.1 a 4h0.ax.

; <<>> DiG 9.18 <<>> +dnssec @194.112.0.1 a 4h0.ax.
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 16223
;; flags: qr aa rd; QUERY: 1, ANSWER: 0, AUTHORITY: 6, ADDITIONAL: 1
;; WARNING: recursion requested but not available

;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags: do; udp: 4096
;; QUESTION SECTION:
;4h0.ax.                                IN      A

;; AUTHORITY SECTION:
ax.                     7200    IN      SOA     ns1.aland.net. hostmaster.alcom.ax. 2023021889 1800 900 2419200 7200
ax.                     7200    IN      RRSIG   SOA 8 1 86400 20230318183823 20230216173823 10086 ax. ZC2L/HLYLy/fZUutB1vpUVYydv+hVAfZg613ECpLv5H85NXF8KqOK15F Sbx3w7FlDr5hUTPNZgGw9ScpnuhijA7z1FBM+yf72f7NOU31TgRT9OwQ slojorEfFJZIm6zjlgwGxtUtqJdCs6UcTMl8EF3ss2gLuATdHrk+rKTR 8ns=
ax.                     7200    IN      NSEC    00.ax. NS SOA RRSIG NSEC DNSKEY TYPE65534
ax.                     7200    IN      RRSIG   NSEC 8 1 7200 20230318134808 20230216131933 10086 ax. WjrgPOB2zYq0gXenPePcisdvxIOPItacWvr4wgtTUQYcSnQ8/wpJDnHR UCk769zsuluh8SaR/jYULTlRcdv97U8FIjm/z6bKktmwH/wwWtQrlnm9 HI7WcV+oLoPuvE8gozKpoXDGerabAMZWNbmsoRp/ilVyn1t7lxpJZjrt dfY=
4h.ax.                  7200    IN      NSEC    4m.ax. NS RRSIG NSEC
4h.ax.                  7200    IN      RRSIG   NSEC 8 2 7200 20230318143653 20230216134236 10086 ax. BZmis5n/0JUUtE+qf/a7jFTXELf/1kMMFAPcmts+wZsZBqBMejSXJKYY 5A/FNOSmpbKbwgpy+Yy9hVVAI9MN9jx0Gh8M6u4vg27Plpaj0mVEFhfC 6fG+3owlQOnHLSv3N1qICZe2euqP57C5STqZ7uyHlRBX0IZzXH1uGPFU oKM=

;; Query time: 48 msec
;; SERVER: 194.112.0.1#53(194.112.0.1) (UDP)
;; WHEN: Thu Feb 16 19:46:44 CET 2023
;; MSG SIZE  rcvd: 679

Would be nice, if this approach would be tried before declaring a nameserver to be misbehaving.

NB: I'm not yet sure, why this kills all four nameservers for this domain, but likely because the zone is authoritive there too, but not published in the NS RRset in the parent zone we are iterating.

FWIW: Using --query-mode=NSEC produces the same problem.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.