La máquina Eighteen es una máquina fácil de HTB.
NO PUDE CONTINUAR LA ESCALADA A ROOT POR SER MÁQUINA YA RETIRADA Y VIP.
SÓLO PUDE LLEGAR HASTA LA FLAG USER.TXT
Si es tu primera máquina en Hack The Box y no sabes cómo conectarte a la máquina del laboratorio, te recomiendo que visites este post donde te cuento cómo introducirte en esta plataforma.
Si quieres empezar con Hack The Box te dejo el enlace para que puedas crearte una cuenta y comenzar a practicar con sus laboratorios y Academia.
A continuación, para conectarte a la máquina, tendrás que establecer la conexión con la máquina víctima de HTB conectándote a la VPN desde la carpeta donde la tengas descargada, y desde ahí ejecutarás el comando «sudo openvpn NOMBRE_VPN.ovpn».
Estructura del contenido
NUMERACIÓN -> ESCANEO DE PUERTOS
Comenzamos con la enumeración de puertos y conocimiento de versiones y servicios que corren sobre los mismos.
Antes, a mi me gusta asegurarme que efectivamente la máquina víctima está activa y ante qué sistema operativo (OS) nos enfrentamos. Para ello, ejecutamos los siguientes comandos:
nmap -sn 10.10.11.95
ping -c 1 10.10.11.95 -R

Sabemos por tanto que la máquina víctima está activa y que su distribución es Windows.
¿Por qué? porque el TTL (Time To Live) nos dice que es de 127 el cual está asociado con máquinas Windows. En este caso como estamos en un laboratorio de HTB, se usa un nodo intermediario de conexión que lo reduce a 127 (en normal son 128).

Ahora que sabemos que la máquina víctima está activa, procedemos escanear la red lanzando un nmap para detectar qué puertos están abiertos. En mi caso uso siempre este comando (en este post te cuento lo que hace cada comando):
nmap -p- --open -sS --min-rate 5000 -vvv -n -Pn 10.10.11.95 -oG escaneo

Detectamos los puertos web http 80, 1433 y 5985 por TCP.
- 80 http web
- 1433 Microsoft SQL Server (está corriendo una base de datos SQL server)
- 5985 WinRM funciona sobre el protocolo wsman (equivaldría al ssh de linux pero en windows)
Estos puertos se encontraron haciendo un escaneo por el protocolo TCP (el más habitual en laboratorios), pero vamos a probar a ver si encontramos alguno abierto por UDP mediante el comando:
nmap -sU --top-ports 200 --min-rate 5000 -vvv -Pn 10.10.11.95
y encontramos un listado muy largo de puertos udp abiertos pero sin respuesta, salvo el puerto 53/udp service = domain . Por ahora lo dejamos en stand-by por si tuviéramos que retomarlo para hacer la intrusión por él.

Continuo por la parte TCP y en este caso lanzo el siguiente comando en nmap para ver servicios y versiones que corren para esos tres puertos abiertos:
nmap -sCV -p80,1433,5985 10.10.11.95

Vemos que el 80 no sigue una redirección al dominio http://eighteen.htb/ por lo que tendremos que asociar la IP a ese dominio para aplicar resolución DNS (lo haremos a través del fichero /etc/hosts), y los otros puertos nos devuelven un estado filtered el 1433 donde nmap no sabe si en realidad está abierto o no porque algo puede estar filtrando la conexión como por ejemplo un firewall (el de la bbdd de Microsoft que solo puede estar abierto en interno y no externamente) y open el 5985 (WinRM Windows Remote Management, que permite conexión remota por PowerShell -como un SSH de Windows).
Empezamos con la modificación del /etc/hosts para ver qué información podemos sacar a través de la aplicación web:

si volvemos a aplicar el comando para conocer los servicios anteriores, nos saca más información:

Si empezamos a analizar el puerto web 80 vemos de primeras los enlaces de login y registro así como de features. Vemos con whatweb que el servidor es un IIS 10.0.


Al buscar esa versión de Windows en searchsploit no nos aparece nada…y mediante los script de nmap para encontrar vulnerabilidad sobre esos puertos, tampoco:

Interactuando con la aplicación web, al crearme una cuenta y entrar en el panel de usuario, se muestra una opción en el menú que pone Admin … sin embargo si intentamos acceder a la ruta /admin , nos da este error…

La app muestra un enlace Admin aunque nuestro usuario no debería verlo.
Analizando el resto de la aplicación, podemos ver que nos deja incluir ciertos campos, por lo que quizás la entrada sea a través de un SQLi.
Si analizamos mediante fuzzing web si existen directorios abiertos, nos reporta lo que ya hemos visto a nivel registro del usuario, es decir, admin/dashboard/logout:
ffuf -u "http://eighteen.htb/FUZZ" -w /usr/share/wordlists/dirb/common.txt

A partir de aquí vamos a intentar ver si se puede explotar la vulnerabilidad JWT:
La app usa MSSQL (puerto 1433). Lo normal es:
- Te registras → se guarda un usuario en la base de datos
- Tu cookie solo guarda el ID de sesión
- El servidor mira la sesión en la base de datos
- Y ahí encuentra tu campo: is_admin = 0
- Por eso no deja entrar a /admin.
La escalada a admin NO se hace manipulando la cookie sino manipulando la base de datos.
Tenemos que entrar a MSSQL usando credenciales desde la propia web.
CURIOSO: me caducó la sesión que había creado antes y tuve que crearme un nuevo usuario en el registro. Sin embargo, en lugar de crear un nuevo usuario, creé el mismo que había registrado antes, y al ser el mismo, la aplicación me dio un error con este aviso:

De este error lo más importante es que:
Cannot insert duplicate key in object ‘dbo.users’.
The duplicate key value is (test@test.com).
Eso quiere decir que:
- La web guardó mi usuario en una base de datos SQL Server
- El usuario sigue existiendo, aunque mi sesión haya caducado
- La aplicación está devolviendo errores SQL reales, sin ocultarlos
Esto significa que la aplicación NO está protegiendo bien las consultas SQL y nos abre la puerta a una SQL Injection ya que la app está construyendo consultas SQL directamente con los datos del usuario, sin sanearlos.
Analizando de nuevo realizo un fuzzing más profundo para intentar encontrar extensiones de ficheros que IIS suele servir como .config, .json, .aspx, .ashx, .axd, .txt, .bak, .old, .zip y encuentro:

¿Qué significa esto?
- El servidor responde 200 OK a cualquier archivo con extensión .config, .json, .bak, .zip, etc.
- El servidor tiene un handler genérico de IIS para archivos estáticos.
- El directorio raíz contiene archivos internos pero no están en rutas directas, sino en rutas con nombre específico.
Sin embargo el fuzzing que hice fue solo de directorios, NO de archivos con nombre específico por eso no aparecieron, si no con un /.
Dentro del dashboard de la app como el usuario test, lo que hago es registrar los campos de Add Expense y capturar el envío al servidor a través de BurpSuite y manipular la respuesta.

Capturada la petición por POST y enviada al Repeater, vemos que se está enviando esta información:

El puerto 1433 por otro lado corresponde a Microsoft SQL Server. Usando las credenciales que nos da el laboratorio de HTB -> kevin:iNa2we6haRj2gaw!, intentamos conectarnos a la base de datos.
Para ello usamos la herramienta Impacket, que ofrece el script mssqlclient.py para interactuar con MSSQL usando NTLM:
impacket-mssqlclient kevin:'iNa2we6haRj2gaw!'@10.10.11.95
Esta conexión fue exitosa y nos dio una consola interactiva de SQL. (Nota: MSSQL requiere por defecto conexiones cifradas TLS; mssqlclient lo maneja automáticamente al conectarse). Ahora tenemos acceso como el usuario de BD kevin.

Enumerando privilegios en SQL: Dentro de SQL, lo primero es ver qué puede hacer el usuario kevin. Usamos el comando interno de Impacket enum_impersonate para listar permisos de impersonación. El resultado mostró: appdev

Esto significa que la cuenta SQL de Kevin tiene privilegio para impersonar al login appdev. En SQL Server, impersonate es potente: permite asumir el rol de otro usuario de base de datos, potencialmente con más privilegios.
Procedemos a impersonar al usuario appdev ejecutando la consulta:

Ahora nuestro contexto en SQL es como appdev. Exploramos qué hay disponible:
- Bases de datos: Listamos las bases de datos en el servidor (por ejemplo, con
SELECT name FROM master..sysdatabases;). Identificamos una BD interesante llamada financial_planner, que coincide con la temática de la web. - Usar la base de datos financial_planner: Cambiamos a esta base de datos:

Al consultar sus tablas (SELECT table_name FROM information_schema.tables;), encontramos varias, entre ellas una tabla users . Esto sugiere que la aplicación almacena credenciales de usuarios allí.

Schema de la tabla users: Verificamos las columnas de users:

Confirmamos campos relevantes: username, email, password_hash, is_admin, etc.
Volcado de credenciales de usuarios: Ejecutamos una query para extraer los datos sensibles:
SELECT username, email, password_hash FROM financial_planner.dbo.users;

Vemos que las contraseñas están almacenadas con un algoritmo PBKDF2-HMAC-SHA256 con 600,000 iteraciones. Es un hashing robusto, pero si la contraseña subyacente es débil, podemos intentar romperlo con fuerza bruta.
pbkdf2:sha256:600000$AMtzteQIG7yAbZIa$0673ad90a0b4afb19d662336f0fce3a9edd0b7b19193717be28ce4d66c887133
El campo is_admin probablemente marca a admin como administrador de la app (no extraído aquí, pero se intuye).
Hasta ahora, hemos aprovechado MSSQL para extraer credenciales cifradas de la aplicación web. Nuestro siguiente paso será descifrar estos hashes para obtener contraseñas en texto claro.
Cracking de la contraseña PBKDF2-SHA256
Los hashes obtenidos tienen formato de la librería Werkzeug (común en aplicaciones Flask/Django), por ejemplo:
pbkdf2:sha256:600000$[SALT]$[HASH]
Donde salt es una cadena aleatoria (en este caso AMtzteQIG7yAbZIa) y el hash es el resultado de aplicar PBKDF2-SHA256 600k iteraciones. Ni Hashcat ni John tienen un modo preconfigurado sencillo para este formato específico, así que creamos un script en Python para probar contraseñas contra el hash usando la misma función PBKDF2.
Después de tardar un rato en ejecutar el python creado, nos devuelve la contraseña del admin:

Este password es débil (una frase común con un número). Ahora tenemos credenciales potencialmente útiles. En particular, el usuario admin parece ser propio de la aplicación web, pero sospechamos que esta misma contraseña podría reutilizarse en el sistema o en Active Directory por algún usuario.
Recordatorio: Siempre que obtengas credenciales de una aplicación, prueba si funcionan en otros servicios. Muchas veces, empleados reutilizan contraseñas entre cuentas (por ejemplo, el admin de la app podría haber usado la misma para su cuenta de dominio corporativo). Dado que la máquina es un DC con varios usuarios, intentaremos identificar si iloveyou1 coincide con la contraseña de alguno de ellos.
Enumeración de usuarios del dominio a través de MSSQL
El flag --rid-brute realiza un RID bruteforcing, enumerando usuarios del dominio. En nuestro caso, esto devolvió una lista de usuarios de AD como jamie.dunn, jane.smith, alice.jones, adam.scott, bob.brown, etc. Esto confirma:
- La máquina es efectivamente el Controlador de Dominio (DC01 del dominio EIGHTEEN).
- Kevin era una cuenta de dominio válida (posiblemente un empleado común) con la que pudimos consultar AD.
nxc mssql 10.10.11.95 -u kevin -p 'iNa2we6haRj2gaw!' --rid-brute --local-auth

Creamos con nano la lista de esos usuarios para probar la contraseña descubierta “iloveyou1” contra cada usuario enumerado. Esto para detectar si algún usuario de dominio reutilizó esa contraseña.
Para ello usamos CrackMapExec para hacer un password spraying contra WinRM (puerto 5985):
crackmapexec winrm 10.10.11.95 -u users.txt -p 'iloveyou1'

adam.scott : iloveyou1 autenticó correctamente por WinRM confirmando que tenemos ejecución remota con esas credenciales. En otras palabras, adam.scott es un usuario de dominio que usaba “iloveyou1” – la misma contraseña débil del admin de la app. Esta reutilización nos otorgó acceso.
Nota: Este paso ejemplifica una debilidad de reutilización de contraseñas entre servicios. Aquí el administrador de la aplicación (o un empleado) usó una contraseña débil tanto en la app web (cuyos datos filtramos) como en su cuenta de dominio. Siempre que consigas credenciales en un servicio, pruébalas en otros (RDP, SSH, SMB, WinRM, etc.).
Obtención de la flag de usuario (shell como adam.scott)
Con las credenciales de adam.scott, procedemos a obtener una shell en la máquina víctima. El servicio WinRM abierto nos permite usar Evil-WinRM, una herramienta para obtener una sesión PowerShell interactiva:
evil-winrm -i 10.10.11.95 -u adam.scott -p 'iloveyou1'

Ya estamos dentro de la máquina Windows con privilegios de ese usuario. Miramos carpetas internas hasta encontrar algún archivo que nos de la flag de user, y vemos que en el escritorio tenemos la flag user.txt. En la shell de PowerShell ejecutamos:

Escalada de privilegios a SYSTEM (Administrador del dominio)
Ahora, el reto es elevarnos de adam.scott (usuario relativamente sin privilegios altos) a Administrador del dominio (o SYSTEM en la máquina DC). Dado que estamos en un entorno Active Directory moderno (Windows Server 2025), debemos buscar vulnerabilidades o misconfiguraciones de AD.
Empezamos con enumeración interna:
- Privilegios locales: Ejecutamos
whoami /privywhoami /groupspara ver si adam.scott tiene privilegios especiales a nivel del host. No observamos nada como SeBackupPrivilege habilitado (técnicas comunes de escalada en Windows), ni pertenecía al grupo local Administrators. Así que no parece tener privilegios elevados locales directos.

- Roles en Active Directory: Inspeccionamos si adam.scott pertenece a grupos de AD con privilegios. Por el nombre, parece un usuario estándar. Sin embargo, notamos que en la enumeración previa adam.scott puede estar en la OU «Staff» (por su nombre común). En muchos entornos, los usuarios pueden tener permisos delegados en ciertas OU del dominio. Una práctica común (aunque insegura) es permitir que usuarios no admins creen ciertos objetos en el AD (por ejemplo, cuentas de equipo) dentro de una OU específica.
OU (Unidad Organizativa), es un contenedor lógico dentro del dominio que se utiliza para organizar, administrar y aplicar políticas a usuarios, equipos y otros objetos de forma estructurada.
- Posible vía de escalada – BadSuccessor (dMSA): algunas investigaciones de 2025 revelaron un método llamado BadSuccessor que abusa de las Delegated Managed Service Accounts (dMSA) para escalar privilegios en dominios Windows Server 2025. Los requisitos son justamente los que sospechamos:
- Un DC Windows Server 2025 (nuestro caso).
- Permiso para crear objetos en alguna OU (por ejemplo, crear cuentas de servicio/computadora en la OU Staff).
- Capacidad de ejecutar herramientas en el contexto de un equipo unido al dominio (ya la tenemos con Evil-WinRM).
¿Qué es BadSuccessor? Es una técnica que se aprovecha de cómo AD maneja las dMSA al “migrar” identidades de cuentas legacy a cuentas administradas. En resumen, si podemos crear una dMSA (un tipo de cuenta de servicio delegada) y establecer ciertos atributos, podemos hacer que el KDC (Key Distribution Center) piense que nuestra nueva cuenta sucede (reemplaza) a una cuenta privilegiada existente (por ej. Administrator). Al hacerlo, hereda todos los SIDs (pertenencias a grupos) de la víctima, incluyendo ser Domain Admin.
Los pasos serían:
- Crear una cuenta dMSA controlada: usando PowerShell o LDAP, creamos un nuevo objeto de tipo
msDS-DelegatedManagedServiceAccounten una OU donde adam.scott tenga permiso de creación (digamos OU=Staff). Ejemplo PowerShell:New-ADServiceAccount -Name EvilAccount -DNSHostName dc01.eighteen.htb -Path "OU=Staff,DC=eighteen,DC=htb"(asegurándonos de especificar tipo dMSA). Al ser el creador, adam.scott tiene control total sobre esta cuenta nueva y sus atributos.
