New Privileged Account¶
Alert¶
An account was added to a privileged Active Directory group (Domain Admins, Enterprise Admins, Administrators, and similar) or assigned a privileged Entra ID role (Global Administrator, Privileged Role Administrator, Exchange Administrator, and similar), or a new account was created and given privileges shortly after.
Why It Matters¶
Granting privilege to an account the attacker controls is a common step right before ransomware deployment or data theft, and a common persistence method afterward. It is also a normal admin task, so the question is whether it was authorized.
ATT&CK¶
Questions I Answer¶
- Who made the change, and from where? The actor account, the host or IP, and the time.
- Is there a change ticket or request? And does the actor confirm it, asked by phone or chat, not email?
- Who received the privilege? A brand-new account, a service account, a disabled account that was re-enabled, or an account with a name that imitates a real admin are all warning signs.
- What did the account do after it got privileges?
Queries¶
Active Directory privileged group changes:
SecurityEvent
| where TimeGenerated > ago(7d)
| where EventID in (4728, 4732, 4756)
| where TargetUserName in~ ("Domain Admins", "Enterprise Admins", "Schema Admins", "Administrators", "Account Operators", "Backup Operators", "Server Operators")
| project TimeGenerated, Computer, Actor = SubjectUserName, MemberAdded = MemberName, Group = TargetUserName
Entra ID role assignments:
AuditLogs
| where TimeGenerated > ago(7d)
| where OperationName in ("Add member to role", "Add eligible member to role")
| extend Actor = coalesce(tostring(InitiatedBy.user.userPrincipalName), tostring(InitiatedBy.app.displayName))
| extend Target = tostring(TargetResources[0].userPrincipalName)
| mv-apply prop = TargetResources[0].modifiedProperties on (
where tostring(prop.displayName) == "Role.DisplayName"
| extend Role = trim('"', tostring(prop.newValue)))
| project TimeGenerated, Actor, Target, Role, Result
Accounts created and granted privileges within a day (Active Directory):
let created = SecurityEvent
| where TimeGenerated > ago(7d) and EventID == 4720
| project Created = TimeGenerated, AccountSid = TargetSid, NewAccount = TargetUserName, CreatedBy = SubjectUserName;
SecurityEvent
| where TimeGenerated > ago(7d)
| where EventID in (4728, 4732, 4756)
| project Granted = TimeGenerated, AccountSid = MemberSid, Group = TargetUserName, GrantedBy = SubjectUserName
| join kind=inner created on AccountSid
| where Granted between (Created .. (Created + 1d))
| project Created, Granted, NewAccount, Group, CreatedBy, GrantedBy
The query joins on the account SID, because the group membership events record the member as a distinguished name rather than the account name.
Verdict¶
- Benign true positive: a documented change by an admin who confirms it
- True positive: no ticket, the actor denies it, or the actor account itself shows signs of compromise
- Process gap: a real admin made the change without a ticket; not an intrusion, but worth fixing
Escalate¶
Active Directory Privileged Compromise for on-premises changes, or Compromised Account / BEC for an Entra ID role assigned by a compromised cloud account. I remove the privilege immediately if the change is unauthorized, after recording the details.