HackTheBox "Agile"
April 14th, 2023
Last updated
April 14th, 2023
Last updated
is a medium box released on March 4th, 2023 by 0xdf.
Starting off with an nmap scan reveals a couple things.
We can see that this box is running NGINX. Attempting to connect to the box from a browser gives a redirect for a website called superpass.htb
. Adding this to /etc/hosts
let's us connect to the website properly.
This is pretty standard. An account can be created in the login page. After making an account, the website lets you create entries for passwords. The website also lets you conveniently export your passwords into a .csv file. When you download a file, you get taken to a subdirectory called download
.
This directory takes a parameter called fn
, meaning filename. The website basically generates a .csv file containing your passwords and passes the file as a parameter so it knows which .csv file to take. However, this parameter is not handled properly. Giving the parameter no input gives an error, specifically an IsADirectoryError.
It seems these .csv files are being generated in /tmp
. While this works fine to download files, it is vulnerable to directory traversal, particularly the line:
This line of Python code will read any file with the given path. We can escape the /tmp
directory using two periods, and can grab any file we want. A good persistent file to grab is /etc/passwd
.
There are the standard users, root
, www-data
, and sshd
, but there are some other users that aren't standard, being corum
, runner
, edwards
, and dev_admin
. This is great and all, but we can't really do much since we don't know the where important files are in the server. Those important files might not even be readable.
An interesting feature of Werkzeug is that the error pages feature a Python interpreter meant for debugging. I'm not sure if this isn't supposed to be in production, but it's available, so let's exploit it!
The debugger is accessed through a terminal icon in the traceback on any line of Python code. Being able to run Python code means gaining access to a reverse shell. Unfortunately, Werkzeug were smart enough to lock these interpreters with a PIN.
However, Werkzeug were not smart enough to make the PIN secure. The PIN is actually predictable, as long as you have access to directory traversal, which we do!
Username: This is the username of whoever is running the application. Directory traversal into /proc/self/status/
reveals the user ID to be 33, which is the same user ID of www-data
, so this is www-data
.
Mod Name: This is either flask.app
or werkzeug.debug
.
App Name: This is either wsgi_app
, DebuggedApplication
, or Flask
.
Absolute Path of app.py
: The error page reveals this to be /app/venv/lib/python3.10/site-packages/flask/app.py
.
MAC Address: This is the decimal version of the system's MAC address. This is normally unobtainable, but directory traversal into /sys/class/net/eth0/address
reveals it to be 00:50:56:b9:72:f5
, which is 345052377845
.
Machine ID: This is the concatenation of the machine ID and the app name. The machine ID is also normally unobtainable, but it can be obtained by grabbing the file /etc/machine-id
which reveals it to be ed5b159560f54721827644bc9b220d00
. The app name can be found by grabbing the file /proc/self/cgroup
and using the value after the last forward slash, which is superpass.service
.
Feeding these values into Ben Grewell's PIN cracker will generate different PIN combinations. My correct PIN was 634-326-400
. This PIN used the combo:
www-data
flask.app
wsgi_app
/app/venv/lib/python3.10/site-packages/flask/app.py
345052377845
ed5b159560f54721827644bc9b220d00superpass.service
Listening via netcat gives us access:
After gaining a shell as www-data
, let's explore the app for any sensitive data. We know that the path for the app is /app
from the Werkzeug error page.
A configuration for production, this probably has something good in it.
Login credentials for the MySQL database. Now we can login to MySQL.
We can see what databases are available:
The promising database is superpass
, so let's select it with use superpass;
. After selecting superpass
, we can see which tables are available:
There is a very promising table called passwords
, let's see what's inside it.
That's the good stuff! But it's still not the flag. From earlier directory traversal, we know that corum
is a user for the box. We can rule out 0xdf
since it's just a reference to the author. corum
has three different passwords. Ticketmaster and mgoblog are real things, but agile
is not. I'm assuming Agile means the box itself, since that's the box's name, so let's login to the box using corum
's account and password from the database.
We're in! A simple ls
reveals user.txt
which contains the flag for the user own.
Within the app
directory contains an interesting file: config_test.json
. This file is not readable by corum
though. There's a directory for production using config_prod.json
, and there is also a directory for testing, so let's explore that. Looking at the test_site_interactively.py
file, we can see that this test build is available at test.superpass.htb
, which is running on port 5555.
Looking at test_site_interactively.py
again, we can see that Chrome devtools is running on port 41829.
Note: I wasn't able to see the debugger on Firefox, so I had to use Chrome instead.
This gives us a devtoolsFrontendUrl
, which we can go to:
More MySQL credentials, let's see what this account holds.
superpasstester
is pretty much the same as superpassuser
, so let's get to the good stuff:
More SSH credentials! Hopefully edwards
has more permissions than corum
.
Our version of sudo
is before 1.9.12p2, which means sudoedit
is vulnerable to CVE-2023-22809. To use this CVE, we need a file that dev_admin
can write to and root
can run.
A vulnerable file is /app/venv/bin/activate
. Using the command:
After putting this reverse shell in, we can listen and wait:
Eventually, root
will activate the virtual environment for the app and, as a result, give us a reverse shell as root
. Checking /root
, we can find what we're looking for, root.txt
.
And that's the box!
Following a couple guides on cracking this PIN (Thank you and !), the PIN is generated through the values:
After cracking the PIN for Werkzeug and gaining access to the Python interpreter, a reverse shell can be created in the debug interpreter. The reverse shell I used is from .
Now we have access as to the Chrome debugger. Looking at the documentation for , we can find a useful endpoint: PUT /json/new?{url}
. Fortunately, modern web browsers allow us to open files using the protocol file
. So putting this all together, the previously inaccessible file config_test.txt
can be obtained by going to the URL http://localhost:41829/json/new?file:///app/config_test.json
.
We have access to sudoedit
. Looking up "sudoedit cve", we can find , which is a script for a CVE capable of privilege escalation. Looking at our sudo
version:
We can write to /app/venv/bin/activate
. Now we can put a reverse shell in here, specifically a bash shell from the .