Query Details
id: 5d5dfb1e-29d8-4568-bfa3-f7e4caad5162
name: Secret added to high privileged application
version: 1.0.0
kind: Scheduled
description: |-
A new secret was added to an high privileged application.
Can contain false positives if a secret was deleted but there is still another secret present
severity: High
queryFrequency: 30m
queryPeriod: 30m
triggerOperator: gt
triggerThreshold: 0
tactics:
- CredentialAccess
- Persistence
query: |+
// Needs custom watchlist HighRiskApps
// Must contain objectId, displayName of all high priv apps (manual process)
// objectId must be SearchKey
AuditLogs
| where OperationName has_any ("Add service principal", "Certificates and secrets management")
| where Result =~ "success"
| where tostring(InitiatedBy.user.userPrincipalName) has "@" or tostring(InitiatedBy.app.displayName) has "@"
| extend targetDisplayName = tostring(TargetResources[0].displayName)
| extend targetId = tostring(TargetResources[0].id)
| extend targetType = tostring(TargetResources[0].type)
| extend keyEvents = TargetResources[0].modifiedProperties
| mv-expand keyEvents
| where keyEvents.displayName =~ "KeyDescription"
| extend new_value_set = parse_json(tostring(keyEvents.newValue))
| extend old_value_set = parse_json(tostring(keyEvents.oldValue))
| where old_value_set == "[]"
| mv-expand new_value_set
| parse new_value_set with * "KeyIdentifier=" keyIdentifier:string ",KeyType=" keyType:string ",KeyUsage=" keyUsage:string ",DisplayName=" keyDisplayName:string "]" *
| where keyUsage in ("Verify","")
| extend UserAgent = iff(AdditionalDetails[0].key == "User-Agent",tostring(AdditionalDetails[0].value),"")
| 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))
| project-away new_value_set, old_value_set
| project-reorder TimeGenerated, OperationName, InitiatingUserOrApp, InitiatingIpAddress, UserAgent, targetDisplayName, targetId, targetType, keyDisplayName, keyType, keyUsage, keyIdentifier, CorrelationId, TenantId
| join kind=inner _GetWatchlist('HighRiskApps') on $left.targetId == $right.SearchKey
| extend timestamp = TimeGenerated, AccountCustomEntity = InitiatingUserOrApp, IPCustomEntity = InitiatingIpAddress
suppressionEnabled: false
incidentConfiguration:
createIncident: true
groupingConfiguration:
enabled: false
reopenClosedIncident: false
lookbackDuration: 5h
matchingMethod: AllEntities
groupByEntities: []
groupByAlertDetails: []
groupByCustomDetails: []
eventGroupingSettings:
aggregationKind: AlertPerResult
customDetails:
Application: targetDisplayName
SecretTypeAdded: keyType
entityMappings:
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AccountCustomEntity
- entityType: IP
fieldMappings:
- identifier: Address
columnName: IPCustomEntity
suppressionDuration: 5h
This query is designed to detect when a new secret is added to a high privileged application. It searches the audit logs for operations related to adding service principals or managing certificates and secrets. It filters for successful operations and checks if the initiator is either a user or an application. It then extracts relevant information such as the target display name, target ID, key display name, key type, key usage, and key identifier. It also includes additional details such as the user agent, initiating user or app, and initiating IP address. The query joins the results with a watchlist of high-risk applications and includes specific columns in the final output. The query is scheduled to run every 30 minutes and has a severity level of high. If a match is found, an incident will be created.

Fabian Bader
Released: July 25, 2023
Tables
Keywords
Operators