Query Details
id: aa1f000e-200e-420e-920e-aadprov-hunt14
name: HUNT-14 Provisioning Self-Service Loop - Actor Modifies Own Object (30d)
description: |
Surfaces provisioning events where the initiating identity and the target
identity are the same principal - an actor provisioning, enabling,
re-enabling, or rewriting attributes on their own object through the
provisioning channel. Self-modification through provisioning is a stealthy
privilege-persistence path: the change rarely raises a console alert and
bypasses the usual two-person separation that direct admin portal edits
attract. Benign in some HR-driven self-service scenarios, so treat as a
hunt rather than an alert and triage on the PropName / AssignedRoles
custom output.
MITRE ATT&CK: T1098 (Account Manipulation),
T1078.004 (Valid Accounts: Cloud Accounts).
severity: Medium
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AADProvisioningLogs
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1098
- T1078.004
query: |
let PrivilegedUsers =
IdentityInfo
| where TimeGenerated > ago(14d)
| summarize arg_max(TimeGenerated, *) by AccountUPN
| where isnotempty(AssignedRoles) and AssignedRoles != "[]"
| project AccountUPN, AssignedRoles;
AADProvisioningLogs
| where TimeGenerated > ago(30d)
| where ResultType =~ "Success"
| extend InitiatorUpn = tolower(tostring(parse_json(InitiatedBy).userPrincipalName)),
TargetUpn = tolower(tostring(parse_json(TargetIdentity).userPrincipalName)),
SPName = tostring(parse_json(ServicePrincipal).Name)
| where isnotempty(InitiatorUpn) and InitiatorUpn == TargetUpn
| mv-expand Mod = todynamic(ModifiedProperties)
| extend PropName = tostring(Mod.displayName),
OldValue = tostring(Mod.oldValue),
NewValue = tostring(Mod.newValue)
| summarize
EventCount = count(),
Actions = make_set(ProvisioningAction, 10),
ChangedProps = make_set(PropName, 25),
Jobs = make_set(JobId, 10),
FirstSeen = min(TimeGenerated),
LastSeen = max(TimeGenerated)
by InitiatorUpn, SPName
| join kind=leftouter (PrivilegedUsers) on $left.InitiatorUpn == $right.AccountUPN
| extend IsPrivileged = isnotempty(AssignedRoles)
| project InitiatorUpn, IsPrivileged, AssignedRoles, SPName, EventCount,
Actions, ChangedProps, Jobs, FirstSeen, LastSeen
| order by IsPrivileged desc, EventCount desc
This query is designed to identify and analyze instances where a user modifies their own account attributes through provisioning activities within Azure Active Directory. Here's a simplified breakdown:
Purpose: The query detects self-service provisioning events where a user (the initiator) changes their own account details. This can be a subtle way for a user to maintain privileges without triggering alerts that typically occur with direct admin portal changes.
Context: Such self-modifications can be legitimate in some HR-driven scenarios but may also indicate privilege persistence or escalation attempts. Therefore, these events are treated as hunting opportunities rather than immediate alerts.
Data Source: It uses data from Azure Active Directory provisioning logs.
Process:
Output: The query provides a list of users who have modified their own accounts, highlighting whether they are privileged, the actions they took, and the properties they changed, along with timestamps of these activities. This helps in assessing potential security risks related to account manipulation.

David Alonso
Released: June 1, 2026
Tables
Keywords
Operators