A newly created account being assigned a privileged directory role within 24 hours may indicate an adversary establishing a backdoor for persistent access. SOC teams should proactively hunt for this behavior in Azure Sentinel to detect potential compromise of privileged accounts and mitigate lateral movement risks.
let timeframe = 7d;
let creationWindow = 24h;
let PrivilegedRoles = dynamic([
"Global Administrator",
"Privileged Role Administrator",
"Application Administrator",
"Cloud Application Administrator",
"Exchange Administrator",
"SharePoint Administrator",
"User Account Administrator",
"Authentication Administrator",
"Privileged Authentication Administrator",
"Security Administrator",
"Hybrid Identity Administrator"
]);
let NewAccounts =
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName =~ "Add user"
| where Result =~ "success"
| project
AccountCreatedTime = TimeGenerated,
UserId = tostring(TargetResources[0].id),
NewUserUpn = tostring(TargetResources[0].userPrincipalName);
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where Category =~ "RoleManagement"
| where OperationName in~ ("Add member to role.", "Add member to role")
| where Result =~ "success"
| extend TargetUserId = tostring(TargetResources[0].id)
| extend TargetUpn = tostring(TargetResources[0].userPrincipalName)
| mv-expand ModProp = TargetResources[0].modifiedProperties
| where tostring(ModProp.displayName) =~ "Role.DisplayName"
| extend RoleName = tostring(parse_json(tostring(ModProp.newValue))[0])
| where RoleName in~ (PrivilegedRoles)
| join kind=inner NewAccounts on $left.TargetUserId == $right.UserId
| where TimeGenerated between (AccountCreatedTime .. (AccountCreatedTime + creationWindow))
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| extend AccountName = iff(TargetUpn has "@", tostring(split(TargetUpn, "@")[0]), TargetUpn)
| extend AccountUPNSuffix = iff(TargetUpn has "@", tostring(split(TargetUpn, "@")[1]), "")
| project
TimeGenerated,
RoleName,
TargetUpn,
AccountName,
AccountUPNSuffix,
AccountCreatedTime,
Actor,
ActorIp,
CorrelationId
| sort by TimeGenerated desc
id: 1bb5e930-18be-454d-b0d9-351eef15871a
name: Privileged role assigned to newly created account
description: |
Identifies directory role assignments to accounts created less than 24 hours earlier
in the same tenant. An account receiving a privileged role shortly after creation
may indicate a backdoor account staged by an attacker with existing admin access.
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
tactics:
- Persistence
- PrivilegeEscalation
relevantTechniques:
- T1098.003
- T1136.003
query: |
let timeframe = 7d;
let creationWindow = 24h;
let PrivilegedRoles = dynamic([
"Global Administrator",
"Privileged Role Administrator",
"Application Administrator",
"Cloud Application Administrator",
"Exchange Administrator",
"SharePoint Administrator",
"User Account Administrator",
"Authentication Administrator",
"Privileged Authentication Administrator",
"Security Administrator",
"Hybrid Identity Administrator"
]);
let NewAccounts =
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where OperationName =~ "Add user"
| where Result =~ "success"
| project
AccountCreatedTime = TimeGenerated,
UserId = tostring(TargetResources[0].id),
NewUserUpn = tostring(TargetResources[0].userPrincipalName);
AuditLogs
| where TimeGenerated >= ago(timeframe)
| where Category =~ "RoleManagement"
| where OperationName in~ ("Add member to role.", "Add member to role")
| where Result =~ "success"
| extend TargetUserId = tostring(TargetResources[0].id)
| extend TargetUpn = tostring(TargetResources[0].userPrincipalName)
| mv-expand ModProp = TargetResources[0].modifiedProperties
| where tostring(ModProp.displayName) =~ "Role.DisplayName"
| extend RoleName = tostring(parse_json(tostring(ModProp.newValue))[0])
| where RoleName in~ (PrivilegedRoles)
| join kind=inner NewAccounts on $left.TargetUserId == $right.UserId
| where TimeGenerated between (AccountCreatedTime .. (AccountCreatedTime + creationWindow))
| extend ActorUpn = tostring(InitiatedBy.user.userPrincipalName)
| extend ActorApp = tostring(InitiatedBy.app.displayName)
| extend Actor = iff(isnotempty(ActorUpn), ActorUpn, ActorApp)
| extend ActorIp = iff(
isnotempty(tostring(InitiatedBy.user.ipAddress)),
tostring(InitiatedBy.user.ipAddress),
tostring(InitiatedBy.app.ipAddress))
| extend AccountName = iff(TargetUpn has "@", tostring(split(TargetUpn, "@")[0]), TargetUpn)
| extend AccountUPNSuffix = iff(TargetUpn has "@", tostring(split(TargetUpn, "@")[1]), "")
| project
TimeGenerated,
RoleName,
TargetUpn,
AccountName,
AccountUPNSuffix,
AccountCreatedTime,
Actor,
ActorIp,
CorrelationId
| sort by TimeGenerated desc
entityMappings:
- entityType: Account
fieldMappings:
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
Scenario: A system administrator creates a new service account and immediately assigns it a privileged role to configure a new application.
Filter/Exclusion: Exclude accounts created by known admin users (e.g., admin@domain.com) or those created via the Azure AD PowerShell module (Microsoft.Azure.Commands.ActiveDirectory).
Scenario: A scheduled job runs to automate user provisioning and assigns a privileged role to a newly created account as part of an onboarding process.
Filter/Exclusion: Exclude accounts created by automated processes (e.g., Azure Automation or PowerShell DSC) or those with a specific tag like provisioning-job.
Scenario: A user account is created for a temporary task and is assigned a privileged role to access internal tools during a short-term project.
Filter/Exclusion: Exclude accounts with a short expiration date or those created via the Azure AD portal with a specific note in the description field (e.g., Temp Access - Project XYZ).
Scenario: A new account is created for a third-party service and is assigned a privileged role to access internal APIs or systems as part of integration.
Filter/Exclusion: Exclude accounts associated with known third-party services (e.g., service-accounts@thirdparty.com) or those created via the Azure AD Graph API.
Scenario: A user is created during a bulk import of users and is assigned a privileged role due to a misconfigured script or automation.
Filter/Exclusion: Exclude accounts created during bulk operations (e.g., via Azure AD Connect, PowerShell, or Microsoft Graph API) and filter by creation date range or specific import source.