Query Details
id: d8e9f0a1-b2c3-4d4e-5f6a-7b8c9d0e1f2a
name: "SigninLogs — Attacker in the Middle (AiTM) Token Theft Detected"
version: 1.0.0
kind: Scheduled
description: |
Detects AiTM proxy attacks (Evilginx, Modlishka) that steal session cookies after MFA. Correlates SecurityAlert 'Anomalous Token' events with AADUserRiskEvents where RiskEventType == attackerinTheMiddle. Requires Entra ID P2. MITRE ATT&CK: T1557 (Adversary-in-the-Middle), T1539 (Steal Web Session Cookie).
severity: High
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
queryFrequency: PT1H
queryPeriod: P7D
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
- Collection
relevantTechniques:
- T1557
- T1539
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,
RiskLevelDuringSignIn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
customDetails:
AppDisplayName: AppDisplayName
RiskEventType: RiskEventType
alertDetailsOverride:
alertDisplayNameFormat: "AiTM Token Theft — {{UserPrincipalName}} from {{IPAddress}}"
alertDescriptionFormat: "Attacker-in-the-Middle session hijack detected — {{AppDisplayName}} session token stolen post-MFA."
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT1H
matchingMethod: AllEntities
groupByEntities:
- Account
- IP
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:
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.

David Alonso
Released: April 20, 2026
Tables
Keywords
Operators