
Prueba de concepto que demuestra una evasión del filtro de deserialización en Apache MINA que conduce a la ejecución remota de código, con análisis detallado de la causa raíz, PoCs de explotación y guía de remediación.
CVSS 3.1: 9.8 CRÍTICO AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H
CWE: CWE-502 Deserialización de Datos No Confiables
Reportero: Venkatraman Kumar, Securin
Aviso: Lista de Correo de Apache
Las versiones de Apache MINA 2.1.0 hasta 2.1.11 y 2.2.0 hasta 2.2.6 contienen una omisión del filtro de deserialización en AbstractIoBuffer.resolveClass(). La lista blanca acceptMatchers — diseñada para restringir qué clases Java pueden deserializarse — se omite por completo cuando ObjectStreamClass.forClass() devuelve null.
Un atacante con acceso de red a un endpoint de MINA que utilice ObjectSerializationCodecFactory puede crear una carga útil de protocolo que omita el filtro de clases, lo que permite mediante cadenas de gadgets estándar de deserialización de Java (por ejemplo, Commons Collections).
Esta es una corrección incompleta para CVE-2026-41635. El parche original se aplicó a la rama 2.0.x pero nunca se retroportó a 2.1.x o 2.2.x debido a un descuido en la fusión.
| Rama | Vulnerable | Corregida |
|---|---|---|
| 2.1.x | 2.1.0 – 2.1.11 | 2.1.12 |
| 2.2.x | 2.2.0 – 2.2.6 | 2.2.7 |
La vulnerabilidad está en AbstractIoBuffer.resolveClass(), que maneja la resolución de clases durante la deserialización de objetos Java.
MINA utiliza un protocolo de serialización personalizado con dos tipos de descriptores de clase:
En el código vulnerable, el filtro acceptMatchers solo se verifica en la rama de tipo 1 (cuando forClass() devuelve un valor no nulo). La rama de tipo 0 llama a Class.forName() directamente, omitiendo el filtro por completo:
// AbstractIoBuffer.java — VULNERABLE (2.2.6)
protected Class<?> resolveClass(ObjectStreamClass desc) {
Class<?> clazz = desc.forClass();
if (clazz == null) {
// BUG: Sin verificación de acceptMatchers — filtro completamente omitido
return Class.forName(name, false, classLoader);
} else {
// El filtro solo se aplica aquí
for (ClassNameMatcher matcher : acceptMatchers) { ... }
}
}
La corrección en 2.2.7 mueve la verificación del filtro antes de la rama:
// AbstractIoBuffer.java — CORREGIDO (2.2.7)
protected Class<?> resolveClass(ObjectStreamClass desc) {
String className = desc.getName();
// El filtro se aplica PRIMERO, independientemente del resultado de forClass()
if (!acceptMatchers.stream().anyMatch(m -> m.matches(className))) {
throw new ClassNotFoundException("Class not in accept list " + className);
}
Class<?> clazz = desc.forClass();
// ... la resolución segura continúa
}
Atacante Servidor MINA Vulnerable
| |
| 1. Crea una carga útil de MINA con |
| descriptores de tipo 0 para clases |
| de cadenas de gadgets |
| |
| 2. Envía al endpoint que utiliza |
| ObjectSerializationCodecFactory -------->|
| |
| 3. readClassDescriptor() lee tipo 0 |
| → delega al super (Java estándar)|
| |
| 4. resolveClass() ve forClass()==null
| → Class.forName() SIN filtro |
| |
| 5. La cadena de gadgets se |
| deserializa por completo |
| → readObject() activa la cadena |
| → Runtime.exec() se ejecuta |
| |
| RCE LOGRADO |
IoBuffer.getObject() o ObjectSerializationCodecFactoryaccept() configurado (las aplicaciones sin filtro ya eran explotables mediante CVE-2026-41635)El atacante controla el flujo de bytes serializado. Al usar descriptores de clase de tipo 0 (en lugar de tipo 1) para clases de cadenas de gadgets Serializables, cada clase en el grafo de deserialización omite el filtro acceptMatchers, independientemente de la configuración de lista blanca de la aplicación.
Tres PoCs demuestran un impacto creciente:
| PoC | Qué demuestra |
|---|---|
FilterBypassPoC.java | Omisión del filtro para primitivas, clases no Serializables, arreglos |
CraftedBypassPoC.java | Cargas útiles de tipo 0 creadas por el atacante omiten el filtro para CUALQUIER clase Serializable |
RcePoC.java | RCE completo mediante la cadena de gadgets CC6 a través de la omisión del filtro |
Las clases que no están en la lista de aceptación se deserializan sin restricción:

Un atacante crea cargas útiles de protocolo MINA con descriptores de tipo 0 para cargar cualquier clase más allá de una lista de aceptación de solo String:

La cadena de gadgets variante CC6 (HashSet → TiedMapEntry → LazyMap → ChainedTransformer → Runtime.exec()) logra la ejecución de comandos a través de la omisión del filtro:

Las mismas pruebas se bloquean en la versión corregida:

La cadena de gadgets es rechazada por el filtro:

La forma más rápida de probar — sin JDK ni Maven:
# Clona este repositorio
git clone https://github.com/dinosn/CVE-2026-42779.git
cd CVE-2026-42779
# Compila y ejecuta todos los PoCs
docker build -t cve-2026-42779 .
docker run --rm cve-2026-42779
# Ejecuta PoCs individuales
docker run --rm cve-2026-42779 bypass # Solo omisión del filtro
docker run --rm cve-2026-42779 crafted # Omisión con carga útil creada
docker run --rm cve-2026-42779 rce # RCE completo
# Entra a un shell para explorar
docker run --rm -it cve-2026-42779 shell
La imagen incluye el JAR vulnerable de MINA 2.2.6, Commons Collections 3.2.2 y los tres PoCs precompilados. Todo se ejecuta de forma autónoma dentro del contenedor.
Si prefieres compilar desde el código fuente:
# Clona y compila la versión vulnerable
git clone https://github.com/apache/mina.git /tmp/apache-mina
cd /tmp/apache-mina
git checkout 2.2.6
mvn install -pl mina-core -DskipTests -q
# Descarga commons-collections (para el PoC de RCE)
curl -sL "https://repo1.maven.org/maven2/commons-collections/commons-collections/3.2.2/commons-collections-3.2.2.jar" \
-o commons-collections-3.2.2.jar
# Compila los PoCs
javac -cp mina-core/target/mina-core-2.2.6.jar FilterBypassPoC.java
javac -cp mina-core/target/mina-core-2.2.6.jar CraftedBypassPoC.java
javac -cp mina-core/target/mina-core-2.2.6.jar:commons-collections-3.2.2.jar RcePoC.java
# Ejecuta el PoC de omisión del filtro
java -cp .:mina-core/target/mina-core-2.2.6.jar FilterBypassPoC
# Ejecuta el PoC de carga útil creada
java -cp .:mina-core/target/mina-core-2.2.6.jar CraftedBypassPoC
# Ejecuta el PoC de RCE completo
java -Dorg.apache.commons.collections.enableUnsafeSerialization=true \
--add-opens java.base/java.util=ALL-UNNAMED \
--add-opens java.base/java.lang.reflect=ALL-UNNAMED \
-cp .:mina-core/target/mina-core-2.2.6.jar:commons-collections-3.2.2.jar \
RcePoC
O usa el Makefile incluido:
make run-all # Compila y ejecuta los tres PoCs
make run-rce # Solo el PoC de RCE
Requisitos: JDK 11+ y Maven (para compilar desde el código fuente) o Docker (para el contenedor)
Actualiza a Apache MINA 2.1.12 o 2.2.7.
Si la actualización no es posible de inmediato:
IoBuffer.getObject() ni ObjectSerializationCodecFactory con entrada no confiable| Fecha | Evento |
|---|---|
| 2026-05-01 | Aviso publicado por el PMC de Apache MINA |
| 2026-05-01 | Versiones corregidas 2.1.12 y 2.2.7 publicadas |
| 2026-05-02 | Este PoC desarrollado y probado |
Esta prueba de concepto se proporciona únicamente para investigación de seguridad defensiva, educación y pruebas de penetración autorizadas. Úsala de manera responsable y solo contra sistemas para los que tengas permiso de prueba.