Query Details

Security Event Suspicious AD Attributes Accessed From Unexpected Source

Query

let query_frequency = 1h;
let query_period = 14d;
let _Dictionary =
    _GetWatchlist("Value-WindowsEventsDictionary")
    | project Value = tostring(Value), Translation
;
let _ExpectedAccounts = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity in ("AccountOperator", "ADObjectAttributeAccess") and not(Notes has "[Group]")
    | summarize make_list(ActorPrincipalName)
);
let _ExpectedGroups = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "ADObjectAttributeAccess" and Notes has "[Group]"
    | summarize make_list(Auxiliar)
);
let _Identities =
    IdentityInfo
    | where TimeGenerated > ago(query_period) and isnotempty(AccountDomain)
    | summarize arg_max(TimeGenerated, *) by AccountObjectId
    | project
        SubjectUserName = coalesce(extract(@"(?i:CN\=)([^,]+)", 1, OnPremisesDistinguishedName), AccountName),
        GroupMembership = array_sort_asc(GroupMembership)
;
SecurityEvent
| where TimeGenerated > ago(2 * query_frequency)
| where EventID == 4662
    and (AccessMask == "0x100" or AccessList == "%%7688" or Properties has "%%7688")
    and not(Account in (_ExpectedAccounts))
    and (Properties has_all (
            "612cb747-c0e8-4f92-9221-fdd5f15b550d", // unixUserPassword
            "6617e4ac-a2f1-43ab-b60c-11fbd1facf05", // ms-PKI-RoamingTimeStamp - Indicates the time of the last synchronization
            "b3f93023-9239-4f7c-b99c-6745d87adbc2", // ms-PKI-DPAPIMasterKeys - Stores the DPAPI Master Keys. These symmetric keys encrypt the private keys and are themselves encrypted.
            "b7ff5a38-0818-42b0-8110-d3d154c97f24", // ms-PKI-Credential-Roaming-Tokens
            "b8dfa744-31dc-4ef1-ac7c-84baf7ef9da7"  // ms-PKI-AccountCredentials - Stores certificates, certificate signing requests, private keys and saved passwords.
            )
        or Properties has_all (
            "612cb747-c0e8-4f92-9221-fdd5f15b550d", // unixUserPassword
            "bf967a9c-0de6-11d0-a285-00aa003049e2"  // Group
            )
        or Properties has_any (
            "7b8b558a-93a5-4af7-adca-c017e67f1057", // ms-DS-Group-Managed-Service-Account
            "ea715d30-8f53-40d0-bd1e-6109186d782c", // ms-FVE-RecoveryInformation
            "43061ac1-c8ad-4ccc-b785-2bfac20fc60a"  // ms-FVE-RecoveryPassword
        ))
| summarize
    StartTime = min(TimeGenerated),
    EndTime = max(TimeGenerated),
    EventCount = count(),
    ObjectNameCount = count_distinct(ObjectName),
    ObjectNamesSample = array_sort_asc(make_set_if(trim(@"[\%\{\}\s]+", ObjectName), isnotempty(ObjectName), 20)),
    SubjectLogonId = make_set_if(SubjectLogonId, isnotempty(SubjectLogonId), 20),
    Properties = make_set_if(Properties, isnotempty(Properties), 50),
    take_any(Activity, OperationType, AccountType, SubjectUserName, AccessList, EventOriginId)
    by Computer, Account, AccessMask, ObjectType, bin(TimeGenerated, 1h)
| where ObjectNameCount > 10
| where not(ObjectNameCount < 100 and ObjectType has_any ("bf967aba-0de6-11d0-a285-00aa003049e2", "bf967a86-0de6-11d0-a285-00aa003049e2")) // User Computer
| lookup kind=leftouter _Identities on SubjectUserName
| project-away SubjectUserName
| where not(array_length(_ExpectedGroups) > 0 and GroupMembership has_all (_ExpectedGroups))
| extend AccessList = trim(@"\s+", AccessList)
| lookup kind=leftouter (
    _Dictionary
    | project
        AccessList = Value,
        AccessListTranslated = Translation
    ) on AccessList
| extend ObjectType = trim(@"[\%\{\}\s]+", ObjectType)
| lookup kind=leftouter (
    _Dictionary
    | project
        ObjectType = Value,
        ObjectTypeTranslated = Translation
    ) on ObjectType
| mv-expand Properties to typeof(string)
| mv-expand PropertiesKey = split(translate("{}", "", trim(@"\s+", replace_regex(Properties, @"\s+", " "))), " ") to typeof(string)
| lookup kind=leftouter (
    _Dictionary
    | project
        PropertiesKey = Value,
        PropertiesKeyTranslated = Translation
    )
    on PropertiesKey
| summarize
    take_any(*),
    PropertiesTranslated = strcat_array(make_list(iff(isnotempty(PropertiesKeyTranslated), PropertiesKeyTranslated, PropertiesKey)), " | ")
    by EventOriginId
| as hint.materialized=true _Auxiliar
| mv-expand SubjectLogonId to typeof(string)
| lookup kind=leftouter (
    SecurityEvent
    | where TimeGenerated > ago(query_frequency + 1h)
    | where EventID == 4624 and Account in (toscalar(_Auxiliar | summarize make_list(Account)))
    | project Computer, Account, TargetLogonId, IpAddress
    )
    on Computer, Account, $left.SubjectLogonId == $right.TargetLogonId
| summarize
    SubjectLogonIds = make_set(SubjectLogonId),
    IpAddresses = make_set_if(IpAddress, isnotempty(IpAddress)),
    take_any(*)
    by EventOriginId
| summarize
    StartTime = min(StartTime),
    EndTime = max(EndTime),
    Computers = make_set(Computer),
    SubjectLogonIds = make_set(SubjectLogonIds),
    IpAddresses = make_set(IpAddress),
    EventCount = sum(EventCount),
    AccessLists = make_set(AccessList),
    AccessListsTranslated = make_set(AccessListTranslated),
    ObjectTypes = make_set(ObjectType),
    ObjectTypesTranslated = array_sort_asc(make_set(ObjectTypeTranslated)),
    ObjectNameCount = sum(ObjectNameCount),
    ObjectNamesSample = make_set(ObjectNamesSample),
    Properties = make_set(Properties),
    PropertiesTranslated = make_set(PropertiesTranslated),
    take_any(AccountType, Activity, OperationType, GroupMembership)
    by Account, bin(TimeGenerated, 1h)
| where EndTime > ago(query_frequency)
| where not(array_length(ObjectTypes) == 1 and ObjectTypes has_any ("bf967aba-0de6-11d0-a285-00aa003049e2", "bf967a86-0de6-11d0-a285-00aa003049e2", "bf967a9c-0de6-11d0-a285-00aa003049e2")) // User Computer Group
| project
    StartTime,
    EndTime,
    Computers,
    Account,
    AccountType,
    SubjectLogonIds,
    IpAddress = tostring(IpAddresses[0]),
    IpAddresses,
    Activity,
    EventCount,
    OperationType,
    AccessLists,
    AccessListsTranslated,
    ObjectTypes,
    ObjectTypesTranslated,
    ObjectNameCount,
    ObjectNameEventCountRatio = round(ObjectNameCount / toreal(EventCount), 2),
    ObjectNamesSample,
    Properties,
    PropertiesTranslated,
    AccountGroupMembership = GroupMembership

Explanation

The query is retrieving security events related to specific access permissions and properties. It filters out expected accounts and groups, and then performs various lookups and transformations on the data. The final result includes information about the start and end times of the events, the computers involved, the accounts, account types, subject logon IDs, IP addresses, activity, event count, operation type, access lists, object types, object name count, object name event count ratio, object name samples, properties, properties translations, and account group membership.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: November 30, 2023

Tables

SecurityEvent_Dictionary_ExpectedAccounts_ExpectedGroups_Identities_Auxiliar

Keywords

Devices,Intune,User

Operators

letprojecttoscalarwheresummarizemake_listmake_setarray_sort_asccoalesceextractisnotemptyarg_maxisnotemptyarray_lengthextendlookupmv-expandsplittranslatereplace_regexiffstrcat_arrayhint.materialized=truesumround

Actions