Detection rules › Kusto

Power Platform - DLP policy updated or removed

Status
available
Severity
low
Time window
1d
Group by
EventOriginalUid, PolicyId, TimeGenerated
Source
github.com/Azure/Azure-Sentinel

Identifies changes to DLP policy, specifically policies which are updated or removed.

MITRE ATT&CK coverage

TacticTechniques
Stealth

Telemetry coverage

Rule body

id: 1b2e6172-85c5-417a-90c3-7cc80cb787f5
kind: Scheduled
name: Power Platform - DLP policy updated or removed
description: Identifies changes to DLP policy, specifically policies which are updated
  or removed.
severity: Low
status: Available
requiredDataConnectors:
  - connectorId: PowerPlatformAdmin
    dataTypes:
      - PowerPlatformAdminActivity
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - DefenseEvasion
relevantTechniques:
  - T1480
query: |
  let create_policy_ignore_time_window = 10m;
  let query_frequency = 1h;
  let dlp_policy_events = PowerPlatformAdminActivity
      | where TimeGenerated >= ago(query_frequency)
      | where EventOriginalType == "GovernanceApiPolicyOperation"
      | where PropertyCollection has_any ("DeleteDlpPolicy", "UpdateDlpPolicy", "CreateDlpPolicy")
      | mv-expand PropertyCollection
      | extend
          Name = tostring(PropertyCollection.Name),
          Value = tostring(PropertyCollection.Value)
      | summarize Properties = make_bag(bag_pack(Name, Value))
          by
          TimeGenerated,
          EventOriginalUid
      | extend
          PolicyName = tostring(Properties['powerplatform.analytics.resource.display_name']),
          EventType = tostring(Properties['powerplatform.analytics.resource.tenant.governance.api_policy.operation_name']),
          ActorName = tostring(Properties['enduser.principal_name']),
          PolicyId = tostring(Properties['powerplatform.analytics.resource.id']),
          AdditionalInfo = Properties['powerplatform.analytics.resource.tenant.governance.api_policy.additional_resources'];
  let delete_events = dlp_policy_events
      | where EventType == "DeleteDlpPolicy";
  let update_events = dlp_policy_events
      | where EventType == "UpdateDlpPolicy";
  let create_events = dlp_policy_events
      | where EventType == "CreateDlpPolicy"
      | extend ignore_time = TimeGenerated + create_policy_ignore_time_window;
  union
      delete_events,
      (update_events
      | join kind=leftouter (
          create_events
          | project-away TimeGenerated
          )
          on PolicyId
      | where isempty(ignore_time) or TimeGenerated > ignore_time
      | project-away ignore_time)
  | where TimeGenerated >= ago(query_frequency)
  | extend
      AccountName = tostring(split(ActorName, "@")[0]),
      UPNSuffix = tostring(split(ActorName, "@")[1])
  | project
      TimeGenerated,
      ActorName,
      EventType,
      PolicyName,
      PolicyId,
      AccountName,
      UPNSuffix,
      AdditionalInfo
eventGroupingSettings:
  aggregationKind: SingleAlert
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: UPNSuffix
alertDetailsOverride:
  alertDisplayNameFormat: PowerPlatform - DLP policy {{EventType}} event detected.
  alertDescriptionFormat: A DLP policy {{PolicyName}} was as modfiied or deleted.
    Event type {{EventType}}
customDetails:
  Policy: PolicyId
  PolicyName: PolicyName
version: 3.2.0

Stages and Predicates

Parameters

let create_policy_ignore_time_window = 10m;
let query_frequency = 1h;

let dlp_policy_events and let update_events are inlined into the numbered stages below.

Let binding: delete_events

let delete_events = dlp_policy_events
    | where EventType == "DeleteDlpPolicy";

Let binding: create_events used in Stage 20

let create_events = dlp_policy_events
    | where EventType == "CreateDlpPolicy"
    | extend ignore_time = TimeGenerated + create_policy_ignore_time_window;

Stage 1: union

union of 2 branches

Stage 2: source

PowerPlatformAdminActivity

Stage 3: where

where TimeGenerated >= ago(3600s)

Stage 4: where

where EventOriginalType =~ "GovernanceApiPolicyOperation"

Stage 5: where

where (PropertyCollection contains "DeleteDlpPolicy" or PropertyCollection contains "UpdateDlpPolicy" or PropertyCollection contains "CreateDlpPolicy")

Stage 6: mv-expand

mv-expand PropertyCollection

Stage 7: extend

extend Name, Value

Stage 8: summarize

summarize Properties by TimeGenerated, EventOriginalUid

Stage 9: extend

extend ActorName, AdditionalInfo, EventType, PolicyId, PolicyName

Stage 10: where

where EventType =~ "DeleteDlpPolicy"

Stage 11: source

PowerPlatformAdminActivity

Stage 12: where

where TimeGenerated >= ago(3600s)

Stage 13: where

where EventOriginalType =~ "GovernanceApiPolicyOperation"

Stage 14: where

where (PropertyCollection contains "DeleteDlpPolicy" or PropertyCollection contains "UpdateDlpPolicy" or PropertyCollection contains "CreateDlpPolicy")

Stage 15: mv-expand

mv-expand PropertyCollection

Stage 16: extend

extend Name, Value

Stage 17: summarize

summarize Properties by TimeGenerated, EventOriginalUid

Stage 18: extend

extend ActorName, AdditionalInfo, EventType, PolicyId, PolicyName

Stage 19: where

where EventType =~ "UpdateDlpPolicy"

Stage 20: join

join kind=leftouter (create_events) on PolicyId

Stage 21: where

where (TimeGenerated > ignore_time or isempty(ignore_time))

Stage 22: project-away

project-away ignore_time

Stage 23: where

where TimeGenerated >= ago(3600s)

Stage 24: extend

extend AccountName, UPNSuffix

Stage 25: project

project AccountName, ActorName, AdditionalInfo, EventType, PolicyId, PolicyName, TimeGenerated, UPNSuffix

Stage 26: summarize aggregation inside the join branch

summarize by TimeGenerated, EventOriginalUid

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
EventOriginalTypeeq
  • GovernanceApiPolicyOperation
field:"EventOriginalType" kind:eq value:"GovernanceApiPolicyOperation"
EventTypeeq
  • CreateDlpPolicy
  • DeleteDlpPolicy
  • UpdateDlpPolicy
field:"EventType" kind:eq
PropertyCollectionmatch
  • CreateDlpPolicy transforms: term
  • DeleteDlpPolicy transforms: term
  • UpdateDlpPolicy transforms: term
field:"PropertyCollection" kind:match
TimeGeneratedcross_field_compare
  • ignore_time transforms: op:gt
field:"TimeGenerated" kind:cross_field_compare value:"ignore_time"
ignore_timeis_null
  • (no value, null check)
field:"ignore_time" kind:is_null

Output fields

These fields are emitted when the rule matches.

FieldSource
EventOriginalUidsummarize
TimeGeneratedsummarize