Detection rules › Kusto

Insider Risk_Sensitive Data Access Outside Organizational Geo-location

Severity
high
Time window
6h
Group by
Activity_s, City, Country_Region, LabelName_s, State, TimeGenerated, UserPrincipalName
Source
github.com/Azure/Azure-Sentinel

'This alert joins Azure Information Protection Logs (InformationProtectionLogs_CL) with Microsoft Entra ID Sign in Logs (SigninLogs) to provide a correlation of sensitive data access by geo-location. Results include User Principal Name, Label Name, Activity, City, State, Country/Region, and Time Generated. Recommended configuration is to include (or exclude) Sign in geo-locations (City, State, Country and/or Region) for trusted organizational locations. There is an option for configuration of correlations against Microsoft Sentinel watchlists. Accessing sensitive data from a new or unauthorized geo-location warrants further review. For more information see Sign-in logs in Microsoft Entra ID: Location Filtering'

MITRE ATT&CK coverage

TacticTechniques
ExfiltrationT1567 Exfiltration Over Web Service

Rule body kusto

id: b81ed294-28cf-48c3-bac8-ac60dcef293b
name: Insider Risk_Sensitive Data Access Outside Organizational Geo-location
description: |
  'This alert joins Azure Information Protection Logs (InformationProtectionLogs_CL) with Microsoft Entra ID Sign in Logs (SigninLogs) to provide a correlation of sensitive data access by geo-location. Results include User Principal Name, Label Name, Activity, City, State, Country/Region, and Time Generated. Recommended configuration is to include (or exclude) Sign in geo-locations (City, State, Country and/or Region) for trusted organizational locations. There is an option for configuration of correlations against Microsoft Sentinel watchlists. Accessing sensitive data from a new or unauthorized geo-location warrants further review. For more information see [Sign-in logs in Microsoft Entra ID: Location Filtering](https://docs.microsoft.com/azure/active-directory/reports-monitoring/concept-sign-ins)'
severity: High
requiredDataConnectors:
  - connectorId: AzureInformationProtection
    dataTypes:
      - InformationProtectionLogs_CL 
  - connectorId: AzureActiveDirectory
    dataTypes:
      - SigninLogs 
queryFrequency: 6h
queryPeriod: 6h
triggerOperator: gt
triggerThreshold: 0
tactics:
  - Exfiltration
relevantTechniques:
  - T1567
query: |
  InformationProtectionLogs_CL
  | extend UserPrincipalName = UserId_s
  | where LabelName_s <> ""
  | join kind=inner (SigninLogs) on UserPrincipalName
  | extend City = tostring(LocationDetails.city)
  // | where City <> "New York" // Configure Location Details within Organizational Requirements
  | extend State = tostring(LocationDetails.state)
  // | where State <> "Texas" // Configure Location Details within Organizational Requirements
  | extend Country_Region = tostring(LocationDetails.countryOrRegion)
  // | where Country_Region <> "US" // Configure Location Details within Organizational Requirements
  // | lookup kind=inner _GetWatchlist('<Your Watchlist Name>') on $left.UserPrincipalName == $right.SearchKey
  | summarize count() by UserPrincipalName, LabelName_s, Activity_s, City, State, Country_Region, TimeGenerated
  | sort by count_ desc
  | extend AccountName = tostring(split(UserPrincipalName, "@")[0]), AccountUPNSuffix = tostring(split(UserPrincipalName, "@")[1])
eventGroupingSettings:
  aggregationKind: SingleAlert
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: UserPrincipalName
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
incidentConfiguration:
  createIncident: true
  groupingConfiguration:
    enabled: true
    reopenClosedIncident: true
    lookbackDuration: 3d
    matchingMethod: Selected
    groupByEntities:
      - Account
version: 1.1.3
kind: Scheduled

Stages and Predicates

Stage 1: source

InformationProtectionLogs_CL

Stage 2: extend

| extend UserPrincipalName = UserId_s

Stage 3: where

| where LabelName_s <> ""

Stage 4: join

| join kind=inner (SigninLogs) on UserPrincipalName

Stage 5: extend (3 consecutive steps)

| extend City = tostring(LocationDetails.city)
| extend State = tostring(LocationDetails.state)
| extend Country_Region = tostring(LocationDetails.countryOrRegion)

Stage 6: summarize

| summarize count() by UserPrincipalName, LabelName_s, Activity_s, City, State, Country_Region, TimeGenerated

Stage 7: sort

| sort by count_ desc

Stage 8: extend

| extend AccountName = tostring(split(UserPrincipalName, "@")[0]), AccountUPNSuffix = tostring(split(UserPrincipalName, "@")[1])

Output fields

Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.

FieldSource
Activity_ssummarize
Citysummarize
Country_Regionsummarize
LabelName_ssummarize
Statesummarize
TimeGeneratedsummarize
UserPrincipalNamesummarize
AccountNameextend
AccountUPNSuffixextend