サブドメイン乗っ取り(Subdomain Takeover)は、削除されたサービスのCNAMEが残ったまま第三者にそのCNAME先のドメインを取得され、正規のHTTPS証明書まで発行できてしまう攻撃である。ワイルドカード証明書の誤用と組み合わさると、被害者サイトの任意のサブドメインで攻撃者がHTTPSページを提供できてしまう。本記事ではこの仕組みと検知・防止方法を解説する。
dangling DNS (ゾンビCNAME)とは
blog.example.com CNAME example-blog.github.io ← 削除したのにCNAMEが残っている
example-blog.github.io のGitHub Pagesが削除されると、誰でも example-blog というリポジトリ名でGitHub Pagesを有効にすることができる。こうなると blog.example.com は攻撃者のコンテンツを指すことになる。
ワイルドカード証明書との組み合わせ
*.example.com のワイルドカード証明書が存在していると、サブドメイン乗っ取りが成功した後、攻撃者は blog.example.com でHTTPS(有効な証明書付き)のフィッシングページを提供できる。ブラウザは錠前マークを表示する。
影響を受けやすいサービスパターン
# GitHub Pages
subdomain.example.com CNAME user.github.io
# Heroku
api.example.com CNAME myapp.herokuapp.com
# AWS S3 (バケット削除後)
cdn.example.com CNAME mybucket.s3.amazonaws.com
# Azure
app.example.com CNAME myapp.azurewebsites.net
# Netlify
docs.example.com CNAME mysite.netlify.app
これらのサービスを解約・削除した際にCNAMEレコードを削除し忘れると危険な状態になる。
検知ツール: subjackとnuclei
# subjackのインストールと実行
go install github.com/haccer/subjack@latest
# サブドメインリストを用意して一括チェック
subjack -w subdomains.txt -t 100 -timeout 30 -o result.txt -ssl
# nucleiによる検知(テンプレート利用)
nuclei -l subdomains.txt -t ~/nuclei-templates/http/takeovers/
# サブドメインリストをDNSで総当たりし、CNAMEだけ抽出するPythonスクリプト
import dns.resolver
import sys
def check_cname(domain: str) -> str | None:
try:
answers = dns.resolver.resolve(domain, 'CNAME')
return str(answers[0].target)
except Exception:
return None
subdomains_file = sys.argv[1]
with open(subdomains_file) as f:
for line in f:
sub = line.strip()
cname = check_cname(sub)
if cname:
print(f"{sub} -> {cname}")
実行例:
pip install dnspython
python check_cname.py subdomains.txt > cnames.txt
防止策1: サービス削除時にCNAMEを同時削除する
当たり前だが徹底されていないことが多い。IaCで管理していれば一括削除できる。
# Terraform例: GitHub Pagesを削除するとCNAMEも消える
resource "aws_route53_record" "blog" {
zone_id = aws_route53_zone.main.zone_id
name = "blog.example.com"
type = "CNAME"
ttl = 300
records = ["user.github.io"]
}
# このブロックを削除すれば自動でCNAMEも消える
防止策2: 定期的なゾーンファイル棚卸し
# Route53の全CNAMEレコードを取得して棚卸し
aws route53 list-resource-record-sets \
--hosted-zone-id ZXXXXX \
--query "ResourceRecordSets[?Type=='CNAME'].[Name,ResourceRecords[0].Value]" \
--output table
各CNAMEの参照先が現在も有効なサービスかを月次で確認する。
防止策3: CAA recordでワイルドカード証明書の発行を制限
# 特定CAのみワイルドカード証明書を発行できるよう制限
example.com CAA 0 issue "letsencrypt.org"
example.com CAA 0 issuewild "letsencrypt.org"
example.com CAA 0 iodef "mailto:security@example.com"
issuewild に信頼できるCA以外を記載しなければ、そのCA以外はワイルドカード証明書を発行できなくなる。攻撃者が乗っ取ったサブドメインでLet's Encrypt経由のワイルドカード証明書を取得しにくくなる。
まとめ
サブドメイン乗っ取りは「捨てたものの後始末」の問題である。IaCでDNSを管理し、サービス削除と同時にレコードを消す運用を徹底することが根本解決である。定期的にsubjackやnucleiでスキャンし、dangling CNAMEがないか確認する習慣を付けたい。