Password spraying

Password spraying

TL;DR: Try one (or a handful of) weak password(s) against many accounts so per-account lockout never trips. Devastating against AD, M365/Entra ID, VPN portals, OWA, Citrix, and any SSO front-end that does not enforce conditional access.

What it is

Password spraying inverts brute-force: instead of N passwords against one account (locks the account), it sends one password against N accounts (stays under per-account thresholds). The attacker rides predictable seasonal or organisational passwords (Winter2026!, <Company>123, Welcome1) across a large user list. Because per-account failure counts reset, and many auth back-ends lack per-source rate limiting, the spray can iterate weekly through lockout windows without ever locking a single user.

Preconditions / where it applies

  • A valid user list — pulled from LinkedIn scraping, osint-recon, domain enumeration, GAL via smtp-enum or ldap-enum, or NULL-session smb-enum.
  • An auth surface that returns differentiable success/fail responses: AD over Kerberos AS-REQ, NTLM via SMB/LDAP, M365 login.microsoftonline.com, Citrix/NetScaler, Fortinet/Pulse VPNs, OWA /owa/auth.owa, ADFS, Okta.
  • Knowledge of lockout policy (net accounts /domain) to time waves below threshold.

Technique

Build the user list first. Format-conversion matters — john.doe, jdoe, doejo, john.doe@corp.local are different surfaces. kerbrute userenum validates accounts against AD without generating lockouts (AS-REQ for nonexistent user returns a different error code than for valid user):

1
kerbrute userenum -d corp.local --dc dc01.corp.local users.txt

Spray with one wave per lockout window. Kerberos pre-auth spray is the gold standard internally — does not log as a failed logon on member servers, only on the DC:

1
kerbrute passwordspray -d corp.local --dc dc01.corp.local users.txt 'Winter2026!'

External spray against M365 / Entra ID — use a low-volume, distributed approach. MSOLSpray and successors hit login.microsoftonline.com and parse the AADSTS error codes:

1
Invoke-MSOLSpray -UserList .\users.txt -Password 'Spring2026!' -Force

ADFS / OWA / Exchange — o365spray, Spray365, or custom curl loops against /adfs/ls/?wa=wsignin1.0. For SMB/LDAP spray inside the network use nxc (NetExec):

1
2
nxc smb dc01.corp.local -u users.txt -p 'Winter2026!' --continue-on-success
nxc ldap dc01.corp.local -u users.txt -p 'Winter2026!' --continue-on-success

Rules of engagement: one password per 30–60 minute window, pace below 5 attempts per account per lockout interval, monitor success without locking. Stop on first hit, verify the credential out-of-band (don’t burn it on more sprays). Watch for honeypot accounts (admin, administrator, accounts with SPN like SQLSvc planted as bait).

Password candidates that consistently work: <Season><Year>!, <Season><Year>, <Company>!, <Company>123, Welcome1, Password1, Changeme!, plus anything leaked in recent breach combos for the org’s email domain.

Detection and defence

  • Detection signal: many distinct accounts, single source, identical password timing — 4625 (NTLM) and 4768/4771 (Kerberos pre-auth fail) events with the same workstation field. SIEM rule: >N distinct usernames per source per hour.
  • Defences: MFA on every external surface (especially legacy auth), conditional access blocking legacy protocols, Smart Lockout in Entra ID, Azure AD Password Protection banned-word lists, source-IP rate limiting at the edge, anomaly detection on geographic auth jumps.
  • For internal AD: increase password length (15+), deploy Azure AD Password Protection on-prem, alert on kerbrute/nxc user-agents, and disable NTLM where possible to remove the easiest spray surface.

References