THREAT-M365-PasswordSpray

Microsoft 365 Password Spray Attack Detection

Password spraying against Microsoft 365 / Entra ID remains one of the most effective initial access techniques against SMBs. Attackers use lists of valid corporate usernames (harvested from LinkedIn, HaveIBeenPwned, or prior breaches) and try a small number of common passwords (season+year, company name variations, Welcome1!) across all accounts — staying below per-account lockout thresholds. Microsoft documented Midnight Blizzard (Cozy Bear) using this to gain initial access to Microsoft corporate accounts in 2024. Storm-1152 (bulk account creation / credential fraud group) services this on behalf of other threat actors. NCSC UK has repeatedly warned about Iranian and Russian threat actors using password spraying against UK SMBs in critical sectors. The attack targets legacy authentication protocols (IMAP, SMTP, MAPI) and BasicAuth endpoints that bypass MFA — even if the organisation has MFA deployed for interactive sign-ins.

Microsoft Sentinel / Defender
kusto
// THREAT: Microsoft 365 Password Spray Detection
// Detects systematic password spraying against M365 / Entra ID
// using sign-in failure patterns across multiple users from shared infrastructure

// Alert 1: Single IP targeting many accounts (spray pattern)
let SprayThreshold_UserCount = 10;
let SprayThreshold_FailureCount = 20;
let SprayWindow = 30min;
AADSignInLogs
| where TimeGenerated > ago(24h)
| where Status.errorCode in (50126, 50053, 50055, 50056, 50064, 50074, 50076, 50079)
    // 50126=invalid credentials, 50053=locked, 50055=expired password, 50056=no password
    // 50064=credential validation failure, 50074=strong auth required
| summarize
    FailureCount=count(),
    UniqueUsers=dcount(UserPrincipalName),
    TargetUsers=make_set(UserPrincipalName),
    ErrorCodes=make_set(Status.errorCode),
    Apps=make_set(AppDisplayName)
  by IPAddress, bin(TimeGenerated, SprayWindow)
| where UniqueUsers >= SprayThreshold_UserCount and FailureCount >= SprayThreshold_FailureCount
| extend ThreatType = "PasswordSpray_MultipleUsers_SingleIP"
| extend Severity = "High";
// Alert 2: Successful sign-in following spray activity from same IP
let SprayIPs = AADSignInLogs
| where TimeGenerated > ago(24h)
| where Status.errorCode in (50126, 50053, 50055)
| summarize Failures=count(), Users=dcount(UserPrincipalName)
  by IPAddress, bin(TimeGenerated, 30m)
| where Failures >= 20 and Users >= 10
| distinct IPAddress;
AADSignInLogs
| where TimeGenerated > ago(24h)
| where Status.errorCode == 0
| where IPAddress in (SprayIPs)
| project TimeGenerated, UserPrincipalName, IPAddress, Location,
    AppDisplayName, AuthenticationRequirement, Status
| extend ThreatType = "PasswordSpray_SuccessfulBreachAfterSpray"
| extend Severity = "Critical"
high severity high confidence

Data Sources

Azure AD Sign-In Logs (AADSignInLogs) Microsoft 365 Defender Sign-In Activity Azure Sentinel UEBA

Required Tables

AADSignInLogs

False Positives

  • Misconfigured applications using a service account that have incorrect credentials and fail authentication across multiple tenants
  • Corporate password rotation events where many users have passwords expired simultaneously and attempt sign-in with old credentials
  • Load-balanced authentication infrastructure where many employees share an outbound NAT IP (adjust thresholds upward for organisations with NAT)
  • Vulnerability scanner credentials testing from a shared assessment IP during authorised penetration tests

Unlock Pro Content

Get the full detection package for THREAT-M365-PasswordSpray including response playbook, investigation guide, and atomic red team tests.

Response PlaybookInvestigation GuideHunting QueriesAtomic Red Team TestsTuning Guidance

Related Detections