Query Details

Security Event Non DC Active Directory Replication

Query

let query_frequency = 15m;
let query_period = 3h;
let query_wait = 15m;
let replication_threshold = 10;
let _BenignDSReplication =
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "DSReplication"
    | project Account = ActorPrincipalName, IpAddress = SourceAddress
;
SecurityEvent
| where ingestion_time() between (ago(query_frequency + query_wait) .. ago(query_wait))
| where EventID == 4662 and ObjectServer == "DS" and AccountType != "Machine"
| where Properties has_any (
    // https://learn.microsoft.com/en-us/windows/win32/adschema/extended-rights
    "{1131f6ad-9c07-11d1-f79f-00c04fc2dcd2}", //DS-Replication-Get-Changes-All
    "{1131f6aa-9c07-11d1-f79f-00c04fc2dcd2}", //DS-Replication-Get-Changes
    "{89e95b76-444d-4c62-991a-0facbeda640c}", //DS-Replication-Get-Changes-In-Filtered-Set
    "{9923a32a-3607-11d2-b9be-0000f87a36b2}"  //DS-Install-Replica
    //"{19195a5b-6da0-11d0-afd3-00c04fd930c9}", //Domain-DNS class WRITE_DAC
    //"{1131f6ab-9c07-11d1-f79f-00c04fc2dcd2}", //DS-Replication-Synchronize'
    //"{1131f6ac-9c07-11d1-f79f-00c04fc2dcd2}"  //DS-Replication-Manage-Topology'
    )
| project-away TargetLogonId, IpAddress
| lookup kind=leftouter (
    SecurityEvent
    | where ingestion_time() > ago(query_period)
    | where EventID == 4624 and AccountType != "Machine" and LogonType == 3
    | distinct
        Computer,
        TargetLogonId,
        Logon_Account = Account,
        IpAddress
    ) on Computer, $left.SubjectLogonId == $right.TargetLogonId
// If Account was not registered, substitute by Logon_Account
| extend Account = iff(Account == @"-\-", Logon_Account, Account)
// Remove expected DS replications
| join kind=leftanti _BenignDSReplication on IpAddress, Account
| summarize
    arg_min(TimeGenerated, AccountType, Activity, AccessList, AccessMask, ObjectServer, ObjectType, OperationType, Logon_Account),
    OperationCount = count(),
    PropertiesList = array_sort_asc(make_set(split(replace_string(Properties, "\t", ""), " "))),
    SubjectLogonIdList = make_set(SubjectLogonId, 250)
    by Computer, Account, IpAddress, ObjectName
// Events where logon was not registered, thus IpAddress is not available, are assumed to be benign and happen infrequently
| where not(isempty(IpAddress) and OperationCount < replication_threshold and Account in (toscalar(_BenignDSReplication | summarize make_set(Account))))
| project
    TimeGenerated,
    Computer,
    Account,
    AccountType,
    Activity,
    AccessList,
    AccessMask,
    ObjectServer,
    ObjectType,
    ObjectName,
    OperationType,
    OperationCount,
    PropertiesList,
    SubjectLogonIdList,
    Logon_Account,
    IpAddress

Explanation

This query is looking for security events related to DS replication. It filters the events based on certain criteria and removes expected DS replications. It then summarizes the remaining events and selects specific fields for the final result.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: June 9, 2023

Tables

SecurityEvent_BenignDSReplication

Keywords

SecurityEvent,Account,IpAddress,EventID,ObjectServer,AccountType,Properties,Computer,TargetLogonId,LogonType,Logon_Account,SubjectLogonId,TimeGenerated,Activity,AccessList,AccessMask,ObjectType,OperationType,replication_threshold,ObjectName

Operators

letwhereprojecthas_anyproject-awaylookupextendjoinsummarizearg_mincountarray_sort_ascmake_setsplitreplace_stringbynotisemptytoscalar

Actions