Attackers may create user accounts with incorrect naming formats to evade detection and establish persistent access within the environment. SOC teams should proactively hunt for this behavior in Azure Sentinel to identify potential adversarial account creation attempts that could lead to long-term compromise.
KQL Query
// Add the environments expected username format regex below before deploying
let user_regex = "";
AuditLogs
| where OperationName =~ "Add user"
| where Result =~ "success"
| extend userAgent = tostring(AdditionalDetails[0].value)
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| extend AddedUser = tostring(TargetResources[0].userPrincipalName)
| where AddedUser matches regex user_regex
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| extend TargetAccountName = tostring(split(AddedUser, "@")[0]), TargetAccountUPNSuffix = tostring(split(AddedUser, "@")[1])
id: ee55dc85-d2da-48c1-a6c0-3eaee62a8d56
name: User Account Created Using Incorrect Naming Format
description: |
'This query looks for accounts being created where the name does not match a defined pattern.
Attackers may attempt to add accounts as a means of establishing persistant access to an environment, looking for anomalies in created accounts may help identify illegitimately created accounts.
Created accounts should be investigated to ensure they were legitimated created.
The user_regex field in the query needs to be populated with the expected pattern for the environment before deployment.
Ref: https://docs.microsoft.com/azure/active-directory/fundamentals/security-operations-user-accounts#accounts-not-following-naming-policies'
severity: Low
requiredDataConnectors:
- connectorId: AzureActiveDirectory
dataTypes:
- AuditLogs
queryFrequency: 1d
queryPeriod: 1d
triggerOperator: gt
triggerThreshold: 0
tactics:
- Persistence
relevantTechniques:
- T1136.003
tags:
- AADSecOpsGuide
query: |
// Add the environments expected username format regex below before deploying
let user_regex = "";
AuditLogs
| where OperationName =~ "Add user"
| where Result =~ "success"
| extend userAgent = tostring(AdditionalDetails[0].value)
| extend InitiatingAppName = tostring(InitiatedBy.app.displayName)
| extend InitiatingAppServicePrincipalId = tostring(InitiatedBy.app.servicePrincipalId)
| extend InitiatingUserPrincipalName = tostring(InitiatedBy.user.userPrincipalName)
| extend InitiatingAadUserId = tostring(InitiatedBy.user.id)
| extend InitiatingIPAddress = tostring(InitiatedBy.user.ipAddress)
| extend InitiatedBy = tostring(iff(isnotempty(InitiatingUserPrincipalName),InitiatingUserPrincipalName, InitiatingAppName))
| extend AddedUser = tostring(TargetResources[0].userPrincipalName)
| where AddedUser matches regex user_regex
| extend InitiatingAccountName = tostring(split(InitiatingUserPrincipalName, "@")[0]), InitiatingAccountUPNSuffix = tostring(split(InitiatingUserPrincipalName, "@")[1])
| extend TargetAccountName = tostring(split(AddedUser, "@")[0]), TargetAccountUPNSuffix = tostring(split(AddedUser, "@")[1])
entityMappings:
- entityType: Account
fieldMappings:
- identifier: Name
columnName: InitiatingAppName
- identifier: AadUserId
columnName: InitiatingAppServicePrincipalId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: InitiatingUserPrincipalName
- identifier: Name
columnName: InitiatingAccountName
- identifier: UPNSuffix
columnName: InitiatingAccountUPNSuffix
- entityType: Account
fieldMappings:
- identifier: AadUserId
columnName: InitiatingAadUserId
- entityType: Account
fieldMappings:
- identifier: FullName
columnName: AddedUser
- identifier: Name
columnName: TargetAccountName
- identifier: UPNSuffix
columnName: Ta
| Sentinel Table | Notes |
|---|---|
AuditLogs | Ensure this data connector is enabled |
Scenario: Scheduled Job Creates Temporary User Account
Description: A system maintenance job creates a temporary user account with a non-standard name (e.g., temp_user_20250415) to perform automated tasks.
Filter/Exclusion: Check for accounts created by known system tools or scheduled jobs (e.g., cron, task scheduler, or Ansible playbook execution). Use a filter like:
process.parent_process_name : "cron" OR process.parent_process_name : "task scheduler" OR process.parent_process_name : "ansible"
Scenario: Admin Task to Rename User Account
Description: An administrator renames an existing user account, resulting in a name that temporarily doesn’t match the expected pattern (e.g., renaming john.doe to john.doe_new).
Filter/Exclusion: Filter out accounts that were previously created and are being renamed. Use a filter like:
user.account_creation_time < [some_date] OR user.account_last_modified_time > [some_date]
Scenario: User Account Created via LDAP Sync Tool
Description: A Lightweight Directory Access Protocol (LDAP) synchronization tool creates a user account with a name that doesn’t conform to the naming format due to a misconfiguration or data mapping issue.
Filter/Exclusion: Check for accounts created by LDAP sync tools (e.g., Microsoft Identity Manager, OpenLDAP, or ADSync). Use a filter like:
process.parent_process_name : "ldap" OR process.parent_process_name : "adsync" OR process.parent_process_name : "microsoft.identitymanager"
Scenario: User Account Created via API Integration
Description: A third-party application or internal API creates a user account with a non-standard