Hunting for Impossible Travel and Anomalous Token Sign-Ins in Sentinel

Detect geographic anomalies, session cookie theft, and impossible travel patterns across cloud user logins using geospatial distance calculation functions in KQL.

Dikshant Lather
2 min read ·
Hunting for Impossible Travel and Anomalous Token Sign-Ins in Sentinel

Hunting for Impossible Travel and Anomalous Token Sign-Ins in Sentinel

When adversaries steal OAuth tokens or session cookies via adversary-in-the-middle (AiTM) phishing kits, multi-factor authentication (MFA) is already satisfied. The fastest way to spot active token reuse is through impossible travel speed anomalies.

This article details how to compute the physical velocity between consecutive logins using native KQL geospatial functions.


Prerequisites

  • Microsoft Entra ID SigninLogs ingested with latitude and longitude data populated under LocationDetails.

Advanced Geospatial KQL Detection

let timeWindow = 24h;
let maxRealisticSpeedKph = 900; // Typical commercial airliner cruising speed
SigninLogs
| where TimeGenerated >= ago(timeWindow)
| where ResultType == 0 // Only examine successful sign-ins
| extend Latitude = toreal(LocationDetails.geoCoordinates.latitude),
         Longitude = toreal(LocationDetails.geoCoordinates.longitude),
         City = tostring(LocationDetails.city),
         Country = tostring(LocationDetails.countryOrRegion)
| where isnotempty(Latitude) and isnotempty(Longitude)
| sort by UserPrincipalName asc, TimeGenerated asc
| serialize
| extend PrevTime = prev(TimeGenerated, 1),
         PrevLat = prev(Latitude, 1),
         PrevLon = prev(Longitude, 1),
         PrevCity = prev(City, 1),
         PrevUser = prev(UserPrincipalName, 1)
| where UserPrincipalName == PrevUser
| extend TimeDeltaHours = datetime_diff('second', TimeGenerated, PrevTime) / 3600.0
| where TimeDeltaHours > 0 and TimeDeltaHours < 6 // Look at tight sequential hops
| extend DistanceKm = geo_distance_2points(Longitude, Latitude, PrevLon, PrevLat) / 1000.0
| extend CalculatedSpeedKph = DistanceKm / TimeDeltaHours
| where CalculatedSpeedKph > maxRealisticSpeedKph and DistanceKm > 500
| project TimeGenerated, UserPrincipalName, IPAddress, City, Country, PrevCity, PrevTime, DistanceKm, CalculatedSpeedKph
| order by CalculatedSpeedKph desc

Technical Explanation

  • geo_distance_2points(): Calculates the great-circle geodesic distance in meters between two coordinate points.
  • serialize and prev(): Preserves chronological window order per user to calculate time and coordinate differences between sign-in event N and event N-1.
  • Speed Threshold: By filtering for speeds > 900 km/h over distances > 500 km, local cell tower bounces or nearby ISP rerouting are ignored.

Triage Playbook

  1. Check if the user activated a corporate VPN or ZTNA tunnel between requests.
  2. Verify device compliance status (DeviceDetail.isCompliant).
  3. If unmanaged and unexpected, immediately invoke Entra ID session revocation.

MITRE ATT&CK Mapping

  • Tactic: Defense Evasion (TA0005), Initial Access (TA0001)
  • Technique: Valid Accounts: Cloud Accounts (T1078.004), Steal Web Session Cookie (T1539)
Dikshant Lather
Written by

Dikshant Lather

Cyber Security & AI Architect

Responses (0)

Join the technical conversation or share implementation thoughts.

What are your thoughts?

Sign in to join the technical discussion or share feedback.

There are currently no responses for this story. Be the first to respond.