Detect Password Spray Attacks in Microsoft Entra ID Using KQL
Password spray attacks remain one of the most persistent identity threats targeting enterprise tenants. Unlike standard brute-force attacks that bombard a single account with hundreds of passwords, password spraying tests a single common password across hundreds of different user accounts to circumvent standard account lockout policies.
In this guide, we break down how to craft an enterprise-grade Kusto Query Language (KQL) detection rule in Microsoft Sentinel utilizing the SigninLogs table.
Prerequisites & Log Ingestion
To execute this detection, ensure your Microsoft Sentinel workspace is actively collecting:
- Microsoft Entra ID (Azure AD) SigninLogs (Interactive user sign-ins)
- Optional: AADNonInteractiveUserSignInLogs for service and automation auditing
Detection KQL Query
// Detect Distributed Password Spraying across Multiple Accounts from a Single IP or Subnet
let timeRange = 1h;
let failureThreshold = 10;
let accountThreshold = 8;
SigninLogs
| where TimeGenerated >= ago(timeRange)
// Filter for Bad Password or Account Disabled error codes
| where ResultType in (50126, 50053) // 50126: Invalid password, 50053: Account locked/disabled
| summarize
FailedAccounts = make_set(UserPrincipalName, 50),
TotalFailures = count(),
UniqueAccountCount = dcount(UserPrincipalName),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by IPAddress, Location, AppDisplayName
| where UniqueAccountCount >= accountThreshold and TotalFailures >= failureThreshold
| extend AttackDurationMinutes = datetime_diff('minute', LastSeen, FirstSeen)
| project IPAddress, Location, AppDisplayName, UniqueAccountCount, TotalFailures, AttackDurationMinutes, FailedAccounts
| order by UniqueAccountCount desc
Query Logic Breakdown
- Error Code Filtering (
ResultType): We specifically isolateAADSTS50126(Invalid username or password) andAADSTS50053(Account locked). - Aggregation by Origin IP: Using
summarize ... by IPAddress, we isolate attacking hosts regardless of which usernames they probe. - Distinct Account Threshold (
dcount): A genuine user forgetting their password hits 1 account multiple times. An attacker hits >= 8 distinct accounts from one source. - Duration Calculation: Calculates whether the attack was an automated burst or a slow-and-low campaign.
Tuning False Positives
- Corporate Egress IPs: If your organization routes office traffic through shared proxy egress points, filter out known NAT IPs using an allowed CIDR watch list.
- Misconfigured Internal Apps: Legacy internal apps attempting service binds with expired service account passwords can mimic spray behavior. Inspect
AppDisplayNamebefore triggering containment playbooks.
MITRE ATT&CK Mapping
- Tactic: Credential Access (TA0006)
- Technique: Brute Force: Password Spraying (T1110.003)
Responses (0)
Join the technical conversation or share implementation thoughts.
What are your thoughts?
Sign in to join the technical discussion or share feedback.
There are currently no responses for this story. Be the first to respond.