ワンクリックで
subdomain-takeover
Subdomain takeover detection and verification for dangling DNS records
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Subdomain takeover detection and verification for dangling DNS records
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
| name | subdomain-takeover |
| description | Subdomain takeover detection and verification for dangling DNS records |
| license | MIT |
| metadata | {"category":"recon","locale":"en","phase":"v1"} |
Detects and verifies subdomain takeover vulnerabilities by identifying dangling DNS CNAME records that point to unclaimed or deprovisioned third-party services. For each CNAME, resolves the target, checks the HTTP response against known vulnerable-service fingerprints, and confirms exploitability by verifying the resource can be claimed. Covers 18+ vulnerable services including GitHub Pages, AWS S3, Heroku, Netlify, Azure (Traffic Manager, Blob, CloudApp), Shopify, Fastly, Ghost, Pantheon, Tumblr, WordPress.com, Cargo Collective, Surge.sh, Bitbucket, Zendesk, Readme.io, and Statuspage.
subdomain-enum skill) to check each live CNAMEdig installed (part of dnsutils on Debian/Ubuntu, bind-utils on RHEL/CentOS):
apt install dnsutils # Debian/Ubuntu
curl installedhttpx installed (for bulk HTTP probing):
go install -v github.com/projectdiscovery/httpx/cmd/httpx@latest
go install github.com/haccer/subjack@latest
go install -v github.com/projectdiscovery/nuclei/v3/cmd/nuclei@latest
nuclei -update-templates
SECSKILL_TARGET_DOMAIN: target root domainSECSKILL_SUBDOMAIN_LIST: path to a file of subdomains (one per line); can be output from the subdomain-enum skill| Variable | Required | Description |
|---|---|---|
SECSKILL_SUBDOMAIN_LIST | required | Path to file containing subdomains to check (one per line) |
SECSKILL_TARGET_DOMAIN | required | Root domain (used for labeling output files) |
SECSKILL_OUTPUT_DIR | optional | Directory to save results (default: ./output) |
SECSKILL_USE_SUBJACK | optional | Set to true to run subjack (default: false) |
SECSKILL_USE_NUCLEI | optional | Set to true to run nuclei takeover templates (default: false) |
export TARGET="${SECSKILL_TARGET_DOMAIN:?Set SECSKILL_TARGET_DOMAIN}"
export SUBLIST="${SECSKILL_SUBDOMAIN_LIST:?Set SECSKILL_SUBDOMAIN_LIST}"
export OUTDIR="${SECSKILL_OUTPUT_DIR:-./output}"
mkdir -p "$OUTDIR"
echo "[*] Target domain : $TARGET"
echo "[*] Subdomain list: $SUBLIST ($(wc -l < "$SUBLIST") entries)"
echo "[*] Output dir : $OUTDIR"
For each subdomain, resolve the CNAME chain to find the ultimate target. A dangling record exists when the CNAME target belongs to a third-party service that no longer has the resource provisioned.
echo "[*] Resolving CNAME records..."
> "$OUTDIR/cnames_${TARGET}.txt"
while IFS= read -r SUB; do
CNAME=$(dig +short CNAME "$SUB" 2>/dev/null | sed 's/\.$//')
if [ -n "$CNAME" ]; then
echo "$SUB -> $CNAME" | tee -a "$OUTDIR/cnames_${TARGET}.txt"
fi
done < "$SUBLIST"
TOTAL_CNAMES=$(wc -l < "$OUTDIR/cnames_${TARGET}.txt")
echo "[+] CNAMEs found: $TOTAL_CNAMES"
echo "[+] Saved to: $OUTDIR/cnames_${TARGET}.txt"
Probe each CNAME-bearing subdomain over HTTP/HTTPS and look for service-specific error responses that indicate the resource is unclaimed.
echo "[*] Probing CNAME subdomains for takeover fingerprints..."
# Fingerprint database: service name -> response string indicating unclaimed resource
# See REFERENCE.md for the full fingerprint table.
declare -A FINGERPRINTS
FINGERPRINTS["github-pages"]="There isn't a GitHub Pages site here"
FINGERPRINTS["s3"]="NoSuchBucket"
FINGERPRINTS["heroku"]="No such app"
FINGERPRINTS["netlify"]="Not Found - Request ID"
FINGERPRINTS["azure-trafficmanager"]="404 Not Found"
FINGERPRINTS["azure-blob"]="BlobNotFound"
FINGERPRINTS["azure-cloudapp"]="404 Web Site not found"
FINGERPRINTS["shopify"]="Sorry, this shop is currently unavailable"
FINGERPRINTS["fastly"]="Fastly error: unknown domain"
FINGERPRINTS["ghost"]="Failed to resolve DNS for"
FINGERPRINTS["pantheon"]="The gods are wise, but do not know of the site which you seek"
FINGERPRINTS["tumblr"]="There's nothing here"
FINGERPRINTS["wordpress-com"]="Do you want to register"
FINGERPRINTS["cargo-collective"]="404 Not Found"
FINGERPRINTS["surge-sh"]="project not found"
FINGERPRINTS["bitbucket"]="Repository not found"
FINGERPRINTS["zendesk"]="Help Center Closed"
FINGERPRINTS["readme-io"]="Project doesnt exist"
FINGERPRINTS["statuspage"]="Better Uptime"
> "$OUTDIR/vulnerable_${TARGET}.txt"
while IFS= read -r SUB; do
CNAME=$(dig +short CNAME "$SUB" 2>/dev/null | sed 's/\.$//')
[ -z "$CNAME" ] && continue
RESPONSE=$(curl -sk --max-time 10 "https://$SUB" 2>/dev/null || curl -sk --max-time 10 "http://$SUB" 2>/dev/null)
[ -z "$RESPONSE" ] && continue
for SERVICE in "${!FINGERPRINTS[@]}"; do
FP="${FINGERPRINTS[$SERVICE]}"
if echo "$RESPONSE" | grep -qi "$FP"; then
echo "[VULNERABLE] $SUB -> $CNAME | Service: $SERVICE | Fingerprint: $FP" \
| tee -a "$OUTDIR/vulnerable_${TARGET}.txt"
break
fi
done
done < "$SUBLIST"
VULN_COUNT=$(wc -l < "$OUTDIR/vulnerable_${TARGET}.txt")
echo "[+] Potentially vulnerable subdomains: $VULN_COUNT"
echo "[+] Results saved to: $OUTDIR/vulnerable_${TARGET}.txt"
subjack automates fingerprint detection across all subdomains and checks against an up-to-date fingerprints database.
if [ "${SECSKILL_USE_SUBJACK:-false}" = "true" ]; then
echo "[*] Running subjack..."
subjack \
-w "$SUBLIST" \
-t 100 \
-timeout 30 \
-ssl \
-c "$(go env GOPATH)/pkg/mod/github.com/haccer/subjack@*/fingerprints.json" \
-o "$OUTDIR/subjack_${TARGET}.txt" \
-v
echo "[+] subjack results saved to: $OUTDIR/subjack_${TARGET}.txt"
else
echo "[*] Skipping subjack (enable with SECSKILL_USE_SUBJACK=true)"
fi
nuclei's takeover template pack covers 50+ services and is updated regularly by the ProjectDiscovery community.
if [ "${SECSKILL_USE_NUCLEI:-false}" = "true" ]; then
echo "[*] Running nuclei takeover templates..."
nuclei \
-l "$SUBLIST" \
-t http/takeovers/ \
-o "$OUTDIR/nuclei_takeover_${TARGET}.txt" \
-silent
echo "[+] nuclei results saved to: $OUTDIR/nuclei_takeover_${TARGET}.txt"
else
echo "[*] Skipping nuclei (enable with SECSKILL_USE_NUCLEI=true)"
fi
For each candidate identified in Steps 3–5, manually verify exploitability before reporting. False positives are common — confirm that the specific resource (bucket, GitHub Pages repo, Heroku app name, etc.) is truly unclaimed.
# Manual verification procedure for each candidate:
CANDIDATE_SUB="<subdomain from vulnerable list>"
CANDIDATE_CNAME=$(dig +short CNAME "$CANDIDATE_SUB" | sed 's/\.$//')
echo "[*] Verifying: $CANDIDATE_SUB -> $CANDIDATE_CNAME"
# 1. Confirm CNAME resolution
dig +short CNAME "$CANDIDATE_SUB"
# 2. Check HTTP response and status code
curl -svk "https://$CANDIDATE_SUB" 2>&1 | grep -E "< HTTP|There isn|NoSuch|No such|not found" | head -20
# 3. Identify the service from the CNAME target
echo "$CANDIDATE_CNAME" | grep -oE "(github\.io|s3\.amazonaws\.com|herokuapp\.com|netlify\.app|azurewebsites\.net|trafficmanager\.net|blob\.core\.windows\.net|shopify\.com|fastly\.net|ghost\.io|pantheonsite\.io|tumblr\.com|wordpress\.com|cargocollective\.com|surge\.sh|bitbucket\.io|zendesk\.com|readme\.io|statuspage\.io)"
Service-specific claim verification:
Reference: See REFERENCE.md for the service-specific claim verification table.
Only attempt to claim a resource if you have explicit written authorization from the domain owner. Claiming a subdomain without authorization constitutes unauthorized access in most jurisdictions.
# Example: GitHub Pages claim (authorized only)
# 1. Create a GitHub repository matching the expected Pages URL
# 2. Add a simple index.html with a non-harmful proof-of-concept page
# 3. Enable GitHub Pages on the repository
# 4. Verify the subdomain resolves to your proof page
echo "AUTHORIZED TESTING ONLY — do not claim without written permission"
echo "[*] If claiming for PoC: create a benign proof page (e.g. 'Subdomain takeover PoC - <your name>') "
echo "[*] Do NOT host any malicious content on the claimed resource"
echo "[*] Report immediately and release the resource after confirmation"
echo "[*] Generating summary report..."
cat > "$OUTDIR/takeover_report_${TARGET}.md" << EOF
## Subdomain Takeover Report: $TARGET
**Scan date**: $(date +%Y-%m-%d)
**Subdomains scanned**: $(wc -l < "$SUBLIST")
**CNAMEs found**: $TOTAL_CNAMES
**Vulnerable candidates**: $VULN_COUNT
### Confirmed Vulnerable Subdomains
| Subdomain | CNAME Target | Service | Severity | Status |
|-----------|-------------|---------|----------|--------|
$(cat "$OUTDIR/vulnerable_${TARGET}.txt" 2>/dev/null | sed 's/\[VULNERABLE\] //g' | awk -F' -> | Service: | Fingerprint: ' '{print "| "$1" | "$2" | "$3" | High | Unverified |"}')
### Remediation
For each affected subdomain:
1. Remove the dangling DNS CNAME record immediately, OR
2. Re-provision the target service resource if it is still needed
3. Implement DNS record review as part of decommissioning checklists
### CVSS
Subdomain takeover is typically rated **High (CVSS 8.1)**:
- Attack Vector: Network, Attack Complexity: Low, Privileges Required: None
- User Interaction: Required (victim must visit the subdomain)
- Scope: Changed, Confidentiality: High, Integrity: High, Availability: None
Impact increases to **Critical** if:
- The subdomain handles authentication cookies (cookie scope inheritance)
- The subdomain is trusted by CORS policies of the main application
- The subdomain can serve malicious JS loaded by the main application
EOF
echo "[+] Report saved to: $OUTDIR/takeover_report_${TARGET}.md"
| Symptom | Cause | Resolution |
|---|---|---|
subjack: command not found | Not installed or not in PATH | Run go install github.com/haccer/subjack@latest; ensure $(go env GOPATH)/bin is in $PATH |
| CNAME resolves but HTTP probe returns no response | Service is active but on a non-standard port | Probe ports 80, 443, 8080; some services use HTTP-only on port 80 |
| Fingerprint matched but resource is actually claimed | Stale fingerprint or partial page load | Manually browse the URL and attempt to reproduce the claim; check for custom 404 pages mimicking takeover messages |
| High false positive rate | Generic 404 pages matching fingerprints | Tune fingerprint strings to be more specific; cross-check with service-specific claim verification in Step 6 |
| nuclei templates not found | Templates not downloaded | Run nuclei -update-templates first |
| dig returns NXDOMAIN for subdomain | DNS record already removed | Mark as remediated; no longer vulnerable |
us-east-1 first, then enumerate other regions if the initial bucket creation fails.subdomain-enum skill directly as SECSKILL_SUBDOMAIN_LIST for a complete recon-to-takeover pipeline.Interactive gap analysis against Korea's ISMS-P 102-control certification framework (management, protection, personal information)
Security log analysis and anomaly detection for access, auth, and syslog files
Analyze suspicious files through triage/static/dynamic/code phases to produce IOCs, YARA/Sigma rules, and MITRE ATT&CK mappings
File hash reputation lookup via VirusTotal API v3 for MD5/SHA1/SHA256 detection ratio, threat classification, and vendor results
OWASP Top 10 (2021) checklist-based inspection and compliance matrix generation
Multi-chain smart contract security for Solana, Algorand, Cairo, Cosmos, Substrate, and TON with pre-audit readiness checks