Detection rules › Kusto

Dataverse - Hierarchy security manipulation

Status
available
Severity
medium
Time window
1d
Source
github.com/Azure/Azure-Sentinel

Identifies suspicious behaviors in hierarchy security including: - Hierarchy security disabled. - User assigns themselves as a manager. - User assigns themselves to a monitored position.

MITRE ATT&CK coverage

Telemetry coverage

Rule body

id: 2df0adf5-92a8-4ee0-a123-3eb5be1eed02
kind: Scheduled
name: Dataverse - Hierarchy security manipulation
description: |
  Identifies suspicious behaviors in hierarchy security including:
  - Hierarchy security disabled.
  - User assigns themselves as a manager.
  - User assigns themselves to a monitored position.
severity: Medium
status: Available
requiredDataConnectors:
  - connectorId: Dataverse
    dataTypes:
      - DataverseActivity
queryFrequency: 1h
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
  - PrivilegeEscalation
relevantTechniques:
  - T1548
  - T1078
query: |
  let monitored_position_ids = dynamic([
      // Enter a list of monitored position ID (guids)
      //"79380ac5-da2a-ed11-9db1-000d3a58d546"
      ]);
  let query_frequency = 1h;
  let security_disabled_events = DataverseActivity
      | where TimeGenerated >= ago(query_frequency)
      | where Message == "Update" and EntityName == "organization"
      | mv-expand Fields
      | where Fields.Name == "ishierarchicalsecuritymodelenabled"
      | where Fields.Value == "False"
      | extend Message = "Hierarchy security has been disabled"
      | project TimeGenerated, UserId, ClientIp, InstanceUrl, Message;
  let assign_self_as_manager_events = DataverseActivity
      | where TimeGenerated >= ago(query_frequency)
      | where Message == "Update" and EntityName == "systemuser"
      | mv-expand Fields
      | where Fields.Name == "parentsystemuserid"
      | extend ModifiedManager = tostring(Fields.Value)
      | where SystemUserId == ModifiedManager
      | extend Message = "User added self as manager of another user";
  let assign_self_to_position_events = DataverseActivity
      | where TimeGenerated >= ago(query_frequency)
      | where Message == "Update" and EntityName == "systemuser"
      | mv-expand Position = Fields
      | where Position.Name == "positionid" and tostring(Position.Value) in (monitored_position_ids)
      | mv-expand Target = Fields
      | where Target.Name == "systemuserid"
      | extend UserAssigned = tostring(Target.Value)
      | where SystemUserId == UserAssigned
      | extend
          Message = "User assigned self to a monitored position",
          PositionId = tostring(Position.Value);
  union
      security_disabled_events,
      assign_self_as_manager_events,
      assign_self_to_position_events
  | extend
      CloudAppId = int(32780),
      AccountName = tostring(split(UserId, '@')[0]),
      UPNSuffix = tostring(split(UserId, '@')[1])
  | project
      TimeGenerated,
      UserId,
      ClientIp,
      InstanceUrl,
      Message,
      PositionId,
      CloudAppId,
      AccountName,
      UPNSuffix
eventGroupingSettings:
  aggregationKind: AlertPerResult
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: UPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: ClientIp
  - entityType: CloudApplication
    fieldMappings:
      - identifier: AppId
        columnName: CloudAppId
      - identifier: InstanceName
        columnName: InstanceUrl
alertDetailsOverride:
  alertDisplayNameFormat: 'Dataverse - Suspicious hierarchy security modifications
    in {{InstanceUrl}} '
  alertDescriptionFormat: '{{Message}}. Events detected for user {{UserId}}.'
version: 3.2.0

Stages and Predicates

Stage 0: let

let monitored_position_ids = dynamic([
    ]);
let query_frequency = 1h;
let security_disabled_events = DataverseActivity <inlined as stages below>;
let assign_self_as_manager_events = DataverseActivity <inlined as stages below>;
let assign_self_to_position_events = DataverseActivity <inlined as stages below>;

Stage 1: union

union of 3 branches

Stage 2: source

DataverseActivity

Stage 3: where

| where TimeGenerated >= ago(query_frequency)

Stage 4: where

| where Message == "Update" and EntityName == "organization"

Stage 5: mv-expand

| mv-expand Fields

Stage 6: where

| where Fields.Name == "ishierarchicalsecuritymodelenabled"

Stage 7: where

| where Fields.Value == "False"

Stage 8: extend

| extend Message = "Hierarchy security has been disabled"

Stage 9: project

| project TimeGenerated, UserId, ClientIp, InstanceUrl, Message

Stage 10: source

DataverseActivity

Stage 11: where

| where TimeGenerated >= ago(query_frequency)

Stage 12: where

| where Message == "Update" and EntityName == "systemuser"

Stage 13: mv-expand

| mv-expand Fields

Stage 14: where

| where Fields.Name == "parentsystemuserid"

Stage 15: extend

| extend ModifiedManager = tostring(Fields.Value)

Stage 16: where

| where SystemUserId == ModifiedManager

Stage 17: extend

| extend Message = "User added self as manager of another user"

Stage 18: source

DataverseActivity

Stage 19: where

| where TimeGenerated >= ago(query_frequency)

Stage 20: where

| where Message == "Update" and EntityName == "systemuser"

Stage 21: mv-expand

| mv-expand Position = Fields

Stage 22: where

| where Position.Name == "positionid" and tostring(Position.Value) in (monitored_position_ids)

Stage 23: mv-expand

| mv-expand Target = Fields

Stage 24: where

| where Target.Name == "systemuserid"

Stage 25: extend

| extend UserAssigned = tostring(Target.Value)

Stage 26: where

| where SystemUserId == UserAssigned

Stage 27: extend

| extend
        Message = "User assigned self to a monitored position",
        PositionId = tostring(Position.Value)

Stage 28: extend

extend AccountName, CloudAppId, UPNSuffix

Stage 29: project

project AccountName, ClientIp, CloudAppId, InstanceUrl, Message, PositionId, TimeGenerated, UPNSuffix, UserId

Indicators

These rows show field, operator, and value matches.

FieldKindValuesSearch
EntityNameeq
  • organization
  • systemuser
field:"EntityName" kind:eq
Messageeq
  • Update
field:"Message" kind:eq value:"Update"
Nameeq
  • ishierarchicalsecuritymodelenabled
  • parentsystemuserid
  • positionid
  • systemuserid
field:"Name" kind:eq
SystemUserIdcross_field_compare
  • ModifiedManager transforms: op:eq
  • UserAssigned transforms: op:eq
field:"SystemUserId" kind:cross_field_compare
Valueeq
  • False
field:"Value" kind:eq value:"False"
Valuein
  • [] transforms: tostring
field:"Value" kind:in value:"[]"

Output fields

These fields are emitted when the rule matches.

FieldSource
AccountNameproject
ClientIpproject
CloudAppIdproject
InstanceUrlproject
Messageproject
PositionIdproject
TimeGeneratedproject
UPNSuffixproject
UserIdproject