An adversary is likely leveraging impossible travel to move laterally within the environment while tampering with mailbox permissions to exfiltrate data and escalate privileges by adding an account to a PIM managed group. SOC teams should proactively hunt for this behavior as it indicates a multi-stage attack attempting to maintain persistence and gain elevated access.
KQL Query
SecurityAlert
| where AlertName == "Impossible travel activity"
| extend Extprop = parsejson(Entities)
| mv-expand Extprop
| extend Extprop = parsejson(Extprop)
| extend CmdLine = iff(Extprop['Type']=="process", Extprop['CommandLine'], '')
| extend File = iff(Extprop['Type']=="file", Extprop['Name'], '')
| extend Account = Extprop['Name']
| extend Domain = Extprop['UPNSuffix']
| extend Account = iif(isnotempty(Domain) and Extprop['Type']=="account", tolower(strcat(Account, "@", Domain)), iif(Extprop['Type']=="account", tolower(Account), ""))
| extend IpAddress = iff(Extprop["Type"] == "ip",Extprop['Address'], '')
| extend Process = iff(isnotempty(CmdLine), CmdLine, File)
| project TimeGenerated,Account,IpAddress,CompromisedEntity,Description,ProviderName,ResourceId
| join kind=inner
(
OfficeActivity
| where Operation =~ "Add-MailboxPermission"
| extend value = tostring(parse_json(Parameters)[3].Value)
| where value contains "FullAccess"
| where ResultStatus == "True"
| project Parameters,TimeGenerated,value,RecordType,Operation,OrganizationId,UserType,UserKey,OfficeWorkload,ResultStatus,OfficeObjectId,UserId,ClientIP,ExternalAccess,OriginatingServer,OrganizationName,TenantId,ElevationTime,SourceSystem,OfficeId,OfficeTenantId,Type,SourceRecordId
) on $left.Account == $right.UserId
| join kind=inner
(
AuditLogs
| where ActivityDisplayName =~ "Add eligible member to role in PIM requested (timebound)"
| where AADOperationType =~ "CreateRequestEligibleRole"
| where TargetResources has_any ("-PRIV", "Administrator", "Security")
| extend BuiltinRole = tostring(parse_json(TargetResources[0].displayName))
| extend CustomGroup = tostring(parse_json(TargetResources[3].displayName))
| extend TargetAccount = tostring(parse_json(TargetResources[2].displayName))
| extend Initiatedby = Identity
| project TimeGenerated, ActivityDisplayName, AADOperationType, Initiatedby, TargetAccount, BuiltinRole, CustomGroup, LoggedByService, Result, ResourceId, Id
| sort by TimeGenerated desc
) on $left.UserId == $right.Initiatedby
| extend AccountName = tostring(split(Initiatedby, "@")[0]), AccountUPNSuffix = tostring(split(Initiatedby, "@")[1])
| project AADOperationType, ActivityDisplayName,AccountName, AccountUPNSuffix, Id,ResourceId,IpAddress
id: 1399664f-9434-497c-9cde-42e4d74ae20e
name: Detecting Impossible travel with mailbox permission tampering & Privilege Escalation attempt
description: |
'This hunting query will alert on any Impossible travel activity in correlation with mailbox permission tampering followed by account being added to a PIM managed privileged group.
Ensure this impossible travel incident with increase of privileges is legitimate in your environment.'
severity: Medium
requiredDataConnectors:
- connectorId: AzureSecurityCenter
dataTypes:
- SecurityAlert (ASC)
- connectorId: Office365
dataTypes:
- OfficeActivity
- connectorId: AzureActivity
dataTypes:
- AzureActivity
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- InitialAccess
- PrivilegeEscalation
relevantTechniques:
- T1078
- T1548
query: |
SecurityAlert
| where AlertName == "Impossible travel activity"
| extend Extprop = parsejson(Entities)
| mv-expand Extprop
| extend Extprop = parsejson(Extprop)
| extend CmdLine = iff(Extprop['Type']=="process", Extprop['CommandLine'], '')
| extend File = iff(Extprop['Type']=="file", Extprop['Name'], '')
| extend Account = Extprop['Name']
| extend Domain = Extprop['UPNSuffix']
| extend Account = iif(isnotempty(Domain) and Extprop['Type']=="account", tolower(strcat(Account, "@", Domain)), iif(Extprop['Type']=="account", tolower(Account), ""))
| extend IpAddress = iff(Extprop["Type"] == "ip",Extprop['Address'], '')
| extend Process = iff(isnotempty(CmdLine), CmdLine, File)
| project TimeGenerated,Account,IpAddress,CompromisedEntity,Description,ProviderName,ResourceId
| join kind=inner
(
OfficeActivity
| where Operation =~ "Add-MailboxPermission"
| extend value = tostring(parse_json(Parameters)[3].Value)
| where value contains "FullAccess"
| where ResultStatus == "True"
| project Parameters,TimeGenerated,value,RecordType,Operation,OrganizationId,UserType,UserKey,OfficeWorkload,ResultStatus,OfficeObjectId,UserId,ClientIP,ExternalAccess,OriginatingServer,OrganizationName,TenantId,ElevationTime,SourceSystem,OfficeId,OfficeTenantId,Type,SourceRecordId
) on $left.Account == $right.UserId
| join kind=inner
(
AuditLogs
| where ActivityDisplayName =~ "Add eligible member to role in PIM requested (timebound)"
| where AADOperationType =~ "CreateRequestEligibleRole"
| where TargetResources has_any ("-PRIV", "Administrator", "Security")
| extend BuiltinRole = tostring(parse_json(TargetResources[0].displayName))
| extend CustomGroup = tostring(parse_json(TargetResources[3].displayName))
| extend TargetAccount = tostring(parse_json(TargetResources[2].displayName))
| extend Initiatedby = Identity
| project TimeGenerated, ActivityDisplayName, AADOperationType, Initiatedby, TargetAccount, BuiltinRole, CustomGroup, LoggedByService, Result, ResourceId, Id
| sort by TimeGenera
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
OfficeActivity | Ensure this data connector is enabled |
SecurityAlert | Ensure this data connector is enabled |
Scenario: Scheduled Backup Job with Mailbox Permissions Update
Description: A scheduled backup job runs and temporarily modifies mailbox permissions as part of its routine operation. This could be flagged as mailbox permission tampering.
Filter/Exclusion: Exclude activities originating from the backup tool (e.g., Veeam, Commvault) or tasks with known IDs associated with backup processes.
Scenario: Admin Task to Add User to PIM Group for Compliance
Description: An admin manually adds a user to a Privileged Identity Management (PIM) group as part of a compliance or access review process. This action may be flagged as a privilege escalation attempt.
Filter/Exclusion: Exclude activities where the user has Global Admin or PIM Admin permissions, or where the action is logged under a known compliance task (e.g., Azure AD Privileged Role Management).
Scenario: User Migration with Mailbox Permission Sync
Description: During a user migration (e.g., using Microsoft 365 Migration Tool or Exchange Online PowerShell), mailbox permissions are synchronized across environments, which could be mistaken for tampering.
Filter/Exclusion: Exclude activities involving migration tools or tasks with migration in the command or script name.
Scenario: System-Driven Privilege Adjustment for Security Compliance
Description: A security tool or SIEM system automatically adjusts mailbox permissions or adds an account to a PIM group as part of a security policy enforcement (e.g., Microsoft Defender for Identity or CrowdStrike).
Filter/Exclusion: Exclude actions initiated by known security tools or flagged with a system-generated or automated label in the event log.
Scenario: User Self-Service Access Request Approval
Description: A user requests access to a mailbox or privileged