Accounts being added or removed from Active Directory groups may indicate lateral movement or privilege changes by an adversary, as unauthorized group membership modifications can facilitate persistent access or escalate privileges within the environment. SOC teams should proactively hunt for these changes in Azure Sentinel to identify potential compromise and mitigate risk before further damage occurs.
KQL Query
//Added to group
IdentityDirectoryEvents
| where Application == "Active Directory"
| where ActionType == "Group Membership changed"
| extend parsed=parse_json(AdditionalFields)
| extend INITIATED_BY = iff( isnull(AdditionalFields.["ACTOR.ACCOUNT"]), AdditionalFields.["ACTOR.ACCOUNT"], AdditionalFields.["ACTOR.ACCOUNT"])
| extend GROUP_CHANGED = iff( isnull(AdditionalFields.["TO.GROUP"]), AdditionalFields.["TO.GROUP"], AdditionalFields.["TO.GROUP"])
| where GROUP_CHANGED <> ""
| extend GROUP_ADDED = iff( isnull(AdditionalFields.["TARGET_OBJECT.GROUP"]), AdditionalFields.["TARGET_OBJECT.GROUP"], AdditionalFields.["TARGET_OBJECT.GROUP"])
| extend USER_ADDED = iff( isnull(AdditionalFields.["TARGET_OBJECT.USER"]), AdditionalFields.["TARGET_OBJECT.USER"], AdditionalFields.["TARGET_OBJECT.USER"])
| extend DEVICE_ADDED = iff( isnull(AdditionalFields.["TARGET_OBJECT.DEVICE"]), AdditionalFields.["TARGET_OBJECT.DEVICE"], AdditionalFields.["TARGET_OBJECT.DEVICE"])
| project Timestamp, ActionType, INITIATED_BY, GROUP_CHANGED, GROUP_ADDED, USER_ADDED, DEVICE_ADDED,AdditionalFields
//Removed from group
IdentityDirectoryEvents
| where Application == "Active Directory"
| where ActionType == "Group Membership changed"
| extend parsed=parse_json(AdditionalFields)
| extend INITIATED_BY = iff( isnull(AdditionalFields.["ACTOR.ACCOUNT"]), AdditionalFields.["ACTOR.ACCOUNT"], AdditionalFields.["ACTOR.ACCOUNT"])
| extend GROUP_CHANGED = iff( isnull(AdditionalFields.["FROM.GROUP"]), AdditionalFields.["FROM.GROUP"], AdditionalFields.["FROM.GROUP"])
| where GROUP_CHANGED <> ""
| extend GROUP_REMOVED = iff( isnull(AdditionalFields.["TARGET_OBJECT.GROUP"]), AdditionalFields.["TARGET_OBJECT.GROUP"], AdditionalFields.["TARGET_OBJECT.GROUP"])
| extend USER_REMOVED = iff( isnull(AdditionalFields.["TARGET_OBJECT.USER"]), AdditionalFields.["TARGET_OBJECT.USER"], AdditionalFields.["TARGET_OBJECT.USER"])
| extend DEVICE_REMOVED = iff( isnull(AdditionalFields.["TARGET_OBJECT.DEVICE"]), AdditionalFields.["TARGET_OBJECT.DEVICE"], AdditionalFields.["TARGET_OBJECT.DEVICE"])
| project Timestamp, ActionType, INITIATED_BY, GROUP_CHANGED, GROUP_REMOVED, USER_REMOVED, DEVICE_REMOVED,AdditionalFields
id: b66fb322-247a-4472-a231-2533b34ed059
name: MDI_Group_Memebership_Changes
description: |
Find accounts that have been added/removed from groups in AD.
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- IdentityDirectoryEvents
tactics:
- Credential Access
query: |
//Added to group
IdentityDirectoryEvents
| where Application == "Active Directory"
| where ActionType == "Group Membership changed"
| extend parsed=parse_json(AdditionalFields)
| extend INITIATED_BY = iff( isnull(AdditionalFields.["ACTOR.ACCOUNT"]), AdditionalFields.["ACTOR.ACCOUNT"], AdditionalFields.["ACTOR.ACCOUNT"])
| extend GROUP_CHANGED = iff( isnull(AdditionalFields.["TO.GROUP"]), AdditionalFields.["TO.GROUP"], AdditionalFields.["TO.GROUP"])
| where GROUP_CHANGED <> ""
| extend GROUP_ADDED = iff( isnull(AdditionalFields.["TARGET_OBJECT.GROUP"]), AdditionalFields.["TARGET_OBJECT.GROUP"], AdditionalFields.["TARGET_OBJECT.GROUP"])
| extend USER_ADDED = iff( isnull(AdditionalFields.["TARGET_OBJECT.USER"]), AdditionalFields.["TARGET_OBJECT.USER"], AdditionalFields.["TARGET_OBJECT.USER"])
| extend DEVICE_ADDED = iff( isnull(AdditionalFields.["TARGET_OBJECT.DEVICE"]), AdditionalFields.["TARGET_OBJECT.DEVICE"], AdditionalFields.["TARGET_OBJECT.DEVICE"])
| project Timestamp, ActionType, INITIATED_BY, GROUP_CHANGED, GROUP_ADDED, USER_ADDED, DEVICE_ADDED,AdditionalFields
//Removed from group
IdentityDirectoryEvents
| where Application == "Active Directory"
| where ActionType == "Group Membership changed"
| extend parsed=parse_json(AdditionalFields)
| extend INITIATED_BY = iff( isnull(AdditionalFields.["ACTOR.ACCOUNT"]), AdditionalFields.["ACTOR.ACCOUNT"], AdditionalFields.["ACTOR.ACCOUNT"])
| extend GROUP_CHANGED = iff( isnull(AdditionalFields.["FROM.GROUP"]), AdditionalFields.["FROM.GROUP"], AdditionalFields.["FROM.GROUP"])
| where GROUP_CHANGED <> ""
| extend GROUP_REMOVED = iff( isnull(AdditionalFields.["TARGET_OBJECT.GROUP"]), AdditionalFields.["TARGET_OBJECT.GROUP"], AdditionalFields.["TARGET_OBJECT.GROUP"])
| extend USER_REMOVED = iff( isnull(AdditionalFields.["TARGET_OBJECT.USER"]), AdditionalFields.["TARGET_OBJECT.USER"], AdditionalFields.["TARGET_OBJECT.USER"])
| extend DEVICE_REMOVED = iff( isnull(AdditionalFields.["TARGET_OBJECT.DEVICE"]), AdditionalFields.["TARGET_OBJECT.DEVICE"], AdditionalFields.["TARGET_OBJECT.DEVICE"])
| project Timestamp, ActionType, INITIATED_BY, GROUP_CHANGED, GROUP_REMOVED, USER_REMOVED, DEVICE_REMOVED,AdditionalFields
version: 1.0.0
metadata:
source:
kind: Community
author:
name: Matt Novitsch
support:
tier: Community
categories:
domains: [ "Security - Identity" ]
| Sentinel Table | Notes |
|---|---|
IdentityDirectoryEvents | Ensure this data connector is enabled |
Scenario: Scheduled Group Membership Sync Job
Description: A scheduled job (e.g., using PowerShell or ADSync) runs to synchronize group memberships between on-premises AD and Azure AD.
Filter/Exclusion: Exclude events where the source is a known sync tool (e.g., EventID=4728 with LogonType=10 or LogonProcess=ADSync).
Scenario: Administrative User Group Membership Change
Description: An admin manually adds or removes a user from a group via the Active Directory Users and Computers (ADUC) console or using LDIFDE.
Filter/Exclusion: Exclude events where the user is a known admin (e.g., UserPrincipalName matches a predefined admin list or LogonType=2).
Scenario: Automated Group Membership Update via GPO
Description: A Group Policy Object (GPO) is configured to dynamically update group memberships based on user attributes (e.g., department).
Filter/Exclusion: Exclude events where the change is initiated by a GPO (e.g., EventID=4728 with LogonType=3 or LogonProcess=GroupPolicy).
Scenario: User Migration or Bulk Import via CSV
Description: A bulk import of users via CSVDE or Import-CSV in PowerShell adds multiple users to groups in bulk.
Filter/Exclusion: Exclude events where the source is a bulk import tool (e.g., EventID=4728 with LogonType=11 or LogonProcess=CSVDE).
Scenario: Service Account Group Membership Change
Description: A service account (e.g., `