Query Details
id: c44269aa-9879-42d9-a8f4-56a93bb8c6ac
name: Dangerous API permission consented
version: 1.0.3
kind: Scheduled
description: |
One or more high priv API permission were granted to an application.
Check if this is really necessary and otherwise remove the permissions
severity: High
queryFrequency: 31m
queryPeriod: 31m
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
query: |-
let DangerousAPIPermissions = dynamic({
"9e3f62cf-ca93-4989-b6ce-bf83c28f9fe8": "RoleManagement.ReadWrite.Directory -> Directly promote any user to global admin",
"06b708a9-e830-4db3-a914-8e69da51d44f": "AppRoleAssignment.ReadWrite.All -> Grant RoleManagement.ReadWrite.Directory, then promote to global admin",
"1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9": "Application.ReadWrite.All -> Act as another entity e.g. a global admin user"
});
AuditLogs
| where OperationName == "Add app role assignment to service principal"
| where Result =~ "success"
| mv-expand TargetResources
| where TargetResources.displayName == "Microsoft Graph"
| mv-expand TargetResources.modifiedProperties
| where TargetResources_modifiedProperties.displayName == "AppRole.Id"
// This permission was not part of this application before
| where isnull(TargetResources_modifiedProperties.oldValue)
// The new permission is part of the dangerous API permissions
| extend NewAPIPermission = trim('"', tostring(TargetResources_modifiedProperties.newValue))
| extend PotentialImpact = DangerousAPIPermissions[NewAPIPermission]
| where isnotempty(PotentialImpact)
| extend UserAgent = iff(AdditionalDetails[0].key == "User-Agent", tostring(AdditionalDetails[0].value), "")
| extend ServicePrincipalDisplayName = parse_json(tostring(parse_json(tostring(TargetResources.modifiedProperties))[6].newValue))
| extend ServicePrincipalObjectID = parse_json(tostring(parse_json(tostring(TargetResources.modifiedProperties))[5].newValue))
| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: 5h
matchingMethod: AllEntities
groupByEntities: []
groupByAlertDetails: []
groupByCustomDetails: []
eventGroupingSettings:
aggregationKind: SingleAlert
alertDetailsOverride:
alertDescriptionFormat: "A high impact Graph API permission was granted to an application.\n\nThe granted API permission was {{PotentialImpact}} \n\nPlease verify if this API permission is needed by this application and if so make sure to add it to the watchlist \"HighRiskApps\""
alertDynamicProperties: []
customDetails:
ServicePrincipalId: ServicePrincipalObjectID
ServicePrincipal: ServicePrincipalDisplayName
AddedPermission: NewAPIPermission
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: InitiatingUserOrApp
- entityType: IP
fieldMappings:
- identifier: Address
columnName: InitiatingIpAddress
suppressionDuration: 5h
suppressionEnabled: false
This query is designed to identify instances where high privilege API permissions have been granted to an application. It checks if these permissions are necessary and suggests removing them if not. The query looks for audit logs where an app role assignment is added to a service principal with a successful result. It then expands the target resources and filters for those related to Microsoft Graph. The query further expands the modified properties and checks if the new permission is part of a list of dangerous API permissions. It retrieves additional details such as user agent, service principal display name, and initiating user or app. The query also includes custom incident configuration settings and alert details override.

Fabian Bader
Released: August 28, 2023
Tables
Keywords
Operators