An adversary may reset an admin’s password to gain elevated access and then immediately perform privileged operations to compromise the environment. SOC teams should proactively hunt for this behavior in Azure Sentinel to detect potential credential theft and privilege escalation tactics early.
KQL Query
let timeframe = 1d;
let correlationWindow = 30m;
let PrivilegedOps = dynamic([
"Add member to role.",
"Add member to role",
"Add service principal credentials.",
"Add service principal credentials",
"Update application - Certificates and secrets management",
"Add owner to service principal.",
"Add owner to service principal",
"Set domain authentication.",
"Set domain authentication"
]);
// Admin-initiated password resets (different actor from target)
let PasswordResets =
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName in~ ("Reset user password.", "Reset user password")
| where Result =~ "success"
| extend ResetActorUpn = tolower(tostring(InitiatedBy.user.userPrincipalName))
| extend ResetActorApp = tostring(InitiatedBy.app.displayName)
| mv-expand TargetResource = TargetResources
| where tostring(TargetResource.type) =~ "User"
| extend ResetTargetUpn = tolower(tostring(TargetResource.userPrincipalName))
| where isnotempty(ResetTargetUpn)
| where ResetActorUpn != ResetTargetUpn
| project ResetTime = TimeGenerated, ResetActorUpn, ResetActorApp, ResetTargetUpn;
// Privileged operations initiated by the reset target within the correlation window
let FollowOnOps =
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName in~ (PrivilegedOps)
| where Result =~ "success"
| extend ActorUpn = tolower(tostring(InitiatedBy.user.userPrincipalName))
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| where isnotempty(ActorUpn)
| project OpTime = TimeGenerated, ActorUpn, ActorIp, OperationName;
PasswordResets
| join kind=inner FollowOnOps on $left.ResetTargetUpn == $right.ActorUpn
| where OpTime between (ResetTime .. (ResetTime + correlationWindow))
| extend AccountName = tostring(split(ResetTargetUpn, "@")[0])
| extend AccountUPNSuffix = tostring(split(ResetTargetUpn, "@")[1])
| project
ResetTime,
ResetTargetUpn,
AccountName,
AccountUPNSuffix,
ResetActorUpn,
ResetActorApp,
OpTime,
OperationName,
ActorIp
| sort by ResetTime desc
id: a7589e25-ff97-48ab-aa2f-8de1df7ed9c0
name: Entra ID account performs privileged operation shortly after admin password reset
description: |
Identifies accounts initiating high-impact Entra ID operations within 30 minutes of
having their password reset by a different actor. Cross-actor correlation
(ResetActorUpn != ResetTargetUpn) separates this from self-service and helpdesk
reset flows.
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1098
- T1098.003
- T1078.004
query: |
let timeframe = 1d;
let correlationWindow = 30m;
let PrivilegedOps = dynamic([
"Add member to role.",
"Add member to role",
"Add service principal credentials.",
"Add service principal credentials",
"Update application - Certificates and secrets management",
"Add owner to service principal.",
"Add owner to service principal",
"Set domain authentication.",
"Set domain authentication"
]);
// Admin-initiated password resets (different actor from target)
let PasswordResets =
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName in~ ("Reset user password.", "Reset user password")
| where Result =~ "success"
| extend ResetActorUpn = tolower(tostring(InitiatedBy.user.userPrincipalName))
| extend ResetActorApp = tostring(InitiatedBy.app.displayName)
| mv-expand TargetResource = TargetResources
| where tostring(TargetResource.type) =~ "User"
| extend ResetTargetUpn = tolower(tostring(TargetResource.userPrincipalName))
| where isnotempty(ResetTargetUpn)
| where ResetActorUpn != ResetTargetUpn
| project ResetTime = TimeGenerated, ResetActorUpn, ResetActorApp, ResetTargetUpn;
// Privileged operations initiated by the reset target within the correlation window
let FollowOnOps =
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName in~ (PrivilegedOps)
| where Result =~ "success"
| extend ActorUpn = tolower(tostring(InitiatedBy.user.userPrincipalName))
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| where isnotempty(ActorUpn)
| project OpTime = TimeGenerated, ActorUpn, ActorIp, OperationName;
PasswordResets
| join kind=inner FollowOnOps on $left.ResetTargetUpn == $right.ActorUpn
| where OpTime between (ResetTime .. (ResetTime + correlationWindow))
| extend AccountName = tostring(split(ResetTargetUpn, "@")[0])
| extend AccountUPNSuffix = tostring(split(ResetTargetUpn, "@")[1])
| project
ResetTime,
ResetTargetUpn,
AccountName,
AccountUPNSuffix,
ResetActorUpn,
ResetActorApp,
OpTime,
OperationName,
ActorIp
| sort by ResetTime desc
e
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
Scenario: A system administrator resets their own password using the Azure AD Password Reset tool, then shortly after, performs a scheduled maintenance task such as exporting user reports via Azure AD PowerShell.
Filter/Exclusion: Exclude cases where ResetActorUpn == ResetTargetUpn (self-reset password) or use a filter on the ResetActorUpn field to exclude known admin accounts.
Scenario: A privileged account (e.g., [email protected]) resets the password of a service account (e.g., [email protected]) and then runs a scheduled SQL backup job via Azure Automation.
Filter/Exclusion: Exclude service accounts or use a filter on the ResetTargetUpn field to exclude known service or automation accounts.
Scenario: A user resets their password through the Azure AD Self-Service Password Reset portal, and within 30 minutes, their account is used to execute a backup script via Azure DevOps Pipeline.
Filter/Exclusion: Exclude users who initiated their own password reset or apply a filter on the ResetActorUpn field to exclude self-service password reset events.
Scenario: An admin resets the password of a domain administrator account and then uses that account to run a PowerShell script that updates group memberships via the Graph API.
Filter/Exclusion: Exclude domain admin accounts or use a filter on the ResetTargetUpn field to exclude high-privilege accounts.
Scenario: A security team member resets the password of a monitoring account (e.g., [email protected]) and then uses that account to trigger a scheduled SIEM data ingestion job via Azure Logic Apps.
Filter/Exclusion: Exclude monitoring or collector accounts or use a filter on the ResetTargetUpn field to exclude non-privileged accounts.