Agile — HackTheBox

7 min readAug 5


Agile is a medium machine from HackTheBox. It involves extracting Werkzeug debug console pin with the help of Directory traversal vulnerability, getting credentials from chrome remote debugging window, and exploiting CVE in sudoedit to modify the file used in a cron running as root.


22/tcp open ssh syn-ack OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 f4bcee21d71f1aa26572212d5ba6f700 (ECDSA)
| ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBCeVL2Hl8/LXWurlu46JyqOyvUHtAwTrz1EYdY5dXVi9BfpPwsPTf+zzflV+CGdflQRNFKPDS8RJuiXQa40xs9o=
| 256 65c1480d88cbb975a02ca5e6377e5106 (ED25519)
|_ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIEcaZPDjlx21ppN0y2dNT1Jb8aPZwfvugIeN6wdUH1cK
80/tcp open http syn-ack nginx 1.18.0 (Ubuntu)
|_http-server-header: nginx/1.18.0 (Ubuntu)
| http-methods:
|_ Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://superpass.htb
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Port 80 (HTTP)

Opening the website redirects to http://superpass.htb/ . Add it in hosts file and we get the following page. Its password manager website.

After registering a user and logging, we get access to vault where we can add credentials and export them.

Directory Traversal

Exporting the vault, it gets downloaded in a CSV format. In the proxy, looking at the request to the download endpoint, there’s a parameter in which the name of file in specified.

If we change the filename, we can see that there’s a file not found error. It also reveals the path that files are stored in /tmp directory. Since, this shows error means that debug mode is enabled.

Also, by traversing the directory back, we can read files from server.

Error produced by app reveals the application path. Now, we can download the source code of the application.


Looking in the , we can see that debug is enabled. Since, this a flask app, we can try to access the debug console. We can do so by clicking the little this little command line icon.

But, it is PIN protected

Werkzeug Debug Console PIN Exploit

Since, we have file read vulnerability, we can generate this PIN by leaking all the necessary info from the server. The following resource provides the steps to generate the PIN.

To generate the console PIN, we need the following info, which we can easily get via the file read vulnerability.

  • Username of the user running the Flask application.
  • Module name of the Flask application.
  • Application name of the Flask application.
  • Path to the Flask file.
  • MAC address of the server
  • Machine ID from /etc/machine-id. On newer systems, combine the ID from /etc/machine-id with the last part of the value from /proc/<pid>/cgroup, split on the / character.

We can get the username by reading the environment variables using file read vulnerability.

The module name will be and the application name can found in the source code.

The path to Flask can be found in the error page.

For the mac address first we need to find device id by reading the /proc/net/arp file on the server.

After that, we can get MAC address by reading the/sys/class/net/<device-id>/address file.

Also need to convert the MAC address to decimal. It can done by following

python3 -c 'print(int("00:50:56:b9:50:10".replace(":",""), 16))'

Next, we need Machine ID, which can be extracted from /etc/machine-id and combine it with the output of /proc/self/cgroup after the last slash (/)


After gathering all the required info, our script to generate the PIN will look like following.

import hashlib
from itertools import chain
probably_public_bits = [
'www-data',# username
'',# mod name
'wsgi_app',# app name
'/app/venv/lib/python3.10/site-packages/flask/' # flask

private_bits = [
'345052368912',# MAC Address
'ed5b159560f54721827644bc9b220d00superpass.service'# machine id

#h = hashlib.md5() # Changed in
h = hashlib.sha1()
for bit in chain(probably_public_bits, private_bits):
if not bit:
if isinstance(bit, str):
bit = bit.encode('utf-8')

cookie_name = '__wzd' + h.hexdigest()[:20]

num = None
if num is None:
num = ('%09d' % int(h.hexdigest(), 16))[:9]

rv =None
if rv is None:
for group_size in 5, 4, 3:
if len(num) % group_size == 0:
rv = '-'.join(num[x:x + group_size].rjust(group_size, '0')
for x in range(0, len(num), group_size))
rv = num


Running the script, we get the PIN.

After providing the PIN on debug console, we get access to python console.

Now, we can easily get a reverse shell.

Reading the config_prod.json file in the /app directory, we get the credentials for mysql db.

The passwords table in the superpass database contains the plain-text credentials.

Using the credentials in the last row, we can login via SSH as corum user.

Privilege Escalation (corum -> edwards)

Checking users, there are three more users on the server.

Running linpeas for enumeration, it would appear that there is a --remote-debugging-port flag being used in the chrome browser. Essentially, it means that this port is open and running Chrome.

With credentials for SSH, we can port forward this and perhaps access it from our machine to see what the user is doing.

Opening the url in our browser the page is empty.

Searching on google following resource comes to help.

Following the above resource, open the chrome://inspect/#devices in the chrome browser.

In the remote target section, we can see the superpass. Clicking on the inspect, following window opens which contains credentials of edward user.

Using the credentials, we can login as edward user.

Privilege Escalation (edwards -> root)

Now checking sudo permissions of edward user, it appears that edward can run some commands as devadmin user.

However, these leads to dead end. Searching on google, it appears that there’s a recent CVE-2023–22809 in the sudoedit.

The version on the server is vulnerable to this CVE.

Using this CVE, i tried to edit sudoers file but it did not work.

Next, running PSPY, it appears that a cron is running as root to activate the virtual environment.

Checking the permissions on it, the dev_admin group has write permissions on it and also it is a bash script.

So, we can edit using the above CVE and place a reverse shell in it.

export EDITOR='vim -- /app/venv/bin/activate'
sudo -u dev_admin sudoedit /app/config_test.json

When the cron is executed, we get a reverse shell as root.