4. TLS版本降级攻击:检测降级到SSLv3或TLS1.0的特征

版本降级攻击,说白了就是攻击者篡改握手参数,迫使客户端和服务端用更弱的老旧协议通信。我最早接触这玩意是在一次金融APP安全审计里——明明两边都支持TLS1.2,握手包里的ServerHello却吐出一个SSLv3。当时吓一跳,赶紧翻协议栈实现,后来才发现是被中间人劫持了。今天咱们就专门聊聊如何从流量中嗅出这种降级行为。

降级攻击的本质

核心就一句话:客户端发最高版本,服务端回最低版本。
正常握手时,ClientHello里会填客户端支持的最高版本(比如TLS1.2),ServerHello则回应一个双方都支持的版本(一般是TLS1.2)。攻击者要做的,就是把ClientHello中的版本字段改低,或者把ServerHello的版本改低。你想想看,如果服务器端实现有bug或配置不当,直接接收了一个不合逻辑的低版本,降级就成功了。

💡 提示: 注意!有些场景下降级是“合法”的——比如老旧客户端只支持TLS1.0。我们要抓的是明明两边都支持高版本,却硬退回到低版本的情况。

关键检测维度

我个人习惯从三个层面入手抓降级痕迹:版本号、扩展字段、密码套件。下面列几个我碰过的真实特征。

检测维度 降级到SSLv3 降级到TLS1.0 降级到TLS1.1
ClientHello最高版本 TLS1.2 / 1.3 TLS1.2 / 1.3 TLS1.2 / 1.3
ServerHello响应版本 0x0300 (SSL 3.0) 0x0301 (TLS 1.0) 0x0302 (TLS 1.1)
支持的密码套件 多为RSA+RC4或3DES 可能含CBC模式 类似TLS1.0但新增AES
secure_renegotiation扩展 ❌ 不可能存在 ✅ 可选存在 ✅ 可选存在
extended_master_secret ❌ 不支持 ✅ 可选存在 ✅ 可选存在
signature_algorithms扩展 ❌ 不支持 ✅ 存在 ✅ 存在
⚠️ 警告: 表中“❌不支持”意味着:如果服务端返回SSLv3,但在ServerHello中带上了secure_renegotiation扩展,那一定是假包——因为SSLv3根本没有这个扩展定义。这种矛盾就是明显的攻击特征。

我在项目里遇到过一次奇葩情况:客户端发送的ClientHello版本是TLS1.2,但密码套件只列了SSLv3的RC4。后来追查发现,因为一个老旧中间件升级策略出错,导致握手协商阶段把密码套件列表单独降了版本。所以你不能只看版本号,套件列表和扩展的匹配才是铁证。

看懂握手包里的版本博弈

下面这张流程图,清晰地对比了正常握手和降级攻击下的版本流转。注意深色节点就是关键差异点。

TLS版本降级攻击:握手阶段对比 正常 ClientHello (版本=1.2) 正常 ServerHello (版本=1.2) 恶意 ClientHello (版本=1.0) 降级 ServerHello (版本=1.0) 中间人篡改版本字段 检测关键点 ClientHello版本 ≠ ServerHello版本?检查中间包是否被插入篡改。 📌 判定规则:版本对不上 + 扩展/套件矛盾 = 降级攻击 举例:ClientHello支持TLS1.2,ServerHello返回SSLv3且缺失secure_renegotiation扩展

实战检测步骤

我自己在做流量分析时,一般按下面几步排查。嗯,这里要注意——不要只看一个包,要看整个握手阶段的连续包。

  1. 定位ClientHello和ServerHello。用Wireshark过滤:tls.handshake.type == 1 || tls.handshake.type == 2
  2. 比较版本字段。检查tls.handshake.version(ClientHello里的最高版本) vs tls.handshake.version(ServerHello里的版本)。如果前者是0x0303(TLS1.2),后者是0x0300/0x0301/0x0302,先标记可疑。
  3. 检查扩展存在性。强制关注三个扩展:
    • tls.handshake.extension.type == 0xff01 (secure_renegotiation) —— 如果ServerHello版本是SSLv3但出现了这个扩展,100%被改过。
    • tls.handshake.extension.type == 0x0017 (extended_master_secret) —— TLS1.0及以上才可能带,SSLv3不带。
    • tls.handshake.extension.type == 0x000d (signature_algorithms) —— TLS1.2才开始定义,如果ServerHello是TLS1.0但带了这个扩展,说明服务端是伪造的。
  4. 辅助验证密码套件。列表里如果出现0x0004(TLS_RSA_WITH_RC4_128_MD5)这类老古董,而客户端本不该支持它,那极可能是被攻击者替换了。
🔍 实战案例: 我曾经排查过一个银行网银的异常证书告警。用户反馈偶然证书错误,我抓包发现ClientHello版本是1.2,ServerHello回的是TLS1.0。仔细一看,ServerHello里居然带了一个signature_algorithms扩展——这个扩展是TLS1.2才有的。这就是典型的降级攻击重放包,攻击者把旧握手包里的ServerHello原封不动重放了一遍。我建议你遇到类似矛盾时,直接检查扩展字段是否“穿越”了。

工具与快速脚本

下面是tcpdump + tshark的自动化检测脚本片段,我常用它跑离线pcap。短小精悍,适合放到流水线上

#!/bin/bash
# 检测降级到TLS1.0或更低的握手
tshark -r traffic.pcap -Y "tls.handshake.type == 2" -T fields \
  -e frame.number \
  -e tls.handshake.version \
  -e tls.handshake.extensions_extension_type \
  2>/dev/null | awk '
{
  # 假设ClientHello的最高版本已知(可另取)
  # 这里简单演示:如果ServerHello版本 < 0x0303 且出现0x000d则报警
  if ($2 < "0x0303" && $3 ~ /0x000d/) {
    print "⚠️ 可疑降级帧 #" $1 " 版本:" $2 " 含signature_algorithms"
  }
}'
💡 避坑指南: 我曾经遇到过厂商负载均衡器自作聪明,把高版本握手“降级”成低版本给后端老旧服务器用——这叫协议桥接,不是攻击。检测时一定要区分:如果客户端到负载均衡是1.2,负载均衡到后端是1.0,这属于架构设计;如果客户端‑服务端直接握手却降级,那才是攻击。我的建议是:结合网络拓扑一起看,别误报。

总结一下:降级攻击的痕迹就藏在版本矛盾、扩展穿越、套件错配这三个方向里。我个人的原则是:看到ServerHello版本低于ClientHello版本时,先兴奋一下,然后立刻查扩展——扩展是最难伪造的,因为它们必须遵守协议规范。做到这一步,大部分降级攻击都逃不过你的抓包分析。