Rabbit Store
Demonstrate your web application testing skills and the basics of Linux to escalate your privileges. - by iklak
The following post by 0xb0b is licensed under CC BY 4.0
Recon
We start with a Nmap scan and find four open ports, including port 22 SSH, 80 a web server, 4369 Erlang Port Mapper Daemon, 25672 RabbitMQ.

From our service and script scan we directly find out the domain of the webserver:
We add this in our /etc/hosts and visit the page. We find a static page with a login.

Since we have a domain given, we use FFuF to search for subdomains and find storage.cloudsite.thm and add it to our /etc/hosts file.

If we had tried to log in, we would have noticed the subdomain. We click on Signup and create an account.

After we have logged in with our created account, we see that the services are only available for internal users and our newly created account has to be activated by an administrator.

Privileged Web Access
We find a jwt token in our cookies.

We inspect the token using jwt.io and see that the subscription is also defined in it. Unfortunately, changing the token does not help, as the signature would no longer be valid.

We go back one step and create another account and inspect the request using Burp Suite. We see that email and password are transmitted in plain text in JSON.

We simply add the attribute "subscription": "active" in the hope that this will be taken into account when the token is created and that we have a JWT token forgery vulnerability in front of us.

After we have created the account, we log in and inspect the token. The set attribute of the subscription has indeed been taken into account.

We are now able to use the services. Including a file upload.

However, this does not appear to be vulnerable...

API Docs via SSRF
We noticed the /api/ path during registration and are looking for further API endpoints. We enumerate these using FFuF. Here we find /api/docs, among others. Perhaps there are others that we cannot find with our wordlist.

Unfortunately, we do not have access to these.

If we scroll down a little further we also find an upload via URL. Server side request forgery could be possible here. And perhaps we could then use it to call up http://storage.cloudsite.thm/api/docs.

Firstly, we test it with our web server.

And see the request made.

Next we try to access the /api/docs endpoint locally on port 80:

We receive an upload path. But port 80 does not seem to be the API endpoint.

We use a script to find more services on other ports on localhost. To do this, we simply check whether the requested service gives us a download link.
And there is another service running on port 3000.

We make a request for http://127.0.0.1:3000/api/docs...

... And we recieve the documentation with the endpoint /api/fetch_messeges_from_chatbot, which is still under development.
SSTI to RCE
We try to make a request, but GET methods are not allowed.

We capture our GET request using Burp Suite...

... and change it to a POST request using Burp. We get a message, that the token is required, we removed.

We add the token, and a username parameter is required.

Since the error message is JSON, and we know the format from the login as JSON, we also provide the username in JSON. Our username gets reflected.

We simply test for Server Side Template Injection (SSTI) and it gets evaluated.

We use a payload from Ingo Kleiber to test for RCE on Flask (Jinja2) SSTI and are successful.

Shell as azrael
Since we have RCE through SSTI, we prepare a reverse shell using revshells.com.

Next, we prepare our SSTI payload, set up a listener on our desired port and submit the request.

We get a connection back, and are the user azrael. We upgrade our shell.

The user flag can be found in the home directory of azrael.

Shell as rabbitmq
On enumerating the target we also use pspy. It is a command line tool designed to snoop on processes without need for root permissions.
We download and execute the tool.

And there is something going on using Erlang and RabbitMQ. We recall the Nmap scan with the results on 4369 Erlang Port Mapper Daemon, 25672 RabbitMQ.

If we ask ChatGPT about the output we get some more information. It might be related to RabbitMQ and Erlang. RabbitMQ is an open-source message broker that enables applications to communicate using a queue-based messaging system, supporting multiple protocols like AMQP. It is used for distributed systems, event-driven architectures, and microservices to decouple and scale workloads efficiently.
ChatGPT:
This log appears to represent a series of shell commands being executed by the user with UID 124, involving RabbitMQ and the Erlang environment, specifically invoking various Unix shell commands. The frequent appearance of sh -c exec /bin/sh -s unix:cmd suggests the use of shell scripts or commands being run in response to Unix system-level interactions.
Several commands reference Erlang's epmd (Erlang Port Mapper Daemon), which indicates that RabbitMQ (built on top of Erlang) is likely being managed or configured. The sequence where Erlang's beam.smp and epmd are invoked points to RabbitMQ processes being started, stopped, or checked. Additionally, these may involve DNS queries or hostname resolution (inet_gethost commands).
This log suggests the orchestration of processes related to RabbitMQ and possibly diagnostics or system administration tasks within an environment relying heavily on Erlang.
If you’re analyzing this for potential security or performance issues, I’d suggest investigating why multiple sh shells are being spawned and what commands are being passed to the Unix shell to ensure there is no unintended behavior or vulnerability exploitation. Is this part of your current challenge or a live environment
A look into the /etc/passwd file confirms, that there is the user rabbitmq.

At /var/lib/rabbitmq/ we can find an erlang cookie.

This cookie might enable us to get RCE via Erlang.
The following repository contains several exploits regarding Erlang with RabbitMQ. One of which would allow us RCE: shell-erldp.py.
But we receive errors on running the exploit.

For a fix we use ChatGPT to add verbose debugging and error handling:
We use the our customized shell-erldp2.py and are able to get an instable shell.

Next, we prepare a reverse shell payload using revshells.com.

We set up a listener and issue the command to get a reverse shell.

We get a connection back and are the user rabbitmq.

Shell as root
Since we are now the rabbitmq user, we could issue RabbitMQ commands with rabbitmqctl. One of the ideas could be to retrieve the users and passwords to check if they are reused. But we get an error. The .erlang.cookie is not only owned by the owner itself. With that issue we are not able to execute rabbitmqctl commands.

Nevertheless, we can view the rabbit_user.DCD. This file is part of the RabbitMQ database. There is a message indicating that the root user's password is the same as the SHA-256 hash of the RabbitMQ root user's password.

Alternatively, we can also correct the permissions of the Erlang cookie, which will be necessary for later use.

When reading up on how RabbitMQ works, we find the rabbit definitions that we can export as admin. Those include the password_hash mentiond in the users file. The idea now is to create an admin user and get the definitions with this user.

Since we have already corrected the authorizations for the Erlang cookie, we can create the user and export the definitions.

In these we find the hash for the root user.

The following gist shows us how the rabbit password hash is composed.
We only need to decode this base64. Since we only need the SHA-256 hash.
We decode the hash...

... and use that hash to switch user to root and find the final flag in the root's home directory.

Last updated
Was this helpful?