Skip to content

Identity Attacks: AiTM Phishing & Token Theft

Multi-factor authentication was supposed to be the silver bullet. Then Adversary-in-the-Middle (AiTM) phishing kits turned MFA into a speedbump. Attackers now routinely intercept session tokens in real-time, bypassing even hardware-backed MFA, and replaying stolen cookies to walk right into mailboxes, file shares, and cloud admin consoles.

This post dissects the AiTM attack chain, maps it to MITRE ATT&CK, and provides detection queries you can deploy today. We follow Pinnacle Manufacturing (fictional) through a real-time token theft incident that compromised their CFO's mailbox and nearly enabled a $2.8M wire transfer.


1. The MFA Bypass Problem

Traditional phishing steals passwords. AiTM phishing steals authenticated sessions — the token your identity provider issues after you successfully complete MFA. The attacker never needs your password or your second factor.

How it works:

User → Attacker Proxy → Real Login Page
     ←               ←
     (Session token intercepted in transit)

Attacker replays token → Full account access (MFA already satisfied)

Key Insight

AiTM doesn't break MFA — it bypasses it entirely. The user completes legitimate MFA with the real identity provider. The attacker's reverse proxy captures the resulting session cookie.

ATT&CK Mapping

Technique ID Phase
Phishing: Spearphishing Link T1566.002 Initial Access
Adversary-in-the-Middle T1557 Credential Access
Steal Web Session Cookie T1539 Credential Access
Use Alternate Authentication Material T1550.004 Defense Evasion
Email Collection: Email Forwarding Rule T1114.003 Collection
Financial Theft T1657 Impact

2. AiTM Attack Anatomy

Phase 1: Phishing Infrastructure Setup

The attacker deploys a reverse proxy (Evilginx, Modlishka, or custom) that sits between the victim and the real identity provider:

  • Domain: login-portal.pinnacle-mfg.example.com (typosquat of portal.pinnacle-mfg.example.com)
  • SSL certificate: Let's Encrypt (valid cert, green padlock)
  • Hosting: bulletproof VPS at 203.0.113.44

Phase 2: Credential & Token Harvest

1. Victim clicks link in phishing email
2. Reverse proxy forwards request to real Azure AD login
3. Victim enters username → proxy forwards to Azure AD
4. Azure AD prompts MFA → victim approves push notification
5. Azure AD issues session token → proxy INTERCEPTS token
6. Proxy forwards legitimate login page to victim (looks normal)
7. Attacker replays stolen session token from 198.51.100.77

Phase 3: Post-Compromise Actions

Within minutes of token capture, the attacker typically:

  1. Creates inbox rules — forward all emails to external address, delete sent items
  2. Reads email — searches for "wire transfer", "payment", "invoice", "bank"
  3. Registers new MFA device — adds attacker-controlled authenticator
  4. Modifies mailbox permissions — grants delegate access to another compromised account
  5. Initiates BEC — sends wire transfer request from legitimate account

3. Detection Strategies

Impossible Travel Detection

// Detect impossible travel: login from two locations faster than physically possible
let timeWindow = 10m;
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0  // Successful logins only
| where AppDisplayName != "Windows Sign In"
| extend City = tostring(LocationDetails.city)
| extend Country = tostring(LocationDetails.countryOrRegion)
| extend Lat = todouble(LocationDetails.geoCoordinates.latitude)
| extend Lon = todouble(LocationDetails.geoCoordinates.longitude)
| sort by UserPrincipalName, TimeGenerated asc
| serialize
| extend PrevCity = prev(City, 1), PrevCountry = prev(Country, 1),
         PrevTime = prev(TimeGenerated, 1), PrevUser = prev(UserPrincipalName, 1),
         PrevLat = prev(Lat, 1), PrevLon = prev(Lon, 1)
| where UserPrincipalName == PrevUser
| extend TimeDiffMinutes = datetime_diff('minute', TimeGenerated, PrevTime)
| where TimeDiffMinutes < 60 and City != PrevCity and Country != PrevCountry
| project TimeGenerated, UserPrincipalName, City, Country, PrevCity, PrevCountry, 
          TimeDiffMinutes, IPAddress, AppDisplayName
index=azure sourcetype=azure:signin status=Success
| sort 0 user, _time
| streamstats window=2 current=t earliest(_time) as prev_time, 
    earliest(src_ip) as prev_ip, earliest(City) as prev_city by user
| eval time_diff_min=round((_time - prev_time) / 60, 0)
| where time_diff_min < 60 AND City != prev_city AND isnotnull(prev_city)
| table _time, user, City, Country, prev_city, time_diff_min, src_ip, app

Suspicious Inbox Rule Creation

// Detect inbox rules that forward to external domains or delete items
OfficeActivity
| where TimeGenerated > ago(7d)
| where Operation in ("New-InboxRule", "Set-InboxRule", "Enable-InboxRule")
| extend RuleParams = tostring(Parameters)
| where RuleParams has_any ("ForwardTo", "ForwardAsAttachmentTo", "RedirectTo", 
                             "DeleteMessage", "MoveToFolder")
| where RuleParams !has "@pinnacle-mfg.example.com"  // External forwarding
| project TimeGenerated, UserId, Operation, RuleParams, ClientIP, SessionId
| sort by TimeGenerated desc
index=o365 sourcetype=o365:management:activity
    Operation IN ("New-InboxRule", "Set-InboxRule")
| where match(Parameters, "ForwardTo|RedirectTo|DeleteMessage")
| where NOT match(Parameters, "@pinnacle-mfg\.example\.com")
| table _time, UserId, Operation, Parameters, ClientIP
| sort - _time

Token Replay from New IP

// Detect session token reuse from a different IP than the original authentication
let authSessions = SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| summarize AuthIP = arg_min(TimeGenerated, IPAddress) by CorrelationId, UserPrincipalName;

SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| join kind=inner authSessions on CorrelationId, UserPrincipalName
| where IPAddress != AuthIP
| project TimeGenerated, UserPrincipalName, IPAddress, AuthIP, 
          AppDisplayName, DeviceDetail, LocationDetails
index=azure sourcetype=azure:signin status=Success
| stats earliest(src_ip) as auth_ip, values(src_ip) as all_ips by CorrelationId, user
| where mvcount(all_ips) > 1
| eval replay_ips=mvfilter(all_ips != auth_ip)
| where isnotnull(replay_ips)
| table CorrelationId, user, auth_ip, replay_ips

New MFA Device Registration

// Alert on new MFA method registration — high priority after any phishing indicator
AuditLogs
| where TimeGenerated > ago(24h)
| where OperationName has_any ("User registered security info", 
                                 "User registered all required security info",
                                 "Admin registered security info")
| extend UserPrincipalName = tostring(TargetResources[0].userPrincipalName)
| extend Method = tostring(AdditionalDetails[0].value)
| project TimeGenerated, UserPrincipalName, OperationName, Method, 
          InitiatedBy, CorrelationId
| sort by TimeGenerated desc
index=azure sourcetype=azure:audit
    operationName IN ("User registered security info", 
                      "Admin registered security info")
| table _time, targetResources{}.userPrincipalName, operationName, 
        additionalDetails{}.value, initiatedBy
| sort - _time

4. Case Study: Pinnacle Manufacturing

Scenario: CFO Mailbox Compromise via AiTM (Fictional)

Organization: Pinnacle Manufacturing (fictional, 3,200 employees) Target: CFO Victoria Chen (fictional) Method: AiTM phishing via typosquat domain Impact: Near-miss $2.8M wire transfer (caught by dual authorization)

Timeline

Time (UTC) Event Detection
09:12 CFO receives email: "Q3 Financial Review — Action Required" from spoofed board member
09:14 CFO clicks link to portal.pinnacle-mfg.example.com (typosquat)
09:15 CFO enters credentials, approves MFA push notification
09:15 AiTM proxy captures session cookie
09:18 Attacker replays token from 198.51.100.77 (VPS) Impossible travel alert fires
09:19 Attacker creates inbox rule: forward all "payment" emails to external Inbox rule alert fires
09:22 Attacker reads 47 emails, finds vendor payment schedule
09:31 Attacker registers new MFA authenticator app MFA registration alert fires
09:45 Attacker sends wire transfer request as CFO to Accounts Payable
09:52 AP analyst follows dual-authorization policy, calls CFO to verify
09:55 CFO confirms she did NOT send the request IR activated
10:05 SOC revokes all active sessions, disables account Containment
10:15 Attacker's MFA device removed, inbox rules deleted Eradication
10:30 CFO re-authenticates with hardware security key only Recovery

What Saved Pinnacle

  1. Dual authorization for wire transfers — financial control caught what technical controls missed
  2. Behavioral detection — impossible travel + inbox rule alerts fired within 4 minutes
  3. SOC response time — 10 minutes from IR activation to full containment
  4. Session revocation capability — Azure AD Continuous Access Evaluation (CAE) enabled

What Failed

  1. MFA alone was insufficient — push notification MFA is vulnerable to AiTM relay
  2. No phishing-resistant MFA — hardware security keys (FIDO2) would have prevented token theft
  3. Domain monitoring gap — typosquat domain registered 48 hours prior, not flagged

5. Defense-in-Depth for AiTM

Layer Control Effectiveness
Prevention FIDO2/passkeys (phishing-resistant MFA) Blocks AiTM entirely
Prevention Conditional Access: compliant device required Blocks token replay from unmanaged devices
Prevention Token binding / CAE Limits token replay window
Detection Impossible travel analytics Catches geographic anomalies
Detection Inbox rule monitoring Catches persistence setup
Detection MFA registration alerts Catches privilege persistence
Response Session revocation automation Rapid containment
Response Dual authorization for financial transactions Business process control

The Bottom Line

The only MFA that stops AiTM is phishing-resistant MFA — FIDO2 security keys or device-bound passkeys. Push notifications, SMS codes, and TOTP are all vulnerable to real-time relay.


6. Key Takeaways

  1. AiTM bypasses MFA — it doesn't break it, it captures the session token after successful authentication
  2. Phishing-resistant MFA is mandatory — FIDO2/passkeys are the only technical prevention
  3. Behavioral detection fills the gap — impossible travel, inbox rules, MFA registration alerts catch what prevention misses
  4. Business process controls matter — dual authorization for wire transfers saved Pinnacle $2.8M
  5. Token hygiene — short-lived tokens, CAE, and conditional access reduce the replay window