---
name: rt-subdomain-enum
description: "Subdomain enumeration skill. Use to discover all subdomains using passive (crt.sh, Subfinder, Amass passive, SecurityTrails) and active (DNS brute force, permutation) techniques. Output: alive subdomains with HTTP status codes and tech stack. Feeds rt-attack-surface-map. Tools: subfinder, amass, gobuster, httpx, subjack."
---

# rt-subdomain-enum — Subdomain Enumeration Skill

## Overview

Subdomain enumeration is the first active recon phase in any external red team engagement. The goal is to map every resolvable hostname belonging to the target organization before any exploitation begins. A missed subdomain is a missed attack path — forgotten staging servers, unpatched admin panels, and legacy APIs all live here.

This skill covers:
- **Passive enumeration** — querying public data sources without touching the target (crt.sh, Subfinder, Amass passive, SecurityTrails, VirusTotal, DNSdumpster)
- **Active enumeration** — direct DNS queries: brute-force, permutation/alteration, zone transfer attempts
- **HTTP probing** — resolving which discovered hosts are actually alive, their status codes, titles, and technology fingerprints
- **Takeover screening** — checking for dangling CNAMEs that may be vulnerable to subdomain takeover

Output feeds directly into `rt-attack-surface-map` for prioritization and attack planning.

---

## Skill Levels

### BEGINNER

Entry-level operators focus on passive-only sources. No active DNS queries. Safe to run against any target in scope without notifying the client.

```bash
# 1. Certificate Transparency logs via crt.sh (no tooling required)
TARGET="example.com"
curl -s "https://crt.sh/?q=%25.${TARGET}&output=json" \
  | jq -r '.[].name_value' \
  | sed 's/\*\.//g' \
  | sort -u > passive_crt.txt

# 2. Subfinder — passive only, default sources
subfinder -d "${TARGET}" -o subfinder_passive.txt -v

# 3. Combine and deduplicate
cat passive_crt.txt subfinder_passive.txt | sort -u > passive_combined.txt
echo "[*] Unique passive subdomains: $(wc -l < passive_combined.txt)"

# 4. Probe which ones are alive
cat passive_combined.txt | httpx -silent -status-code -title -o alive_passive.txt
```

**Expected output:** A deduplicated list of subdomains with HTTP status codes and page titles.

---

### INTERMEDIATE

Operators add active brute-force DNS enumeration using curated wordlists, and run Amass in passive mode for additional OSINT sources.

```bash
TARGET="example.com"
WORDLIST="/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt"
OUTPUT_DIR="./recon/${TARGET}/subdomains"
mkdir -p "${OUTPUT_DIR}"

# 1. Amass passive — mines ASNs, WHOIS, CT logs, APIs
amass enum -passive -d "${TARGET}" -o "${OUTPUT_DIR}/amass_passive.txt" -config ~/.config/amass/config.ini

# 2. Subfinder with all sources
subfinder -d "${TARGET}" -all -o "${OUTPUT_DIR}/subfinder_all.txt" -v

# 3. Certificate transparency
curl -s "https://crt.sh/?q=%25.${TARGET}&output=json" \
  | jq -r '.[].name_value' \
  | sed 's/\*\.//g' \
  | sort -u > "${OUTPUT_DIR}/crt_sh.txt"

# 4. Active DNS brute-force with gobuster
gobuster dns -d "${TARGET}" \
  -w "${WORDLIST}" \
  -t 50 \
  --timeout 5s \
  -o "${OUTPUT_DIR}/gobuster_dns.txt"

# 5. Merge all results
cat "${OUTPUT_DIR}"/*.txt | sort -u > "${OUTPUT_DIR}/all_subdomains.txt"
echo "[*] Total unique subdomains: $(wc -l < "${OUTPUT_DIR}/all_subdomains.txt")"

# 6. Probe alive hosts — full detail
cat "${OUTPUT_DIR}/all_subdomains.txt" | httpx \
  -silent \
  -status-code \
  -title \
  -tech-detect \
  -content-length \
  -web-server \
  -o "${OUTPUT_DIR}/alive_hosts.txt"
```

---

### ADVANCED

Full active enumeration with permutation fuzzing, wildcard detection, DNS record harvesting, and takeover screening. Uses larger wordlists and parallelism.

```bash
TARGET="example.com"
WORDLIST_LARGE="/usr/share/seclists/Discovery/DNS/dns-Jhaddix.txt"
OUTPUT_DIR="./recon/${TARGET}/subdomains"
mkdir -p "${OUTPUT_DIR}"

# 1. Full passive sweep (parallel)
subfinder -d "${TARGET}" -all -o "${OUTPUT_DIR}/subfinder.txt" -v &
amass enum -passive -d "${TARGET}" -o "${OUTPUT_DIR}/amass.txt" &
curl -s "https://crt.sh/?q=%25.${TARGET}&output=json" | jq -r '.[].name_value' | sed 's/\*\.//g' | sort -u > "${OUTPUT_DIR}/crt.txt" &
wait

# 2. Merge passive
cat "${OUTPUT_DIR}/subfinder.txt" "${OUTPUT_DIR}/amass.txt" "${OUTPUT_DIR}/crt.txt" \
  | sort -u > "${OUTPUT_DIR}/passive_merged.txt"

# 3. Active brute-force with large wordlist
gobuster dns -d "${TARGET}" \
  -w "${WORDLIST_LARGE}" \
  -t 100 \
  --timeout 3s \
  -o "${OUTPUT_DIR}/gobuster_large.txt"

# 4. Permutation/alteration enumeration with altdns
# Generate mutations from known subdomains
altdns -i "${OUTPUT_DIR}/passive_merged.txt" \
  -o "${OUTPUT_DIR}/altdns_mutations.txt" \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt

# Resolve mutations that actually exist
puredns resolve "${OUTPUT_DIR}/altdns_mutations.txt" \
  --resolvers /opt/resolvers/resolvers.txt \
  -w "${OUTPUT_DIR}/altdns_resolved.txt"

# 5. Merge everything
cat "${OUTPUT_DIR}"/*.txt | sort -u > "${OUTPUT_DIR}/all_subdomains.txt"

# 6. Wildcard detection — puredns handles this automatically
puredns bruteforce "${WORDLIST_LARGE}" "${TARGET}" \
  --resolvers /opt/resolvers/resolvers.txt \
  -w "${OUTPUT_DIR}/puredns_brute.txt"

# 7. HTTP probe — full fingerprint
cat "${OUTPUT_DIR}/all_subdomains.txt" | httpx \
  -silent \
  -status-code \
  -title \
  -tech-detect \
  -content-length \
  -web-server \
  -ip \
  -cname \
  -cdn \
  -json \
  -o "${OUTPUT_DIR}/alive_full.json"

# 8. Extract clean alive list for downstream tools
cat "${OUTPUT_DIR}/alive_full.json" | jq -r '.url' > "${OUTPUT_DIR}/alive_urls.txt"

# 9. Subdomain takeover screening
subjack -w "${OUTPUT_DIR}/all_subdomains.txt" \
  -t 50 \
  -timeout 30 \
  -o "${OUTPUT_DIR}/takeover_candidates.txt" \
  -ssl \
  -c /usr/share/subjack/fingerprints.json
```

---

### EXPERT

Full-spectrum enumeration with custom DNS resolvers, ASN-based pivoting, Amass active mode (AXFR, brute, scraping), SecurityTrails API, VHost discovery, and automated RTExit autodoc integration.

```bash
TARGET="example.com"
TARGET_ASN="AS12345"
OUTPUT_DIR="./recon/${TARGET}/subdomains"
RESOLVERS="/opt/resolvers/public_resolvers.txt"
SECTRAILS_API="YOUR_SECTRAILS_API_KEY"
mkdir -p "${OUTPUT_DIR}"/{passive,active,probe,takeover,vhost}

#########################################
# PHASE 1: PASSIVE ENUMERATION
#########################################

# SecurityTrails API
curl -s --request GET \
  --url "https://api.securitytrails.com/v1/domain/${TARGET}/subdomains" \
  --header "APIKEY: ${SECTRAILS_API}" \
  | jq -r '.subdomains[]' \
  | sed "s/$/.${TARGET}/" \
  > "${OUTPUT_DIR}/passive/securitytrails.txt"

# VirusTotal passive DNS
curl -s "https://www.virustotal.com/vtapi/v2/domain/report?apikey=${VT_API_KEY}&domain=${TARGET}" \
  | jq -r '.subdomains[]?' \
  >> "${OUTPUT_DIR}/passive/virustotal.txt"

# Subfinder all sources
subfinder -d "${TARGET}" -all -o "${OUTPUT_DIR}/passive/subfinder.txt" -v

# Amass passive with config (API keys configured in ~/.config/amass/config.ini)
amass enum -passive -d "${TARGET}" \
  -o "${OUTPUT_DIR}/passive/amass_passive.txt" \
  -config ~/.config/amass/config.ini \
  -json "${OUTPUT_DIR}/passive/amass_passive.json"

# Certificate Transparency
curl -s "https://crt.sh/?q=%25.${TARGET}&output=json" \
  | jq -r '.[].name_value' | sed 's/\*\.//g' | sort -u \
  > "${OUTPUT_DIR}/passive/crt_sh.txt"

# DNSdumpster (scrape — use with caution, rate-limit applies)
python3 /opt/tools/dnsdumpster/dnsdumpster.py "${TARGET}" \
  > "${OUTPUT_DIR}/passive/dnsdumpster.txt" 2>/dev/null

# Merge passive
cat "${OUTPUT_DIR}/passive/"*.txt | sort -u \
  > "${OUTPUT_DIR}/passive/merged.txt"
echo "[PASSIVE] Unique subdomains: $(wc -l < "${OUTPUT_DIR}/passive/merged.txt")"

#########################################
# PHASE 2: ACTIVE ENUMERATION
#########################################

# Zone transfer attempt against all NS records
for NS in $(dig +short NS "${TARGET}"); do
  echo "[*] Trying AXFR on ${NS}"
  dig AXFR "${TARGET}" "@${NS}" >> "${OUTPUT_DIR}/active/axfr_attempt.txt" 2>&1
done

# Amass active (brute + scrape + AXFR)
amass enum -active -brute -d "${TARGET}" \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt \
  -o "${OUTPUT_DIR}/active/amass_active.txt" \
  -config ~/.config/amass/config.ini \
  -json "${OUTPUT_DIR}/active/amass_active.json" \
  -p 80,443,8080,8443

# Puredns brute-force (wildcard-aware, fast)
puredns bruteforce \
  /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt \
  "${TARGET}" \
  --resolvers "${RESOLVERS}" \
  --resolvers-trusted /opt/resolvers/trusted_resolvers.txt \
  -w "${OUTPUT_DIR}/active/puredns_brute.txt"

# Permutation with DNSx + altdns
altdns -i "${OUTPUT_DIR}/passive/merged.txt" \
  -o "${OUTPUT_DIR}/active/altdns_wordlist.txt" \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt

dnsx -l "${OUTPUT_DIR}/active/altdns_wordlist.txt" \
  -r "${RESOLVERS}" \
  -silent \
  -a -cname \
  -o "${OUTPUT_DIR}/active/dnsx_permutations.txt"

# Gobuster DNS with Jhaddix list
gobuster dns -d "${TARGET}" \
  -w /usr/share/seclists/Discovery/DNS/dns-Jhaddix.txt \
  -t 150 \
  --timeout 3s \
  -o "${OUTPUT_DIR}/active/gobuster_jhaddix.txt"

# Merge active
cat "${OUTPUT_DIR}/active/"*.txt | grep -oP '[a-zA-Z0-9._-]+\.'"${TARGET}" \
  | sort -u > "${OUTPUT_DIR}/active/merged.txt"

#########################################
# PHASE 3: RESOLVE + PROBE
#########################################

# Final dedup across passive + active
cat "${OUTPUT_DIR}/passive/merged.txt" "${OUTPUT_DIR}/active/merged.txt" \
  | sort -u > "${OUTPUT_DIR}/all_subdomains.txt"
echo "[ALL] Total unique: $(wc -l < "${OUTPUT_DIR}/all_subdomains.txt")"

# Resolve with dnsx — get A, CNAME, MX, NS records
dnsx -l "${OUTPUT_DIR}/all_subdomains.txt" \
  -r "${RESOLVERS}" \
  -a -aaaa -cname -mx -ns -txt \
  -resp \
  -json \
  -o "${OUTPUT_DIR}/probe/dns_records.json"

# Extract resolved hosts
cat "${OUTPUT_DIR}/probe/dns_records.json" \
  | jq -r '.host' | sort -u \
  > "${OUTPUT_DIR}/probe/resolved.txt"

# HTTP probe — full stack fingerprint
cat "${OUTPUT_DIR}/probe/resolved.txt" | httpx \
  -silent \
  -status-code \
  -title \
  -tech-detect \
  -content-length \
  -web-server \
  -ip \
  -cname \
  -cdn \
  -follow-redirects \
  -random-agent \
  -threads 50 \
  -json \
  -o "${OUTPUT_DIR}/probe/alive_full.json"

# Human-readable summary
cat "${OUTPUT_DIR}/probe/alive_full.json" \
  | jq -r '[.url, .status_code, .title, .webserver] | @tsv' \
  | column -t \
  > "${OUTPUT_DIR}/probe/alive_summary.txt"

echo "[ALIVE] Hosts with HTTP response: $(wc -l < "${OUTPUT_DIR}/probe/alive_summary.txt")"

#########################################
# PHASE 4: VIRTUAL HOST DISCOVERY
#########################################

# Collect unique IPs from probe
cat "${OUTPUT_DIR}/probe/alive_full.json" \
  | jq -r '.host' | sort -u \
  > "${OUTPUT_DIR}/vhost/target_ips.txt"

# VHost brute-force with gobuster
while read -r IP; do
  gobuster vhost \
    -u "https://${IP}" \
    -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
    --append-domain \
    -t 40 \
    -o "${OUTPUT_DIR}/vhost/vhost_${IP//./_}.txt" 2>/dev/null
done < "${OUTPUT_DIR}/vhost/target_ips.txt"

#########################################
# PHASE 5: TAKEOVER SCREENING
#########################################

subjack -w "${OUTPUT_DIR}/all_subdomains.txt" \
  -t 100 \
  -timeout 30 \
  -o "${OUTPUT_DIR}/takeover/subjack_results.txt" \
  -ssl \
  -c /usr/share/subjack/fingerprints.json

# Also check with nuclei takeover templates
nuclei -l "${OUTPUT_DIR}/probe/alive_full.json" \
  -t /opt/nuclei-templates/takeovers/ \
  -o "${OUTPUT_DIR}/takeover/nuclei_takeover.txt" \
  -silent

#########################################
# PHASE 6: AUTODOC INTEGRATION (RTExit)
#########################################

python3 /opt/rtexit/autodoc.py \
  --skill rt-subdomain-enum \
  --target "${TARGET}" \
  --input "${OUTPUT_DIR}/probe/alive_full.json" \
  --dns-records "${OUTPUT_DIR}/probe/dns_records.json" \
  --takeover "${OUTPUT_DIR}/takeover/subjack_results.txt" \
  --output "./reports/${TARGET}/subdomain_enum_$(date +%Y%m%d).md" \
  --format markdown

echo "[DONE] Enumeration complete. Results in: ${OUTPUT_DIR}"
echo "[DONE] Report: ./reports/${TARGET}/subdomain_enum_$(date +%Y%m%d).md"
```

---

## Step-by-Step Workflow

### Step 1: Environment Setup

```bash
# Create engagement directory structure
TARGET="example.com"
ENGAGEMENT="ENG-2024-001"
mkdir -p ~/engagements/${ENGAGEMENT}/recon/${TARGET}/subdomains/{passive,active,probe,takeover,vhost}
cd ~/engagements/${ENGAGEMENT}

# Verify tools are installed
for tool in subfinder amass gobuster httpx subjack dnsx puredns altdns nuclei; do
  command -v "${tool}" &>/dev/null \
    && echo "[OK] ${tool}" \
    || echo "[MISSING] ${tool} — install required"
done
```

### Step 2: Configure API Keys

API keys dramatically expand passive enumeration coverage. Store them in Amass and Subfinder config files so they are used automatically.

```bash
# Subfinder provider config (~/.config/subfinder/provider-config.yaml)
cat > ~/.config/subfinder/provider-config.yaml << 'EOF'
securitytrails:
  - YOUR_SECURITYTRAILS_KEY
shodan:
  - YOUR_SHODAN_KEY
censys:
  - YOUR_CENSYS_API_ID:YOUR_CENSYS_SECRET
virustotal:
  - YOUR_VT_KEY
chaos:
  - YOUR_CHAOS_KEY
passivetotal:
  - YOUR_PT_USERNAME:YOUR_PT_KEY
binaryedge:
  - YOUR_BE_KEY
EOF

# Amass config (~/.config/amass/config.ini)
# See: https://github.com/owasp-amass/amass/blob/master/examples/config.ini
```

### Step 3: Passive Enumeration

```bash
TARGET="example.com"
OUTPUT="${HOME}/engagements/${ENGAGEMENT}/recon/${TARGET}/subdomains"

# Run passive tools
subfinder -d "${TARGET}" -all -o "${OUTPUT}/passive/subfinder.txt"
amass enum -passive -d "${TARGET}" -o "${OUTPUT}/passive/amass.txt"
curl -s "https://crt.sh/?q=%25.${TARGET}&output=json" \
  | jq -r '.[].name_value' | sed 's/\*\.//g' | sort -u \
  > "${OUTPUT}/passive/crt.txt"

# Merge
cat "${OUTPUT}/passive/"*.txt | sort -u > "${OUTPUT}/passive/merged.txt"
echo "Passive total: $(wc -l < "${OUTPUT}/passive/merged.txt")"
```

### Step 4: Active DNS Brute-Force

```bash
# Small/fast first pass (5000 words)
puredns bruteforce \
  /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt \
  "${TARGET}" \
  --resolvers /opt/resolvers/resolvers.txt \
  -w "${OUTPUT}/active/puredns_5k.txt"

# Larger pass if time permits
puredns bruteforce \
  /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt \
  "${TARGET}" \
  --resolvers /opt/resolvers/resolvers.txt \
  -w "${OUTPUT}/active/puredns_20k.txt"
```

### Step 5: Permutation Generation

```bash
# Generate mutations from known subdomains
altdns \
  -i "${OUTPUT}/passive/merged.txt" \
  -o "${OUTPUT}/active/mutations_raw.txt" \
  -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt

# Resolve mutations
dnsx \
  -l "${OUTPUT}/active/mutations_raw.txt" \
  -r /opt/resolvers/resolvers.txt \
  -silent \
  -o "${OUTPUT}/active/mutations_resolved.txt"
```

### Step 6: Merge All Results

```bash
cat "${OUTPUT}/passive/merged.txt" \
    "${OUTPUT}/active/"*.txt \
  | grep -oP '[a-zA-Z0-9._-]+\.'"${TARGET}"'$' \
  | sort -u \
  > "${OUTPUT}/all_subdomains.txt"

echo "Total unique subdomains: $(wc -l < "${OUTPUT}/all_subdomains.txt")"
```

### Step 7: HTTP Probing

```bash
cat "${OUTPUT}/all_subdomains.txt" | httpx \
  -silent \
  -status-code \
  -title \
  -tech-detect \
  -content-length \
  -web-server \
  -ip \
  -cname \
  -cdn \
  -json \
  -o "${OUTPUT}/probe/alive.json"

# Quick summary
cat "${OUTPUT}/probe/alive.json" \
  | jq -r '[.url, (.status_code|tostring), .title] | @tsv' \
  | sort -t$'\t' -k2 -n \
  | column -t
```

### Step 8: Takeover Screening

```bash
subjack \
  -w "${OUTPUT}/all_subdomains.txt" \
  -t 50 \
  -o "${OUTPUT}/takeover/candidates.txt" \
  -ssl

# Review candidates immediately
cat "${OUTPUT}/takeover/candidates.txt"
```

### Step 9: Export for Attack Surface Mapping

```bash
# Extract alive URLs for rt-attack-surface-map
cat "${OUTPUT}/probe/alive.json" | jq -r '.url' \
  > "${OUTPUT}/alive_urls_final.txt"

# Export DNS records for pivot analysis
cat "${OUTPUT}/probe/dns_records.json" \
  | jq -r 'select(.cname != null) | [.host, .cname[]] | @tsv' \
  > "${OUTPUT}/cname_chains.tsv"

echo "[COMPLETE] Feed alive_urls_final.txt into rt-attack-surface-map"
```

### Step 10: Autodoc Report Generation

```bash
python3 /opt/rtexit/autodoc.py \
  --skill rt-subdomain-enum \
  --target "${TARGET}" \
  --input "${OUTPUT}/probe/alive.json" \
  --dns-records "${OUTPUT}/probe/dns_records.json" \
  --takeover "${OUTPUT}/takeover/candidates.txt" \
  --output "./reports/${TARGET}/subdomain_enum_$(date +%Y%m%d_%H%M).md" \
  --format markdown \
  --engagement "${ENGAGEMENT}"
```

---

## Tool Reference

### subfinder
Passive subdomain discovery using multiple data sources (cert logs, APIs, scrapers).

- **GitHub:** https://github.com/projectdiscovery/subfinder
- **Install:** `go install -v github.com/projectdiscovery/subfinder/v2/cmd/subfinder@latest`
- **Key flags:** `-d` (domain), `-all` (all sources), `-o` (output), `-v` (verbose)

```bash
subfinder -d example.com -all -o subs.txt -v
```

### amass
OWASP subdomain enumeration and network mapping tool. Best-in-class for ASN pivoting and OSINT.

- **GitHub:** https://github.com/owasp-amass/amass
- **Install:** `go install -v github.com/owasp-amass/amass/v4/...@master`
- **Docs:** https://github.com/owasp-amass/amass/blob/master/doc/user_guide.md

```bash
# Passive
amass enum -passive -d example.com -o amass_passive.txt

# Active (brute + AXFR)
amass enum -active -brute -d example.com -w wordlist.txt -o amass_active.txt
```

### gobuster
Directory/DNS/VHost brute-forcer written in Go. Fast and reliable for DNS mode.

- **GitHub:** https://github.com/OJ/gobuster
- **Install:** `go install github.com/OJ/gobuster/v3@latest`

```bash
gobuster dns -d example.com -w wordlist.txt -t 50 -o dns_results.txt
gobuster vhost -u https://10.10.10.10 -w subdomains.txt --append-domain
```

### httpx
Multi-purpose HTTP probing toolkit from ProjectDiscovery. Supports tech detection, status codes, screenshots.

- **GitHub:** https://github.com/projectdiscovery/httpx
- **Install:** `go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest`

```bash
cat subdomains.txt | httpx -silent -status-code -title -tech-detect -json -o alive.json
```

### subjack
Subdomain takeover detection tool.

- **GitHub:** https://github.com/haccer/subjack
- **Install:** `go install github.com/haccer/subjack@latest`

```bash
subjack -w subdomains.txt -t 50 -o takeover.txt -ssl -c fingerprints.json
```

### dnsx
Fast DNS toolkit for running multiple DNS queries at scale.

- **GitHub:** https://github.com/projectdiscovery/dnsx
- **Install:** `go install -v github.com/projectdiscovery/dnsx/cmd/dnsx@latest`

```bash
cat subdomains.txt | dnsx -silent -a -cname -resp -o dns_records.txt
```

### puredns
Wildcard-aware DNS brute-forcer and resolver. Essential for accurate active enumeration.

- **GitHub:** https://github.com/d3mondev/puredns
- **Install:** `go install github.com/d3mondev/puredns/v2@latest`

```bash
puredns bruteforce wordlist.txt example.com --resolvers resolvers.txt -w out.txt
puredns resolve subdomains.txt --resolvers resolvers.txt -w resolved.txt
```

### altdns
Subdomain permutation/alteration and mutation engine.

- **GitHub:** https://github.com/infosec-au/altdns
- **Install:** `pip3 install py-altdns` or `pip3 install altdns`

```bash
altdns -i subdomains.txt -o mutations.txt -w words.txt
```

### nuclei
Fast template-based vulnerability scanner. Used here for takeover templates.

- **GitHub:** https://github.com/projectdiscovery/nuclei
- **Install:** `go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest`

```bash
nuclei -l alive.txt -t nuclei-templates/takeovers/ -o takeover_hits.txt
```

---

## Output Instructions

### Directory Structure

```
recon/<TARGET>/subdomains/
├── passive/
│   ├── subfinder.txt
│   ├── amass.txt
│   ├── crt.txt
│   ├── securitytrails.txt
│   └── merged.txt
├── active/
│   ├── puredns_5k.txt
│   ├── puredns_20k.txt
│   ├── gobuster_jhaddix.txt
│   ├── altdns_mutations.txt
│   └── merged.txt
├── probe/
│   ├── dns_records.json
│   ├── alive_full.json
│   └── alive_summary.txt
├── takeover/
│   ├── subjack_results.txt
│   └── nuclei_takeover.txt
├── vhost/
│   └── vhost_<IP>.txt
├── all_subdomains.txt
└── alive_urls_final.txt
```

### Files to Save and Their Purpose

| File | Purpose | Downstream Consumer |
|---|---|---|
| `passive/merged.txt` | Deduplicated passive results | Active phase, permutations |
| `all_subdomains.txt` | All discovered subdomains | httpx probing, subjack |
| `probe/alive_full.json` | Full HTTP probe with tech stack | rt-attack-surface-map, nuclei |
| `probe/alive_summary.txt` | Human-readable alive hosts | Operator review, reporting |
| `probe/dns_records.json` | Full DNS records (A, CNAME, MX, TXT) | Pivot analysis, takeover detection |
| `takeover/subjack_results.txt` | Takeover candidates | Immediate exploitation |
| `alive_urls_final.txt` | Clean URL list | rt-attack-surface-map |
| `cname_chains.tsv` | CNAME pivot map | Infrastructure mapping |

### Naming Convention

```
<ENGAGEMENT_ID>_<TARGET>_subdomain_enum_<YYYYMMDD_HHMM>.md
e.g. ENG-2024-001_example.com_subdomain_enum_20241115_1430.md
```

### Minimum Required Outputs

Before closing enumeration phase, confirm these files exist and are non-empty:
1. `all_subdomains.txt` — raw discovered subdomains
2. `probe/alive_full.json` — HTTP probed hosts with status + tech
3. `probe/alive_summary.txt` — human-readable summary
4. `takeover/subjack_results.txt` — takeover screening complete (even if empty)
5. `alive_urls_final.txt` — ready for `rt-attack-surface-map`

---

## Useful Python Scripts

### crt.sh Bulk Fetch with Rate Limiting

```python
#!/usr/bin/env python3
# crtsh_enum.py — Fetch subdomains from crt.sh with retry logic
import requests, json, time, sys
from urllib.parse import quote

def fetch_crtsh(domain, retries=3, delay=5):
    url = f"https://crt.sh/?q=%.{domain}&output=json"
    for attempt in range(retries):
        try:
            r = requests.get(url, timeout=30)
            r.raise_for_status()
            data = r.json()
            subdomains = set()
            for entry in data:
                for name in entry.get("name_value", "").splitlines():
                    clean = name.strip().lstrip("*.")
                    if clean.endswith(domain):
                        subdomains.add(clean.lower())
            return sorted(subdomains)
        except Exception as e:
            print(f"[!] Attempt {attempt+1} failed: {e}", file=sys.stderr)
            time.sleep(delay)
    return []

if __name__ == "__main__":
    domain = sys.argv[1] if len(sys.argv) > 1 else "example.com"
    subs = fetch_crtsh(domain)
    print(f"[*] Found {len(subs)} subdomains via crt.sh", file=sys.stderr)
    for s in subs:
        print(s)
```

Usage:
```bash
python3 crtsh_enum.py example.com > crt_results.txt
```

### Parse httpx JSON Output

```python
#!/usr/bin/env python3
# parse_alive.py — Parse httpx JSON to CSV for reporting
import json, sys, csv

def parse_httpx(input_file, output_file):
    results = []
    with open(input_file) as f:
        for line in f:
            try:
                entry = json.loads(line.strip())
                results.append({
                    "url": entry.get("url", ""),
                    "status_code": entry.get("status_code", ""),
                    "title": entry.get("title", ""),
                    "webserver": entry.get("webserver", ""),
                    "tech": ", ".join(entry.get("tech", [])),
                    "ip": entry.get("host", ""),
                    "cname": ", ".join(entry.get("cname", [])),
                    "cdn": entry.get("cdn", False),
                    "content_length": entry.get("content_length", ""),
                })
            except json.JSONDecodeError:
                continue

    with open(output_file, "w", newline="") as f:
        writer = csv.DictWriter(f, fieldnames=results[0].keys() if results else [])
        writer.writeheader()
        writer.writerows(results)
    print(f"[*] Wrote {len(results)} entries to {output_file}")

if __name__ == "__main__":
    parse_httpx(sys.argv[1], sys.argv[2])
```

Usage:
```bash
python3 parse_alive.py probe/alive_full.json probe/alive_report.csv
```

---

## SecLists Wordlist Reference

| Wordlist | Path | Size | Use Case |
|---|---|---|---|
| subdomains-top1million-5000.txt | `/usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt` | 5k | Fast initial pass |
| subdomains-top1million-20000.txt | `/usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt` | 20k | Standard engagement |
| subdomains-top1million-110000.txt | `/usr/share/seclists/Discovery/DNS/subdomains-top1million-110000.txt` | 110k | Thorough assessment |
| dns-Jhaddix.txt | `/usr/share/seclists/Discovery/DNS/dns-Jhaddix.txt` | 1.8M | Comprehensive brute |
| bitquark-subdomains-top100000.txt | `/usr/share/seclists/Discovery/DNS/bitquark-subdomains-top100000.txt` | 100k | Alternative large list |

Install SecLists:
```bash
sudo apt install seclists
# or
git clone https://github.com/danielmiessler/SecLists /usr/share/seclists
```

---

## Public DNS Resolvers

High-quality resolver lists are critical for accurate active enumeration. Use puredns with trusted resolvers to avoid false positives from wildcard DNS.

```bash
# Download fresh resolver list
curl -s https://raw.githubusercontent.com/trickest/resolvers/main/resolvers.txt \
  -o /opt/resolvers/resolvers.txt

# Verify resolver quality
dnsvalidator -tL /opt/resolvers/resolvers.txt -threads 200 -o /opt/resolvers/valid_resolvers.txt
```

---

## Integration with RTExit Autodoc Engine

The autodoc engine ingests structured JSON from httpx and generates engagement-ready Markdown reports automatically.

```bash
# Trigger autodoc after enumeration completes
python3 /opt/rtexit/autodoc.py \
  --skill rt-subdomain-enum \
  --target "${TARGET}" \
  --engagement "${ENGAGEMENT}" \
  --input "${OUTPUT}/probe/alive_full.json" \
  --dns-records "${OUTPUT}/probe/dns_records.json" \
  --takeover "${OUTPUT}/takeover/subjack_results.txt" \
  --output "./reports/${TARGET}/subdomain_enum_$(date +%Y%m%d_%H%M).md" \
  --format markdown

# RTExit also accepts the alive URLs file directly for indexing
python3 /opt/rtexit/index_asset.py \
  --type subdomain \
  --source "${OUTPUT}/alive_urls_final.txt" \
  --engagement "${ENGAGEMENT}"
```

The autodoc engine produces:
- Executive summary table (alive hosts, status breakdown, tech stack summary)
- Takeover risk section (high/medium/low)
- CNAME chain analysis
- CDN-hosted vs direct-hosted breakdown
- Recommended next steps (feeds `rt-attack-surface-map`)

---

## Resources

### Official Documentation
- Subfinder README: https://github.com/projectdiscovery/subfinder/blob/main/README.md
- Amass User Guide: https://github.com/owasp-amass/amass/blob/master/doc/user_guide.md
- Amass Config Examples: https://github.com/owasp-amass/amass/blob/master/examples/config.ini
- httpx README: https://github.com/projectdiscovery/httpx/blob/master/README.md
- puredns README: https://github.com/d3mondev/puredns/blob/master/README.md

### Wordlists and Data
- SecLists: https://github.com/danielmiessler/SecLists
- Trickest Resolvers: https://github.com/trickest/resolvers
- Commonspeak2 wordlists: https://github.com/assetnote/commonspeak2-wordlists

### OSINT APIs (require registration)
- SecurityTrails API: https://securitytrails.com/app/account/credentials
- VirusTotal API: https://www.virustotal.com/gui/my-apikey
- Chaos (ProjectDiscovery): https://chaos.projectdiscovery.io/
- Shodan API: https://account.shodan.io/
- Censys API: https://search.censys.io/account/api

### Certificate Transparency
- crt.sh: https://crt.sh/
- crt.sh JSON API: https://crt.sh/?q=%.example.com&output=json
- Facebook CT Monitor: https://developers.facebook.com/tools/ct/
- Google CT Log List: https://www.gstatic.com/ct/log_list/v3/log_list.json

### Learning and Reference
- HackTricks Subdomain Enumeration: https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/web-discovery-and-information-gathering#subdomain-enumeration
- Bug Bounty Recon Methodology (Jason Haddix): https://www.youtube.com/watch?v=p4JgIu1mceI
- Subdomain Takeover Reference: https://github.com/EdOverflow/can-i-take-over-xyz
- DNS Recon Cheatsheet: https://pentestbook.six2dez.com/recon/domains
- Assetnote Blog — Subdomain Enumeration: https://www.assetnote.io/resources/research/subdomains-in-the-age-of-scope-creep
- NahamCon Recon Talk: https://www.youtube.com/watch?v=G3A1H5RQGjA

### Related RTExit Skills
- `rt-attack-surface-map` — consumes output of this skill for prioritization
- `rt-scope-definition` — must be run before this skill to confirm in-scope domains
- `rt-threat-model` — informs which subdomain categories to prioritize
- `rt-create-sead` — SEAD operations may leverage discovered subdomains for phishing infrastructure
