Detection rules › Kusto
Threat Essentials - User Assigned Privileged Role
Identifies when a new privileged role is assigned to a user. Any account eligible for a role is now being given privileged access. If the assignment is unexpected or into a role that isn't the responsibility of the account holder, investigate. Ref : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor-1
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Persistence |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Azure | any: Entra ID audit event (any operation) |
Rules detecting the same action
These rules filter on the same operation.
- [Entra ID] Application Assigned Administrator Permissions Immediately After Obtaining Role Management Permissions (Kusto)
- [Entra ID] Mass Privileged Role Change Activity Detected (Kusto)
- [Entra ID] Privilege Elevation Request Denied (Kusto)
- [Entra ID] Privileged Role Assigned to a New User (Kusto)
- [Entra ID] Privileged Role Assigned to User (Kusto)
- Account Elevated to New Role (Kusto)
- Admin promotion after Role Management Application Permission Grant (Kusto)
- App Assigned To Azure RBAC/Microsoft Entra Role (Sigma)
Rule body
id: b09795c9-8dce-47ab-8f75-5a4afb78ef0c
name: Threat Essentials - User Assigned Privileged Role
description: |
'Identifies when a new privileged role is assigned to a user. Any account eligible for a role is now being given privileged access. If the assignment is unexpected or into a role that isn't the responsibility of the account holder, investigate.
Ref : https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-privileged-accounts#things-to-monitor-1'
severity: High
status: Available
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 2h
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1078.004
tags:
- AADSecOpsGuide
query: |
AuditLogs
| where Category =~ "RoleManagement"
| where AADOperationType in~ ("Assign", "AssignEligibleRole")
| where ActivityDisplayName has_any ("Add eligible member to role", "Add member to role")
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties
| extend displayName_ = tostring(TargetResources_modifiedProperties.displayName)
| where displayName_ =~ "Role.DisplayName"
| extend RoleName = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue)))
| where RoleName contains "Admin"
| extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName))
| extend Target = tostring(TargetResources.userPrincipalName)
| summarize by bin(TimeGenerated, 1h), OperationName, RoleName, Target, Initiator, Result
| extend InitiatorName=split(Initiator, "@")[0], InitiatorUPNSuffix=split(Initiator, "@")[1]
| extend TargetName=split(Target, "@")[0], TargetUPNSuffix=split(Target, "@")[1]
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InitiatorName
- identifier: UPNSuffix
columnName: InitiatorUPNSuffix
- entityType: Account
fieldMappings:
- identifier: Name
columnName: TargetName
- identifier: UPNSuffix
columnName: TargetUPNSuffix
version: 1.0.3
kind: Scheduled
Stages and Predicates
Stage 1: source
AuditLogs
Stage 2: where
| where Category =~ "RoleManagement"
Stage 3: where
| where AADOperationType in~ ("Assign", "AssignEligibleRole")
Stage 4: where
| where ActivityDisplayName has_any ("Add eligible member to role", "Add member to role")
Stage 5: mv-expand
| mv-expand TargetResources
Stage 6: mv-expand
| mv-expand TargetResources.modifiedProperties
Stage 7: extend
| extend displayName_ = tostring(TargetResources_modifiedProperties.displayName)
Stage 8: where
| where displayName_ =~ "Role.DisplayName"
Stage 9: extend
| extend RoleName = tostring(parse_json(tostring(TargetResources_modifiedProperties.newValue)))
Stage 10: where
| where RoleName contains "Admin"
Stage 11: extend (3 consecutive steps)
| extend InitiatingApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
| extend Initiator = iif(isnotempty(InitiatingApp), InitiatingApp, tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName))
| extend Target = tostring(TargetResources.userPrincipalName)
Stage 12: summarize
| summarize by bin(TimeGenerated, 1h), OperationName, RoleName, Target, Initiator, Result
Stage 13: extend
| extend InitiatorName=split(Initiator, "@")[0], InitiatorUPNSuffix=split(Initiator, "@")[1]
Stage 14: extend
| extend TargetName=split(Target, "@")[0], TargetUPNSuffix=split(Target, "@")[1]
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
AADOperationType | in |
| field:"AADOperationType" kind:in |
ActivityDisplayName | match |
| field:"azure_ad::activity_display_name" kind:match |
Category | eq |
| field:"Category" kind:eq value:"RoleManagement" |
RoleName | contains |
| field:"RoleName" kind:contains value:"Admin" |
displayName_ | eq |
| field:"displayName_" kind:eq value:"Role.DisplayName" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Initiator | summarize |
OperationName | summarize |
Result | summarize |
RoleName | summarize |
Target | summarize |
InitiatorName | extend |
InitiatorUPNSuffix | extend |
TargetName | extend |
TargetUPNSuffix | extend |