Query Details

Security Event Activity With Monitored AD Group

Query

let _ADGroups =
    _GetWatchlist('SID-AuditADObjects')
    | where Notes has ("[GroupActivity]")
    | project GroupSID = SID, SAMAccountName, Auditors = Auditor, MonitoredEventID, Severity
    | mv-apply split(MonitoredEventID, " ") to typeof(string) on (
        summarize
            take_any(*),
            ValidEventIDs = make_list_if(MonitoredEventID, isnotempty(MonitoredEventID) and not(MonitoredEventID startswith "-")),
            ExcludedEventIDs = make_list_if(replace_string(MonitoredEventID, "-", ""), isnotempty(MonitoredEventID) and MonitoredEventID startswith "-")
        )
;
let _ExpectedActivityADGroups =
    _GetWatchlist('Activity-ExpectedSignificantActivity')
    | where Activity == "ADGroupEventID"
    | project
        Activity = Auxiliar,
        ActorAccount = ActorPrincipalName,
        GroupSid = DestinationResource
;
let _ExpectedADGroupDomains = toscalar(
    _GetWatchlist('Activity-ExpectedSignificantActivity')
    | where Activity == "MonitorADGroupFromDomain"
    | summarize make_list(Auxiliar)
);
let _AccountOperators = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "AccountOperator"
    | summarize make_list(ActorPrincipalName)
);
let add_member_eventids = dynamic([4728, 4732, 4756]);
let remove_member_eventids = dynamic([4729, 4733, 4757]);
SecurityEvent
| where isnotempty(TargetSid)
// Remove local group events where the domain of the actor account is not the expected tenant domain
| where not(EventID in (4732, 4733) and SubjectDomainName !in (_ExpectedADGroupDomains))
// Remove group enumeration events where the domain of the actor account is not the expected tenant domain
| where not(EventID in (4799) and SubjectDomainName !in (_ExpectedADGroupDomains))
// Remove local group event where account "NT AUTHORITY\NETWORK SERVICE" is added to "IIS_IUSRS" group
| where not(EventID in (4732, 4733) and MemberSid == "S-1-5-20" and TargetSid == "S-1-5-32-568")
| lookup kind=inner _ADGroups on $left.TargetSid == $right.GroupSID
| as _AuxiliarEvents
| join kind=leftanti (
    _AuxiliarEvents
    | where EventID in (array_concat(add_member_eventids, remove_member_eventids))
    | extend EventID = case(
        EventID in (4728, 4729), 4737,
        EventID in (4732, 4733), 4735,
        EventID in (4756, 4757), 4755,
        int(null)
    )
) on Account, SourceComputerId, EventID, SubjectLogonId, TargetSid
| where not(array_length(ValidEventIDs) > 0 and not(ValidEventIDs has tostring(EventID)))
| where not(array_length(ExcludedEventIDs) > 0 and ExcludedEventIDs has tostring(EventID))
| as _FilteredAuxiliarEvents
| lookup kind=leftouter (
    _FilteredAuxiliarEvents
    | where EventID in (4735, 4737, 4755)
    | project Account, SourceComputerId, EventID, SubjectLogonId, TargetUserName
    | join kind=inner (
        SecurityEvent
        | where EventID == 5136
        | project Account, SourceComputerId, SubjectLogonId, OperationType, EventData
        | mv-apply Auxiliar = parse_xml(EventData)["EventData"]["Data"] on (
            summarize BagToUnpack = make_bag(pack(tostring(Auxiliar["@Name"]), tostring(Auxiliar["#text"])))
        )
        | evaluate bag_unpack(BagToUnpack, columnsConflict="keep_source") : (Account:string, SourceComputerId:string, SubjectLogonId:string, OperationType:string, EventData:string, OpCorrelationID:string, ObjectDN:string, ObjectGUID:string, AttributeLDAPDisplayName:string, AttributeValue:string)
        | extend TargetUserName = extract(@"(?i:CN\=)([^,]+)", 1, ObjectDN)
    ) on Account, SourceComputerId, SubjectLogonId, TargetUserName
    | extend SplitAttributeValue = iff(AttributeLDAPDisplayName =~ "nTSecurityDescriptor", split(AttributeValue, "("), pack_array(AttributeValue))
    | summarize
        ValueAdded = take_anyif(SplitAttributeValue, OperationType == "%%14674"),
        ValueDeleted = take_anyif(SplitAttributeValue, OperationType == "%%14675"),
        AttributeValue_EventData = take_anyif(EventData, OperationType == "%%14674"),
        take_any(Account, SourceComputerId, EventID, SubjectLogonId, TargetUserName, AttributeLDAPDisplayName)
        by OpCorrelationID, ObjectGUID
    | extend
        ValueAdded = set_difference(ValueAdded, ValueDeleted),
        ValueDeleted = set_difference(ValueDeleted, ValueAdded)
    | mv-expand OperationTypeTranslated = pack_array("ValueAdded", "ValueDeleted") to typeof(string), ModifiedAttributeValue = pack_array(ValueAdded, ValueDeleted) to typeof(dynamic)
    | mv-expand ModifiedAttributeValue to typeof(string)
    | where isnotempty(ModifiedAttributeValue)
    | project Account, SourceComputerId, EventID, SubjectLogonId, TargetUserName, OperationTypeTranslated, AttributeLDAPDisplayName, ModifiedAttributeValue, AttributeValue_EventData
) on Account, SourceComputerId, EventID, SubjectLogonId, TargetUserName
| extend
    Activity = trim_end(@"\.", Activity),
    ActorAccount = SubjectAccount,
    GroupSid = TargetSid
// Remove expected activity
| join kind=leftanti _ExpectedActivityADGroups on Activity, ActorAccount, GroupSid
| extend
    AttributeValue_MemberSid = extract(@"([^;]+)\)\s*$", 1, ModifiedAttributeValue),
    AttributeValue_MemberName = extract(@"^((?i:CN\=.*))$", 1, ModifiedAttributeValue),
    ModifiedAttributeValue = trim_end(@"\)\s*$", ModifiedAttributeValue)
| extend
    MemberAccount = case(
        MemberSid == SubjectUserSid, SubjectUserName,
        isnotempty(MemberName), extract(@"(?i:CN\=)([^,]+)", 1, MemberName),
        isnotempty(AttributeValue_MemberName), extract(@"(?i:CN\=)([^,]+)", 1, AttributeValue_MemberName),
        ""
    ),
    MemberSid = case(
        isnotempty(MemberSid), MemberSid,
        isnotempty(AttributeValue_MemberSid), AttributeValue_MemberSid,
        MemberSid
    ),
    GroupName = SAMAccountName,
    ActorSid = SubjectUserSid,
    ActorAccountType = AccountType,
    ActorDomainName = SubjectDomainName,
    AlertSeverity = case(
        IsWorkingTime(TimeGenerated) and ActorAccount in (_AccountOperators), "Informational",
        Severity
    )
| project
    TimeGenerated,
    Computer,
    ActorAccount,
    Activity,
    GroupName,
    MemberAccount,
    ActorSid,
    GroupSid,
    MemberSid,
    ActorAccountType,
    ActorDomainName,
    AlertSeverity,
    Auditors,
    EventData,
    AttributeValue_EventData,
    AttributeLDAPDisplayName,
    OperationTypeTranslated,
    ModifiedAttributeValue

Explanation

The query is retrieving security events related to Active Directory (AD) groups and their members. It filters out events that are not relevant or expected. The query then joins the filtered events with a watchlist of AD groups to get additional information about the groups. It also performs some transformations and calculations to extract relevant data from the events. The final result includes various attributes of the events, such as the time generated, computer, actor account, activity, group name, member account, actor SID, group SID, member SID, actor account type, actor domain name, alert severity, auditors, event data, attribute value event data, attribute LDAP display name, operation type translated, and modified attribute value.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: December 29, 2022

Tables

_ADGroups_ExpectedActivityADGroupsSecurityEvent

Keywords

ADGroups,GetWatchlist,SID-AuditADObjects,GroupActivity,Notes,SAMAccountName,Auditors,MonitoredEventID,Severity,ValidEventIDs,ExcludedEventIDs,replace_string,make_list_if,split,typeof,summarize,take_any,make_list,isnotempty,startswith,_ExpectedActivityADGroups,Activity-ExpectedSignificantActivity,Activity,Auxiliar,ActorAccount,GroupSid,_ExpectedADGroupDomains,toscalar,MonitorADGroupFromDomain,_AccountOperators,AccountOperator,add_member_eventids,remove_member_eventids,SecurityEvent,isnotempty,TargetSid,EventID,SubjectDomainName,lookup,inner,leftanti,array_concat,extend,case,ValidEventIDs,tostring,ExcludedEventIDs,array_length,has,leftouter,project,join,5136,OperationType,EventData,parse_xml,BagToUnpack,evaluate,bag_unpack,columnsConflict,extract,split,set_difference,iff,trim_end,SubjectAccount,TargetSid,SubjectUserSid,SubjectUserName,AttributeValue_MemberSid,AttributeValue_MemberName,MemberSid,MemberName,ActorSid,AccountType,ActorDomainName,IsWorkingTime,TimeGenerated,Computer,AlertSeverity

Operators

wherehasprojectmv-applysplittypeofonsummarizetake_anymake_list_ifisnotemptystartswithreplace_stringmake_listtoscalararray_concatdynamiclookupkind=innerkind=leftantijoinarray_lengthtostringleftouteriff=~extractsplitset_differencetrim_endcaseisnotemptyisnotemptypack_arrayisnotemptytrim_end

Actions