← All labs
MediumReconnaissance ~35 min

DNS Enumeration & Zone Transfer

Enumerate subdomains of a misconfigured DNS server using dig and a zone transfer, then map every host.

↳ Based on the lesson: Ports, DNS & HTTP

Legal Use Only

DNS enumeration against domains you do not own or have explicit written authorization to test is unauthorized access. Zone transfers specifically are designed for administrative use between nameservers. Never attempt zone transfers against production domains outside of an authorized bug bounty or penetration test scope. This lab uses a local, intentionally misconfigured DNS server.

Scenario

You're doing external recon on a target organization that has given you written authorization for a full external penetration test. Your first job is to map their internet-facing DNS infrastructure: find every subdomain, identify nameservers, collect all record types, and test for zone transfer misconfiguration.

For this lab, we'll use dnsmasq on a local Kali VM to simulate a misconfigured DNS server, plus public DNS recon tools against a local zone file.

Setup:

# Install tools if needed (should be on Kali already)
$ sudo apt install dnsmasq dnsenum dnsrecon -y
 
# Create a local zone file to simulate the target
$ sudo mkdir -p /etc/dnsmasq.d
$ cat > /tmp/vr4cs-lab.zone << 'EOF'
www       IN A     10.10.10.10
mail      IN A     10.10.10.20
ftp       IN A     10.10.10.30
admin     IN A     10.10.10.40
staging   IN A     10.10.10.50
vpn       IN A     10.10.10.60
dev       IN CNAME staging.lab.vr4cs
shop      IN CNAME shopify-external.myshopify.com.
          IN MX 10 mail.lab.vr4cs.
          IN MX 20 mail2.lab.vr4cs.
EOF

For the full lab experience, you can also use HackTheBox or TryHackMe DNS challenge boxes, which ship with misconfigured bind servers specifically for this practice.

Your Objective

  1. Identify the authoritative nameservers for a target domain
  2. Enumerate subdomains using brute-force wordlists and passive sources
  3. Collect all DNS record types (A, AAAA, MX, TXT, NS, CNAME)
  4. Attempt a zone transfer (AXFR) and demonstrate what a misconfigured server reveals
  5. Identify any CNAME records pointing to potentially abandoned external services

Hints

Start with NS records

Before enumerating subdomains, find the authoritative nameservers with dig NS target.com. Zone transfer attempts must be directed at the authoritative nameserver - not your ISP's resolver - or they'll always fail.

dig vs nslookup vs host

dig is the most powerful and scriptable. nslookup is more interactive. host is simpler. For automation and CTFs, use dig. Use +short to get just the answer without the extra metadata.

dnsenum automates everything

dnsenum --dnsserver <ns> --enum <domain> will automatically: query NS/MX/A records, attempt zone transfers, and brute-force subdomains from a wordlist. It's the single-tool approach.

Walkthrough

Step 1: Find authoritative nameservers
# For a real target:
$ dig NS targetdomain.com +short
ns1.targetdomain.com.
ns2.targetdomain.com.
 
# Or with host:
$ host -t NS targetdomain.com
targetdomain.com name server ns1.targetdomain.com.
targetdomain.com name server ns2.targetdomain.com.
 
# Resolve the nameserver IPs:
$ dig A ns1.targetdomain.com +short
198.51.100.53

Write down the NS IPs - zone transfer attempts must target these directly.

Step 2: Query all major record types
# A records (IPv4):
$ dig A www.targetdomain.com +short
10.10.10.10
 
# MX records (mail servers - note the priority):
$ dig MX targetdomain.com
;; ANSWER SECTION:
targetdomain.com.  3600  IN  MX  10  mail.targetdomain.com.
targetdomain.com.  3600  IN  MX  20  mail2.targetdomain.com.
 
# TXT records (SPF, DKIM, cloud verification):
$ dig TXT targetdomain.com
;; ANSWER SECTION:
targetdomain.com.  IN  TXT  "v=spf1 include:_spf.google.com ~all"
targetdomain.com.  IN  TXT  "google-site-verification=abc123XYZ"
 
# CNAME records (chase the alias chain):
$ dig CNAME shop.targetdomain.com +short
shopify-external.myshopify.com.

The TXT record reveals they use Google Workspace for email and have Google Search Console set up. The CNAME points to Shopify - useful for understanding their tech stack.

Step 3: Attempt zone transfer (AXFR)

A zone transfer requests the entire DNS zone from an authoritative nameserver. Properly configured servers restrict this to trusted secondary nameservers only. Misconfigured ones allow it from anywhere.

# Attempt zone transfer against the authoritative nameserver:
$ dig axfr @198.51.100.53 targetdomain.com
 
# If misconfigured, the full zone dumps:
; <<>> DiG 9.18.1 <<>> axfr @198.51.100.53 targetdomain.com
;; global options: +cmd
targetdomain.com.     3600  IN  SOA   ns1.targetdomain.com. admin.targetdomain.com. ...
www.targetdomain.com. 3600  IN  A     10.10.10.10
mail.targetdomain.com.3600  IN  A     10.10.10.20
ftp.targetdomain.com. 3600  IN  A     10.10.10.30
admin.targetdomain.com.3600 IN  A     10.10.10.40
staging.targetdomain.com.3600 IN A   10.10.10.50
vpn.targetdomain.com. 3600  IN  A     10.10.10.60
dev.targetdomain.com. 3600  IN  CNAME staging.targetdomain.com.
shop.targetdomain.com.3600  IN  CNAME shopify-external.myshopify.com.
targetdomain.com.     3600  IN  SOA   ns1.targetdomain.com. admin.targetdomain.com. ...
 
# If properly configured, you get:
; Transfer failed.

A successful zone transfer reveals every hostname the organization has ever configured - internal naming conventions, staging servers, VPN gateways, admin panels, development servers. This is a critical finding.

Step 4: Subdomain brute-force with dnsenum
$ dnsenum --dnsserver 198.51.100.53 \
  --enum targetdomain.com \
  -f /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  -o dnsenum-results.txt
 
# Or with subfinder (passive - no brute force, uses public sources):
$ subfinder -d targetdomain.com -silent -o passive-subs.txt
 
# Or with dnsrecon:
$ dnsrecon -d targetdomain.com -t brt \
  -D /usr/share/seclists/Discovery/DNS/fierce-hostlist.txt
Step 5: Identify dangling CNAME records
# For each CNAME found, check if the target exists:
$ dig CNAME shop.targetdomain.com +short
shopify-external.myshopify.com.
 
# Check if the Shopify subdomain exists:
$ curl -s -o /dev/null -w "%{http_code}" https://shopify-external.myshopify.com
404
 
# A 404 / "no app at this hostname" means the CNAME is dangling - subdomain takeover candidate

Solution

# 1. Find nameservers
dig NS targetdomain.com +short
 
# 2. Collect all record types
for type in A AAAA MX TXT NS CNAME SOA; do
  echo "=== $type ===" && dig $type targetdomain.com +short
done
 
# 3. Attempt zone transfer
dig axfr @$(dig NS targetdomain.com +short | head -1 | tr -d '.') targetdomain.com
 
# 4. Brute-force subdomains
dnsenum --dnsserver <ns-ip> --enum targetdomain.com \
  -f /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
 
# 5. Check CNAMEs for dangling records
dig CNAME shop.targetdomain.com +short | xargs curl -s -o /dev/null -w "%{http_code}\n"

Key takeaway: A misconfigured zone transfer collapses weeks of subdomain enumeration into one command. Even without AXFR, passive subdomain enumeration (certificate transparency, public sources) combined with brute-force wordlists reveals the majority of an organization's DNS surface. DNS recon is always the first step of external reconnaissance - before you touch a single HTTP endpoint.