Subdomain Enumeration Tools

Comprehensive collection of subdomain enumeration tools and techniques for reconnaissance and web application security testing.

Subfinder

Basic Subdomain Enumeration

# Basic subdomain enumeration
subfinder -d TARGET_DOMAIN

# With multiple domains
subfinder -d TARGET_DOMAIN1,TARGET_DOMAIN2,TARGET_DOMAIN3

# With output file
subfinder -d TARGET_DOMAIN -o results.txt

# With JSON output
subfinder -d TARGET_DOMAIN -o results.json -json

# With verbose output
subfinder -d TARGET_DOMAIN -v

# With silent output
subfinder -d TARGET_DOMAIN -silent

# With threads
subfinder -d TARGET_DOMAIN -t 50

# With timeout
subfinder -d TARGET_DOMAIN -timeout 10

# With retries
subfinder -d TARGET_DOMAIN -retries 3

Advanced Subfinder Options

# With specific sources
subfinder -d TARGET_DOMAIN -sources shodan,crtsh,passivetotal

# With all sources
subfinder -d TARGET_DOMAIN -all

# With exclude sources
subfinder -d TARGET_DOMAIN -exclude-sources shodan,crtsh

# With config file
subfinder -d TARGET_DOMAIN -config config.yaml

# With proxy
subfinder -d TARGET_DOMAIN -proxy http://127.0.0.1:8080

# With rate limit
subfinder -d TARGET_DOMAIN -rate-limit 100

# With wildcard detection
subfinder -d TARGET_DOMAIN -wildcard

# With recursive enumeration
subfinder -d TARGET_DOMAIN -recursive

Amass

Basic Subdomain Enumeration

# Basic subdomain enumeration
amass enum -d TARGET_DOMAIN

# With multiple domains
amass enum -d TARGET_DOMAIN1,TARGET_DOMAIN2

# With output file
amass enum -d TARGET_DOMAIN -o results.txt

# With JSON output
amass enum -d TARGET_DOMAIN -json results.json

# With verbose output
amass enum -d TARGET_DOMAIN -v

# With silent output
amass enum -d TARGET_DOMAIN -silent

# With threads
amass enum -d TARGET_DOMAIN -t 50

# With timeout
amass enum -d TARGET_DOMAIN -timeout 10

Advanced Amass Options

# With specific sources
amass enum -d TARGET_DOMAIN -sources shodan,crtsh,passivetotal

# With all sources
amass enum -d TARGET_DOMAIN -all

# With exclude sources
amass enum -d TARGET_DOMAIN -exclude-sources shodan,crtsh

# With config file
amass enum -d TARGET_DOMAIN -config config.yaml

# With proxy
amass enum -d TARGET_DOMAIN -proxy http://127.0.0.1:8080

# With rate limit
amass enum -d TARGET_DOMAIN -rate-limit 100

# With wildcard detection
amass enum -d TARGET_DOMAIN -wildcard

# With recursive enumeration
amass enum -d TARGET_DOMAIN -recursive

# With brute force
amass enum -d TARGET_DOMAIN -brute

# With wordlist
amass enum -d TARGET_DOMAIN -w wordlist.txt

Assetfinder

Basic Subdomain Enumeration

# Basic subdomain enumeration
assetfinder TARGET_DOMAIN

# With multiple domains
assetfinder TARGET_DOMAIN1 TARGET_DOMAIN2 TARGET_DOMAIN3

# With output file
assetfinder TARGET_DOMAIN > results.txt

# With subs-only
assetfinder --subs-only TARGET_DOMAIN

# With alive check
assetfinder --alive TARGET_DOMAIN

# With verbose output
assetfinder -v TARGET_DOMAIN

Sublist3r

Basic Subdomain Enumeration

# Basic subdomain enumeration
sublist3r -d TARGET_DOMAIN

# With multiple domains
sublist3r -d TARGET_DOMAIN1,TARGET_DOMAIN2

# With output file
sublist3r -d TARGET_DOMAIN -o results.txt

# With verbose output
sublist3r -d TARGET_DOMAIN -v

# With threads
sublist3r -d TARGET_DOMAIN -t 50

# With timeout
sublist3r -d TARGET_DOMAIN -t 10

# With specific engines
sublist3r -d TARGET_DOMAIN -e google,yahoo,bing

# With all engines
sublist3r -d TARGET_DOMAIN -e all

# With exclude engines
sublist3r -d TARGET_DOMAIN -e google,yahoo -x bing,duckduckgo

DNSrecon

Basic DNS Enumeration

# Basic DNS enumeration
dnsrecon -d TARGET_DOMAIN

# With multiple domains
dnsrecon -d TARGET_DOMAIN1,TARGET_DOMAIN2

# With output file
dnsrecon -d TARGET_DOMAIN -o results.txt

# With JSON output
dnsrecon -d TARGET_DOMAIN -j results.json

# With verbose output
dnsrecon -d TARGET_DOMAIN -v

# With threads
dnsrecon -d TARGET_DOMAIN -t 50

# With timeout
dnsrecon -d TARGET_DOMAIN -t 10

# With specific record types
dnsrecon -d TARGET_DOMAIN -t A,AAAA,CNAME,MX,NS,SOA,TXT

# With all record types
dnsrecon -d TARGET_DOMAIN -t all

# With brute force
dnsrecon -d TARGET_DOMAIN -b

# With wordlist
dnsrecon -d TARGET_DOMAIN -w wordlist.txt

Fierce

Basic Subdomain Enumeration

# Basic subdomain enumeration
fierce -dns TARGET_DOMAIN

# With multiple domains
fierce -dns TARGET_DOMAIN1,TARGET_DOMAIN2

# With output file
fierce -dns TARGET_DOMAIN -file results.txt

# With verbose output
fierce -dns TARGET_DOMAIN -verbose

# With threads
fierce -dns TARGET_DOMAIN -threads 50

# With timeout
fierce -dns TARGET_DOMAIN -timeout 10

# With wordlist
fierce -dns TARGET_DOMAIN -wordlist wordlist.txt

# With range
fierce -dns TARGET_DOMAIN -range 192.168.1.0/24

# With delay
fierce -dns TARGET_DOMAIN -delay 1

DNSenum

Basic DNS Enumeration

# Basic DNS enumeration
dnsenum TARGET_DOMAIN

# With multiple domains
dnsenum TARGET_DOMAIN1 TARGET_DOMAIN2

# With output file
dnsenum TARGET_DOMAIN -o results.txt

# With verbose output
dnsenum TARGET_DOMAIN -v

# With threads
dnsenum TARGET_DOMAIN -t 50

# With timeout
dnsenum TARGET_DOMAIN -t 10

# With wordlist
dnsenum TARGET_DOMAIN -w wordlist.txt

# With range
dnsenum TARGET_DOMAIN -r 192.168.1.0/24

# With delay
dnsenum TARGET_DOMAIN -d 1

Custom Scripts

Python Subdomain Enumeration

import requests
import threading
import queue
import time
import dns.resolver

def subdomain_enumeration(domain, wordlist, threads=10, delay=0):
    def worker():
        while True:
            try:
                subdomain = wordlist.get()
                if subdomain is None:
                    break
                
                full_domain = f"{subdomain}.{domain}"
                
                # DNS resolution
                try:
                    dns.resolver.resolve(full_domain, 'A')
                    print(f"[DNS] {full_domain}")
                except:
                    pass
                
                # HTTP check
                try:
                    response = requests.get(f"http://{full_domain}", timeout=5)
                    print(f"[HTTP] {full_domain} - {response.status_code}")
                except:
                    pass
                
                # HTTPS check
                try:
                    response = requests.get(f"https://{full_domain}", timeout=5)
                    print(f"[HTTPS] {full_domain} - {response.status_code}")
                except:
                    pass
                
                time.sleep(delay)
                
            except Exception as e:
                pass
            finally:
                wordlist.task_done()
    
    # Start threads
    for i in range(threads):
        t = threading.Thread(target=worker)
        t.daemon = True
        t.start()
    
    # Add subdomains to queue
    with open(wordlist_file, 'r') as f:
        for line in f:
            wordlist.put(line.strip())
    
    # Wait for completion
    wordlist.join()

# Usage
domain = "TARGET_DOMAIN"
wordlist_file = "/usr/share/wordlists/subdomains.txt"
wordlist = queue.Queue()
subdomain_enumeration(domain, wordlist, threads=20, delay=0.1)

Bash Subdomain Enumeration

#!/bin/bash

DOMAIN="TARGET_DOMAIN"
WORDLIST="/usr/share/wordlists/subdomains.txt"
THREADS=10

# Function to check subdomain
check_subdomain() {
    local subdomain=$1
    local full_domain="${subdomain}.${DOMAIN}"
    
    # DNS resolution
    if nslookup "$full_domain" > /dev/null 2>&1; then
        echo "[DNS] $full_domain"
    fi
    
    # HTTP check
    if curl -s -o /dev/null -w "%{http_code}" "http://$full_domain" | grep -q "200\|301\|302\|403\|401"; then
        echo "[HTTP] $full_domain"
    fi
    
    # HTTPS check
    if curl -s -o /dev/null -w "%{http_code}" "https://$full_domain" | grep -q "200\|301\|302\|403\|401"; then
        echo "[HTTPS] $full_domain"
    fi
}

# Export function for parallel
export -f check_subdomain
export DOMAIN

# Run parallel subdomain check
cat "$WORDLIST" | parallel -j "$THREADS" check_subdomain {}

Wordlists

Common Subdomain Wordlists

# SecLists subdomain wordlists
/usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt
/usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-110000.txt
/usr/share/wordlists/SecLists/Discovery/DNS/dns-Jhaddix.txt

# Custom subdomain wordlists
/usr/share/wordlists/custom/subdomains.txt
/usr/share/wordlists/custom/api-subdomains.txt
/usr/share/wordlists/custom/admin-subdomains.txt

# Generate custom wordlists
echo "www,mail,ftp,admin,api,dev,test,staging,prod" | tr ',' '\n' > custom_subdomains.txt

Creating Custom Wordlists

# Extract subdomains from certificate transparency logs
curl -s "https://crt.sh/?q=%.TARGET_DOMAIN&output=json" | jq -r '.[].name_value' | sort -u > crt_subdomains.txt

# Extract subdomains from DNS records
dig @8.8.8.8 TARGET_DOMAIN ANY | grep -oP 'IN\s+\w+\s+\K[^\s]+' | sort -u > dns_subdomains.txt

# Combine multiple wordlists
cat wordlist1.txt wordlist2.txt wordlist3.txt | sort -u > combined_wordlist.txt

# Remove empty lines and duplicates
grep -v '^$' wordlist.txt | sort -u > clean_wordlist.txt

API-based Enumeration

Shodan API

# Using Shodan CLI
shodan domain TARGET_DOMAIN

# Using Shodan API
curl -s "https://api.shodan.io/dns/domain/TARGET_DOMAIN?key=YOUR_API_KEY" | jq -r '.data[].subdomain' | sort -u

Censys API

# Using Censys API
curl -s "https://censys.io/api/v1/search/certificates" \
  -H "Authorization: Basic YOUR_API_KEY" \
  -d '{"query": "TARGET_DOMAIN", "fields": ["parsed.names"]}' | jq -r '.result.hits[].parsed.names[]' | sort -u

VirusTotal API

# Using VirusTotal API
curl -s "https://www.virustotal.com/vtapi/v2/domain/report" \
  -d "apikey=YOUR_API_KEY" \
  -d "domain=TARGET_DOMAIN" | jq -r '.subdomains[]' | sort -u

Passive vs Active Enumeration

Passive Enumeration

# Using only passive sources
subfinder -d TARGET_DOMAIN -sources crtsh,passivetotal,shodan

# Using only passive DNS
dnsrecon -d TARGET_DOMAIN -t A,AAAA,CNAME,MX,NS,SOA,TXT

# Using only certificate transparency
curl -s "https://crt.sh/?q=%.TARGET_DOMAIN&output=json" | jq -r '.[].name_value' | sort -u

Active Enumeration

# Using brute force
amass enum -d TARGET_DOMAIN -brute

# Using wordlist
subfinder -d TARGET_DOMAIN -w wordlist.txt

# Using recursive enumeration
subfinder -d TARGET_DOMAIN -recursive

Best Practices

Rate Limiting

# Add delay between requests
subfinder -d TARGET_DOMAIN -rate-limit 100

# Use fewer threads
subfinder -d TARGET_DOMAIN -t 10

# Use proxy rotation
subfinder -d TARGET_DOMAIN -proxy http://proxy1:8080

Stealth Mode

# Use random user agents
subfinder -d TARGET_DOMAIN -a "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36"

# Use realistic delays
subfinder -d TARGET_DOMAIN -rate-limit 50

# Use smaller wordlists
subfinder -d TARGET_DOMAIN -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt

Output Analysis

# Save results to file
subfinder -d TARGET_DOMAIN -o results.txt

# Filter by status code
grep "200" results.txt
grep "403" results.txt
grep "301\|302" results.txt

# Sort by response size
sort -k3 -n results.txt

Troubleshooting

Common Issues

# Connection timeout
subfinder -d TARGET_DOMAIN -t 5

# Too many requests
subfinder -d TARGET_DOMAIN -rate-limit 50

# Invalid SSL certificate
subfinder -d TARGET_DOMAIN -k

# Authentication required
subfinder -d TARGET_DOMAIN -u admin -p password

Performance Optimization

# Use appropriate thread count
subfinder -d TARGET_DOMAIN -t 20

# Use smaller wordlists for initial scan
subfinder -d TARGET_DOMAIN -w /usr/share/wordlists/SecLists/Discovery/DNS/subdomains-top1million-5000.txt

# Use specific sources
subfinder -d TARGET_DOMAIN -sources crtsh,passivetotal
  • Always obtain proper authorization before testing
  • Respect rate limits and server resources
  • Use appropriate wordlists for the target
  • Document findings properly
  • Follow responsible disclosure practices