Detection rules › Kusto
[Entra ID] Privilege Elevation Request Denied
Detects denied privilege elevation requests in Microsoft Entra ID. Review the requester and the target workflow for possible abuse or misconfiguration.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Initial Access | |
| Persistence | |
| Privilege Escalation | |
| Stealth |
Telemetry coverage
| Platform | Record / event type |
|---|---|
| Azure | Add member to role request denied (PIM activation) |
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] 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)
- Azure AD Application Administrator Role Assigned (Splunk)
Rule body
id: aceee46e-8fb3-42d9-967a-aac637bcefd4
name: "[Entra ID] Privilege Elevation Request Denied"
version: 1.0.0
kind: Scheduled
description: |
Detects denied privilege elevation requests in Microsoft Entra ID. Review the requester and the target workflow for possible abuse or misconfiguration.
severity: High
status: Available
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 2h
queryPeriod: 2h
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
- PrivilegeEscalation
- DefenseEvasion
- InitialAccess
relevantTechniques:
- T1078.004
query: |
AuditLogs
| where ActivityDisplayName =~ 'Add member to role request denied (PIM activation)'
| mv-apply ResourceItem = TargetResources on
(
where ResourceItem.type =~ "Role"
| extend Role = trim(@'"', tostring(ResourceItem.displayName))
)
| mv-apply ResourceItem = TargetResources on
(
where ResourceItem.type =~ "User"
| extend TargetUserPrincipalName = trim(@'"', tostring(ResourceItem.userPrincipalName))
)
//| where ResultReason != "RoleAssignmentExists"
| where isnotempty(InitiatedBy.user)
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
| extend
TargetName = tostring(split(TargetUserPrincipalName, '@', 0)[0]),
TargetUPNSuffix = tostring(split(TargetUserPrincipalName, '@', 1)[0])
| extend
InitiatedByName = tostring(split(InitiatingUserPrincipalName, '@', 0)[0]),
InitiatedByUPNSuffix = tostring(split(InitiatingUserPrincipalName, '@', 1)[0])
| project-reorder
TimeGenerated,
TargetUserPrincipalName,
Role,
OperationName,
Result,
ResultDescription
| extend
InitiatingUser = tostring(InitiatedBy.user.userPrincipalName)
| extend Source_Network_IPLocation = ""
| project
Alert_Category_en = "Entra ID",
Alert_SubCategory_en = "Anomaly Identity Privilege Modification",
Alert_Name_en = "Privilege Elevation Request Denied",
Alert_Description_en=strcat(
"At Taiwan time: ",
format_datetime(datetime_utc_to_local(TimeGenerated, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
" in Entra ID: ",
"",
", detected PIM role activation failure: target user: ",
iff(isnotempty(TargetUserPrincipalName), TargetUserPrincipalName, "<NoTargetUser>"),
", target role: ",
iff(isnotempty(Role), Role, "<NoRole>"),
", initiator: ",
iff(isnotempty(InitiatingUser), InitiatingUser, "<NoInitiator>"),
", source IP: ",
iff(isnotempty(InitiatingIpAddress), InitiatingIpAddress, "<NoIP>"),
", result: ",
iff(isnotempty(Result), Result, "<NoResult>"),
" (reason: ",
iff(isnotempty(ResultDescription), ResultDescription, "<NoReason>"),
")."
),
Alert_TriageStep_en=strcat(
"1. Confirm the activation target: user: ",
iff(isnotempty(TargetUserPrincipalName), TargetUserPrincipalName, "<NoTargetUser>"),
", role: ",
iff(isnotempty(Role), Role, "<NoRole>"),
" is an expected PIM activation request.",
"2. Check the failure reason: ",
iff(isnotempty(ResultDescription), ResultDescription, "<NoReason>"),
", and determine whether it was caused by MFA/Conditional Access/approval process/insufficient permissions.",
"3. Check source risk: ",
iff(isnotempty(InitiatingUser), InitiatingUser, "<NoInitiator>"),
", IP:",
iff(isnotempty(InitiatingIpAddress), InitiatingIpAddress, "<NoIP>"),
" to determine whether it is a company named location/VPN/jump server, abnormal location, or uncommon source."
),
Alert_Containment_en=strcat(
"1. If determined to be a suspicious attempt, immediately restrict initiator: ",
iff(isnotempty(InitiatingUser), InitiatingUser, "<NoInitiator>"),
" 's PIM activation permissions or suspend the scope of high-risk roles that can be activated. ",
"2. Immediately revoke suspicious sign-in tokens/sessions and force re-authentication (initiator: ",
iff(isnotempty(InitiatingUser), InitiatingUser, "<NoInitiator>"),
"), and reset the password and re-register MFA if necessary. ",
"3. Apply stricter Conditional Access to source IP: ",
iff(isnotempty(InitiatingIpAddress), InitiatingIpAddress, "<NoIP>"),
" (named locations/compliant devices/MFA only), or block it first to stop repeated attempts. ",
"4. If the failure was caused by the approval process/policy, suspend activation requests outside the change window and notify administrators for confirmation."
),
Alert_Remediation_en=strcat(
"1. Strengthen PIM governance: require approval and justification for high-privilege role activation, and limit the scope of activatable roles (least privilege/separation of duties). ",
"2. Strengthen Conditional Access: enforce MFA, compliant devices, and named locations for PIM/management-plane operations, and directly block abnormal IPs/locations. ",
"3. Establish alerts and automated response: set thresholds and automated SOAR for PIM activation failures (notification, IP blocking, account suspension). "
),
Alert_Time_TW = datetime_utc_to_local(TimeGenerated, 'Asia/Taipei'),
Alert_Time_UTC0 = TimeGenerated,
Event_Action = OperationName,
Event_Status = Result,
Event_Description = ResultDescription,
Source_Identity_FullName = InitiatingUser,
Source_Identity_ID = InitiatingAadUserId,
// Source_Identity_Name = InitiatingName,
Source_Identity_Type = iff(isnotempty(InitiatingUser), "User", "Service"),
Source_Network_IPAddress = InitiatingIpAddress,
Target_Identity_FullName = TargetUserPrincipalName,
Source_Resource_ID = InitiatingAppServicePrincipalId,
Source_Resource_Name = InitiatingAppName,
//Target_Identity_Name = InvitedUserName,
Target_Identity_Type = "User",
Target_Identity_DomainType = iff(TargetUserPrincipalName contains "EXT", 'External', 'Internal'),
Target_Resource_ID = "",
Target_Resource_Name = "Microsoft Entra ID",
Target_Resource_Type = "Microsoft Entra ID"
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Source_Identity_FullName
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: Target_Identity_FullName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: Source_Network_IPAddress
Stages and Predicates
Stage 1: source
AuditLogs
Stage 2: where
| where ActivityDisplayName =~ 'Add member to role request denied (PIM activation)'
Stage 3: kusto:mv-apply
| mv-apply ResourceItem = TargetResources on
(
where ResourceItem.type =~ "Role"
| extend Role = trim(@'"', tostring(ResourceItem.displayName))
)
Stage 4: kusto:mv-apply
| mv-apply ResourceItem = TargetResources on
(
where ResourceItem.type =~ "User"
| extend TargetUserPrincipalName = trim(@'"', tostring(ResourceItem.userPrincipalName))
)
Stage 5: where
| where isnotempty(InitiatedBy.user)
Stage 6: extend (7 consecutive steps)
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))
| extend
TargetName = tostring(split(TargetUserPrincipalName, '@', 0)[0]),
TargetUPNSuffix = tostring(split(TargetUserPrincipalName, '@', 1)[0])
| extend
InitiatedByName = tostring(split(InitiatingUserPrincipalName, '@', 0)[0]),
InitiatedByUPNSuffix = tostring(split(InitiatingUserPrincipalName, '@', 1)[0])
Stage 7: project-reorder
| project-reorder
TimeGenerated,
TargetUserPrincipalName,
Role,
OperationName,
Result,
ResultDescription
Stage 8: extend
| extend
InitiatingUser = tostring(InitiatedBy.user.userPrincipalName)
Stage 9: extend
| extend Source_Network_IPLocation = ""
Stage 10: project
| project
Alert_Category_en = "Entra ID",
Alert_SubCategory_en = "Anomaly Identity Privilege Modification",
Alert_Name_en = "Privilege Elevation Request Denied",
Alert_Description_en=strcat(
"At Taiwan time: ",
format_datetime(datetime_utc_to_local(TimeGenerated, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"),
" in Entra ID: ",
"",
", detected PIM role activation failure: target user: ",
iff(isnotempty(TargetUserPrincipalName), TargetUserPrincipalName, "<NoTargetUser>"),
", target role: ",
iff(isnotempty(Role), Role, "<NoRole>"),
", initiator: ",
iff(isnotempty(InitiatingUser), InitiatingUser, "<NoInitiator>"),
", source IP: ",
iff(isnotempty(InitiatingIpAddress), InitiatingIpAddress, "<NoIP>"),
", result: ",
iff(isnotempty(Result), Result, "<NoResult>"),
" (reason: ",
iff(isnotempty(ResultDescription), ResultDescription, "<NoReason>"),
")."
),
Alert_TriageStep_en=strcat(
"1. Confirm the activation target: user: ",
iff(isnotempty(TargetUserPrincipalName), TargetUserPrincipalName, "<NoTargetUser>"),
", role: ",
iff(isnotempty(Role), Role, "<NoRole>"),
" is an expected PIM activation request.",
"2. Check the failure reason: ",
iff(isnotempty(ResultDescription), ResultDescription, "<NoReason>"),
", and determine whether it was caused by MFA/Conditional Access/approval process/insufficient permissions.",
"3. Check source risk: ",
iff(isnotempty(InitiatingUser), InitiatingUser, "<NoInitiator>"),
", IP:",
iff(isnotempty(InitiatingIpAddress), InitiatingIpAddress, "<NoIP>"),
" to determine whether it is a company named location/VPN/jump server, abnormal location, or uncommon source."
),
Alert_Containment_en=strcat(
"1. If determined to be a suspicious attempt, immediately restrict initiator: ",
iff(isnotempty(InitiatingUser), InitiatingUser, "<NoInitiator>"),
" 's PIM activation permissions or suspend the scope of high-risk roles that can be activated. ",
"2. Immediately revoke suspicious sign-in tokens/sessions and force re-authentication (initiator: ",
iff(isnotempty(InitiatingUser), InitiatingUser, "<NoInitiator>"),
"), and reset the password and re-register MFA if necessary. ",
"3. Apply stricter Conditional Access to source IP: ",
iff(isnotempty(InitiatingIpAddress), InitiatingIpAddress, "<NoIP>"),
" (named locations/compliant devices/MFA only), or block it first to stop repeated attempts. ",
"4. If the failure was caused by the approval process/policy, suspend activation requests outside the change window and notify administrators for confirmation."
),
Alert_Remediation_en=strcat(
"1. Strengthen PIM governance: require approval and justification for high-privilege role activation, and limit the scope of activatable roles (least privilege/separation of duties). ",
"2. Strengthen Conditional Access: enforce MFA, compliant devices, and named locations for PIM/management-plane operations, and directly block abnormal IPs/locations. ",
"3. Establish alerts and automated response: set thresholds and automated SOAR for PIM activation failures (notification, IP blocking, account suspension). "
),
Alert_Time_TW = datetime_utc_to_local(TimeGenerated, 'Asia/Taipei'),
Alert_Time_UTC0 = TimeGenerated,
Event_Action = OperationName,
Event_Status = Result,
Event_Description = ResultDescription,
Source_Identity_FullName = InitiatingUser,
Source_Identity_ID = InitiatingAadUserId,
Source_Identity_Type = iff(isnotempty(InitiatingUser), "User", "Service"),
Source_Network_IPAddress = InitiatingIpAddress,
Target_Identity_FullName = TargetUserPrincipalName,
Source_Resource_ID = InitiatingAppServicePrincipalId,
Source_Resource_Name = InitiatingAppName,
Target_Identity_Type = "User",
Target_Identity_DomainType = iff(TargetUserPrincipalName contains "EXT", 'External', 'Internal'),
Target_Resource_ID = "",
Target_Resource_Name = "Microsoft Entra ID",
Target_Resource_Type = "Microsoft Entra ID"
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActivityDisplayName | eq |
| field:"azure_ad::activity_display_name" kind:eq value:"Add member to role request denied (PIM activation)" |
type | eq |
| field:"type" kind:eq |
user | is_not_null | field:"user" kind:is_not_null |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
Alert_Category_en | project |
Alert_Containment_en | project |
Alert_Description_en | project |
Alert_Name_en | project |
Alert_Remediation_en | project |
Alert_SubCategory_en | project |
Alert_Time_TW | project |
Alert_Time_UTC0 | project |
Alert_TriageStep_en | project |
Event_Action | project |
Event_Description | project |
Event_Status | project |
Source_Identity_FullName | project |
Source_Identity_ID | project |
Source_Identity_Type | project |
Source_Network_IPAddress | project |
Source_Resource_ID | project |
Source_Resource_Name | project |
Target_Identity_DomainType | project |
Target_Identity_FullName | project |
Target_Identity_Type | project |
Target_Resource_ID | project |
Target_Resource_Name | project |
Target_Resource_Type | project |