Query Details
id: f6a7b8c9-d0e1-4f2a-3b4c-5d6e7f8a9b0c
name: "SigninLogs — Concurrent Sessions from Multiple Countries (Same User)"
version: 1.0.0
kind: Scheduled
description: |
Detects a single user successfully signing in from 2 or more distinct countries within a 30-minute window. Unlike ML-based impossible travel this is deterministic, requires no Entra ID P2, and catches concurrent attacker + victim sessions running in parallel from different geos. MITRE ATT&CK: T1078 (Valid Accounts).
severity: High
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- SigninLogs
queryFrequency: PT1H
queryPeriod: PT1H
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- CredentialAccess
relevantTechniques:
- T1078
query: |
// ---- Network Allowlist (exclude trusted IPs / CIDR / ranges) --------------
let _allow = materialize(union isfuzzy=true (print R="" | take 0), (_GetWatchlist('NetworkAllowlist') | project R = tostring(IPOrRange)) | where isnotempty(R));
let _allowCIDR = toscalar(_allow | where not(R matches regex @'^\d+\.\d+\.\d+\.\d+-\d+\.\d+\.\d+\.\d+$') | extend R = iff(R has '/', R, strcat(R, '/32')) | summarize make_list(R));
let _allowRange = toscalar(_allow | where R matches regex @'^\d+\.\d+\.\d+\.\d+-\d+\.\d+\.\d+\.\d+$' | summarize make_list(R));
let _ExcludeAllowlistedIPs = (T:(IPAddress:string)) {
T
| extend IPAddress = tostring(IPAddress)
| where array_length(_allowCIDR) == 0 or isnull(ipv4_is_in_any_range(IPAddress, _allowCIDR)) or not(ipv4_is_in_any_range(IPAddress, _allowCIDR))
| mv-apply _r = _allowRange to typeof(string) on (
extend _lo = tostring(split(_r,'-')[0]), _hi = tostring(split(_r,'-')[1])
| extend _inRange = ipv4_compare(IPAddress, _lo) >= 0 and ipv4_compare(IPAddress, _hi) <= 0
| summarize _anyInRange = max(toint(_inRange)))
| where isnull(_anyInRange) or _anyInRange == 0
| project-away _anyInRange
};
// ---------------------------------------------------------------------------
let lookback = 1h;
let maxWindowM = 30;
SigninLogs
| invoke _ExcludeAllowlistedIPs()
| where TimeGenerated > ago(lookback)
| where ResultType == "0"
| where isnotempty(Location) and Location != "Unknown"
| summarize
UniqueCountries = dcount(Location),
Countries = make_set(Location, 10),
SourceIPs = make_set(IPAddress, 10),
Apps = make_set(AppDisplayName, 5),
FirstSignIn = min(TimeGenerated),
LastSignIn = max(TimeGenerated)
by UserPrincipalName
| where UniqueCountries >= 2
| extend WindowMinutes = datetime_diff("minute", LastSignIn, FirstSignIn)
| where WindowMinutes <= maxWindowM
| project
TimeGenerated = FirstSignIn,
UserPrincipalName, UniqueCountries,
Countries, SourceIPs, WindowMinutes,
Apps, LastSignIn
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
customDetails:
UniqueCountries: UniqueCountries
Countries: Countries
WindowMinutes: WindowMinutes
alertDetailsOverride:
alertDisplayNameFormat: "Concurrent Multi-Country Sessions — {{UserPrincipalName}} in {{UniqueCountries}} countries ({{WindowMinutes}}min)"
alertDescriptionFormat: "User {{UserPrincipalName}} authenticated from {{UniqueCountries}} different countries within {{WindowMinutes}} minutes — possible concurrent attacker session."
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT1H
matchingMethod: AllEntities
groupByEntities:
- Account
This query is designed to detect suspicious login activity by identifying instances where a single user successfully signs in from two or more different countries within a 30-minute window. This could indicate potential unauthorized access, such as an attacker using the same credentials as the legitimate user but from a different location.
Here's a simple breakdown of the query's components:
Network Allowlist: The query first defines a list of trusted IP addresses or ranges (allowlist) to exclude them from the analysis. This helps in focusing only on potentially suspicious activities.
Data Source: It uses data from Azure Active Directory's SigninLogs to analyze user sign-ins.
Time Frame: The query looks at sign-in activities within the last hour (lookback) and checks if multiple sign-ins occurred within a 30-minute window (maxWindowM).
Filter Criteria:
ResultType == "0").Analysis:
Output: If such activity is detected, it generates an alert with details like the user's name, the number of countries, the IP addresses used, the applications accessed, and the time of the first and last sign-in.
Alert Configuration: The alert is configured to create an incident if such activity is detected, with details formatted to highlight the user's name, the number of countries involved, and the time window of the activity.
Overall, this query helps in identifying potential security threats by flagging unusual sign-in patterns that could indicate concurrent sessions from different geographical locations, possibly involving an attacker.

David Alonso
Released: April 20, 2026
Tables
Keywords
Operators