Query Details
id: e5f6a7b8-c9d0-1e2f-3a4b-5c6d7e8f9a0b
name: ROPC Impossible Travel - Multiple Countries via Password Grant
version: 1.0.0
kind: Scheduled
description: |
Detects the same user successfully authenticating via ROPC from two or more distinct
countries inside a 1-hour window. Because ROPC requires the cleartext password on every
call, multi-country activity within an hour implies parallel use of stolen credentials
from different attacker locations (or a compromised script running from multiple egress
points).
Trigger: >= 2 distinct Location values for the same UPN inside 1 hour.
Tuning:
- LegitRopcApps suppresses known-good ROPC clients.
- Allowlist IPs are stripped via ExcludeAllowlistedIPs_AADNI(). Add corporate
VPN egress IPs to NetworkAllowlist if multi-country VPN clusters cause noise.
MITRE ATT&CK: T1078 (Valid Accounts), T1550 (Use Alternate Auth Material)
severity: High
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AADNonInteractiveUserSignInLogs
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- CredentialAccess
relevantTechniques:
- T1078
- T1550
query: |
let LegitRopcApps = dynamic([
"Microsoft Authentication Broker",
"Microsoft Intune Company Portal",
"Azure AD Connect",
"Microsoft Office",
"Microsoft Office Authentication Broker"
]);
AADNonInteractiveUserSignInLogs
| invoke ExcludeAllowlistedIPs_AADNI()
| where TimeGenerated > ago(1h)
| where AuthenticationProtocol =~ "ropc"
| where ResultType == 0
| where AppDisplayName !in~ (LegitRopcApps)
| where isnotempty(Location)
| summarize
Count = count(),
Countries = make_set(Location),
CountryCount = dcount(Location),
IPs = make_set(IPAddress),
Apps = make_set(AppDisplayName),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by UserPrincipalName
| where CountryCount >= 2
| extend IPAddress = tostring(IPs[0])
| order by CountryCount desc, Count desc
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: UserPrincipalName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPAddress
customDetails:
SignInCount: Count
CountryCount: CountryCount
Countries: Countries
Apps: Apps
alertDetailsOverride:
alertDisplayNameFormat: "ROPC impossible travel for {{UserPrincipalName}} ({{CountryCount}} countries / 1h)"
alertDescriptionFormat: "User {{UserPrincipalName}} authenticated via ROPC from {{CountryCount}} countries ({{Countries}}) within 1 hour. ROPC bypasses MFA - strong account-takeover signal."
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: true
reopenClosedIncident: false
lookbackDuration: PT5H
matchingMethod: AnyAlert
groupByEntities:
- Account
groupByAlertDetails: []
groupByCustomDetails: []
This query is designed to detect suspicious login activity using the Resource Owner Password Credentials (ROPC) flow in Azure Active Directory. Here's a simple breakdown of what it does:
Purpose: It identifies cases where the same user successfully logs in from two or more different countries within a one-hour period using the ROPC authentication method. This could indicate that the user's credentials have been stolen and are being used by attackers in different locations.
How It Works:
Alerting:
Additional Features:
Overall, this query helps security teams identify potential account compromises by detecting unusual login patterns that suggest credential theft and misuse.

David Alonso
Released: May 29, 2026
Tables
Keywords
Operators