Adversary-in-the-middle phishing bypasses MFA by intercepting authentication sessions in real time rather than stealing passwords. The attacker proxies the victim through a legitimate-looking phishing site, relays their credentials and MFA code to the real service, then captures the resulting session token. From the identity provider’s perspective, the authentication was legitimate — the right password and the right MFA code were provided. The attack surface is the session cookie issued after authentication, not the credentials themselves.
Kits like Evilginx, Tycoon 2FA, Modlishka, and EvilProxy handle the proxy logic automatically. Evilginx in particular provides ready-made “phishlets” for Microsoft 365, Outlook, and Entra ID that strip security headers, proxy the full session, and exfiltrate the ESTSAUTH and ESTSAUTHPERSISTENT cookies that maintain M365 session state.
This guide covers what AitM attacks look like in Entra ID telemetry and the KQL queries that surface them.
What the Logs Show
Entra ID sign-in logs capture three data points that distinguish AitM-captured sessions from legitimate authentications:
IP address anomalies: The phishing proxy originates from a hosting provider, VPN endpoint, or residential proxy network. The IP used to authenticate via the proxy typically differs from the IP the victim was actually connecting from and from any IP the account has historically used.
User agent consistency failures: Evilginx and similar kits proxy the browser session, but the subsequent token use (when the attacker opens a new browser session with the stolen cookie) uses a different user agent than the authentication event. Entra ID logs capture the user agent at sign-in; downstream M365 API calls and mailbox access log separate user agents.
Geographic and ASN velocity: Token use frequently occurs within minutes of authentication from a different country, city, or ASN. A sign-in from a UK residential ISP followed by token use from a Frankfurt data centre IP is a strong signal.
Device compliance state: AitM authentication often occurs from devices that are not registered or compliant in the tenant. If conditional access is enforced, the phishing proxy cannot pass device compliance checks — but many tenants have gaps in conditional access coverage.
KQL Queries for Entra ID
These queries run against the SigninLogs and AADNonInteractiveUserSignInLogs tables in Microsoft Sentinel.
1. Token Use from Different ASN than Authentication
Detects cases where a user authenticates and then has non-interactive token refresh from a different autonomous system number — a common pattern when a stolen cookie is used in a different location.
let auth_events = SigninLogs
| where TimeGenerated > ago(1h)
| where ResultType == 0
| where AuthenticationRequirement == "multiFactorAuthentication"
| project AuthTime = TimeGenerated, UserPrincipalName, AuthIP = IPAddress,
AuthASN = tostring(parse_json(NetworkLocationDetails)[0].networkNames),
SessionId = CorrelationId;
let noninteractive = AADNonInteractiveUserSignInLogs
| where TimeGenerated > ago(2h)
| where ResultType == 0
| project TokenTime = TimeGenerated, UserPrincipalName, TokenIP = IPAddress,
TokenASN = tostring(parse_json(NetworkLocationDetails)[0].networkNames),
SessionId = CorrelationId;
auth_events
| join kind=inner noninteractive on UserPrincipalName
| where AuthASN != TokenASN
| where TokenTime between (AuthTime .. (AuthTime + 30m))
| where AuthIP != TokenIP
| project AuthTime, TokenTime, UserPrincipalName, AuthIP, AuthASN, TokenIP, TokenASN
| order by AuthTime desc
2. MFA Success Followed by Impossible Travel Token Use
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| where AuthenticationRequirement == "multiFactorAuthentication"
| extend Location = strcat(tostring(LocationDetails.city), ", ", tostring(LocationDetails.countryOrRegion))
| summarize
Sessions = count(),
Locations = make_set(Location),
IPs = make_set(IPAddress),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by UserPrincipalName, bin(TimeGenerated, 1h)
| where array_length(Locations) > 1
| where datetime_diff("minute", LastSeen, FirstSeen) < 60
| project UserPrincipalName, Sessions, Locations, IPs, FirstSeen, LastSeen
3. Evilginx Proxy Hosting ASN Detection
Evilginx operators frequently use specific VPS and hosting providers. This query flags authentications from known AitM infrastructure ASNs (update the list as intelligence develops):
let aitm_asns = dynamic(["AS200351", "AS209103", "AS62240", "AS14618"]); // example — update with threat intel
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| extend ASN = tostring(parse_json(NetworkLocationDetails)[0].networkNames)
| where ASN has_any (aitm_asns)
| where AuthenticationRequirement == "multiFactorAuthentication"
| project TimeGenerated, UserPrincipalName, IPAddress, ASN, AppDisplayName,
ConditionalAccessStatus, DeviceDetail
| order by TimeGenerated desc
4. ESTSAUTH Cookie Replay Pattern
Token replay often surfaces in the AADAuditLogs as bulk mailbox access shortly after an unusual sign-in. This detects mailbox access spikes correlated with atypical sign-ins:
let unusual_signins = SigninLogs
| where TimeGenerated > ago(2h)
| where ResultType == 0
| where RiskLevelDuringSignIn in ("high", "medium")
| project UserPrincipalName, SuspiciousSignIn = TimeGenerated;
OfficeActivity
| where TimeGenerated > ago(2h)
| where Operation in ("MailItemsAccessed", "SearchQueryInitiated", "FileDownloaded")
| join kind=inner unusual_signins on $left.UserId == $right.UserPrincipalName
| where TimeGenerated > SuspiciousSignIn
| where TimeGenerated < (SuspiciousSignIn + 30m)
| summarize Operations = count(), ActivityTypes = make_set(Operation)
by UserPrincipalName, SuspiciousSignIn
| where Operations > 50
Sigma Rule: AitM Session Anomaly
title: AitM Phishing - MFA Authentication IP Mismatch
id: a4c7e8f2-3b91-4d2e-95f6-1c8b234a7d9e
status: experimental
description: Detects AitM phishing pattern where MFA-authenticated session is subsequently
used from a different IP address within a short window, indicating stolen token replay
author: SOC Analyst Hub
date: 2026/08/09
logsource:
product: azure
service: signinlogs
detection:
selection:
ResultType: 0
AuthenticationRequirement: multiFactorAuthentication
condition: selection
falsepositives:
- Corporate VPN split tunneling where auth and traffic routes differ
- Users switching between mobile and desktop within a session
level: medium
tags:
- attack.credential_access
- attack.t1539
- attack.t1556.006
- attack.initial_access
- attack.t1566
Correlation with Endpoint Telemetry
If you have Microsoft Defender for Endpoint or similar EDR, correlate Entra ID anomalies with:
- Browser process spawning curl, PowerShell, or certutil shortly after unusual sign-in (attacker using webshell or forwarded session for data staging)
- Outlook.exe or teams.exe opening network connections to IPs not in Microsoft’s published CDN ranges
- New persistence mechanisms (scheduled tasks, registry run keys) created in the 30-minute window after a flagged sign-in
Hardening That Reduces Detection Surface
Token theft is harder to detect if you haven’t eliminated the attack surface:
- Token binding / Continuous Access Evaluation (CAE): Microsoft’s CAE feature revokes tokens when context changes. Enable it in Entra ID — it doesn’t prevent token theft, but it limits the window of token validity.
- Device-bound sessions: Require compliant or hybrid Azure AD joined devices via conditional access. Evilginx proxies cannot pass device compliance checks.
- Named locations and CA policies: Block authentication from known hosting provider IP ranges at the conditional access policy level.
- Phishing-resistant MFA: FIDO2/passkey MFA is not bypassable by AitM proxies — the key exchange binds to the origin domain. Prioritise rollout for privileged accounts.
The core problem with AitM detection is that the authentication log shows a successful MFA challenge. Detection depends on correlating the authentication event with downstream token use — which requires cross-table analysis and knowledge of what “normal” looks like for each account.