文章总结: CVE-2026-34486是ApacheTomcat集群加密组件的回归漏洞,因修复CVE-2026-29146时异常处理逻辑错误导致加密校验被绕过,攻击者可在满足集群启用、加密配置等条件时通过4000端口发送恶意序列化数据实现RCE。关键发现包括漏洞触发需同时满足四个前提条件,且利用链依赖反序列化Gadget。建议立即升级至安全版本或通过防火墙限制端口访问。 综合评分: 90 文章分类: 漏洞分析,应急响应,WEB安全,红队,威胁情报
CVE-2026-34486 ( Apache Tomcat 集群加密绕过 RCE)
Ly Ly
船山信安
2026年4月22日 18:11 广东
在小说阅读器读本章
去阅读
一行代码的位置引发的问题
CVE-2026-34486 是修复 CVE-2026-29146(Padding Oracle 攻击)时引入的回归 Bug,根本原因是一行代码的位置移错了。
但这行代码的代价是:任何启用了 Tomcat 集群加密通信的服务器,都可以被远程执行任意代码。
CVE-2026-29146
今年年初,Tomcat 修复了 CVE-2026-29146。那个漏洞出在 Tribes 集群通信组件的 EncryptInterceptor 上,问题是对 AES/CBC 模式下 PKCS5 Padding 的校验不够严格,攻击者可以通过观察服务端对不同填充错误的响应差异,逐字节还原密文,典型的 Padding Oracle 攻击。
Apache 随后发布了补丁,对应版本 Tomcat 9.0.116、10.1.53、11.0.20。
补丁重构了 EncryptInterceptor.messageReceived() 方法的异常处理逻辑。重构本身的方向是对的:捕获解密异常,避免异常传播导致整个集群通信中断。但在具体实现上,开发者犯了一个致命的错误。
异常与消息的问题
安全版本的逻辑应该是这样的:在 try 块内完成 AES 解密,成功后再调用 super.messageReceived(msg) 把消息传给后续拦截器链。解密失败时,catch 块直接 return,消息被丢弃。这说的是 Fail-Close(失败关闭)原则,验证不通过,处理就终止。
但在修复 CVE-2026-29146 后的版本中;super.messageReceived(msg) 被移到了 try-catch 块的外面。catch 块里只做了一件事:记一条 warn 级别的日志。没有 return,没有 throw。
这带来有一个大的问题,无论解密是否成功,消息都会流向后续处理链。攻击者发送一段精心构造的 Java 序列化字节流,EncryptInterceptor 尝试用 AES 解密–>必然失败–>异常被 catch 吃掉,super.messageReceived(msg) 照常执行,原始的恶意字节流以”正常消息”的身份进入了后续反序列化流程。
从 Fail-Close 退化成了 Fail-Open。整个加密防线形同虚设。
// 漏洞版本的关键结构
public void messageReceived(ChannelMessage msg) {
try {
byte[] decryptedBytes = decrypt(msg.getMessage().getBytes());
// ...
} catch (GeneralSecurityException e) {
log.warn("Failed to decrypt message from cluster peer.", e);
// 没有return,异常被吞,msg保持原始字节
}
super.messageReceived(msg); // 无论解密成败都会执行
}
四个前提
光有代码缺陷还不够,实际利用需要四个条件同时成立。
- 第一,集群功能必须启用。Tomcat 的 Tribes 集群不是默认开启的,需要
server.xml里配置<Cluster>元素,并且应用的web.xml中要有<distributable/>标签。单机部署的 Tomcat 完全不受影响。 - 第二,必须配置了 EncryptInterceptor。只有同时配置了 Cluster和 EncryptInterceptor 的实例才存在漏洞。如果集群通信根本没开启加密,那 EncryptInterceptor 不参与处理,漏洞自然不触发。
- 第三,攻击者要能访问到 Tribes 集群通信端口。NioReceiver
默认监听 TCP 4000 端口,这个端口在正常的生产环境中应该被防火墙限制为仅允许集群节点互访。如果 4000 端口暴露在公网,或者攻击者已经拿到了内网的立足点,那就可以直接发报文过去。
- 第四,目标环境的 Classpath 里得有可利用的反序列化 Gadget 链。最典型的是 Apache Commons Collections 3.1,大量使用 Struts2 和老版本 Spring 的项目都有这个依赖。反序列化执行最终靠的是
ObjectInputStream.readObject()触发 Gadget 链,如果 Classpath 里没有可利用的库,序列化字节流进来也不会执行任何代码,但会留下解密失败的日志。
攻击链
奇安信 CERT 已经完成了复现,腾讯云和 ZONE.CI 也发布了详细的技术分析。
攻击者首先通过 nmap 等工具探测目标 4000 端口是否开放,确认是 Tribes 服务。然后用 ysoserial 生成基于 Commons Collections 的序列化 payload,内嵌要执行的命令。接下来把 payload 按照 Tribes 私有协议封装——加上固定的协议头 FLT2002、4字节长度字段、协议尾 TLF003。最后通过 TCP 直连 4000 端口把报文发过去。
服务端 NioReceiver 接收报文后进入 EncryptInterceptor,解密失败,异常被吞,super.messageReceived() 照常走,原始序列化字节流流入 ObjectInputStream,Gadget 链触发,命令执行。
整个过程不需要知道 AES 密钥。加密本身就是为了防住这种攻击的,但加密校验的失败路径出了问题,密钥就变成了摆设。
复现验证
ZONE.CI 的深度分析文章给出了双节点集群的 server.xml 配置。节点间通过 NioReceiver 监听 TCP 4000 端口,使用 NioReceiver 接收,Membership 通过多播地址 228.0.0.4 发现节点。 EncryptInterceptor 配置了 AES-256 密钥(32字节十六进制编码),使用 AES/CBC/PKCS5Padding 模式。节点2除了 HTTP 端口和 Tribes 端口不同外,其余配置一致。两个节点的应用 web.xml 都需要 声明 <distributable/> 以启用 Session 复制。
奇安信 CERT 的复现中,成功通过反弹 Shell 在受害服务器上获取了交互式会话。
检测
排查上,先看 Tomcat 版本是否在 9.0.116、10.1.53、11.0.20 之内,再检查 server.xml 是否同时存在 Cluster 和 EncryptInterceptor 配置,最后确认 4000 端口的防火墙策略。如果 catalina.out 里出现大量来自非集群节点 IP 的 “Failed to decrypt” 日志,结合 /tmp 目录下的可疑文件和异常出站连接,基本可以判定已被利用。
修复方案很直接:升级到 9.0.117、10.1.54 或 11.0.21。临时缓解的话,要么用防火墙封锁 4000 端口的外部访问,要么直接关掉集群配置如果不用的话,或者部署 JEP 290 反序列化过滤器做纵深防御。
对于这个漏洞。Apache 的开发者不是不知道 Fail-Close 的道理,他们只是在重构异常处理时,把一个方法调用从 try 块里面挪到了外面。这可能是为了防止解密异常导致的集群中断,出发点是可用性,但可用性和安全性之间存在一种微妙的关系。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:船山信安 Ly Ly《CVE-2026-34486 ( Apache Tomcat 集群加密绕过 RCE)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论