SigninLogs — Attacker in the Middle (AiTM) Token Theft Detected
08 SIGNIN Attacker In The Middle
Query
// ---- Network Allowlist (exclude trusted IPs / CIDR / ranges) --------------
let _allow = materialize(union isfuzzy=true (print R="" | take 0), (_GetWatchlist('NetworkAllowlist') | project R = tostring(IPOrRange)) | where isnotempty(R));
let _allowCIDR = toscalar(_allow | where not(R matches regex @'^\d+\.\d+\.\d+\.\d+-\d+\.\d+\.\d+\.\d+$') | extend R = iff(R has '/', R, strcat(R, '/32')) | summarize make_list(R));
let _allowRange = toscalar(_allow | where R matches regex @'^\d+\.\d+\.\d+\.\d+-\d+\.\d+\.\d+\.\d+$' | summarize make_list(R));
let _ExcludeAllowlistedIPs = (T:(IPAddress:string)) {
T
| extend IPAddress = tostring(IPAddress)
| where array_length(_allowCIDR) == 0 or isnull(ipv4_is_in_any_range(IPAddress, _allowCIDR)) or not(ipv4_is_in_any_range(IPAddress, _allowCIDR))
| mv-apply _r = _allowRange to typeof(string) on (
extend _lo = tostring(split(_r,'-')[0]), _hi = tostring(split(_r,'-')[1])
| extend _inRange = ipv4_compare(IPAddress, _lo) >= 0 and ipv4_compare(IPAddress, _hi) <= 0
| summarize _anyInRange = max(toint(_inRange)))
| where isnull(_anyInRange) or _anyInRange == 0
| project-away _anyInRange
};
// ---------------------------------------------------------------------------
let AnomalousTokenRequestIds =
SecurityAlert
| where TimeGenerated > ago(7d)
| where AlertName == "Anomalous Token"
| mv-expand todynamic(Entities)
| project Entities
| extend RequestId = tostring(Entities.RequestId)
| distinct RequestId;
AADUserRiskEvents
| where TimeGenerated > ago(7d)
| where RequestId has_any (AnomalousTokenRequestIds)
| where RiskEventType == "attackerinTheMiddle"
| join kind=leftouter (
SigninLogs
| invoke _ExcludeAllowlistedIPs()
| where TimeGenerated > ago(7d)
| project
UserPrincipalName, CorrelationId,
Location, AppDisplayName, IPAddress,
RiskLevelDuringSignIn
) on $left.CorrelationId == $right.CorrelationId
| project
TimeGenerated,
UserPrincipalName,
RiskEventType, IPAddress,
Location, AppDisplayName,
RiskLevelDuringSignInExplanation
This query is designed to detect potential Attacker-in-the-Middle (AiTM) token theft incidents, which involve stealing session cookies after a user has completed multi-factor authentication (MFA). Here's a simple breakdown of what the query does:
-
Purpose: The query identifies suspicious activities that may indicate an AiTM attack, specifically focusing on session token theft using tools like Evilginx or Modlishka.
-
Data Sources: It uses data from Azure Active Directory's SigninLogs and SecurityAlert logs, as well as AADUserRiskEvents.
-
Detection Logic:
- It first identifies "Anomalous Token" security alerts from the past 7 days.
- It then looks for user risk events where the risk type is "attackerinTheMiddle" and correlates these with the anomalous token alerts.
- The query excludes any IP addresses that are on a predefined allowlist (trusted IPs) to reduce false positives.
-
Output: The query produces a list of incidents with details such as the user's principal name, IP address, location, application name, and risk level during sign-in.
-
Severity and Response: The severity of these alerts is marked as high, and the system is configured to create incidents for further investigation. Alerts are grouped by account and IP to streamline incident management.
-
Alert Customization: The alert display name and description are customized to provide clear information about the detected threat, including the user and IP involved.
-
Incident Management: The query is set to automatically create incidents, with a configuration that groups related alerts to avoid duplication and streamline response.
Overall, this query helps security teams quickly identify and respond to sophisticated attacks that bypass traditional security measures by hijacking session tokens post-MFA.
Details

David Alonso
Released: April 20, 2026
Tables
Keywords
Operators