The Bandit Surfer
The Bandit Yeti is surfing to town. - by hadrian3689
Last updated
The Bandit Yeti is surfing to town. - by hadrian3689
Last updated
All banner and comic images are courtesy of TryHackMe - https://www.tryhackme.com
The following post by 0xb0b is licensed under CC BY 4.0
The QR Code to Side Quest 3 can be found in the Challenge Task 27 [Day 21] DevSecOps Yule be Poisoned: A Pipeline of Insecure Code!
We look at the merge requests to understand what happened there as part of the challenge.
Within this one merge request we find the user Frostlino, let's have a look at his activity feed.
He deleted a branch there, ok, maybe the QR code could be hidden here.
In the images' directory, we find the defaced image as well as the original.
And lo and behold, the original image contains the QR code for the challenge.
OK, let's start with side quest number 4 and see what we have in front of us.
We start with a Nmap scan and find only two open ports. SSH is running on port 22 and a web server on port 8000.
The service scan provides us with further important information, including the fact that OpenSSH 8.2p1 is in use and that the web server is a Python Werkzeug
web server, often associated with flask
web applications.
Let's first visit the website while the Gobuster scan is running to enumerate the directories. we are greeted with a download portal. If you click on one of the elves, it will be downloaded as an SVG.
When inspecting the source, you will see that /download
is passed with the parameter ID to download files. When enumerating further IDs with burp suite, intruder ID 4 only gave a result with a PNG of the Yeti gang. We may be able to exploit this function to exfiltrate other files on the system. Let's continue enumerating for now.
In addition to the download directory, Gobuster also finds the directory console. Nice, Werkzeug / Flask Debug might be enabled and provides us eventually a foothold.
The interactive console is activated, nice. However, it is protected with a pin. But we can easily bypass this by reverse engineering the pin. There is a script for this on hacktricks: https://book.hacktricks.xyz/network-services-pentesting/pentesting-web/werkzeug
However, this requires internal information on the system, which we must first obtain. As already mentioned, the download portal may help us there.
Let's try to restore the pin and focus on getting the necessary information from the system. For this we need something like a path traversal vulnerability or a local file inclusion vulnerability for example.
So we take a look at the download portal. Since IDs are used here, there could be a database behind it, let's try a simple SQL injection probe and see what error we get.
And we have a hit, SQL injection is possible, and we also see why it works. The use of string formatting with %s
without proper validation or sanitization allows for potential SQL injection attacks.
With the following construct we are able to retrieve arbitrary files, for example the /etc/passwd
file in the scope of the user running the service.
10.10.63.23:8000/download?id=' UNION SELECT "file:///etc/passwd" -- -
Attempting to retrieve the user flag has been successful, but we need to progress and exfiltrate more of the system to establish an initial foothold via the Flask debug console
10.10.63.23:8000/download?id=' UNION SELECT "file:///home/mcskidy/user.txt" -- -
Nice, we are able to retrieve files from the system. We move on to the pin exploit. A detailed explanation can be found here: https://www.daehee.com/werkzeug-console-pin-exploit/
For now, we move on with the exploits presented at hacktricks.xyz
.
Here, we have to provide the script the following parameters. We already know the user mcskidy from the error message, as well as the path to app.py
. We retrieve the private bits by retrieving that information using the download portal.
First, we need the decimal expression of the mac address of the system. We get the MAC at file:///sys/class/net/<device id>/address
. To get the device id we query for the file /proc/net/arp
, its eth0
.
10.10.63.23:8000/download?id=' UNION SELECT "file:///proc/net/arp" -- -
Next, we query for /sys/class/net/eth0/address
to get the MAC address.
10.10.63.23:8000/download?id=' UNION SELECT "file:///sys/class/net/eth0/address" -- -
To convert the mac address, we use the following resource, and chose the EUI-48 representation:
Next, we query the machine-id at /etc/machine-id
.
10.10.63.23:8000/download?id=' UNION SELECT "file:///etc/machine-id" -- -
We would also be able to get the used hash algorithm and used salt at /home/mcskidy/.local/lib/python3.8/site-packages/werkzeug/debug/__init__.py
10.10.63.23:8000/download?id=' UNION SELECT "file:///home/mcskidy/.local/lib/python3.8/site-packages/werkzeug/debug/
init
.py" -- -
Now that we have the private bits, we are able to modify the pin cracking script to the challenge needs.
Here is the following complete script. At this point, only the MAC should be different to yours. Since this is the case, you should get another working pin.
We generate the pin and provide it to the login field. Unfortunately, this isn’t a consistent exploit, as in this case and in the initial compromise approach this failed at some points, and you might have to restart the machine.
After restarting the machine only the mac has to be queried again, since this is the only thing that changed.
After updating the script with the new decimal representation of the MAC, we get the following pin.
We provide it to the login mask and are able to use the interactive console.
We use the Python3#2 reverse shell from revshells.com and only use the actual code. (Highlighted one)
We set up a netcat listener on port 4445 and execute the python payload.
We receive a connection back and have a reverse shell as the user mcskidy
. First, we upgrade the shell and continue with our enumeration.
Upgrade shell:
https://0xffsec.com/handbook/shells/full-tty/
python3 -c 'import pty; pty.spawn("/bin/bash")'
CRTL+Z
stty raw -echo && fg
We find the user flag in the home directory of mcskidy
.
From there, we are able to inspect the application folder app of the flask web server. We see that it is a git repository. Let’s see if we can find some valuable information in this repository.
For this we make use of GitTools.
First, we set up a python web server on the victim machine in the app folder, to retrieve all of its information.
We use gitdumper.sh
to dump the repository.
Then we move into the folder and run extractor.sh
to get the entire commit history.
Via git log
, we see all commits. Commit e9855c8a10cb97c287759f498c3314912b7f4713
looks promising, there they changed the MySQL user.
Via git show e9855c8a10cb97c287759f498c3314912b7f4713
we see the changed users, and we are able to get a password for user mcskidy
. Let’s check if it is reused.
The credentials are being reused, and we are able to query sudo -l
. Here we two valuable information, first the secure path is set to /home/mcskidy
.
The secure_path
is an environment variable that specifies the directories where the system looks for executable files.
Secondly, we are able to run /usr/bin/bash /opt/check.sh
. Nice, so if the script uses something without an absolute path, we are able to control what it is executing by having that binary placed in /home/mcskidy.
So there might be our privilege escalation vector.
Looking into /opt
we see also .bashrc
. That's really odd, strange to find it here. The .bashrc
file is normally a script file that is executed whenever a new interactive Bash shell is started for a user. It stands for "Bash Run Commands" This file is commonly found in a user's home directory and is used to customize and configure the behavior of the Bash shell for that specific user.
Oh, and the /opt/.bashrc
is also sourced in the script. That is really odd too. At first glance, despite this strange inclusion of bashrc, the script does not seem to offer an entry point. We are only facing absolute paths.
And here comes the mind-blowing part. The square brackets are a synonym for the test
command.
The test command is in that bash file via the -n
flag inside the .bashrc
disabled, but worked running the script, it seems. So the shell command does get disabled, but since it worked, it gets sourced from one of the secure_paths
. So a binary is used instead.
See for shell commands like cd:
Here we have our binary, which we can provide in the home directory of mcskidy
to escalate privileges.
We set up a reverse shell script in the file [
in /home/mcskidy
, set up a listener and executes it to test if it is working.
Nice, we get a connection back.
Ok, we terminate the connection and set up a listener again. Now we execute sudo /bin/bash /opt/checks.sh
. We receive a connection back as the root
user and head directly to /root
.
Here we are able to find the root flag.
yetikey4.txt
flag?Still in /root
, we are able to access the yetikey4.txt
Check out Sumanroy's writeups: https://sumanroy.gitbook.io/ctf-writeups/
For fully automated exploits created by my teammates, visit their GitHub profiles: