Password Spraying & Brute-Force Telemetry Analysis
Despite the widespread promotion of passwordless authentication, passwords remain the primary authentication factor for the vast majority of Microsoft 365 enterprise tenants. While traditional brute-force attacks (rapidly testing thousands of passwords against a single target account) are rendered obsolete by Microsoft Entra ID’s Smart Lockout mechanisms, Password Spraying remains an extraordinarily effective initial access vector.
In a password spray attack, the threat actor reverses the brute-force paradigm: rather than trying many passwords against one user, they test a single common password (e.g., Autumn2026!, Company123#) across thousands of distinct tenant identities over an extended period. By distributing requests across rotating residential proxy networks and targeting legacy authentication protocols, adversaries stay beneath rate-limiting thresholds and evade automated perimeter blocks.
This guide provides an exhaustive architectural and forensic dissection of password spraying in Entra ID, analyzes pre-attack user enumeration techniques, details critical sign-in error codes, and delivers production-grade KQL detection queries.
1. Attack Mechanics: Brute Force vs Distributed Password Spraying
Section titled “1. Attack Mechanics: Brute Force vs Distributed Password Spraying”graph TD subgraph "Vertical Brute Force (Defeated by Smart Lockout)" ATT1[Attacker] -->|1,000 Passwords / 1 User| USER_A[alice@target.com] USER_A --> LOCKOUT[Smart Lockout Triggered<br/>ResultType: 50053<br/>IP Banned / Account Frozen] end
subgraph "Horizontal Password Spray (Stealthy)" ATT2[Attacker Botnet / Residential Proxies] -->|Single Password: Spring2026!| POOL{User Pool} POOL -->|Attempt 1 / IP 1| U1[user1@target.com] POOL -->|Attempt 1 / IP 2| U2[user2@target.com] POOL -->|Attempt 1 / IP 3| U3[user3@target.com] POOL -->|Attempt 1 / IP N| UN[userN@target.com] U1 & U2 & U3 & UN --> IDP[Entra ID Security Token Service] IDP -->|Thresholds Not Exceeded| STEALTH[Bypasses Account Lockout & Egress Blocks] endWhy Password Spraying Evades Traditional Defenses:
Section titled “Why Password Spraying Evades Traditional Defenses:”- Low Frequency per Identity: Testing one password every 2 to 4 hours per account avoids triggering Entra ID Smart Lockout (which typically locks accounts after 10 failed attempts within a rolling window).
- Residential IP Rotation: Modern spray tooling routes each HTTP request through rotating residential proxy networks (e.g., BrightData, Oxylabs), ensuring that no single egress IP address executes more than 1 or 2 attempts.
- Legacy Protocol Exploitation: Threat actors frequently direct spray attempts against legacy mail endpoints (IMAP4, POP3, ActiveSync, SMTP AUTH) that do not support interactive MFA challenges or Conditional Access device compliance checks.
2. Pre-Attack Reconnaissance: The GetCredentialType Endpoint
Section titled “2. Pre-Attack Reconnaissance: The GetCredentialType Endpoint”Before launching a spray campaign, sophisticated adversaries curate their target user list to eliminate nonexistent usernames, ensuring they do not generate unnecessary audit noise or invalid-user error codes.
2.1 Probing the Authentication Metadata API
Section titled “2.1 Probing the Authentication Metadata API”Entra ID exposes an unauthenticated, publicly accessible API endpoint used by the Microsoft login portal to determine tenant branding, realm type (managed vs federated), and credential requirements:
POST /common/GetCredentialType?mkt=en-US HTTP/1.1Host: login.microsoftonline.comContent-Type: application/json
{ "username": "victim.user@target.com", "isOtherIdpSupported": true, "checkPhones": false, "isRemoteNGCSupported": true, "isCookieBannerShown": false, "isFidoSupported": true, "country": "US", "forceotclogin": false, "isExternalFederationDisallowed": false, "isRemoteConnectSupported": false, "federationFlags": 0, "isSignup": false, "flowToken": "..."}2.2 Forensic Interpretation of IfExistsResult
Section titled “2.2 Forensic Interpretation of IfExistsResult”The API response returns an internal integer field, IfExistsResult, which discloses the existence of the identity without recording any entry in SigninLogs:
IfExistsResult Value | Identity State in Entra ID | Forensic Implication |
|---|---|---|
0 | User Exists (Valid Account) | The account is an active cloud identity in the tenant. Added to spray target list. |
1 | User Does Not Exist | The username is invalid. Discarded by attacker. |
5 | Throttled / Rate Limited | Microsoft STS throttled the request from this specific IP address. |
6 | Domain Exists, Realm is Federated | The tenant uses federated authentication (ADFS/Ping); requests redirect to on-premises STS. |
3. Entra ID Sign-In Telemetry & Error Code Decoding
Section titled “3. Entra ID Sign-In Telemetry & Error Code Decoding”When an adversary executes a password spray campaign, Entra ID records each attempt in the SigninLogs table. Understanding the exact ResultType status codes is critical for separating benign user mistyping from an active adversary who has uncovered valid credentials:
graph TD ATT[Spray Attempt Received by STS] --> EVAL{Credential Evaluation}
EVAL -->|Wrong Password| RT_50126[ResultType: 50126<br/>Invalid username or password] EVAL -->|Account Locked| RT_50053[ResultType: 50053<br/>Smart Lockout triggered] EVAL -->|Nonexistent User| RT_50056[ResultType: 50056<br/>User does not exist in tenant]
EVAL -->|Password is Correct!| MFA_CHECK{Does User Have MFA Required?} MFA_CHECK -->|Yes| RT_50076[ResultType: 50076<br/>CRITICAL FORENSIC SIGNAL:<br/>Password valid, redirected to MFA!] MFA_CHECK -->|No / Legacy Protocol| RT_0[ResultType: 0<br/>SUCCESS: Complete account takeover]3.1 Essential Sign-In Error Codes for Spray Analysis
Section titled “3.1 Essential Sign-In Error Codes for Spray Analysis”ResultType | Error Description | Investigation Significance |
|---|---|---|
0 | Success | Successful authentication. If preceded by multiple 50126 errors, marks a successful spray penetration. |
50126 | Invalid username or password | The standard failed attempt. Baseline indicator of password spraying when observed across many accounts. |
50053 | Account is locked (Smart Lockout) | The account exceeded lockout thresholds. Indicates aggressive or concurrent spraying. |
50056 | User does not exist | Indicates the attacker sprayed without prior user enumeration (dirty user dictionary). |
50076 | User redirected to MFA | HIGHEST FORENSIC VALUE. Proves the attacker guessed the correct password, but the session was intercepted by an MFA requirement. Immediate containment required! |
50079 | User must register for MFA | Attacker guessed valid password on an un-onboarded account; attacker can register their own MFA! |
50074 | Strong Auth Failed (MFA Rejected) | The user was prompted for MFA (push/SMS) and rejected or ignored the prompt. |
53003 | Blocked by Conditional Access | Credential was valid, but a CA policy (e.g., location, platform, device) blocked access. |
4. Production KQL Hunting Queries
Section titled “4. Production KQL Hunting Queries”4.1 Detecting Distributed Password Sprays Across Multiple Accounts
Section titled “4.1 Detecting Distributed Password Sprays Across Multiple Accounts”Identify instances where many unique accounts experience failed logins (50126) within a 2-hour window, originating from multiple distinct IP addresses sharing similar client characteristics:
let ThresholdFailedUsers = 15; // Minimum unique targeted userslet TimeWindow = 2h;SigninLogs| where TimeGenerated >= ago(24h)| where ResultType in (50126, 50053) // Invalid password or locked out| summarize FailedAttemptCount = count(), TargetedUsers = make_set(UserPrincipalName), TargetedUserCount = dcount(UserPrincipalName), IPAddresses = make_set(IPAddress), IPCount = dcount(IPAddress), Locations = make_set(Location), AppNames = make_set(AppDisplayName), UserAgents = make_set(UserAgent) by bin(TimeGenerated, TimeWindow), ClientAppUsed| where TargetedUserCount >= ThresholdFailedUsers| project TimeGenerated, ClientAppUsed, TargetedUserCount, FailedAttemptCount, IPCount, AppNames, UserAgents, TargetedUsers, IPAddresses| sort by TargetedUserCount desc4.2 The “Valid Credential Discovery” Query (50126 Followed by 50076 or 0)
Section titled “4.2 The “Valid Credential Discovery” Query (50126 Followed by 50076 or 0)”Identify specific accounts where an adversary successfully discovered the correct password during a spray campaign:
let SprayedUsers = SigninLogs| where TimeGenerated >= ago(24h)| where ResultType == 50126| distinct UserPrincipalName;SigninLogs| where TimeGenerated >= ago(24h)| where UserPrincipalName in (SprayedUsers)| where ResultType in (0, 50076, 50079) // Succeeded or valid password requiring MFA| project TimeGenerated, UserPrincipalName, IPAddress, Location, ResultType, ResultDescription, AppDisplayName, ClientAppUsed, UserAgent| sort by TimeGenerated asc4.3 Hunting Legacy Authentication Password Spraying
Section titled “4.3 Hunting Legacy Authentication Password Spraying”Detect brute-force or spray attacks targeting legacy protocols that bypass modern authentication:
SigninLogs| where TimeGenerated >= ago(7d)| where ClientAppUsed in ("IMAP4", "POP3", "SMTP", "Exchange ActiveSync", "MAPI over HTTP", "Autodiscover")| where ResultType in (50126, 50053, 0)| summarize Attempts = count(), SuccessfulLogins = countif(ResultType == 0), FailedLogins = countif(ResultType != 0), DistinctUsers = dcount(UserPrincipalName), TargetedAccounts = make_set(UserPrincipalName) by IPAddress, Location, AutonomousSystemNumber, ClientAppUsed, bin(TimeGenerated, 1h)| where DistinctUsers >= 5| sort by DistinctUsers desc5. Architectural Hardening & Mitigation Strategy
Section titled “5. Architectural Hardening & Mitigation Strategy”To effectively neutralize password spraying, organizations must deploy layered defenses targeting protocol availability, lockout intelligence, and credential requirements:
graph TD DEF[Anti-Password Spray Architecture] --> L1[1. Block Legacy Authentication<br/>Conditional Access: Client apps = Other / Exchange ActiveSync] DEF --> L2[2. Configure Entra Smart Lockout<br/>Lockout threshold = 5 / Duration = 15 min / Separate on-prem vs cloud] DEF --> L3[3. Enforce Phishing-Resistant MFA<br/>Require FIDO2 / Windows Hello / CBA via CA Authentication Strengths] DEF --> L4[4. Deploy Passwordless Authentication<br/>FIDO2 Keys, Microsoft Authenticator Passwordless, Temporary Access Pass]- Block Legacy Authentication via Conditional Access:
- Create a tenant-wide Conditional Access policy blocking all client apps categorized as
"Exchange ActiveSync clients"and"Other clients"(IMAP, POP, SMTP, MAPI).
- Create a tenant-wide Conditional Access policy blocking all client apps categorized as
- Harden Entra ID Smart Lockout:
- In the Entra Admin Center (
Protection$\rightarrow$Authentication methods$\rightarrow$Password protection), set Lockout threshold to 5 or 10, and Lockout duration to at least 60 seconds. Smart Lockout tracks IP familiarity, locking out adversary IPs without locking out legitimate users on corporate networks.
- In the Entra Admin Center (
- Transition to Passwordless Authentication:
- Eliminating the user password completely removes the attack surface targeted by password spraying.
6. Cross-Reference & Investigation Navigation
Section titled “6. Cross-Reference & Investigation Navigation”- Previous Fiche: 23. OAuth Illicit Consent Grant & Application Phishing
- Next Fiche: 25. OAuth Device Code Flow Abuse & Token Hijacking
- Related Guides: