关于 hunt-tls-network
面向安全测试人员的 TLS、DNS 与邮件安全排查技能,提供审计和验证流程,并区分可证实的漏洞与单纯的加固缺失。内容涵盖区域传送、邮件伪造、证书透明度和客户端证书绕过。
主要功能
- 01TLS 配置与漏洞验证
- 02DNS 区域传送检查
- 03SPF、DKIM 和 DMARC 测试
- 04证书透明度子域名发现
- 05悬空 DNS 记录接管验证
- 06mTLS 访问绕过检查
适用场景
- 01确认 TLS 弱点是否能实际利用
- 02检查 DNS 区域传送是否泄露内部主机
- 03验证伪造邮件是否送达收件箱
- 04排查子域名记录是否指向可认领资源
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ elementalsouls/ claude-bughunter --skill hunt-tls-network安装后在 Claude Code 中输入/hunt-tls-network确认已加载。
详细介绍
HUNT-TLS-NETWORK — TLS/SSL 与 DNS 安全
现实情况核查(请先阅读)
此类发现大多属于 Info/Low,分流时通常会以「最佳实践」/「缺少安全加固」为由拒绝。这项技能旨在避免你浪费提交机会。在报告此类问题前,先问自己两个问题:
- 是否存在真实受害者和真实操作?「缺少 HSTS」不是漏洞——对你实施 MitM 攻击的受害者,证明其会话 Cookie 被捕获才是。「缺少 CAA」永远不是你能证明的漏洞。
- 该计划是否接受此类问题?许多计划明确将缺少 SPF/DMARC、缺少安全标头、无利用证据的弱密码套件,以及 CAA 列为范围外。请先阅读范围说明,并在报告中引用范围内的条款。
此类问题中真正有价值的发现(按顺序排列):
- 悬空 CNAME / 悬空 A 记录子域接管——你能控制
target.com子域上的内容。影响真实,也有实际奖励。(深入内容由hunt-subdomain负责;此处从 TLS/DNS 侦察角度介绍。) - 可伪造的 DMARC,且有邮件成功送达收件箱的证据——不是「存在
p=none」,而是一封来自[email protected]的邮件实际进入真实收件箱,且邮件头中的 DMARC 判定为通过/none。 - DNS AXFR 返回内部主机——获得完整的内部主机名/IP 映射。侦察价值明确,通常为 Medium。
- 内部服务上的 mTLS / 客户端证书绕过——无需证书即可访问仅限认证用户使用的功能。真实的身份验证绕过 = High。
- 通过 TLS 弱点利用成功,并有可运行的解密/MitM PoC——在 2024-2026 年,针对已修补的协议栈,远程利用几乎不可能;参见第 1 阶段的注意事项。
**没有实际价值的发现(不要单独报告):**缺少 CAA、没有 MitM PoC 的情况下缺少 HSTS、单独缺少安全标头、没有利用证据的弱密码套件支持、非生产主机使用自签名证书、仅启用 TLS 1.0/1.1 而没有降级攻击受害者。
第 1 阶段 — TLS/SSL 审计
# Quick TLS test with testssl.sh
brew install testssl
testssl.sh --fast $TARGET 2>/dev/null | grep -E "CRITICAL|HIGH|MEDIUM|OK|NOT" | head -30
# Or use sslyze (Python)
pip3 install sslyze
python3 -m sslyze $TARGET --json_out /tmp/sslyze_$TARGET.json 2>/dev/null
cat /tmp/sslyze_$TARGET.json | python3 -m json.tool | grep -i "vulnerability\|insecure\|error" | head -20
# Check certificate expiry and chain
echo | openssl s_client -connect $TARGET:443 -servername $TARGET 2>/dev/null | \
openssl x509 -noout -dates -subject -issuer 2>/dev/null
# Check for weak ciphers manually (a successful handshake = the cipher is OFFERED, not exploitable)
openssl s_client -connect $TARGET:443 -cipher RC4-SHA 2>/dev/null | grep -i "cipher\|handshake"
openssl s_client -connect $TARGET:443 -cipher DES-CBC3-SHA 2>/dev/null | grep -i "cipher\|handshake"
# Protocol downgrade surface — TLS 1.0/1.1 still negotiable?
openssl s_client -connect $TARGET:443 -tls1 2>/dev/null | grep -E "Protocol|Cipher"
openssl s_client -connect $TARGET:443 -tls1_1 2>/dev/null | grep -E "Protocol|Cipher"
准确性/分流注意事项——切勿夸大 TLS 漏洞:
- **支持 ≠ 可利用。**testssl/sslyze 标记出 RC4、3DES 或 TLS 1.0,表示服务器会协商使用它们。这是安全加固方面的问题,并非已证实的解密攻击。没有 PoC 时,该发现属于 Info/Low,且经常被视为范围外。
- SWEET32 (CVE-2016-2183)——3DES 生日攻击。需要持续时间较长的 TLS 会话、处于通信路径上的攻击者,以及约数百 GB/数小时的同密钥流量。在漏洞赏金计划中,实际上无法证明;仅报告支持 3DES 这一点,并预期评级为 Low/Info。
- POODLE (CVE-2014-3566)——针对 SSLv3 CBC 填充的预言机攻击。必须确实启用了 SSLv3;几乎没有现代协议栈会提供该协议。使用
testssl.sh --poodle(或nmap --script ssl-poodle)确认——现代 OpenSSL 3.x 已移除-ssl3标志。如果无法协商 SSLv3,就不存在 POODLE。 - FREAK (CVE-2015-0204) 和 DROWN (CVE-2016-0800)——分别要求使用出口级 RSA,或存在共享 SSLv2 端点。你必须证明这些前置条件确实存在,不能想当然。DROWN 要求某个共享证书/密钥的主机可通过网络访问 SSLv2——在声称存在此问题前,使用
testssl.sh --drown(或nmap --script sslv2-drown)扫描证书的 SAN 列表;现代 OpenSSL 没有-ssl2标志。 - Heartbleed (CVE-2014-0160)——如果确实发现未修补的 OpenSSL 1.0.1 正在泄露内存,并且有真实 PoC(转储内容中包含密钥/Cookie),那就是 High/Critical。使用
testssl.sh --heartbleed验证并捕获泄露的字节;这是少数值得完整报告的 TLS 漏洞。
第 2 阶段 — HSTS 检查
# Check HSTS header on main domain and all subdomains
curl -sI "https://$TARGET/" | grep -i "strict-transport-security"
# Expected: Strict-Transport-Security: max-age=31536000; includeSubDomains; preload
# Check critical subdomains (login, api, auth)
for sub in login auth api account pay www; do
HSTS=$(curl -sI "https://$sub.$TARGET/" 2>/dev/null | grep -i "strict-transport-security")
if [ -z "$HSTS" ]; then
echo "[!] MISSING HSTS: https://$sub.$TARGET/"
else
echo "[OK] $sub.$TARGET: $HSTS"
fi
done
# Check HTTP (non-HTTPS) redirect
curl -sI "http://$TARGET/" | grep -i "location"
# Should redirect to HTTPS immediately
# HSTS preload check
curl -s "https://hstspreload.org/api/v2/status?domain=$TARGET" | python3 -m json.tool 2>/dev/null
第 3 阶段 — DNS 区域传送(AXFR)
# Find nameservers
dig NS $TARGET +short
# Attempt zone transfer on each nameserver
for NS in $(dig NS $TARGET +short); do
echo "=== Trying AXFR from $NS ==="
dig AXFR $TARGET @$NS 2>/dev/null | grep -v "^;" | head -30
done
# Zone transfer via alternative tools
host -t AXFR $TARGET $(dig NS $TARGET +short | head -1) 2>/dev/null | head -30
nmap -sn --script dns-zone-transfer $TARGET 2>/dev/null | head -30
# If AXFR succeeds → full internal hostname map
# Look for: internal IPs, staging servers, admin hostnames, CI/CD servers
第 4 阶段 — 电子邮件安全(SPF/DKIM/DMARC)
# Check SPF record
dig TXT $TARGET +short | grep "v=spf1"
# Missing SPF → potential email spoofing
# Check DMARC
dig TXT _dmarc.$TARGET +short
# Missing DMARC → attacker can send as @target.com with no enforcement
# Check DKIM selectors (common: default, google, mail, k1)
for selector in default google mail k1 selector1 selector2 s1 s2 dkim; do
RESULT=$(dig TXT $selector._domainkey.$TARGET +short 2>/dev/null)
[ -n "$RESULT" ] && echo "DKIM selector found: $selector → $RESULT"
done
# --- Spoofability evaluation (heuristic only; PROOF is the swaks test below) ---
SPF=$(dig +short TXT $TARGET | tr -d '"' | grep -i "v=spf1")
DMARC=$(dig +short TXT _dmarc.$TARGET | tr -d '"' | grep -i "v=DMARC1")
# SPF "+all" / "all" with no qualifier = pass-everything = spoofable from any IP
echo "$SPF" | grep -Eq '[+ ]all($|[^-~?])' && echo "[CRITICAL] SPF passes all senders (+all)"
echo "$SPF" | grep -q "~all" && echo "[INFO] SPF softfail (~all) — may still deliver to inbox"
[ -z "$SPF" ] && echo "[INFO] No SPF record"
# Correct DMARC-absence check: test the variable for emptiness, do NOT pipe dig|wc -c
if [ -z "$DMARC" ]; then
echo "[INFO] No DMARC record (no published policy)"
else
POLICY=$(echo "$DMARC" | grep -oiE 'p=[a-z]+' | head -1)
echo "[INFO] DMARC present: $POLICY"
echo "$POLICY" | grep -qi "p=none" && echo " -> p=none: monitors only, does NOT block spoofed mail"
echo "$POLICY" | grep -qiE "p=(quarantine|reject)" && echo " -> enforcing policy: spoofing likely blocked at receiver"
fi
原先的 dig ... | wc -c | grep '^1$' 检查为何有问题:dig +short 的输出为空时,得到的是长度为零的字符串;通过管道传给 wc -c 后,通常会输出 0,而周围的换行符处理方式取决于 shell,因此 ^1$ 匹配可能会在两种情况下都出错。请始终将结果保存到变量中,并使用 [ -z "$VAR" ] 进行判断。
可伪造性由接收方决定,不是靠读取记录来判断
不要只凭 dig 输出就报告“缺少 DMARC = 电子邮件可被伪造”。DMARC p=none(或不存在)意味着发送域未发布强制策略——但接收方邮件服务商(Gmail、M365、目标程序自己的 MX)仍可能根据 SPF、自身启发式规则或 ARC,将你的伪造邮件送入垃圾邮件文件夹或拒收。只有成功投递到真实收件箱的邮件,才是经得起分诊审查的证据。
# PROOF: send a spoofed mail and confirm INBOX delivery (use a tester account you own)
# Use an account on the receiver the program actually uses (check their MX: dig MX $TARGET)
swaks --to [email protected] \
--from "CEO <ceo@$TARGET>" \
--header "Subject: [TEST] DMARC spoof PoC for $TARGET" \
--body "Authorized bug-bounty test. Spoofed from-domain: $TARGET" \
--server <an-smtp-relay-you-control-or-localhost>
确认门槛——只有满足以下条件,伪造 PoC 才有效:
- 邮件进入了收件箱(不是垃圾邮件/Spam),并截取文件夹的屏幕截图。
- 原始标头中:
Authentication-Results:显示dmarc=none|fail,且邮件仍然成功投递(未退信)。退信或进入垃圾邮件文件夹都不算漏洞发现——记下结果后继续。 - 收件人看到的
From:显示@$TARGET(标头 From 伪造,这是钓鱼攻击真正关心的部分),而不只是耍envelope-from花招。
严重性最高为中危,且仅在邮件成功投递到收件箱时成立。许多计划会直接将电子邮件身份验证问题标记为超出范围(OOS)——先检查范围。
阶段 5 — 安全标头审计
# Check all security headers
HEADERS=$(curl -sI "https://$TARGET/")
# Check each critical header
for HEADER in "Strict-Transport-Security" "Content-Security-Policy" "X-Frame-Options" \
"X-Content-Type-Options" "Referrer-Policy" "Permissions-Policy"; do
RESULT=$(echo "$HEADERS" | grep -i "$HEADER")
if [ -z "$RESULT" ]; then
echo "[MISSING] $HEADER"
else
echo "[OK] $HEADER: $RESULT"
fi
done
# Automated security headers check
curl -s "https://securityheaders.com/?q=https://$TARGET&followRedirects=on" | \
grep -oP "grade-\K[A-F+]" | head -3
阶段 6 — 证书透明度(子域名发现)
# crt.sh — certificate transparency logs
curl -s "https://crt.sh/?q=%25.$TARGET&output=json" | \
python3 -m json.tool 2>/dev/null | grep "name_value" | \
grep -oP '"name_value": "\K[^"]+' | \
sed 's/\*\.//g' | sort -u > recon/$TARGET/ct-subdomains.txt
echo "[+] CT subdomains found: $(wc -l < recon/$TARGET/ct-subdomains.txt)"
# Compare with existing subdomain list
comm -23 <(sort recon/$TARGET/ct-subdomains.txt) \
<(sort recon/$TARGET/subdomains.txt 2>/dev/null) | head -20
# New entries = recently issued certs = new services to investigate
阶段 6.5 — 悬空记录 → 子域名接管(真正有价值的发现)
这是整个技能中影响最大的项目。指向已停用第三方资源(S3 存储桶、Azure CDN/App Service、GitHub Pages、Heroku、Fastly 等)的 CNAME/A 记录,可让你认领该资源,并从 *.target.com 提供内容。完整内容请参阅 hunt-subdomain;以下是 TLS/DNS 侦察的入门内容。
# For each subdomain from CT logs, resolve the CNAME chain and check for a live origin
while read sub; do
CNAME=$(dig +short CNAME "$sub" | head -1)
[ -z "$CNAME" ] && continue
CODE=$(curl -s -o /dev/null -w "%{http_code}" --max-time 8 "https://$sub/" 2>/dev/null)
echo "$sub -> $CNAME [http $CODE]"
done < recon/$TARGET/ct-subdomains.txt | tee recon/$TARGET/cname-map.txt
# Flag CNAMEs that point at known takeoverable providers, then confirm the
# fingerprint string in the body (e.g. "NoSuchBucket", "There isn't a GitHub Pages site here",
# "Fastly error: unknown domain", "The specified bucket does not exist", Azure "Web App - Unavailable").
验证门槛——要声称存在接管漏洞,你必须实际完成认领:
- 确认悬空目标未注册/可认领(S3 存储桶名称可用、Heroku 应用不存在等)——仅凭服务商错误特征虽然必要,但远远不够。
- 自行注册该资源并提供唯一的金丝雀文件,例如让
https://$sub/<random>.txt返回只有你知道的字符串。截取通过受害者子域名和有效 TLS 提供该文件的屏幕截图。 - PoC 完成后立即拆除资源;绝不要让攻击者控制的内容继续留在目标域名上。
影响:窃取 Cookie 作用域(为 .target.com 设置的 Cookie)、滥用 OAuth redirect_uri/CORS 信任、在受信任的源上进行钓鱼。通常为高危(如果位于 OAuth/SSO 重定向处或共享会话 Cookie,则为严重)。
阶段 7 — CAA 记录(仅作侦察信号,不是可报告的发现)
# CAA records DECLARE which CAs the domain owner permits to issue certs.
dig CAA $TARGET +short
dig CAA "*.$TARGET" +short
**不要将“缺少 CAA”报告为漏洞。**这是此类问题中最常见的误报。正确的表述如下:
- **缺少 CAA 记录不会让攻击者获得证书。**这只意味着所有者尚未选择限制哪些 CA 可以签发证书。无论是否配置 CAA,攻击者仍需通过域名控制权验证(HTTP-01 / DNS-01 / 电子邮件验证)——这要求攻击者已经控制该域名、DNS 或 Web 根目录。
- “欺诈性签发”情形需要CA 被攻破,或通过社会工程诱使 CA 错误签发证书。这几乎始终超出漏洞赏金计划的范围,也无法通过实际操作证明。CAA 强制执行是 CA 端的控制措施,不是面向攻击者的攻击面。
- CAA 最多只能算信息级加固建议,而且通常会以 Won't-Fix / OOS 结案。若要提及,可放在侦察笔记附录中;绝不要单独提交报告。
CAA 侦察的实用价值(不构成漏洞发现,仅供参考):issue/issuewild 值可以告诉你组织使用哪家 CA(例如 letsencrypt.org、digicert.com、amazon.com)。这能暗示其是否使用自动化(ACME),也能提示在何处发生的真实接管(阶段 6.5 的悬空记录)可能让你通过 DCV 签发有效证书,因为你将控制该主机。
阶段 8 — mTLS 绕过尝试
# Check if endpoint requires client certificate
curl -sk "https://$TARGET/internal/" 2>&1 | grep -i "ssl\|certificate\|403\|401"
# Try without client cert (should fail)
curl -sk --cert "" "https://$TARGET/internal/api" | head -5
# Try common bypass paths (some apps skip mTLS on health checks)
for path in /health /ping /status /metrics /api/health; do
STATUS=$(curl -sk -o /dev/null -w "%{http_code}" "https://$TARGET$path")
echo "$path: $STATUS"
done
# Header-injection bypass — nginx/HAProxy/Envoy commonly terminate mTLS at the edge and
# forward the verdict as a request header the backend trusts. If the edge does NOT strip
# client-supplied copies of that header, you spoof a verified client. Try the real header
# names used by each proxy:
for combo in \
"X-SSL-Client-Verify: SUCCESS|X-SSL-Client-S-DN: CN=admin" \
"ssl-client-verify: SUCCESS|ssl-client-subject-dn: CN=admin" \
"X-Client-Verify: SUCCESS|X-Client-DN: CN=admin,O=target" \
"X-Forwarded-Client-Cert: By=spiffe://x;Hash=0;Subject=\"CN=admin\""; do
H1="${combo%%|*}"; H2="${combo##*|}"
echo "== $H1 / $H2 =="
curl -sk "https://$TARGET/internal/api" -H "$H1" -H "$H2" -o /dev/null -w "%{http_code}\n"
done
mTLS 绕过验证——这是真正的身份验证绕过,因此要证明能够访问,而不只是提供状态码:
200可能只是通用页面。请确认你访问到了仅限已通过身份验证用户使用的功能:展示没有客户端证书就无法获取的数据或执行的操作(例如仅限管理员访问的对象、仅限内部使用的响应正文)。- 区分服务器策略与服务器状态:如果伪造的标头让
403变成200,这很有意义;如果有无该标头都返回200,则说明此路径原本就没有受到保护(不算发现)。 - 对于绕过路径(
/health、/metrics):只有当端点暴露了敏感数据(内部 IP、构建密钥、暴露内部拓扑的 Prometheus 指标)时才算发现——返回空内容的200 OK健康检查不算。 - 在 Burp Repeater 中捕获请求/响应对,清楚证明伪造的标头 → 特权响应。
漏洞链表
下方严重性等级依据漏洞分诊实际认可的标准校准,刻意采取保守评估;请勿在报告中夸大。
| TLS/DNS 发现 | 实际可达到的单项严重性 | 说明 / 提升严重性的因素 |
|---|---|---|
| 悬空 CNAME 子域名接管(已认领 + 已提供 canary) | 高 | 如果涉及 OAuth redirect_uri/SSO,或共享 .target.com 会话 Cookie,则为严重 |
| 绕过 mTLS / 客户端证书验证并访问已通过身份验证的功能 | 高 | 必须展示特权数据/操作,不能只展示 200 |
| AXFR 返回内部主机/IP | 中 | 有侦察价值;可与内部服务相关发现结合 |
| 可伪造的 DMARC,且已投递到真实收件箱(PoC 邮件头) | 中 | 通常不在范围内——请检查范围;必须投递到收件箱(而非垃圾邮件)。仅用 dig 读取 p=none = 信息级,不要提交 |
| Heartbleed / 实时内存泄露并捕获到密钥 | 高–严重 | 仅限实际转储中包含密钥/Cookie |
| 身份验证子域名缺少 HSTS | 低 / 信息级 | 并非高危——利用需要主动 MitM 位置,无法远程证明;仅在有可行的降级捕获 PoC 时报告 |
| 支持弱加密套件(RC4/3DES/SWEET32),但没有解密 PoC | 信息级 / 低 | 仅涉及加固;经常不在范围内 |
| 缺少 CAA | 信息级(不要提交) | 缺少 CAA 并不会允许签发证书;无法由攻击者证明 |
工具
# testssl.sh — comprehensive TLS audit
brew install testssl
testssl.sh $TARGET
# sslyze — Python TLS scanner
pip3 install sslyze
# MXToolbox for email security
curl -s "https://mxtoolbox.com/api/v1/Lookup/spf?argument=$TARGET" 2>/dev/null
# dmarc-inspector
curl -s "https://dmarcian.com/dmarc-inspector/?domain=$TARGET" 2>/dev/null
验证
每项发现都必须附上所列的证明——绝不能只提供 dig/标头输出。
- **子域名接管:**你已注册该悬空资源,并在
https://sub.target.com/上通过有效 TLS 提供了独特的 canary。附上截图和 canary 字符串。(之后撤除。) - **mTLS 绕过:**伪造客户端验证标头后返回特权数据/操作,而证书必需的路径会拒绝该请求。提供 Burp 请求/响应对。
- **AXFR:**区域传送从权威 NS 返回内部主机名/IP。提供完整记录。
- DMARC 伪造:使用 swaks 发送带有
From: @target.com的邮件,且已投递到真实收件箱(而非垃圾邮件),并附上原始Authentication-Results标头。退信或进入垃圾邮件 = 不算发现。 - **缺少 HSTS:**只有在有可行的降级 PoC 并捕获到受害者通过明文传输的 Cookie 时才能报告;否则只是最佳实践层面的噪声。
严重性(保守评估——与漏洞链表一致):
- 子域名接管(已认领):高(涉及 OAuth/SSO 重定向或共享会话 Cookie 时为严重)
- 绕过 mTLS 并访问已通过身份验证的功能:高
- AXFR 返回内部主机:中
- DMARC 伪造且已投递到收件箱:中(通常不在范围内——请核实范围)
- 身份验证端点缺少 HSTS(有降级 PoC):低–中;无 PoC:信息级
- 支持弱加密套件但无解密 PoC:信息级–低
- 仅缺少安全标头 / 缺少 CAA:信息级(通常不要提交)
**提交前的范围检查:**提交此处的任何问题前,请确认项目没有将其列为范围外(电子邮件身份验证、缺少标头、没有利用证据的弱 TLS,以及 CAA 通常都在范围外)。请在报告中引用范围内的相关条款。