Back
Idef34b272-930c-41c8-a682-8c2093cd2024
Rulename[Entra ID] Application Granted Administrative Permission to Assign Microsoft Entra ID Roles
DescriptionDetects when an application receives permission to assign Microsoft Entra ID roles. This can enable directory privilege escalation and should be reviewed immediately.
SeverityHigh
TacticsPersistence
Impact
PrivilegeEscalation
TechniquesT1098.003
Required data connectorsAzureActiveDirectory
KindScheduled
Query frequency2h
Query period2h
Trigger threshold0
Trigger operatorgt
Source Urihttps://github.com/Azure/Azure-Sentinel/blob/master/Solutions/eDCRule/Analytic%20Rules/%5BEntra%20ID%5D%20Application%20Granted%20Administrative%20Permission%20to%20Assign%20Microsoft%20Entra%20ID%20Roles.yaml
Version1.0.0
Arm templateef34b272-930c-41c8-a682-8c2093cd2024.json
Deploy To Azure
AuditLogs
| where Category =~ "ApplicationManagement"
    and LoggedByService =~ "Core Directory"
    and OperationName in~ ("Add delegated permission grant", "Add app role assignment to service principal")
| mv-apply TargetResource = TargetResources on
    (
    where TargetResource.type =~ "ServicePrincipal"
        and array_length(TargetResource.modifiedProperties) > 0
        and isnotnull(TargetResource.displayName)
    | extend props = TargetResource.modifiedProperties
    )
| mv-apply Property = props on
    (
    where Property.displayName in~ ("AppRole.Value", "DelegatedPermissionGrant.Scope")
    | extend
        DisplayName = tostring(Property.displayName),
        PermissionGrant = trim('"', tostring(Property.newValue))
    )
| where PermissionGrant has "RoleManagement.ReadWrite.Directory"
| mv-apply Property = props on
    (
    where Property.displayName =~ "ServicePrincipal.DisplayName"
    | extend TargetAppDisplayName = trim('"', tostring(Property.newValue))
    )
| mv-apply Property = props on
    (
    where Property.displayName =~ "ServicePrincipal.ObjectID"
    | extend TargetAppServicePrincipalId = trim('"', tostring(Property.newValue))
    )
| 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 TargetAppDisplayName = tostring(iff(isnotempty(TargetAppDisplayName), TargetAppDisplayName, TargetAppServicePrincipalId))
| extend
    InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]),
    InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| extend Initiator = InitiatingAccountName, Target = TargetAppDisplayName
| extend
    Source_Network_IPLocation = ""
| project
        Alert_Category_en = "Entra ID",
    Alert_SubCategory_en = "Anomaly Identity Privilege Modification",
    Alert_Name_en = "Application Granted Administrative Permission to Assign Microsoft Entra ID Roles",
    Alert_Description_en = strcat("At Taiwan time", format_datetime(datetime_utc_to_local(TimeGenerated, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"), ". ", "EntraID:", "", ". ", "detected source user/service principal ", iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName), " granted application: ", TargetAppDisplayName, ".", " administrative permission to assign Microsoft Entra ID roles: ", ActivityDisplayName, ". Source IP: ", InitiatingIpAddress, ", source location: ", Source_Network_IPLocation),
    Alert_TriageStep_en = strcat(
                          "1. Confirm whether the operating user/service principal: ",
                          iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),
                          ", source IP: ",
                          InitiatingIpAddress,
                          " is abnormal. ",
                          "2. Review the authorized target application ",
                          TargetAppDisplayName,
                          "  authorization content: ",
                          ActivityDisplayName,
                          " to determine whether it is an expected operation or maintenance task."
                      ),
    Alert_Containment_en = strcat(
                           "1. If determined to be unauthorized or suspicious privilege escalation, immediately remove the permissions from target application: ",
                           TargetAppDisplayName,
                           " and disable it.",
                           "2. Perform risk handling for the initiator  ",
                           iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),
                           "  (revoke sessions/force re-authentication, and suspend directory management permissions if necessary)."
                       ),
    Alert_Remediation_en =
    "1. Strengthen application and permission governance: apply least privilege and administrator approval processes for high-risk Graph/Directory permissions, and include Service Principal credential/permission changes in regular audits.  "
    "2. Strengthen detection and automation: establish automated response (SOAR) for notification/source blocking/user verification.",
            Alert_Time_TW = datetime_utc_to_local(TimeGenerated, "Asia/Taipei"),
    Alert_Time_UTC0 = TimeGenerated,
    Event_Action = ActivityDisplayName,
    Event_Status = Result,
    Event_Description = PermissionGrant,
    Source_Identity_FullName = iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),
    Source_Identity_ID = iff(isnotempty(InitiatingAadUserId), InitiatingAadUserId, InitiatingAppServicePrincipalId),
    Source_Identity_Type = iff(isnotempty(InitiatingUserPrincipalName), "User", "Service"),
    Source_Network_IPAddress = InitiatingIpAddress,
    Source_Network_IPLocation = Source_Network_IPLocation,
    Target_Identity_FullName = TargetAppDisplayName,
    Target_Identity_ID = TargetAppServicePrincipalId,
    Target_Identity_Type = "Service",
    Target_Resource_ID = "",
    Target_Resource_Name = "Microsoft Entra ID",
    Target_Resource_Type = "Microsoft Entra ID"
entityMappings:
- entityType: Account
  fieldMappings:
  - columnName: Source_Identity_FullName
    identifier: FullName
- entityType: IP
  fieldMappings:
  - columnName: Source_Network_IPAddress
    identifier: Address
- entityType: CloudApplication
  fieldMappings:
  - columnName: Target_Identity_FullName
    identifier: Name
query: |
  AuditLogs
  | where Category =~ "ApplicationManagement"
      and LoggedByService =~ "Core Directory"
      and OperationName in~ ("Add delegated permission grant", "Add app role assignment to service principal")
  | mv-apply TargetResource = TargetResources on
      (
      where TargetResource.type =~ "ServicePrincipal"
          and array_length(TargetResource.modifiedProperties) > 0
          and isnotnull(TargetResource.displayName)
      | extend props = TargetResource.modifiedProperties
      )
  | mv-apply Property = props on
      (
      where Property.displayName in~ ("AppRole.Value", "DelegatedPermissionGrant.Scope")
      | extend
          DisplayName = tostring(Property.displayName),
          PermissionGrant = trim('"', tostring(Property.newValue))
      )
  | where PermissionGrant has "RoleManagement.ReadWrite.Directory"
  | mv-apply Property = props on
      (
      where Property.displayName =~ "ServicePrincipal.DisplayName"
      | extend TargetAppDisplayName = trim('"', tostring(Property.newValue))
      )
  | mv-apply Property = props on
      (
      where Property.displayName =~ "ServicePrincipal.ObjectID"
      | extend TargetAppServicePrincipalId = trim('"', tostring(Property.newValue))
      )
  | 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 TargetAppDisplayName = tostring(iff(isnotempty(TargetAppDisplayName), TargetAppDisplayName, TargetAppServicePrincipalId))
  | extend
      InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]),
      InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
  | extend Initiator = InitiatingAccountName, Target = TargetAppDisplayName
  | extend
      Source_Network_IPLocation = ""
  | project
          Alert_Category_en = "Entra ID",
      Alert_SubCategory_en = "Anomaly Identity Privilege Modification",
      Alert_Name_en = "Application Granted Administrative Permission to Assign Microsoft Entra ID Roles",
      Alert_Description_en = strcat("At Taiwan time", format_datetime(datetime_utc_to_local(TimeGenerated, "Asia/Taipei"), "yyyy-MM-dd HH:mm:ss"), ". ", "EntraID:", "", ". ", "detected source user/service principal ", iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName), " granted application: ", TargetAppDisplayName, ".", " administrative permission to assign Microsoft Entra ID roles: ", ActivityDisplayName, ". Source IP: ", InitiatingIpAddress, ", source location: ", Source_Network_IPLocation),
      Alert_TriageStep_en = strcat(
                            "1. Confirm whether the operating user/service principal: ",
                            iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),
                            ", source IP: ",
                            InitiatingIpAddress,
                            " is abnormal. ",
                            "2. Review the authorized target application ",
                            TargetAppDisplayName,
                            "  authorization content: ",
                            ActivityDisplayName,
                            " to determine whether it is an expected operation or maintenance task."
                        ),
      Alert_Containment_en = strcat(
                             "1. If determined to be unauthorized or suspicious privilege escalation, immediately remove the permissions from target application: ",
                             TargetAppDisplayName,
                             " and disable it.",
                             "2. Perform risk handling for the initiator  ",
                             iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),
                             "  (revoke sessions/force re-authentication, and suspend directory management permissions if necessary)."
                         ),
      Alert_Remediation_en =
      "1. Strengthen application and permission governance: apply least privilege and administrator approval processes for high-risk Graph/Directory permissions, and include Service Principal credential/permission changes in regular audits.  "
      "2. Strengthen detection and automation: establish automated response (SOAR) for notification/source blocking/user verification.",
              Alert_Time_TW = datetime_utc_to_local(TimeGenerated, "Asia/Taipei"),
      Alert_Time_UTC0 = TimeGenerated,
      Event_Action = ActivityDisplayName,
      Event_Status = Result,
      Event_Description = PermissionGrant,
      Source_Identity_FullName = iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),
      Source_Identity_ID = iff(isnotempty(InitiatingAadUserId), InitiatingAadUserId, InitiatingAppServicePrincipalId),
      Source_Identity_Type = iff(isnotempty(InitiatingUserPrincipalName), "User", "Service"),
      Source_Network_IPAddress = InitiatingIpAddress,
      Source_Network_IPLocation = Source_Network_IPLocation,
      Target_Identity_FullName = TargetAppDisplayName,
      Target_Identity_ID = TargetAppServicePrincipalId,
      Target_Identity_Type = "Service",
      Target_Resource_ID = "",
      Target_Resource_Name = "Microsoft Entra ID",
      Target_Resource_Type = "Microsoft Entra ID"
id: ef34b272-930c-41c8-a682-8c2093cd2024
queryFrequency: 2h
alertDetailsOverride:
  alertDynamicProperties: []
status: Available
severity: High
relevantTechniques:
- T1098.003
version: 1.0.0
kind: Scheduled
tactics:
- Persistence
- Impact
- PrivilegeEscalation
requiredDataConnectors:
- dataTypes:
  - AuditLogs
  connectorId: AzureActiveDirectory
description: |
  Detects when an application receives permission to assign Microsoft Entra ID roles. This can enable directory privilege escalation and should be reviewed immediately.
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/eDCRule/Analytic%20Rules/%5BEntra%20ID%5D%20Application%20Granted%20Administrative%20Permission%20to%20Assign%20Microsoft%20Entra%20ID%20Roles.yaml
triggerOperator: gt
name: '[Entra ID] Application Granted Administrative Permission to Assign Microsoft Entra ID Roles'
triggerThreshold: 0
queryPeriod: 2h
{
  "$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
  "contentVersion": "1.0.0.0",
  "parameters": {
    "workspace": {
      "type": "String"
    }
  },
  "resources": [
    {
      "apiVersion": "2024-01-01-preview",
      "id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/ef34b272-930c-41c8-a682-8c2093cd2024')]",
      "kind": "Scheduled",
      "name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/ef34b272-930c-41c8-a682-8c2093cd2024')]",
      "properties": {
        "alertDetailsOverride": {
          "alertDynamicProperties": []
        },
        "alertRuleTemplateName": "ef34b272-930c-41c8-a682-8c2093cd2024",
        "customDetails": null,
        "description": "Detects when an application receives permission to assign Microsoft Entra ID roles. This can enable directory privilege escalation and should be reviewed immediately.\n",
        "displayName": "[Entra ID] Application Granted Administrative Permission to Assign Microsoft Entra ID Roles",
        "enabled": true,
        "entityMappings": [
          {
            "entityType": "Account",
            "fieldMappings": [
              {
                "columnName": "Source_Identity_FullName",
                "identifier": "FullName"
              }
            ]
          },
          {
            "entityType": "IP",
            "fieldMappings": [
              {
                "columnName": "Source_Network_IPAddress",
                "identifier": "Address"
              }
            ]
          },
          {
            "entityType": "CloudApplication",
            "fieldMappings": [
              {
                "columnName": "Target_Identity_FullName",
                "identifier": "Name"
              }
            ]
          }
        ],
        "OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/eDCRule/Analytic%20Rules/%5BEntra%20ID%5D%20Application%20Granted%20Administrative%20Permission%20to%20Assign%20Microsoft%20Entra%20ID%20Roles.yaml",
        "query": "AuditLogs\n| where Category =~ \"ApplicationManagement\"\n    and LoggedByService =~ \"Core Directory\"\n    and OperationName in~ (\"Add delegated permission grant\", \"Add app role assignment to service principal\")\n| mv-apply TargetResource = TargetResources on\n    (\n    where TargetResource.type =~ \"ServicePrincipal\"\n        and array_length(TargetResource.modifiedProperties) > 0\n        and isnotnull(TargetResource.displayName)\n    | extend props = TargetResource.modifiedProperties\n    )\n| mv-apply Property = props on\n    (\n    where Property.displayName in~ (\"AppRole.Value\", \"DelegatedPermissionGrant.Scope\")\n    | extend\n        DisplayName = tostring(Property.displayName),\n        PermissionGrant = trim('\"', tostring(Property.newValue))\n    )\n| where PermissionGrant has \"RoleManagement.ReadWrite.Directory\"\n| mv-apply Property = props on\n    (\n    where Property.displayName =~ \"ServicePrincipal.DisplayName\"\n    | extend TargetAppDisplayName = trim('\"', tostring(Property.newValue))\n    )\n| mv-apply Property = props on\n    (\n    where Property.displayName =~ \"ServicePrincipal.ObjectID\"\n    | extend TargetAppServicePrincipalId = trim('\"', tostring(Property.newValue))\n    )\n| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)\n| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)\n| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)\n| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)\n| extend InitiatingIpAddress = tostring(iff(isnotempty(InitiatedBy.user.ipAddress), InitiatedBy.user.ipAddress, InitiatedBy.app.ipAddress))\n| extend TargetAppDisplayName = tostring(iff(isnotempty(TargetAppDisplayName), TargetAppDisplayName, TargetAppServicePrincipalId))\n| extend\n    InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, \"@\")[0]),\n    InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, \"@\")[1])\n| extend Initiator = InitiatingAccountName, Target = TargetAppDisplayName\n| extend\n    Source_Network_IPLocation = \"\"\n| project\n        Alert_Category_en = \"Entra ID\",\n    Alert_SubCategory_en = \"Anomaly Identity Privilege Modification\",\n    Alert_Name_en = \"Application Granted Administrative Permission to Assign Microsoft Entra ID Roles\",\n    Alert_Description_en = strcat(\"At Taiwan time\", format_datetime(datetime_utc_to_local(TimeGenerated, \"Asia/Taipei\"), \"yyyy-MM-dd HH:mm:ss\"), \". \", \"EntraID:\", \"\", \". \", \"detected source user/service principal \", iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName), \" granted application: \", TargetAppDisplayName, \".\", \" administrative permission to assign Microsoft Entra ID roles: \", ActivityDisplayName, \". Source IP: \", InitiatingIpAddress, \", source location: \", Source_Network_IPLocation),\n    Alert_TriageStep_en = strcat(\n                          \"1. Confirm whether the operating user/service principal: \",\n                          iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),\n                          \", source IP: \",\n                          InitiatingIpAddress,\n                          \" is abnormal. \",\n                          \"2. Review the authorized target application \",\n                          TargetAppDisplayName,\n                          \"  authorization content: \",\n                          ActivityDisplayName,\n                          \" to determine whether it is an expected operation or maintenance task.\"\n                      ),\n    Alert_Containment_en = strcat(\n                           \"1. If determined to be unauthorized or suspicious privilege escalation, immediately remove the permissions from target application: \",\n                           TargetAppDisplayName,\n                           \" and disable it.\",\n                           \"2. Perform risk handling for the initiator  \",\n                           iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),\n                           \"  (revoke sessions/force re-authentication, and suspend directory management permissions if necessary).\"\n                       ),\n    Alert_Remediation_en =\n    \"1. Strengthen application and permission governance: apply least privilege and administrator approval processes for high-risk Graph/Directory permissions, and include Service Principal credential/permission changes in regular audits.  \"\n    \"2. Strengthen detection and automation: establish automated response (SOAR) for notification/source blocking/user verification.\",\n            Alert_Time_TW = datetime_utc_to_local(TimeGenerated, \"Asia/Taipei\"),\n    Alert_Time_UTC0 = TimeGenerated,\n    Event_Action = ActivityDisplayName,\n    Event_Status = Result,\n    Event_Description = PermissionGrant,\n    Source_Identity_FullName = iff(isnotempty(InitiatingUserPrincipalName), InitiatingUserPrincipalName, InitiatingAppName),\n    Source_Identity_ID = iff(isnotempty(InitiatingAadUserId), InitiatingAadUserId, InitiatingAppServicePrincipalId),\n    Source_Identity_Type = iff(isnotempty(InitiatingUserPrincipalName), \"User\", \"Service\"),\n    Source_Network_IPAddress = InitiatingIpAddress,\n    Source_Network_IPLocation = Source_Network_IPLocation,\n    Target_Identity_FullName = TargetAppDisplayName,\n    Target_Identity_ID = TargetAppServicePrincipalId,\n    Target_Identity_Type = \"Service\",\n    Target_Resource_ID = \"\",\n    Target_Resource_Name = \"Microsoft Entra ID\",\n    Target_Resource_Type = \"Microsoft Entra ID\"\n",
        "queryFrequency": "PT2H",
        "queryPeriod": "PT2H",
        "severity": "High",
        "status": "Available",
        "subTechniques": [
          "T1098.003"
        ],
        "suppressionDuration": "PT1H",
        "suppressionEnabled": false,
        "tactics": [
          "Impact",
          "Persistence",
          "PrivilegeEscalation"
        ],
        "techniques": [
          "T1098"
        ],
        "templateVersion": "1.0.0",
        "triggerOperator": "GreaterThan",
        "triggerThreshold": 0
      },
      "type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
    }
  ]
}