Playbooks

T1078

Suspicious 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

  1. Contact the user via out-of-band channel (phone call, not email) — ask if they logged in from both locations
  2. If the user confirms both logins — check for VPN usage, VDI session, or roaming device — could be legitimate
  3. If the user cannot confirm — lock the account, force password reset, revoke all sessions
  4. Check the IP — is it from a known data center (AWS, Azure, DigitalOcean)? Attackers often use cloud IPs for credential stuffing
SignalConfidenceAction
User confirms, IP is corporate VPNLowNo action needed — mark as expected
User confirms, IP is familiar but no VPNMediumInvestigate further — check device details
User does not respond, IP is cloud providerHIGHLock account immediately
User denies, IP is unknownCRITICALLock 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

  1. Check if any MFA request was approved — one “approved” event in the flood means the attacker is in
  2. If any approval found — immediately revoke all sessions and force password reset
  3. 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
  4. Notify the user — confirm they ignored/denied all prompts. If they fat-finger accepted one by accident, you have a breach
SignalConfidenceAction
MFA denied 10+ times, 0 approvedMediumBlock IP, advise user, implement number matching
MFA denied 10+ times, 1+ approvedCRITICALLock account, revoke sessions, incident response
MFA push received by user who was not activeHighCheck 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

  1. Check if the device is managed — MDM/MEM enrollment? If yes, likely legitimate (new laptop or phone)
  2. Check if the device OS is unusual — a Windows user suddenly logging in from macOS or Linux is suspicious
  3. Check the IP location — does it match the user’s expected location?
  4. 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 IDLog SourceWhy Monitor
4624Windows SecuritySuccessful logon — track every authentication
4625Windows SecurityFailed logon — brute force, password spray
4648Windows SecurityExplicit credential use — clear-text authentication to remote host
4776Windows SecurityNTLM authentication — credential relay detection
4768Windows SecurityKerberos TGT request — anomalous timing
4769Windows SecurityKerberos service ticket request — Silver Ticket detection
500121Azure AD Sign-in LogsMFA denied — push bombing detection
50074Azure AD Sign-in LogsMFA completed from unfamiliar location
50053Azure AD Sign-in LogsAccount locked due to too many attempts

Sources