Reconnaissance

Subdomain Discovery

Subdomains often host development environments, staging servers, admin panels, and legacy applications with weaker security controls. Comprehensive subdomain enumeration is critical for mapping the complete attack surface.

Why Subdomain Discovery Matters

Subdomains represent hidden attack surface. Development and staging environments often have default credentials, debug endpoints, and unpatched vulnerabilities. Finding forgotten subdomains like dev., staging., or old. frequently leads to critical findings.

Tip

Combine multiple subdomain discovery methods. Passive techniques miss active-only subdomains, while brute-forcing misses non-dictionary entries. Use both for comprehensive coverage.

Tools & Resources

Subfinder

Fast passive subdomain enumeration

go install ...subfinder@latest GitHub →

Amass

OWASP subdomain discovery tool

go install ...amass/v4@master GitHub →

httpx

Fast HTTP probing toolkit

go install ...httpx@latest GitHub →

Assetfinder

Simple and fast asset discovery

go install assetfinder@latest GitHub →

Passive Subdomain Discovery

Passive techniques query third-party databases and services without touching target infrastructure.

Subfinder

subfinder.sh
bash
# Basic subdomain enumeration
subfinder -d example.com -o subdomains.txt

# Silent mode (just results)
subfinder -d example.com -silent

# Multiple domains
subfinder -dL domains.txt -o all_subdomains.txt

# Recursive enumeration
subfinder -d example.com -recursive

# Use all sources (requires API keys configured)
subfinder -d example.com -all

# Output in JSON
subfinder -d example.com -json -o subdomains.json

# Configure sources in ~/.config/subfinder/provider-config.yaml
# Add API keys for: SecurityTrails, Shodan, Censys, VirusTotal, etc.

Amass (Passive Mode)

amass-passive.sh
bash
# Passive enumeration only
amass enum -passive -d example.com -o amass_passive.txt

# With specific data sources
amass enum -passive -d example.com -src

# Intel mode for additional discovery
amass intel -d example.com -whois

# Find ASN and expand
amass intel -org "Example Company"
amass intel -asn 12345

# Config file for API keys
amass enum -passive -d example.com -config ~/.config/amass/config.ini

Certificate Transparency

ct-subdomain.sh
bash
# crt.sh - Query CT logs
curl -s "https://crt.sh/?q=%25.example.com&output=json" | \
  jq -r '.[].name_value' | sed 's/\*\.//g' | sort -u

# Filter unique subdomains
curl -s "https://crt.sh/?q=%.example.com&output=json" | \
  jq -r '.[].name_value' | \
  grep -v "\*" | \
  sort -u > ct_subdomains.txt

# Certspotter API
curl -s "https://api.certspotter.com/v1/issuances?domain=example.com&include_subdomains=true&expand=dns_names" | \
  jq -r '.[].dns_names[]' | sort -u

# Facebook CT
curl -s "https://graph.facebook.com/certificates?query=example.com&access_token=TOKEN" | jq

Other Passive Sources

passive-sources.sh
bash
# Assetfinder
assetfinder --subs-only example.com

# Findomain
findomain -t example.com -q

# Chaos (ProjectDiscovery database)
chaos -d example.com -o chaos_subs.txt

# Archive-based discovery
# Wayback URLs
waybackurls example.com | unfurl --unique domains

# GAU (GetAllUrls)
gau --subs example.com | unfurl --unique domains

# SecurityTrails API
curl -s "https://api.securitytrails.com/v1/domain/example.com/subdomains" \
  -H "APIKEY: your_api_key" | jq -r '.subdomains[]' | \
  sed 's/$/.example.com/'

# VirusTotal API
curl -s "https://www.virustotal.com/vtapi/v2/domain/report?apikey=KEY&domain=example.com" | \
  jq -r '.subdomains[]'

Active Subdomain Discovery

Warning

Active enumeration involves DNS queries and brute-forcing. This creates traffic detectable by target monitoring systems. Ensure authorization.

DNS Brute-Forcing

dns-bruteforce.sh
bash
# Amass active mode with brute-force
amass enum -active -d example.com -brute -w /path/to/wordlist.txt

# DNSRecon brute-force
dnsrecon -d example.com -t brt -D /path/to/wordlist.txt

# Knockpy
knockpy example.com -w /path/to/wordlist.txt

# Gobuster DNS mode
gobuster dns -d example.com -w /path/to/wordlist.txt -t 50

# Aiodnsbrute (async, fast)
aiodnsbrute -w /path/to/wordlist.txt example.com

# Massdns (extremely fast, use with wordlist)
massdns -r resolvers.txt -t A -o S wordlist.txt | grep example.com

Recommended Wordlists

Wordlist Size Use Case
SecLists DNS ~100k entries General purpose, good balance
Jhaddix all.txt ~2M entries Comprehensive, slow but thorough
n0kovo_subdomains ~3M entries Large-scale enumeration
commonspeak2 ~4k entries Quick initial scan
wordlists.sh
bash
# Download common wordlists
# SecLists
git clone https://github.com/danielmiessler/SecLists.git
# Best subdomain list: SecLists/Discovery/DNS/subdomains-top1million-110000.txt

# Jhaddix all.txt
wget https://gist.githubusercontent.com/jhaddix/86a06c5dc309d08580a018c66354a056/raw/all.txt

# Assetnote Wordlists
wget https://wordlists-cdn.assetnote.io/data/manual/best-dns-wordlist.txt

# Generate custom wordlist from target
# Scrape website and extract words
cewl https://example.com -d 3 -w custom_wordlist.txt

Subdomain Validation

After enumeration, validate which subdomains are live and gather additional information.

httpx-validation.sh
bash
# httpx - Fast HTTP probing
cat subdomains.txt | httpx -silent -o live_subdomains.txt

# With additional data
cat subdomains.txt | httpx -title -status-code -tech-detect -o httpx_results.txt

# JSON output with all details
cat subdomains.txt | httpx -json -o httpx_results.json

# Filter by status code
cat subdomains.txt | httpx -mc 200,301,302,403

# Screenshot live hosts
cat subdomains.txt | httpx -screenshot -ss-timeout 5

# Check for specific technologies
cat subdomains.txt | httpx -tech-detect | grep -i "wordpress\|joomla\|drupal"
dns-validation.sh
bash
# DNS resolution check
cat subdomains.txt | dnsx -silent -a -resp

# Check CNAME for subdomain takeover
cat subdomains.txt | dnsx -silent -cname -resp

# Mass DNS resolution with massdns
massdns -r resolvers.txt -t A -o S subdomains.txt > resolved.txt

# Filter only resolved
cat resolved.txt | grep -E "\. A " | cut -d " " -f 1 | sed 's/\.$//' > resolved_subs.txt

Subdomain Takeover Detection

Subdomains pointing to unclaimed cloud services or expired resources can be taken over.

subdomain-takeover.sh
bash
# Check CNAME records for takeover candidates
cat subdomains.txt | dnsx -cname -resp | grep -E "(amazonaws|azure|cloudfront|herokuapp|github|shopify|fastly|pantheon|zendesk|ghost)"

# nuclei subdomain takeover templates
nuclei -l subdomains.txt -t ~/nuclei-templates/takeovers/

# Subjack - Subdomain takeover checker
subjack -w subdomains.txt -t 100 -timeout 30 -ssl -c fingerprints.json -v

# Can-I-Take-Over-XYZ reference
# https://github.com/EdOverflow/can-i-take-over-xyz

# Common takeover fingerprints:
# - "There isn't a GitHub Pages site here" (GitHub)
# - "NoSuchBucket" (AWS S3)
# - "The specified bucket does not exist" (GCS)
# - "Sorry, this shop is currently unavailable" (Shopify)
# - "Fastly error: unknown domain" (Fastly)

Automation Pipeline

subdomain-enum.sh
bash
#!/bin/bash
# Comprehensive subdomain enumeration pipeline

DOMAIN=$1
OUTPUT_DIR="recon/$DOMAIN"
mkdir -p $OUTPUT_DIR

echo "[*] Running subdomain enumeration for $DOMAIN"

# Passive sources
echo "[+] Subfinder..."
subfinder -d $DOMAIN -silent >> $OUTPUT_DIR/subs_raw.txt

echo "[+] Amass passive..."
amass enum -passive -d $DOMAIN -silent >> $OUTPUT_DIR/subs_raw.txt

echo "[+] Assetfinder..."
assetfinder --subs-only $DOMAIN >> $OUTPUT_DIR/subs_raw.txt

echo "[+] crt.sh..."
curl -s "https://crt.sh/?q=%25.$DOMAIN&output=json" | \
  jq -r '.[].name_value' 2>/dev/null | sed 's/\*\.//g' >> $OUTPUT_DIR/subs_raw.txt

# Deduplicate
echo "[+] Deduplicating..."
cat $OUTPUT_DIR/subs_raw.txt | sort -u > $OUTPUT_DIR/subdomains.txt

# Resolve and probe
echo "[+] Probing live hosts..."
cat $OUTPUT_DIR/subdomains.txt | httpx -silent -threads 100 -o $OUTPUT_DIR/live_subdomains.txt

# Results
TOTAL=$(wc -l < $OUTPUT_DIR/subdomains.txt)
LIVE=$(wc -l < $OUTPUT_DIR/live_subdomains.txt)
echo "[*] Found $TOTAL subdomains, $LIVE are live"

# Check for takeover
echo "[+] Checking subdomain takeover..."
nuclei -l $OUTPUT_DIR/subdomains.txt -t ~/nuclei-templates/takeovers/ -silent -o $OUTPUT_DIR/takeovers.txt

echo "[*] Results saved to $OUTPUT_DIR"

Subdomain Discovery Checklist

🔍 Passive Discovery

  • ☐ Subfinder enumeration
  • ☐ Amass passive mode
  • ☐ Certificate Transparency logs
  • ☐ Wayback/Archive URLs
  • ☐ SecurityTrails/VirusTotal APIs

⚡ Active Discovery

  • ☐ DNS brute-forcing
  • ☐ Multiple wordlists tested
  • ☐ Permutation generation
  • ☐ Zone transfer attempted
  • ☐ Virtual host discovery

✅ Validation

  • ☐ Live hosts identified (httpx)
  • ☐ Technologies detected
  • ☐ Status codes documented
  • ☐ Screenshots captured
  • ☐ Results deduplicated

🎯 Takeover Check

  • ☐ CNAME records analyzed
  • ☐ Cloud services identified
  • ☐ Takeover fingerprints checked
  • ☐ Nuclei takeover templates
  • ☐ Dangling records documented

Practice Labs