New Credential Added To Sensitive SP
Query
// New access credential added to sensitive Application or Service Principal from non-privileged user
// Modified version from "New access credential added to Application or Service Principal" (79566f41-df67-4e10-a703-c38a6213afd8)
AuditLogs
| where TimeGenerated >ago(90d)
| where OperationName has_any ("Add service principal", "Certificates and secrets management") // captures "Add service principal", "Add service principal credentials", and "Update application - Certificates and secrets management" events
| where Result =~ "success"
| where tostring(InitiatedBy.user.userPrincipalName) has "@" or tostring(InitiatedBy.app.displayName) has "@"
| mv-apply TargetResource = TargetResources on
(
where TargetResource.type =~ "Application"
| extend AppDisplayName = tostring(TargetResource.displayName),
AppId = tostring(TargetResource.id),
AppType = tostring(TargetResource.type),
keyEvents = TargetResource.modifiedProperties
)
| mv-apply Property = keyEvents on
(
where Property.displayName =~ "KeyDescription"
| extend new_value_set = parse_json(tostring(Property.newValue)),
old_value_set = parse_json(tostring(Property.oldValue))
)
| where old_value_set != "[]"
| extend diff = set_difference(new_value_set, old_value_set)
| where isnotempty(diff)
| parse diff with * "KeyIdentifier=" keyIdentifier:string ",KeyType=" keyType:string ",KeyUsage=" keyUsage:string ",DisplayName=" keyDisplayName:string "]" *
| where keyUsage =~ "Verify"
| mv-apply AdditionalDetail = AdditionalDetails on
(
where AdditionalDetail.key =~ "User-Agent"
| extend UserAgent = tostring(AdditionalDetail.value)
)
| 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))
| project-away diff, new_value_set, old_value_set
| extend timestamp = TimeGenerated, Name = tostring(split(InitiatingUserOrApp,'@',0)[0]), UPNSuffix = tostring(split(InitiatingUserOrApp,'@',1)[0])
| join kind=inner(
AzADSPI
| project-rename AppClassification = EnterpriseAccessModelTiering
) on $left.AppId == $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
| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingUserOrAppId, InitiatingIpAddress, InitiatingUserOrAppClassification, UserAgent, AppDisplayName, AppId, AppType, AppClassification, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationIdExplanation
This query is designed to identify and analyze instances where a non-privileged user adds a new access credential to a sensitive application or service principal. Here's a simplified breakdown of what the query does:
-
Data Source: It starts by looking at the
AuditLogstable for events that occurred in the last 90 days. -
Filter Events: It filters for successful operations related to adding service principals or managing certificates and secrets.
-
Identify Initiator: It checks if the action was initiated by a user or an application, ensuring the initiator has an email-like identifier.
-
Target Resource Details: It examines the target resources, specifically focusing on applications, and extracts relevant details like display name, ID, and type.
-
Key Changes: It looks for changes in key properties, specifically where there is a difference between the old and new values, and focuses on keys used for verification.
-
User-Agent Information: It extracts the user-agent information from additional details.
-
Initiator Details: It gathers details about the initiator, including their name, ID, and IP address.
-
Application Classification: It joins with another dataset (
AzADSPI) to get the classification of the application. -
User Classification: It joins with a privileged access management dataset (
PrivilegedEAM_CL) to determine the classification of the initiating user or application. -
Mismatch Detection: It filters out cases where the classification of the initiator does not match the classification of the application, indicating a potential security concern.
-
Output: Finally, it organizes the results to show relevant details like the time of the event, operation name, initiator details, application details, and key information.
In essence, this query helps in detecting and investigating unauthorized or suspicious credential additions to sensitive applications by non-privileged users, which could indicate a security risk.
Details

Thomas Naunheim
Released: October 28, 2023
Tables
Keywords
Operators