T1110.003

Password Spraying

Adversaries may use a single or small list of commonly used passwords against many different accounts to attempt to acquire valid account credentials. Password spraying uses one password (e.g. 'Password01'), or a small list of commonly used passwords, that may match the complexity policy of the domain. Logins are attempted with that password against many different accounts on a network to avoid account lockouts that would normally occur when brute forcing a single account with many passwords. This technique is deliberately throttled to avoid triggering per-account lockout thresholds — the defining characteristic that distinguishes spraying from brute force (T1110.001). Adversaries including APT28, APT29, HAFNIUM, Storm-0940, Chimera, and APT33 have used this technique at scale against OWA, Microsoft 365, VPN portals, SSH, RDP, SMB, and LDAP. Slow-spray variants (approximately 4 attempts per account per hour) are specifically designed to evade detection thresholds, and Kerberos-based spraying is used to avoid generating the high-visibility Event ID 4625 typically alerted on.

Microsoft Sentinel / Defender
kusto
let SprayAccountThreshold = 10;
let BruteForceMaxPerAccount = 5;
let LookbackWindow = 24h;
let SprayWindow = 30m;
// Azure AD / Entra ID password spray detection via SigninLogs
let AzureADSpray = SigninLogs
    | where TimeGenerated > ago(LookbackWindow)
    | where ResultType != "0"
    | where ResultType in (
        "50126",  // Invalid username or password
        "50055",  // Expired password
        "50056",  // Null password in store
        "50064",  // Credentials expired
        "50053",  // Account locked out
        "50057",  // User account disabled
        "50074",  // Strong auth required but not provided
        "50059",  // Tenant not found
        "50076"   // MFA required but not provided
    )
    | where isnotempty(IPAddress) and IPAddress !in ("127.0.0.1", "::1")
    | summarize
        FailureCount = count(),
        DistinctAccounts = dcount(UserPrincipalName),
        TargetAccounts = make_set(UserPrincipalName, 30),
        FirstSeen = min(TimeGenerated),
        LastSeen = max(TimeGenerated),
        TargetApps = make_set(AppDisplayName, 10),
        UserAgents = make_set(UserAgent, 5)
      by IPAddress, bin(TimeGenerated, SprayWindow)
    | where DistinctAccounts >= SprayAccountThreshold
    | extend AvgFailuresPerAccount = round(toreal(FailureCount) / toreal(DistinctAccounts), 2)
    | where AvgFailuresPerAccount <= BruteForceMaxPerAccount
    | extend DetectionSource = "AzureAD_SigninLogs";
// On-premises AD password spray detection via Security Event 4625
let OnPremADSpray = SecurityEvent
    | where TimeGenerated > ago(LookbackWindow)
    | where EventID == 4625
    | where LogonType in (3, 10)  // Network, RemoteInteractive
    | where IpAddress !in ("-", "", "::1", "127.0.0.1")
    | summarize
        FailureCount = count(),
        DistinctAccounts = dcount(TargetUserName),
        TargetAccounts = make_set(TargetUserName, 30),
        FirstSeen = min(TimeGenerated),
        LastSeen = max(TimeGenerated),
        TargetApps = make_set(WorkstationName, 10),
        UserAgents = dynamic([])
      by IpAddress, bin(TimeGenerated, SprayWindow)
    | where DistinctAccounts >= SprayAccountThreshold
    | extend AvgFailuresPerAccount = round(toreal(FailureCount) / toreal(DistinctAccounts), 2)
    | where AvgFailuresPerAccount <= BruteForceMaxPerAccount
    | extend DetectionSource = "OnPremAD_SecurityEvent"
    | project-rename IPAddress = IpAddress;
union AzureADSpray, OnPremADSpray
| sort by DistinctAccounts desc
high severity high confidence

Data Sources

Authentication: Authentication Logs Logon Session: Logon Session Creation Azure Active Directory Sign-in Logs Windows Security Event Log

Required Tables

SigninLogs SecurityEvent

False Positives

  • Misconfigured service accounts using stale credentials that authenticate against multiple systems simultaneously during a configuration failure event
  • Authorized penetration testing or red team exercises targeting multiple accounts with common passwords from a designated test IP
  • ADFS or federated identity proxy services whose single IP proxies authentication for all federated users — these IPs will appear as the source for all federation failures
  • Vulnerability scanners (Tenable, Qualys, Rapid7) performing authenticated scans with cycling credentials across multiple hosts
  • Password synchronization failures during Active Directory migrations or forest trust establishment generating bulk 4625 events from the migration service account IP

Unlock Pro Content

Get the full detection package for T1110.003 including response playbook, investigation guide, and atomic red team tests.

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections