Overview
Altdns is a specialized subdomain discovery tool that leverages permutation and mutation techniques to identify previously unknown subdomains within a target domain. Unlike traditional brute-force subdomain enumeration, Altdns takes a list of known subdomains and generates variations by applying common naming conventions, abbreviations, and patterns. It then attempts DNS resolution on these generated candidates to discover valid subdomains. This approach is particularly effective for bug bounty programs and penetration testing engagements where maximizing attack surface discovery is critical.
Installation
Prerequisites
# System requirements
- Python 3.6+
- pip package manager
- Network connectivity for DNS resolution
- DNS resolver (system resolver or custom)
Installation via pip
# Install from PyPI
pip install altdns
# Verify installation
altdns --version
# Display help
altdns --help
Installation from Source
# Clone repository
git clone https://github.com/infosec-au/altdns.git
cd altdns
# Install dependencies
pip install -r requirements.txt
# Install package
pip install -e .
# Verify installation
python -m altdns --help
Docker Installation
# Pull Docker image
docker pull infosecau/altdns
# Run with Docker
docker run --rm infosecau/altdns -i subdomains.txt -w /wordlists/words.txt -o results.txt
# Interactive mode with mounted directory
docker run -it --rm -v $(pwd):/data infosecau/altdns \
-i /data/subdomains.txt \
-w /data/words.txt \
-o /data/results.txt
Basic Usage
Command Structure
altdns -i <input_file> -w <wordlist> -o <output_file> [options]
Required Arguments
-i, --input Path to file containing known subdomains (one per line)
-w, --wordlist Path to wordlist file for permutation generation
-o, --output Path to output file for discovered subdomains
Simple Example
# Basic subdomain discovery
altdns -i subdomains.txt -w words.txt -o discovered.txt
# Verbose output
altdns -i subdomains.txt -w words.txt -o discovered.txt -v
# Save as CSV format
altdns -i subdomains.txt -w words.txt -o discovered.csv
Advanced Options
DNS Resolution
# Specify custom DNS resolver
altdns -i subdomains.txt -w words.txt -o results.txt --resolver 8.8.8.8
# Use multiple DNS resolvers
altdns -i subdomains.txt -w words.txt -o results.txt \
--resolver 8.8.8.8 1.1.1.1 9.9.9.9
# Use resolvers from file
altdns -i subdomains.txt -w words.txt -o results.txt \
--resolver-file resolvers.txt
# Adjust thread count (default: 5)
altdns -i subdomains.txt -w words.txt -o results.txt -t 20
# Maximum threads for fast resolution
altdns -i subdomains.txt -w words.txt -o results.txt -t 100
# Single-threaded mode (slowest)
altdns -i subdomains.txt -w words.txt -o results.txt -t 1
# With timeout adjustment
altdns -i subdomains.txt -w words.txt -o results.txt \
--timeout 10 -t 50
Wordlist Options
# Use single wordlist
altdns -i subdomains.txt -w /wordlists/words.txt -o results.txt
# Use multiple wordlists
altdns -i subdomains.txt \
-w /wordlists/words.txt /wordlists/subdomains.txt \
-o results.txt
# Custom wordlist (any permutations)
altdns -i subdomains.txt -w custom_words.txt -o results.txt
Wordlist Management
Common Wordlists
| Wordlist | Source | Size | Use Case |
|---|
| words.txt (altdns default) | GitHub | Small | Quick testing |
| SecLists | SecLists repo | Large | Comprehensive enumeration |
| subdomains-top1million-110000.txt | SecLists | Large | Most common subdomains |
| subdomains.txt | Various | Medium | Alternative patterns |
| dns-wordlists | Assetnote | Large | Specialized DNS discovery |
Creating Custom Wordlist
# Extract common subdomain patterns
cat common_subdomains.txt | sort -u > custom_wordlist.txt
# Combine multiple wordlists
cat /wordlists/*.txt | sort -u > combined_wordlist.txt
# Remove duplicates and sort
sort -u input_wordlist.txt -o cleaned_wordlist.txt
# Count words
wc -l wordlist.txt
# View sample
head -20 wordlist.txt
Download Common Wordlists
# SecLists repository
git clone https://github.com/danielmiessler/SecLists.git
# Located in SecLists/Discovery/DNS/
# Assetnote DNS wordlists
wget https://wordlists-cdn.assetnote.io/data/automated/subdomains-top1million-5000.txt
# OneListForAll
git clone https://github.com/six2dez/OneListForAll.git
# Create ultimate wordlist
cat SecLists/Discovery/DNS/*.txt | sort -u > ultimate_wordlist.txt
Known Subdomains Format
# subdomains.txt (one domain per line)
api.example.com
app.example.com
blog.example.com
admin.example.com
mail.example.com
vpn.example.com
dev.example.com
test.example.com
staging.example.com
cdn.example.com
Extracting Subdomains
# From certificate transparency logs
curl -s "https://crt.sh/?q=%25.example.com&output=json" | \
jq -r '.[].name_value' | sort -u > subdomains.txt
# From DNS zone transfer (if allowed)
dig axfr @ns1.example.com example.com | grep -oE '\w+\.example\.com' | sort -u > subdomains.txt
# From previous reconnaissance
cat found_subdomains.txt | sort -u > subdomains.txt
# From multiple sources
cat ct_logs.txt subfinder_output.txt amass_output.txt | sort -u > subdomains.txt
Permutation Strategies
How Altdns Generates Mutations
Base subdomain: api.example.com
Generated permutations:
- api-dev.example.com
- api-test.example.com
- api-staging.example.com
- dev-api.example.com
- test-api.example.com
- apidev.example.com
- apiv1.example.com
- api2.example.com
- api3.example.com
- apibeta.example.com
- apialpha.example.com
Common Mutation Patterns
Prefixes: dev-, test-, prod-, staging-, demo-, old-, new-
Suffixes: -v1, -v2, -api, -web, -admin, -test, -dev, -beta, -alpha, -internal
Numbers: 1, 2, 3, 4, 5 appended or inserted
Abbreviations: Converting api → a, admin → adm
Consolidation: api-dev → apidev, test.dev → testdev
Environment: qa, staging, production, sandbox variants
Standard Text Output
# Default format (one domain per line)
altdns -i subdomains.txt -w words.txt -o results.txt
# View results
cat results.txt
api-staging.example.com
api-dev.example.com
api-test.example.com
app-dev.example.com
CSV Output
# Generate CSV with metadata
altdns -i subdomains.txt -w words.txt -o results.csv --csv
# Format: domain, ip, record_type, response_code
api-dev.example.com, 10.0.0.1, A, 200
api-test.example.com, 10.0.0.2, A, 200
JSON Output
# JSON formatted results
altdns -i subdomains.txt -w words.txt -o results.json --json
# Sample output structure
{
"subdomains": [
{"domain": "api-dev.example.com", "ip": "10.0.0.1", "cname": null},
{"domain": "api-test.example.com", "ip": "10.0.0.2", "cname": null}
]
}
Using with Subfinder
# Collect subdomains with subfinder
subfinder -d example.com -o subfinder_results.txt
# Feed to altdns
altdns -i subfinder_results.txt -w words.txt -o altdns_results.txt
# Combine results
cat subfinder_results.txt altdns_results.txt | sort -u > all_subdomains.txt
Using with Amass
# Enumerate with amass
amass enum -d example.com -o amass_results.txt
# Enhance with altdns
altdns -i amass_results.txt -w words.txt -o enhanced_results.txt
# Merge findings
cat amass_results.txt enhanced_results.txt | sort -u > comprehensive_list.txt
Using with Assetfinder
# Gather subdomains with assetfinder
assetfinder --subs-only example.com > assetfinder_results.txt
# Apply altdns mutations
altdns -i assetfinder_results.txt -w words.txt -o mutations.txt
# Unique combined list
cat assetfinder_results.txt mutations.txt | sort -u > final_list.txt
Integrated Reconnaissance Pipeline
#!/bin/bash
# Complete subdomain discovery workflow
DOMAIN=$1
WORDLIST="words.txt"
echo "[*] Starting reconnaissance for $DOMAIN"
# Step 1: Certificate transparency
echo "[*] Querying certificate logs..."
curl -s "https://crt.sh/?q=%25.${DOMAIN}&output=json" | \
jq -r '.[].name_value' | grep -oE '\w+\.'${DOMAIN} | sort -u > ct_results.txt
# Step 2: Subfinder enumeration
echo "[*] Running subfinder..."
subfinder -d $DOMAIN -o subfinder_results.txt
# Step 3: Combine and deduplicate
echo "[*] Combining results..."
cat ct_results.txt subfinder_results.txt | sort -u > combined.txt
# Step 4: Altdns mutation
echo "[*] Generating permutations with altdns..."
altdns -i combined.txt -w $WORDLIST -o mutations.txt -t 50
# Step 5: Final compilation
echo "[*] Finalizing results..."
cat combined.txt mutations.txt | sort -u > final_subdomains.txt
echo "[*] Reconnaissance complete!"
echo "[*] Results saved to final_subdomains.txt"
wc -l final_subdomains.txt
DNS Resolution Verification
Resolving Discovered Domains
# Check DNS resolution with nslookup
nslookup api-dev.example.com
# Resolve with dig
dig api-dev.example.com
# Batch resolution with host
while read domain; do
host $domain | grep "has address"
done < results.txt
# Using parallel for speed
cat results.txt | parallel 'host {}'
IP Address Enumeration
# Resolve and extract IPs
altdns -i subdomains.txt -w words.txt -o results.txt -r
# Extract unique IPs from results
grep -oE '\b([0-9]{1,3}\.){3}[0-9]{1,3}\b' results.txt | sort -u
# Map domains to IPs
while read domain; do
ip=$(dig +short $domain | head -1)
echo "$domain -> $ip"
done < results.txt > domain_ip_mapping.txt
Optimization Strategies
| Parameter | Value | Speed | Thoroughness |
|---|
| Threads (-t) | 5 (default) | Slow | High accuracy |
| Threads (-t) | 20 | Medium | Good |
| Threads (-t) | 100 | Fast | May lose results |
| Timeout | 3 seconds | Very fast | May miss slow DNS |
| Timeout | 10 seconds | Moderate | Better results |
Fast Enumeration
# Aggressive scanning
altdns -i subdomains.txt -w words.txt -o results.txt \
-t 100 --timeout 3 -v
# Multiple DNS resolvers for speed
altdns -i subdomains.txt -w words.txt -o results.txt \
--resolver 8.8.8.8 1.1.1.1 9.9.9.9 8.26.56.26 \
-t 50
Thorough Enumeration
# Conservative, accurate scanning
altdns -i subdomains.txt -w words.txt -o results.txt \
-t 5 --timeout 10 -v
# Single resolver for reliability
altdns -i subdomains.txt -w words.txt -o results.txt \
--resolver 8.8.8.8 -t 10
Real-World Scenarios
Bug Bounty Reconnaissance
#!/bin/bash
# Complete bug bounty subdomain enumeration
TARGET=$1
echo "[+] Subdomain enumeration for $TARGET"
# Gather initial subdomains
subfinder -d $TARGET -silent > initial.txt
assetfinder --subs-only $TARGET >> initial.txt
crt.sh $TARGET >> initial.txt
sort -u initial.txt -o subdomains.txt
# Apply altdns mutations
altdns -i subdomains.txt -w top-wordlist.txt -o mutations.txt -t 50
# Combine results
cat subdomains.txt mutations.txt | sort -u > all_subdomains.txt
# Probe for live services
echo "[+] Probing live subdomains..."
cat all_subdomains.txt | httprobe -p 80,443,8080,8443 | tee alive_subdomains.txt
# Further enumeration
echo "[+] Technology detection..."
cat alive_subdomains.txt | wappanalyzer > tech_stack.txt
echo "[+] Enumeration complete!"
Penetration Test Scoping
# Identify all potential targets within scope
echo "[*] Generating comprehensive target list"
# Start with known domains
cat in_scope_domains.txt > targets.txt
# Use altdns for each domain
for domain in $(cat in_scope_domains.txt); do
echo "[*] Processing $domain"
altdns -i <(echo $domain) -w wordlist.txt -o ${domain}_mutations.txt -t 30
cat ${domain}_mutations.txt >> all_mutations.txt
done
# Deduplicate
cat targets.txt all_mutations.txt | sort -u > complete_scope.txt
# Filter out-of-scope
grep -v "exclude\.pattern" complete_scope.txt > final_scope.txt
echo "[*] Scope complete: $(wc -l < final_scope.txt) targets"
Continuous Monitoring
#!/bin/bash
# Monitor for new subdomains daily
DOMAIN="example.com"
WORDLIST="words.txt"
LOGDIR="logs"
# Create log directory
mkdir -p $LOGDIR
# Current scan
altdns -i <(subfinder -d $DOMAIN -silent) -w $WORDLIST \
-o $LOGDIR/$(date +%Y%m%d)_subdomains.txt -t 50
# Compare with previous scan
if [ -f "$LOGDIR/previous.txt" ]; then
NEW=$(comm -23 <(sort $LOGDIR/$(date +%Y%m%d)_subdomains.txt) \
<(sort $LOGDIR/previous.txt))
if [ ! -z "$NEW" ]; then
echo "[!] New subdomains discovered:"
echo "$NEW"
# Send alert (email, Slack, webhook, etc.)
fi
fi
# Update previous
cp $LOGDIR/$(date +%Y%m%d)_subdomains.txt $LOGDIR/previous.txt
Troubleshooting
Common Issues
| Issue | Cause | Solution |
|---|
| No results found | DNS timeout or no valid domains | Increase timeout, verify resolver, check wordlist |
| Slow execution | Too few threads | Increase -t value or add multiple resolvers |
| Memory errors | Large wordlist | Use smaller wordlist or increase system memory |
| DNS resolution failures | Bad resolver | Switch to public DNS (8.8.8.8, 1.1.1.1) |
| Incomplete results | Thread limit reached | Reduce threads or DNS queries timeout |
Debugging
# Verbose output for troubleshooting
altdns -i subdomains.txt -w words.txt -o results.txt -v -v
# Test DNS resolver
nslookup api.example.com 8.8.8.8
# Check internet connectivity
ping 8.8.8.8
# Monitor process
htop -p $(pgrep -f altdns)
# Verify wordlist format
head wordlist.txt
wc -l wordlist.txt
Best Practices
Effective Enumeration
- Start with multiple reconnaissance sources (CT logs, certificate data, DNS)
- Use comprehensive wordlists matching target organization
- Apply altdns to multiply discovered subdomains
- Verify results with multiple DNS resolvers
- Combine with HTTP probing to identify live services
- Document findings with timestamps
Ethical Considerations
- Only enumerate domains within authorized scope
- Respect robots.txt and .well-known/security.txt
- Avoid overwhelming targets with excessive queries
- Use rate limiting when required
- Document authorization before testing
- Report findings responsibly
Optimization Tips
# For large-scale operations
altdns -i 10k_subdomains.txt \
-w million_wordlist.txt \
-o results.txt \
--resolver 8.8.8.8 1.1.1.1 9.9.9.9 \
-t 50 \
--timeout 5
# Parallel processing for multiple domains
parallel 'altdns -i {} -w words.txt -o {}.results' ::: *.txt
# Resource-efficient batch processing
for file in *.txt; do
altdns -i "$file" -w words.txt -o "${file}.out" -t 10 --timeout 10
done
Additional Resources