Query Details

HQ 014 Password Reset High Privileged User

Query

// HQ-014 — Password Reset on High-Privileged User
// Purpose  : Detect password resets or forced password profile updates where the TARGET
//            account holds (or previously held) a high-privilege Entra ID role.
//            Resetting a privileged account's password is a classic account-takeover step
//            and may indicate lateral movement toward a more privileged identity.
// Tables   : AuditLogs (two correlated datasets)
// MITRE    : TA0006 Credential Access — T1110 Brute Force / Password Manipulation
//            TA0003 Persistence — T1098 Account Manipulation
// Author   : Custom
// ---------------------------------------------------------------------------

let LookbackDays    = 14d;
let RoleLookback    = 90d;    // Look further back for role membership history
let PrivilegedRoles = dynamic([
    "Global Administrator",
    "Security Administrator",
    "Privileged Role Administrator",
    "User Administrator",
    "Authentication Administrator",
    "Privileged Authentication Administrator",
    "Exchange Administrator",
    "SharePoint Administrator",
    "Compliance Administrator",
    "Conditional Access Administrator",
    "Application Administrator",
    "Cloud Application Administrator",
    "Helpdesk Administrator",
    "Password Administrator"
]);
let PasswordActivities = dynamic([
    "Reset password",
    "Reset password (self-service)",
    "Admin reset user password",
    "Change password",
    "Update user"    // Catches forced PasswordProfile modifications
]);
// ── Step 1: Build list of privileged role holders from role assignment history ─
// Expand TargetResources; reconstruct one row per event with RoleName + TargetUserUPN
let PrivilegedRoleMembers = AuditLogs
| where TimeGenerated > ago(RoleLookback)
| where Category == "RoleManagement"
| where ActivityDisplayName has "Add member"
| mv-expand TargetResource = TargetResources
| extend ResType    = tostring(TargetResource.type)
| extend ResName    = tostring(TargetResource.displayName)
| extend ResUserUPN = tostring(TargetResource.userPrincipalName)
| summarize
    RoleName      = max(iff(ResType == "Role", ResName, "")),
    TargetUserUPN = tolower(max(iff(isnotempty(ResUserUPN), ResUserUPN, "")))
    by Id
| where RoleName in (PrivilegedRoles) and isnotempty(TargetUserUPN)
| summarize PrivilegedRolesList = make_set(RoleName) by TargetUserUPN;
// ── Step 2: Collect password reset / profile update events ──────────────────
let PasswordResets = AuditLogs
| where TimeGenerated > ago(LookbackDays)
| where ActivityDisplayName in~ (PasswordActivities)
    // For "Update user", narrow to actual password profile changes
    or (ActivityDisplayName == "Update user"
        and tostring(AdditionalDetails) has_any ("PasswordProfile", "ForceChangePasswordNextSignIn"))
| extend TargetResetUPN = tolower(tostring(TargetResources[0].userPrincipalName))
| extend InitiatorUPN   = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatorApp   = tostring(InitiatedBy.app.displayName)
| extend InitiatorType  = iff(isnotempty(tostring(InitiatedBy.user.userPrincipalName)), "User", "Application")
| where isnotempty(TargetResetUPN)
| project
    ResetTime       = TimeGenerated,
    TargetResetUPN,
    InitiatorUPN,
    InitiatorApp,
    InitiatorType,
    ActivityDisplayName,
    Result,
    LoggedByService,
    CorrelationId;
// ── Step 3: Join — password reset on a user who holds/held a privileged role ─
PasswordResets
| join kind=inner (PrivilegedRoleMembers)
    on $left.TargetResetUPN == $right.TargetUserUPN
| extend SelfReset = tolower(InitiatorUPN) == TargetResetUPN
| extend RiskAnnotation = case(
    SelfReset and InitiatorType == "User",  "Self-service reset of privileged account",
    InitiatorType == "Application",        "Automated reset — verify service principal authorization",
    isnotempty(InitiatorUPN),              "Admin-initiated reset on privileged account",
    "Password reset — initiator unknown"
)
| project
    ResetTime,
    TargetResetUPN,
    PrivilegedRoles  = PrivilegedRolesList,
    InitiatorUPN,
    InitiatorApp,
    InitiatorType,
    SelfReset,
    ActivityDisplayName,
    Result,
    RiskAnnotation,
    LoggedByService,
    CorrelationId
| sort by ResetTime desc

Explanation

This query is designed to detect potentially suspicious password resets or profile updates for high-privileged user accounts in Entra ID (formerly Azure AD). Here's a simplified breakdown of what the query does:

  1. Purpose: The query aims to identify password resets or forced updates for accounts that currently have or previously had high-privilege roles. Such actions could indicate an attempt to take over an account, which is a common step in unauthorized access or lateral movement within a system.

  2. Lookback Periods:

    • It examines password reset activities over the past 14 days.
    • It checks role membership history over the past 90 days to see if the account ever held a privileged role.
  3. Privileged Roles: The query focuses on accounts with specific high-privilege roles, such as Global Administrator, Security Administrator, and others listed in the query.

  4. Password Activities: It looks for specific activities related to password changes, including resets and updates, whether done by an admin or self-service.

  5. Steps in the Query:

    • Step 1: It compiles a list of users who have held any of the specified privileged roles within the last 90 days.
    • Step 2: It collects events related to password resets or profile updates from the past 14 days.
    • Step 3: It joins the data from the first two steps to find password reset events involving users who have held privileged roles.
  6. Risk Annotation: The query categorizes the risk level of each event based on who initiated the reset:

    • Self-service reset by the user.
    • Automated reset by an application.
    • Admin-initiated reset.
    • Resets where the initiator is unknown.
  7. Output: The results are sorted by the time of the reset, showing details like the user affected, the roles they held, who initiated the reset, and a risk annotation to help assess the potential threat level.

This query helps security teams monitor and investigate potentially unauthorized or risky password changes on high-privileged accounts, which are critical to maintaining security in an organization.

Details

David Alonso profile picture

David Alonso

Released: April 6, 2026

Tables

AuditLogs

Keywords

AuditLogsEntraIDRoleTargetAccountUserPasswordResetPrivilegedRoleAdministratorSecurityAdministratorUserAdministratorAuthenticationAdministratorExchangeAdministratorSharePointAdministratorComplianceAdministratorConditionalAccessAdministratorApplicationAdministratorCloudApplicationAdministratorHelpdeskAdministratorPasswordAdministratorRoleManagementActivityDisplayNameTargetResourcesTargetUserUPNInitiatedByAdditionalDetailsTimeGeneratedResultLoggedByServiceCorrelationId

Operators

letdynamicagohasmv-expandtostringsummarizemaxiffisnotemptymake_setinin~extendtolowerprojectjoinkind=inneroncasesort by

Actions