Subdomain Enumeration: Passive & Active Recon
Before you attack a web target you map it. Most companies run far more than www, there are api, dev, staging, vpn, admin, forgotten side projects, and old infrastructure. Each subdomain is another door. Finding them all is how you expand the attack surface, and it is the first step of almost every bug-bounty or pentest engagement.
Passive vs active
| Passive | Active | |
|---|---|---|
| Talks to the target? | No, queries third parties | Yes, sends DNS/HTTP to the target |
| Noise / detection | Silent | Can trip rate limits / WAFs |
| Finds | Anything ever made public | Hidden names not in public data |
Real recon uses both: passive first (free and silent), then active to fill the gaps.
Passive enumeration
Certificate Transparency (crt.sh). Every TLS certificate a CA issues is logged publicly. Searching those logs leaks subdomains for free, even internal-looking ones that accidentally got a cert.
curl -s 'https://crt.sh/?q=%.acme.com&output=json' | jq -r '.[].name_value' | sort -u
Aggregator tools query 30+ sources (CT logs, DNS datasets, search engines) for you:
subfinder -d acme.com -all -silent -o subfinder.txt
amass enum -passive -d acme.com -o amass.txt
assetfinder --subs-only acme.com
Search-engine dorking surfaces indexed hosts automation misses:
site:*.acme.com -site:www.acme.com
Other rich sources: SecurityTrails, Censys, Shodan (DNS history and exposed services), and github-subdomains (subdomains leaked in public code).
Active enumeration
DNS brute-forcing. Take a wordlist (the SecLists DNS lists are the standard) and test every word.acme.com. This finds names that were never published anywhere public.
gobuster dns -d acme.com -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
puredns bruteforce wordlist.txt acme.com -r resolvers.txt
Permutations. Mutate known names (api -> api-dev, api2, staging-api) with dnsgen, gotator, or altdns, then resolve the candidates.
Virtual-host (vhost) fuzzing. Many sites share one IP and route by the Host: header. Spray the header to reveal hidden vhosts:
ffuf -u https://acme.com -H 'Host: FUZZ.acme.com' -w wordlist.txt -mc 200,403
Zone transfer (AXFR). A misconfigured nameserver will hand you the entire DNS zone in one request, an instant, complete list:
dig axfr @ns1.acme.com acme.com
Most servers refuse this, but it is always worth one try. The public zonetransfer.me zone is left open on purpose so you can see a successful dump.
Resolve, then probe
A raw name list is full of dead entries. Two steps clean it up:
- Resolve which names actually point somewhere (
dnsx). - Probe which of those run a live web server (
httpx/httprobe).
cat subfinder.txt amass.txt | sort -u | dnsx -silent > resolved.txt
httpx -l resolved.txt -title -sc -ip
A [403] or [401] host is still alive, do not throw away non-200 results; locked-down admin panels are exactly what you want to find.
Try it (terminal)
subfinder -d acme.com, see the passive results.curl -s 'https://crt.sh/?q=%.acme.com', certificate transparency names.gobuster dns -d acme.com -w wordlist.txt, notice it findsinternal,jenkins,gitthat passive missed.ffuf -u https://FUZZ.acme.com -w wordlist.txt, vhost fuzzing.httpx -l subs.txt, probe which names are live web servers.dig axfr @ns1.acme.com acme.com(refused), thendig axfr @nsztm1.digi.ninja zonetransfer.me(leaks the zone).
Stay in scope
Active enumeration sends real traffic. Only test domains you are authorised to (your own, or those in a bug-bounty program's scope). Rate-limit brute force, respect robots.txt and program rules, or you will get your IP banned, or worse.
Why this matters
The biggest bugs are usually not on the main site, they are on the forgotten dev, staging, or admin subdomain nobody patched. Thorough subdomain enumeration is the difference between testing one app and testing the company's whole exposed estate.