TL;DR: Take known subdomains as seeds, mutate them into new plausible candidates (gotator, altdns, dnsgen, regulator), then resolve at scale. Catches subdomains that wordlist brute-force misses because they follow the org’s internal naming conventions.
What it is
Passive sources (certificate-transparency) give you a seed list. Wordlist brute-force gives you common patterns. Permutation fills the gap in between — generating candidates that look like the seeds (dev-api-v2.target.tld, api-v3.target.tld, staging-api-v2.target.tld) and resolving them. It’s the highest-yield active-DNS technique for mature targets where common wordlists are already exhausted.
Preconditions / where it applies
- You have a seed list of 20+ known subdomains from passive sources
- You can resolve at high QPS (parallel resolvers, public DNS, no aggressive rate-limiting at your end)
- Wildcard DNS detection in place (target may return any subdomain as valid; permutation against wildcards is useless without filtering)
Technique
- Build a clean seed set. Deduplicate, strip the apex, normalise case:
1
2
3
4
5
| api.target.tld
api-v2.target.tld
dev.target.tld
dev-api.target.tld
staging-api.target.tld
|
- Run permutation. Different tools use different mutation strategies:
1
2
3
4
5
6
7
8
| # gotator — pattern-based, controllable depth
gotator -sub seeds.txt -perm common.txt -depth 1 -mindup > candidates.txt
# altdns — alteration patterns (add/replace/insert)
altdns -i seeds.txt -o candidates.txt -w altdns/words.txt
# regulator — learns patterns statistically from seeds (no wordlist)
python3 main.py -t target.tld -f seeds.txt -o candidates.txt
|
- Resolve candidates in parallel.
puredns, massdns, or shuffledns against a resolvers file:
1
2
| puredns resolve candidates.txt -r resolvers.txt --wildcard-tests 10 \
--wildcard-batch 100000 -w resolved.txt
|
- Filter wildcards. Many CDNs return a default IP for any subdomain —
*.target.tld → 1.2.3.4. Either drop everything resolving to a known wildcard IP or post-filter by HTTP response hash via httpx. - Repeat. The newly discovered subdomains become seeds for the next pass (cap at 2-3 iterations; returns diminish fast and traffic grows linearly).
- Track in the asset graph (asset-graphing) and feed live hosts into content-discovery and tech-stack-fingerprinting.
1
2
3
| # minimal pipeline
seeds.txt -> gotator -> candidates.txt -> puredns -> resolved.txt
\ \-> httpx -> live.txt
|
Detection and defence
- Authoritative DNS sees enormous NXDOMAIN bursts; log and alert on QPS spikes from any single resolver
- Don’t follow predictable naming conventions for sensitive subdomains —
admin-secret-app-v2 is permutable from app-v2 - Restrict access to internal-only subdomains by VPN / IP allowlist, not by hoping nobody guesses the name (security by obscurity)
- If you must expose dev / staging hostnames externally, randomise the suffix (UUID) so they don’t appear in permutation output
References