Bulk admin-initiated password reset across multiple accounts


Description

Identifies a single actor resetting passwords for three or more distinct accounts within one hour. Bulk admin-initiated resets in rapid succession suggest active account takeover before detection.

Query · kql

let timeframe = 1d;
let resetThreshold = 3;
let correlationWindow = 1h;
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName in~ (
      "Reset password (by admin)",
      "Reset user password",
      "Reset password"
  )
| where Result =~ "success"
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend ActorIp  = iff(
      isnotempty(tostring(InitiatedBy.user.ipAddress)),
      tostring(InitiatedBy.user.ipAddress),
      tostring(InitiatedBy.app.ipAddress))
| extend Actor      = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend TargetUpn  = tostring(TargetResources[0].userPrincipalName)
| where isnotempty(Actor) and isnotempty(TargetUpn) and Actor != TargetUpn
| summarize
    ResetCount     = dcount(TargetUpn),
    TargetAccounts = make_set(TargetUpn, 20),
    FirstReset     = min(TimeGenerated),
    LastReset      = max(TimeGenerated),
    ActorIp        = take_any(ActorIp)
    by Actor, TimeBucket = bin(TimeGenerated, correlationWindow)
| where ResetCount >= resetThreshold
| extend AccountName      = iff(Actor has "@", tostring(split(Actor, "@")[0]), Actor)
| extend AccountUPNSuffix = iff(Actor has "@", tostring(split(Actor, "@")[1]), "")
| project
    TimeBucket,
    Actor,
    AccountName,
    AccountUPNSuffix,
    ResetCount,
    TargetAccounts,
    FirstReset,
    LastReset,
    ActorIp
| sort by ResetCount desc
Raw source Bulk admin-initiated password reset across multiple accounts · KQL
Esc
Published by Azure/Azure-Sentinel ↗, licensed under MIT ↗. Reproduced here unmodified.
id: 0490ce45-3f01-48e2-a042-3ba0c3e559bc
name: Bulk admin-initiated password reset across multiple accounts
description: |
  Identifies a single actor resetting passwords for three or more distinct accounts
  within one hour. Bulk admin-initiated resets in rapid succession suggest active
  account takeover before detection.
requiredDataConnectors:
  - connectorId: AzureActiveDirectory
    dataTypes:
      - AuditLogs
tactics:
  - CredentialAccess
  - Persistence
relevantTechniques:
  - T1098
  - T1078.004
query: |
  let timeframe = 1d;
  let resetThreshold = 3;
  let correlationWindow = 1h;
  AuditLogs
  | where TimeGenerated >= ago(timeframe)
  | where OperationName in~ (
        "Reset password (by admin)",
        "Reset user password",
        "Reset password"
    )
  | where Result =~ "success"
  | extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
  | extend ActorApp = tostring(InitiatedBy.app.displayName)
  | extend ActorIp  = iff(
        isnotempty(tostring(InitiatedBy.user.ipAddress)),
        tostring(InitiatedBy.user.ipAddress),
        tostring(InitiatedBy.app.ipAddress))
  | extend Actor      = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
  | extend TargetUpn  = tostring(TargetResources[0].userPrincipalName)
  | where isnotempty(Actor) and isnotempty(TargetUpn) and Actor != TargetUpn
  | summarize
      ResetCount     = dcount(TargetUpn),
      TargetAccounts = make_set(TargetUpn, 20),
      FirstReset     = min(TimeGenerated),
      LastReset      = max(TimeGenerated),
      ActorIp        = take_any(ActorIp)
      by Actor, TimeBucket = bin(TimeGenerated, correlationWindow)
  | where ResetCount >= resetThreshold
  | extend AccountName      = iff(Actor has "@", tostring(split(Actor, "@")[0]), Actor)
  | extend AccountUPNSuffix = iff(Actor has "@", tostring(split(Actor, "@")[1]), "")
  | project
      TimeBucket,
      Actor,
      AccountName,
      AccountUPNSuffix,
      ResetCount,
      TargetAccounts,
      FirstReset,
      LastReset,
      ActorIp
  | sort by ResetCount desc
entityMappings:
  - entityType: Account
    fieldMappings:
      - identifier: FullName
        columnName: Actor
      - identifier: Name
        columnName: AccountName
      - identifier: UPNSuffix
        columnName: AccountUPNSuffix
  - entityType: IP
    fieldMappings:
      - identifier: Address
        columnName: ActorIp
version: 1.0.0
metadata:
    source:
        kind: Community
    author:
        name: descambiado
    support:
        tier: Community
    categories:
        domains: [ "Security - Threat Protection", "Identity" ]

Detection rules belong to the projects that publish them and remain under their own licenses. This site indexes and links to them; it claims no rights in them.