Playbooks
T1078Suspicious Authentication
An identity-focused SOC playbook for triaging suspicious authentication events — impossible travel, MFA fatigue, new device logins — with Event IDs, KQL/SPL detection queries, and clear decision points for closing or escalating.
View on Graph
What This Playbook Covers
- This playbook handles the investigation of anomalous authentication events flagged by your identity provider (Azure AD/Entra ID, Okta, Ping, Duo) or SIEM correlation rules.
- These alerts indicate that a user account may be under the control of an adversary.
- MITRE ATT&CK maps this to
T1078(Valid Accounts) — the most common technique for initial access, persistence, and lateral movement because valid credentials bypass all perimeter defenses.
Authentication Threat 1: Impossible Travel
How it works: A user’s account authenticates from two geographically distant locations within a time window that makes physical travel impossible. For example: login from New York at 9:00 AM and login from London at 9:15 AM.
Detection — Identity Provider Logs:
KQL query (Azure Sentinel) — detect impossible travel (see the KQL guide):
let threshold_minutes = 60;
let impossible_travel = SigninLogs
| where ResultType == "0"
| project TimeGenerated, UserPrincipalName, IPAddress, City, Country, latitude, longitude;
impossible_travel
| join kind=inner impossible_travel on UserPrincipalName
| where TimeGenerated < datetime_add('minute', threshold_minutes, TimeGenerated)
| where TimeGenerated > TimeGenerated1
| extend distance = geo_distance_km(latitude, longitude, latitude1, longitude1)
| where distance > 500
| project UserPrincipalName, TimeGenerated, IPAddress, City, Country, TimeGenerated1, IPAddress1, City1, Country1, distance
| sort by distance desc
SPL query (on-prem) — detect logins from multiple geo-locations in short time:
index=windows sourcetype=WinEventLog:Security EventCode=4624
| search LogonType=10 (RemoteInteractive) OR LogonType=3 (Network) OR LogonType=2 (Interactive)
| iplocation IpAddress
| stats earliest(_time) as first_login, latest(_time) as last_login, values(IpAddress) as IPs, values(City) as Cities, values(Country) as Countries by AccountName, Computer
| eval travel_time = last_login - first_login
| where mvcount(Cities) > 1 AND travel_time < 3600
| eval alert = "IMPOSSIBLE TRAVEL — " . AccountName . " logged in from " . mvjoin(IPs, ", ") . " between " . mvjoin(Cities, ", ") . " in " . tostring(travel_time/60, "0.0") . " minutes"
| table _time, AccountName, IPs, Cities, travel_time, alert
Triage Steps
- Contact the user via out-of-band channel (phone call, not email) — ask if they logged in from both locations
- If the user confirms both logins — check for VPN usage, VDI session, or roaming device — could be legitimate
- If the user cannot confirm — lock the account, force password reset, revoke all sessions
- Check the IP — is it from a known data center (AWS, Azure, DigitalOcean)? Attackers often use cloud IPs for credential stuffing
| Signal | Confidence | Action |
|---|---|---|
| User confirms, IP is corporate VPN | Low | No action needed — mark as expected |
| User confirms, IP is familiar but no VPN | Medium | Investigate further — check device details |
| User does not respond, IP is cloud provider | HIGH | Lock account immediately |
| User denies, IP is unknown | CRITICAL | Lock account, begin incident response |
Authentication Threat 2: MFA Fatigue / MFA Push Bombing
How it works: The attacker has the user’s password (from a prior breach or credential stuffing) and triggers repeated MFA push notifications to the user’s device — dozens or hundreds in minutes — hoping the user eventually accepts one out of annoyance or confusion.
Detection — Identity Provider Logs:
KQL query (Azure Sentinel) — detect MFA push denial flood (run in Splunk with equivalent SPL):
SigninLogs
| where ResultType == "500121" // MFA denied
| where Status.additionalDetails has "Denied" or Status.errorCode == 500121
| summarize DenialCount = count(), FirstDenial = min(TimeGenerated), LastDenial = max(TimeGenerated) by UserPrincipalName, IPAddress, AppDisplayName
| where DenialCount > 10
| extend DurationMinutes = datetime_diff('minute', LastDenial, FirstDenial)
| project UserPrincipalName, IPAddress, AppDisplayName, DenialCount, DurationMinutes
| sort by DenialCount desc
SPL query — detect MFA push bombing from SIEM:
index=identity sourcetype=sso_logs
| search result="mfa_denied" OR reason="MFA denied"
| stats count, earliest(_time) as first, latest(_time) as last by user, source_ip, application
| where count > 10
| eval duration_mins = (last - first) / 60
| eval alert = "MFA PUSH BOMBING — " . user . " denied " . count . " MFA prompts in " . tostring(duration_mins, "0.0") . " minutes from " . source_ip
| table _time, user, source_ip, count, duration_mins, alert
Triage Steps
- Check if any MFA request was approved — one “approved” event in the flood means the attacker is in
- If any approval found — immediately revoke all sessions and force password reset
- If no approval found — the user successfully resisted. Block the source IP at the identity provider. Require number matching or passwordless MFA (FIDO2) which is not susceptible to push bombing
- Notify the user — confirm they ignored/denied all prompts. If they fat-finger accepted one by accident, you have a breach
| Signal | Confidence | Action |
|---|---|---|
| MFA denied 10+ times, 0 approved | Medium | Block IP, advise user, implement number matching |
| MFA denied 10+ times, 1+ approved | CRITICAL | Lock account, revoke sessions, incident response |
| MFA push received by user who was not active | High | Check if attacker has the password. Force reset. |
Authentication Threat 3: Unfamiliar Device / New Device Login
How it works: The attacker authenticates from a device the user has never used before — new operating system, new browser, new device ID, or new location — but with valid credentials.
Detection — Identity Provider Device Registration Logs:
SPL query — detect first-time device logins:
index=identity sourcetype=device_login
| search result="success"
| stats count by user, device_id, os, browser
| eventstats first_seen(min(_time)) as first_login by user, device_id
| where first_login > relative_time(now(), "-24h@h")
| eval alert = "NEW DEVICE — " . user . " logged in from new device " . device_id . " (" . os . "/" . browser . ")"
| table _time, user, device_id, os, browser, alert
Triage Steps
- Check if the device is managed — MDM/MEM enrollment? If yes, likely legitimate (new laptop or phone)
- Check if the device OS is unusual — a Windows user suddenly logging in from macOS or Linux is suspicious
- Check the IP location — does it match the user’s expected location?
- Contact the user — “Did you just log in from a new device running [OS]?”
Authentication Threat 4: Brute Force / Password Spraying
How it works: The attacker tries many passwords against a single account (brute force) or a single password against many accounts (password spraying).
SPL query — detect password spraying (one password, many accounts):
index=windows sourcetype=WinEventLog:Security EventCode=4625
| search LogonType=3 OR LogonType=2
| stats count, values(AccountName) as TargetedAccounts by WorkstationName, IpAddress, unique_count=mvcount(AccountName)
| where count > 10 AND unique_count > 5
| eval alert = "PASSWORD SPRAY — " . count . " failed logins targeting " . unique_count . " accounts from " . IpAddress
| table _time, WorkstationName, IpAddress, count, unique_count, alert
| sort - count
SPL query — detect brute force (many passwords, one account):
index=windows sourcetype=WinEventLog:Security EventCode=4625
| search LogonType=2 OR LogonType=3
| stats count, values(IpAddress) as SourceIPs by AccountName, WorkstationName
| where count > 10
| eval alert = "BRUTE FORCE — " . count . " failed logins for " . AccountName . " from " . mvjoin(SourceIPs, ", ")
| table _time, AccountName, count, SourceIPs, alert
Authentication Threat 5: Service Account Authentication Anomaly
How it works: A service account (meant for automated, scheduled tasks between servers) suddenly authenticates interactively, from a new workstation, or at an unusual time.
Detection — Event ID 4624 with unusual LogonType for a service account:
SPL query — detect service account interactive login:
index=windows sourcetype=WinEventLog:Security EventCode=4624
| search AccountName="svc_*" OR AccountName="SQLService*" OR AccountName="backup_*"
| search LogonType IN (2, 10) (Interactive or RemoteInteractive)
| eval alert = "HIGH — Service account " . AccountName . " used for interactive logon (LogonType=" . LogonType . ") from " . IpAddress
| table _time, AccountName, Computer, IpAddress, LogonType, alert
Suspicious Authentication Triage — Decision Framework
Suspicious authentication alert fires
│
├─ Impossible travel?
│ ├─ User confirms, VPN used → Close
│ ├─ User denies or can't confirm → Lock account, force reset, revoke sessions
│ └─ Cloud IP involved → CRITICAL — begin IR
│
├─ MFA push bombing?
│ ├─ No approvals → Block IP, implement number matching or FIDO2
│ └─ One or more approvals → CRITICAL — active session hijack, lock immediately
│
├─ New device login?
│ ├─ Device is MDM-enrolled → Likely legitimate, monitor
│ └─ Unknown device + unusual location → HIGH — force MFA challenge, contact user
│
├─ Brute force/spray?
│ ├─ Single account, many passwords → Lock account temporarily, check for success
│ └─ Many accounts, one password → Password spraying. Block source IP. Force password reset for targeted accounts.
│
└─ Service account anomaly?
├─ Interactive login → HIGH — service accounts don't log in interactively. Investigate.
└─ Network login from unknown source → MEDIUM — check if it's a scheduled task on a new server
Events to Monitor Continuously
| Event ID | Log Source | Why Monitor |
|---|---|---|
| 4624 | Windows Security | Successful logon — track every authentication |
| 4625 | Windows Security | Failed logon — brute force, password spray |
| 4648 | Windows Security | Explicit credential use — clear-text authentication to remote host |
| 4776 | Windows Security | NTLM authentication — credential relay detection |
| 4768 | Windows Security | Kerberos TGT request — anomalous timing |
| 4769 | Windows Security | Kerberos service ticket request — Silver Ticket detection |
| 500121 | Azure AD Sign-in Logs | MFA denied — push bombing detection |
| 50074 | Azure AD Sign-in Logs | MFA completed from unfamiliar location |
| 50053 | Azure AD Sign-in Logs | Account locked due to too many attempts |
Related
- Device Code Phishing — detection and response for T1566, T1528 techniques
- Cloud Incident Response — detection and response for T1525, T1526, T1078, T1530 techniques
- Privilege Escalation Investigation — detection and response for T1068 techniques
- MITRE ATT&CK for Triage — covers the mitre att&ck for triage concepts
- Cloud Threats — Credential Theft, IMDS Abuse, Hijacking, Privilege Escalation — detection and response for T1525, T1552, T1613 techniques
- Container and Kubernetes Threats — detection and response for T1611, T1525, T1574.002 techniques
