← Back to SOC feed Coverage →

Service principal or application credential addition by a rarely observed actor

kql MEDIUM Azure-Sentinel
T1098.001
AuditLogs
backdoorcredential-thefthuntingmicrosoftofficialpersistence
This rule was pulled from an open-source repository and enriched with AI. Validate in a test environment before deploying to production.
View original rule at Azure-Sentinel →
Retrieved: 2026-05-07T11:00:00Z · Confidence: medium

Hunt Hypothesis

A rarely observed actor is adding or updating credentials for service principals or applications, which may indicate unauthorized or malicious credential management activity. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential lateral movement or persistence tactics by unknown actors.

KQL Query

let starttime = todatetime('{{StartTimeISO}}');
let endtime = todatetime('{{EndTimeISO}}');
let baselineLookback = starttime - 90d;
let credOps = dynamic([
    "Add service principal credentials",
    "Update application - Certificates and secrets management"
]);
// Build 90-day baseline of actors who have previously performed credential operations
let KnownActors =
    AuditLogs
    | where TimeGenerated between (baselineLookback .. starttime)
    | where OperationName in~ (credOps)
    | extend ActorUpn = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
    | extend ActorApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
    | extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
    | where isnotempty(Actor)
    | summarize by Actor;
// Credential operations in the current window
AuditLogs
| where TimeGenerated between (starttime .. endtime)
| where OperationName in~ (credOps)
| extend ActorUpn = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
| extend ActorApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
| extend ActorIp  = iff(
      isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)),
      tostring(parse_json(tostring(InitiatedBy.user)).ipAddress),
      tostring(parse_json(tostring(InitiatedBy.app)).ipAddress))
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| where isnotempty(Actor)
// Keep only actors not seen in the 90-day baseline
| join kind=leftanti KnownActors on Actor
| extend TargetDisplayName = tostring(TargetResources[0].displayName)
| extend TargetId = tostring(TargetResources[0].id)
| extend TargetType = tostring(TargetResources[0].type)
| extend AccountName = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[0]), Actor)
| extend AccountUPNSuffix = iff(ActorUpn has "@", tostring(split(ActorUpn, "@")[1]), "")
| project
    TimeGenerated,
    OperationName,
    Actor,
    AccountName,
    AccountUPNSuffix,
    ActorApp,
    ActorIp,
    TargetDisplayName,
    TargetId,
    TargetType,
    CorrelationId,
    Result
| sort by TimeGenerated desc

Analytic Rule Definition

id: 138381e3-95d5-4d21-ab0b-13f941b82acc
name: Service principal or application credential addition by a rarely observed actor
description: |
  Hunting query that looks for credential additions or updates on service principals and
  applications performed by actors (users or apps) that have not been observed initiating
  the same operations in the previous 90 days. Covered operations are
  "Add service principal credentials" and "Update application - Certificates and secrets
  management", which correspond to adding passwordCredentials or keyCredentials to an
  existing registration. A rarely observed actor performing these operations can indicate
  persistence activity, such as a compromised account adding a backdoor credential to a
  high-privilege application.
  This query is hypothesis-driven and requires analyst validation. Benign matches include
  newly onboarded administrators, infrastructure-as-code pipelines running for the first
  time, and certificate rotation performed by a different operator than usual.
  References:
  - https://learn.microsoft.com/azure/active-directory/reports-monitoring/reference-audit-activities
  - https://attack.mitre.org/techniques/T1098/001/
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
tactics:
  - Persistence
relevantTechniques:
  - T1098.001
query: |
  let starttime = todatetime('{{StartTimeISO}}');
  let endtime = todatetime('{{EndTimeISO}}');
  let baselineLookback = starttime - 90d;
  let credOps = dynamic([
      "Add service principal credentials",
      "Update application - Certificates and secrets management"
  ]);
  // Build 90-day baseline of actors who have previously performed credential operations
  let KnownActors =
      AuditLogs
      | where TimeGenerated between (baselineLookback .. starttime)
      | where OperationName in~ (credOps)
      | extend ActorUpn = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
      | extend ActorApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
      | extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
      | where isnotempty(Actor)
      | summarize by Actor;
  // Credential operations in the current window
  AuditLogs
  | where TimeGenerated between (starttime .. endtime)
  | where OperationName in~ (credOps)
  | extend ActorUpn = tostring(parse_json(tostring(InitiatedBy.user)).userPrincipalName)
  | extend ActorApp = tostring(parse_json(tostring(InitiatedBy.app)).displayName)
  | extend ActorIp  = iff(
        isnotempty(tostring(parse_json(tostring(InitiatedBy.user)).ipAddress)),
        tostring(parse_json(tostring(InitiatedBy.user)).ipAddress),
        tostring(parse_json(tostring(InitiatedBy.app)).ipAddress))
  | extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
  | where isnotempty(Actor)
  // Keep only actors not seen in the 90-day baseline
  | join kind=leftanti KnownActors on Actor
  | extend TargetDisplayName = tostring(TargetResources[0].d

Required Data Sources

Sentinel TableNotes
AuditLogsEnsure this data connector is enabled

MITRE ATT&CK Context

References

False Positive Guidance

Original source: https://github.com/Azure/Azure-Sentinel/blob/main/Hunting Queries/AuditLogs/ServicePrincipalCredentialAdditionByRareActor.yaml