Service principal credential addition by non-historical actor
Description
Identifies service principal credential additions or updates by actors with no history of this operation in the preceding 90 days. A new actor outside the established baseline may indicate credential abuse by a compromised account.
Query · kql
let timeframe = 1d;
let lookback = 90d;
let KnownActors =
AuditLogs
| where TimeGenerated >= ago(timeframe + lookback) and TimeGenerated < ago(timeframe)
| where OperationName in~ (
"Add service principal credentials",
"Update application - Certificates and secrets management"
)
| where Result =~ "success"
| extend Actor = iff(
isnotempty(tostring(InitiatedBy.user.userPrincipalName)),
tostring(InitiatedBy.user.userPrincipalName),
tostring(InitiatedBy.app.displayName))
| where isnotempty(Actor)
| distinct Actor;
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName in~ (
"Add service principal credentials",
"Update application - Certificates and secrets management"
)
| where Result =~ "success"
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| extend TargetSP = tostring(TargetResources[0].displayName)
| extend TargetSpId = tostring(TargetResources[0].id)
| where isnotempty(Actor)
| join kind=leftanti KnownActors on Actor
| extend AccountName = iff(Actor has "@", tostring(split(Actor, "@")[0]), Actor)
| extend AccountUPNSuffix = iff(Actor has "@", tostring(split(Actor, "@")[1]), "")
| project TimeGenerated, TargetSP, TargetSpId, Actor, AccountName,
AccountUPNSuffix, ActorIp, OperationName, CorrelationId
| sort by TimeGenerated desc