In this section
TH4.5 Hunting MFA Fatigue Attacks
The previous section covered hunting password spray. This section covers hunting mfa fatigue attacks.
The attacker has the password, they need the push approval
MFA fatigue (T1621. Multi-Factor Authentication Request Generation) is the bridge between a compromised password and full account access. The attacker obtained the password through spray (TH4.4), stuffing (TH4.3), phishing, or purchase on a dark web market. They submit it to the Entra ID login endpoint. MFA challenges the user via push notification. The user denies. The attacker submits again. Another push. And again. After 20 notifications in 10 minutes, the user, tired, confused, or assuming it is a system glitch, approves.
Anti-Pattern
Hunting hunting mfa fatigue attacks without a hypothesis
The hunter opens Advanced Hunting and starts writing queries without a clear hypothesis. They find interesting data but cannot determine whether it represents a threat, a misconfiguration, or normal activity. Every hunt starts with a hypothesis: a specific, testable statement about attacker behavior. Without a hypothesis, you are exploring, not hunting. Exploration has value, but it produces findings you cannot action without additional scoping.
This technique was used in the 2022 Uber breach (Lapsus$) and the 2022 Cisco breach (Yanluowang). It is effective because it exploits human behavior, not a technical vulnerability. Microsoft has since introduced number matching for Authenticator push notifications, which requires the user to enter a displayed number rather than just tapping "Approve." Number matching significantly reduces fatigue effectiveness, but it must be enabled, and not all organizations have enabled it.
Detecting rapid MFA prompts
// MFA Fatigue Hunt — repeated authentication attempts indicating
// rapid MFA push bombardment
let fatigueWindow = 30m;
let minPrompts = 5;
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType in ("50074", "50076", "500121",
"53003", "50079")
// 50074: Strong auth required (MFA challenge issued)
// 50076: MFA required — password correct, awaiting second factor
// 500121: Authentication failed during MFA challenge
// 53003: Blocked by conditional access (MFA not completed)
// 50079: User needs to register for MFA
| summarize
Prompts = count(),
SourceIPs = make_set(IPAddress, 10),
IPCount = dcount(IPAddress),
Errors = make_set(ResultType, 10),
Apps = make_set(AppDisplayName, 5),
TimeSpan = datetime_diff(
'minute', max(TimeGenerated), min(TimeGenerated)),
FirstAttempt = min(TimeGenerated),
LastAttempt = max(TimeGenerated)
by UserPrincipalName, bin(TimeGenerated, fatigueWindow)
| where Prompts >= minPrompts
// 5+ MFA prompts in 30 minutes for one user = fatigue candidate
| extend PromptsPerMinute = round(
todouble(Prompts) / todouble(TimeSpan + 1), 2)
// High prompts-per-minute from a single IP = automated fatigue tool
// Lower rate from multiple IPs = less certain (could be user
// on multiple devices genuinely failing MFA)
| extend HourOfDay = hourofday(FirstAttempt)
| extend IsAfterHours = HourOfDay < 7 or HourOfDay > 19
// After-hours MFA fatigue is higher confidence — the user is
// unlikely to be actively authenticating at 3 AM
| sort by Prompts desc
Correlating fatigue with successful approval
The fatigue attack succeeds when the user approves a push after the bombardment. The critical signal: many MFA failures followed by a success from a different IP.
// Did the user approve after the bombardment?
let fatigueUsers = SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType in ("50074", "50076", "500121", "53003")
| summarize Failures = count() by UserPrincipalName,
bin(TimeGenerated, 30m)
| where Failures >= 5
| distinct UserPrincipalName;
// Find successful sign-ins for fatigue-targeted users
SigninLogs
| where TimeGenerated > ago(24h)
| where UserPrincipalName in (fatigueUsers)
| where ResultType == "0" // Successful authentication
| extend MFAMethod = tostring(
parse_json(AuthenticationDetails)[1].authenticationMethod)
| extend Country = tostring(LocationDetails.countryOrRegion)
| project TimeGenerated, UserPrincipalName, IPAddress,
AppDisplayName, MFAMethod, Country,
DeviceOS = tostring(DeviceDetail.operatingSystem)
// Cross-reference: is this success IP in the user's baseline?
// If the success came from a non-baseline IP AFTER a fatigue
// bombardment, the user approved the attacker's push
// This is a confirmed compromise — escalate immediately
| sort by TimeGenerated asc
Number matching effectiveness check
// Is number matching enabled? Check MFA method distribution
SigninLogs
| where TimeGenerated > ago(7d)
| where ResultType == "0"
| extend MFAMethod = tostring(
parse_json(AuthenticationDetails)[1].authenticationMethod)
| where isnotempty(MFAMethod)
| summarize Users = dcount(UserPrincipalName),
SignIns = count()
by MFAMethod
| sort by Users desc
// "Microsoft Authenticator (push notification)" without number
// matching is vulnerable to fatigue
// "Microsoft Authenticator (number matching)" is resistant
// "FIDO2 security key" and "Passwordless phone sign-in" are
// immune to fatigue (no push to approve)
// If push-without-number-matching is the dominant method,
// your organization is vulnerable to fatigue attacks
Figure TH4.5. MFA fatigue timeline. Two detection opportunities: during the bombardment (preventive) and after the approval (reactive).
Run the fatigue detection query (24-hour window, 5-prompt minimum). Do any users show 5+ MFA prompts in a 30-minute window?
If yes, run the approval correlation query. Did any of those users subsequently authenticate successfully? If the successful auth came from a non-baseline IP (cross-reference TH4.1), the fatigue attack may have succeeded.
Run the number matching check. What percentage of your users authenticate with push-without-number-matching versus number-matching or FIDO2? If push-without-number-matching dominates, your organization is vulnerable to fatigue, recommend enabling number matching as a mitigation.
Compliance Context
Number matching makes fatigue significantly harder: the user must enter a two-digit number displayed on the sign-in screen, not just tap "Approve." But it does not eliminate the risk entirely. A user who receives 20 MFA prompts at 3 AM may call the helpdesk, and a socially engineered helpdesk agent could read the number to the user ("just enter 42 to stop the notifications"). Additionally, not all MFA methods support number matching. SMS OTP, phone call, and hardware OATH tokens are unaffected by the number matching setting. Hunting for fatigue patterns identifies: (1) whether fatigue attacks are being attempted against your organization, (2) which users are targeted (they likely have compromised passwords), and (3) whether any fatigue attempts succeeded despite number matching.
Extend this hunt
Correlate MFA fatigue targets with TH4.3 (credential stuffing) and TH4.4 (password spray) results. A user who appears in both the spray success list (password matched) and the fatigue target list is under active, multi-technique attack. The attacker first sprayed or stuffed to find valid passwords, then used fatigue to bypass MFA. This multi-technique chain, spray → fatigue → access, is the standard playbook for initial access brokers. Finding both patterns for the same user confirms a coordinated campaign rather than opportunistic probing.
References Used in This Subsection
- Microsoft. "Number matching in MFA." Microsoft Learn. https://learn.microsoft.com/en-us/entra/identity/authentication/how-to-mfa-number-match
- Course cross-references: TH4.3 (credential stuffing, often precedes fatigue), TH4.4 (spray, password source for fatigue)
NE environmental considerations
NE's detection environment includes specific factors that influence this rule's operation:
Device diversity: 768 P2 corporate workstations with full Defender for Endpoint telemetry, 58 P1 manufacturing workstations with basic cloud-delivered protection, and 3 RHEL rendering servers with Syslog-only coverage. Rules targeting DeviceProcessEvents operate with full fidelity on P2 devices but may have reduced visibility on P1 devices. Manufacturing workstations in Sheffield and Sunderland represent a detection gap for endpoint-level detections.
Network topology: 11 offices connected via Palo Alto SD-WAN with full-mesh connectivity. The SD-WAN firewall logs feed CommonSecurityLog in Sentinel. Cross-site lateral movement generates firewall allow events that correlate with DeviceLogonEvents, enabling multi-source detection that single-table rules cannot achieve.
User population: 810 users with distinct behavioral profiles, office workers (predictable hours, consistent applications), field engineers (variable hours, travel patterns), IT administrators (elevated privilege, broad access patterns), and manufacturing operators (fixed shifts, limited application access). Each user population has different detection baselines.