Cross-Domain Identity Attacks: MFA Bypass, Help Desk Social Engineering, and Adversary-in-the-Middle

24 March 2026 | 5 min read | justruss.tech

The CrowdStrike 2025 Threat Hunting Report documented a 442% increase in vishing attacks from the first to the second half of 2024. The group responsible for many of these attacks, tracked as SCATTERED SPIDER, demonstrated that with enough patience, a phone call to a help desk is often more effective than the most sophisticated technical exploit. This class of attack targets identity rather than endpoints, which is why traditional endpoint-focused monitoring misses it entirely.

Technique 1: Help desk social engineering for MFA reset

The attacker calls the corporate help desk pretending to be an employee who has lost access to their phone. They provide enough personal information about the employee (gathered from LinkedIn, public breach data, or OSINT) to pass identity verification. The help desk resets or bypasses MFA. The attacker logs in with the real password (obtained from a previous breach or phishing) and the newly reset MFA method they control.

// This technique leaves no technical indicators on endpoints
// Detection relies entirely on identity and behaviour monitoring

// Azure AD / Entra ID: look for MFA method changes followed by new logins
// Unified Audit Log query (Microsoft 365):

Search-UnifiedAuditLog -StartDate (Get-Date).AddHours(-24) `
 -EndDate (Get-Date) `
 -Operations "Update user.", "Change user password.", "Reset user password.",
 "Admin updated StrongAuthenticationMethods" |
 Select-Object CreationDate, UserIds, Operations, ResultStatus |
 Sort-Object CreationDate

// Then correlate with logins from new locations/devices immediately after:
Search-UnifiedAuditLog -StartDate (Get-Date).AddHours(-24) `
 -EndDate (Get-Date) `
 -Operations "UserLoggedIn" |
 Where-Object {
 $_.AuditData -match "NewDevice|NewCountry|NewIP"
 }
// KQL for Microsoft Sentinel: detect MFA change followed by login from new location
let mfa_changes = AuditLogs
| where TimeGenerated > ago(24h)
| where OperationName in ("Update user", "Admin updated StrongAuthenticationMethods",
 "Update Authentication Methods Policy")
| project change_time=TimeGenerated, target_user=TargetResources[0].userPrincipalName;

let logins_after_change = SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0 // successful
| project login_time=TimeGenerated, upn=UserPrincipalName,
 ip=IPAddress, country=Location, is_new_device=DeviceDetail.isCompliant;

mfa_changes
| join kind=inner logins_after_change on $left.target_user == $right.upn
| where login_time > change_time
| where login_time - change_time < 2h // Login within 2 hours of MFA change
| project target_user, change_time, login_time, ip, country, is_new_device

Technique 2: Adversary-in-the-Middle (AiTM) phishing

AiTM phishing tools like Evilginx2, Muraena, and Modlishka sit as a reverse proxy between the victim and the real authentication service. The victim completes MFA normally, the attacker sees the legitimate session token that is issued after MFA succeeds. The attacker then uses that session token directly, bypassing MFA entirely because authentication is already complete.

// AiTM indicators in authentication logs:
// 1. User completes MFA from one IP address
// 2. Session token used from a completely different IP address immediately after
// 3. The second IP is often a VPN exit node or commercial proxy

// KQL: detect session token reuse from different IP than authentication
SigninLogs
| where TimeGenerated > ago(24h)
| where AuthenticationRequirement == "multiFactorAuthentication"
| where ResultType == 0
| extend auth_ip = IPAddress
| join kind=inner (
 // Look for same session ID used from different IP
 AADNonInteractiveUserSignInLogs
 | where TimeGenerated > ago(24h)
 | where ResultType == 0
 | extend use_ip = IPAddress
 ) on UniqueTokenIdentifier
| where auth_ip != use_ip
| where datetime_diff('minute', TimeGenerated1, TimeGenerated) < 30
| project UserPrincipalName, auth_ip, use_ip, TimeGenerated, TimeGenerated1
// Additional AiTM indicators to hunt for:
// 1. Sign-ins with no corresponding MFA challenge (token replay)
// 2. Token used from Tor exit nodes or known proxy ranges
// 3. Impossible travel: MFA from US, token used from Russia 5 minutes later

// Impossible travel detection in Sentinel
SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0
| project UserPrincipalName, TimeGenerated, Location, IPAddress
| order by UserPrincipalName, TimeGenerated
| extend prev_location = prev(Location), prev_time = prev(TimeGenerated)
| where UserPrincipalName == prev(UserPrincipalName)
| extend time_diff_minutes = datetime_diff('minute', TimeGenerated, prev_time)
| where time_diff_minutes < 60 and Location != prev_location
| where time_diff_minutes > 0
| project UserPrincipalName, prev_location, Location, time_diff_minutes, IPAddress

Technique 3: MFA fatigue / push bombing

Send the victim repeated MFA push notifications until they approve one to make the notifications stop. Surprisingly effective, especially against users who do not understand what approving the push means.

// MFA push fatigue generates a specific pattern in auth logs:
// Multiple MFA challenges denied by the user (denied push notifications)
// Followed by a single approval
// Often in the middle of the night when the user wants to sleep

// Azure AD audit log for denied MFA pushes
Search-UnifiedAuditLog -StartDate (Get-Date).AddDays(-1) `
 -EndDate (Get-Date) `
 -Operations "UserLoginFailed" |
 Where-Object {$_.AuditData -match "AuthenticationFailed.*MFA"} |
 Group-Object UserIds | Where-Object {$_.Count -gt 5} |
 Select-Object Name, Count, Group

// Then look for a successful auth immediately after a burst of MFA denials
// KQL version
let mfa_fatigue = SigninLogs
| where TimeGenerated > ago(24h)
| where Status.errorCode == 500121 // MFA denied by user
| summarize denied_count=count(), last_denied=max(TimeGenerated)
 by UserPrincipalName, IPAddress
| where denied_count >= 5;

SigninLogs
| where TimeGenerated > ago(24h)
| where ResultType == 0 // successful
| join kind=inner mfa_fatigue on UserPrincipalName
| where TimeGenerated > last_denied
| where TimeGenerated - last_denied < 2h
| project UserPrincipalName, denied_count, last_denied, TimeGenerated, IPAddress

Cross-domain lateral movement using legitimate tokens

// Once an attacker has a valid session token they move laterally
// using legitimate cloud services and remote access tools
// Detection requires cross-correlating:
// 1. Which cloud resources did the account access?
// 2. Is this normal for this account?
// 3. Were any privileged operations performed?

// Microsoft Sentinel: anomalous cloud resource access
AuditLogs
| where TimeGenerated > ago(24h)
| where OperationName in (
 "Add member to role",
 "Add delegated permission grant",
 "Consent to application",
 "Add service principal credentials",
 "Reset user password"
)
| where InitiatedBy.user.userPrincipalName !in (known_admin_accounts)
| project TimeGenerated, OperationName, InitiatedBy, TargetResources

// Hunt for new OAuth app consents (common persistence method)
AuditLogs
| where OperationName == "Consent to application"
| where TimeGenerated > ago(7d)
| extend app_name=tostring(TargetResources[0].displayName)
| extend consented_by=tostring(InitiatedBy.user.userPrincipalName)
| where app_name !in (known_approved_apps)
| project TimeGenerated, consented_by, app_name