Dangling CNAMEs at scale: certificate transparency plus diffing as a takeover engine
How a forgotten CNAME becomes a claimable subdomain, and how to find them across a wide asset list using CT logs and resolver diffing instead of luck.
The lifecycle that produces these is mundane. A team spins up a marketing page
on a hosted platform, points promo.example.com at it with a CNAME, runs the
campaign, and tears down the platform account. The CNAME stays. Now the name
resolves to a provider that has no idea who you are, and on many providers the
next person to register that hostname becomes who you are, for that subdomain.
What “dangling” actually means
A takeover-able record has three properties at once: the name still resolves, the target it resolves to is unclaimed on the provider, and the provider’s onboarding lets you claim arbitrary hostnames without proving you own the DNS. The fingerprint is usually a provider-specific error served over the bare hostname:
$ dig +short promo.example.com
promo-campaigns.hosted-platform.net.
$ curl -s https://promo.example.com/
There isn't a site here yet. Claim this address to get started.That error string is the tell. It says the DNS points somewhere real, but the
slot at the other end is empty and offered to whoever asks. Not every dangling
record is claimable, which is the part scanners get wrong: a CNAME to a
provider that requires DNS-validated domain verification before serving content
is dangling but not takeover-able, because you cannot pass their verification
for a name you don’t control.
Scaling discovery with certificate transparency
You cannot brute a wordlist and call it coverage. The asset list has to be wide and real, and the cheapest source of real hostnames is certificate transparency. Every TLS certificate a public CA issues is logged, and those logs are queryable. Pulling all certificates ever issued for a registrable domain yields the historical set of hostnames the organisation actually used, including the short-lived campaign and staging names most likely to be abandoned.
The pipeline I run is boring on purpose:
- Enumerate all
*.example.comnames from CT logs. This is the seed list, biased toward names that once had a certificate, which is most of the interesting ones. - Resolve each name and keep only those that
CNAMEto a third party. ACNAMEto your own infrastructure is not a takeover. - Diff the resolution and the response against a fingerprint set: which provider, and does the bare hostname return that provider’s “unclaimed” error.
- Diff over time. Re-resolving the list on a schedule surfaces records that change from healthy to dangling. A name that resolved to live content last week and to a claim-me error today is a fresh takeover, often the same day the account was torn down.
The over-time diff is what turns this from a one-shot scan into an engine. New dangling records appear constantly as teams decommission services; catching the transition is far higher yield than re-scanning a static list and hoping something rotted.
# stage 2 to 3, conceptually
for host in $(cat ct-names.txt); do
cname=$(dig +short CNAME "$host")
[ -z "$cname" ] && continue
body=$(curl -s --max-time 8 "https://$host/")
match_fingerprint "$cname" "$body" && echo "CANDIDATE $host -> $cname"
doneConfirming without crossing a line
Confirmation is a discipline question, not a technical one. I claim the slot on the provider, serve a single static file containing a random marker at a path nobody else would hit, and screenshot the marker being served over the target hostname. That proves control. Then I take it down. I never host content that impersonates the organisation, never collect traffic that lands on the name, and never wire it into an OAuth flow or set a cookie. The takeover is demonstrated by the fact that I could put a marker there; the value of the bug lives in what the parent domain trusts, and you describe that, you don’t exploit it.
That parent trust is the real impact story. A subdomain under a domain with a
wildcard cookie can read and set the session cookie. A subdomain that sits inside
an OAuth redirect_uri allowlist or a *.example.com CSP entry becomes a launch
point for token theft or script execution against the primary. The takeover is
cheap; the reason it matters is everything the organisation already decided to
trust about its own namespace.