Added Owner To Application By Unprivileged
Query
// Owner added to high privileged application by unprivileged or lower privileged user
AuditLogs
| where TimeGenerated >ago(180d)
| where OperationName in ("Add owner to application","Add owner to service principal")
| extend InitiatingUserOrApp = iff(isnotempty(InitiatedBy.user.userPrincipalName),tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend InitiatingUserOrAppId = iff(isnotempty(InitiatedBy.user.id),tostring(InitiatedBy.user.id), tostring(InitiatedBy.app.id))
| extend InitiatingIpAddress = iff(isnotempty(InitiatedBy.user.ipAddress), tostring(InitiatedBy.user.ipAddress), tostring(InitiatedBy.app.ipAddress))
| mv-expand TargetResources
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "Application.ObjectID" | extend ApplicationObjectID = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "Application.DisplayName" | extend ApplicationDisplayName = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| mv-expand TargetResources.modifiedProperties | where TargetResources_modifiedProperties.displayName == "Application.AppId" | extend ApplicationAppId = replace_string(tostring(TargetResources_modifiedProperties.newValue),'"','')
| join kind=inner(
AzADSPI
| project-rename AppClassification = EnterpriseAccessModelTiering
) on $left.ApplicationObjectID == $right.ApplicationObjectId
| join kind=inner (
PrivilegedEAM_CL
| where TimeGenerated > ago(14d)
| summarize arg_max(TimeGenerated, *) by ObjectId
| extend InitiatingUserOrAppClassification = iff(isnotempty(parse_json(Classification)), parse_json(Classification), "UserAccess")
| project ObjectId, ObjectAdminTierLevel, ObjectAdminTierLevelName, InitiatingUserOrAppClassification
) on $left.InitiatingUserOrAppId == $right.ObjectId
| where parse_json(tostring(parse_json(InitiatingUserOrAppClassification))) !contains AppClassification and parse_json(tostring(parse_json(InitiatingUserOrAppClassification))) !contains "ControlPlane"
| project-reorder OperationName, ApplicationObjectID, ApplicationDisplayName, ApplicationAppId, AppClassification, InitiatingUserOrApp, InitiatingUserOrAppId, InitiatingIpAddress, InitiatingUserOrAppClassificationExplanation
This query is designed to identify instances where a user with lower or no privileges has added an owner to a high-privileged application or service principal. Here's a simplified breakdown of what the query does:
-
Data Source: It starts by looking at audit logs from the past 180 days.
-
Filter Operations: It filters for operations where an owner was added to an application or a service principal.
-
Identify Initiator: It determines who initiated the action, whether it's a user or an application, and captures their details like name, ID, and IP address.
-
Extract Application Details: It extracts specific details about the target application, such as its Object ID, Display Name, and App ID.
-
Join with Application Classification: It joins this data with another dataset (
AzADSPI) to get the classification of the application, indicating its privilege level. -
Join with User Classification: It also joins with a dataset (
PrivilegedEAM_CL) to get the classification of the user or app that initiated the action, focusing on their privilege level. -
Filter by Privilege Discrepancy: It filters out cases where the initiator's privilege classification does not match the application's classification and is not part of the "ControlPlane".
-
Output: Finally, it organizes the results to show key details such as the operation name, application details, initiator details, and their classifications.
In essence, the query is used to detect potential security issues where users with insufficient privileges are making changes to high-privileged applications.
Details

Thomas Naunheim
Released: October 28, 2023
Tables
Keywords
Operators