Query Details

Identity Logon Events Unexpected Access To Multiple Devices

Query

let query_frequency = 1h;
let query_period = 14d;
let device_threshold = 15;
let _ExpectedAccounts = toscalar(
    _GetWatchlist("Activity-ExpectedSignificantActivity")
    | where Activity == "DeviceNTLMScan"
    | summarize make_list(ActorPrincipalName)
);
let _ExpectedTargetDevices = toscalar(
    _GetWatchlist("Service-PrivateCorporateServices")
    | where Notes has "[NTLMAccess]"
    | summarize make_list(HostName)
);
IdentityLogonEvents
| where TimeGenerated > ago(query_frequency)
| where LogonType == "Resource access" and not(Protocol == "Kerberos")// and Application == "Active Directory" and ActionType == "LogonSuccess"
| where not(tostring(AdditionalFields["ACTOR.DEVICE"]) == tostring(AdditionalFields["TARGET_OBJECT.DEVICE"]))
| where not(AccountUpn in (_ExpectedAccounts))
| where not(TargetDeviceName has_any (_ExpectedTargetDevices))
| extend SourceEntity = coalesce(AccountUpn, IPAddress, DeviceName)
| summarize
    StartTime = min(TimeGenerated),
    EndTime = max(TimeGenerated),
    SourceDevices = make_set_if(DeviceName, isnotempty(DeviceName)),
    SourceIPAddresses = make_set_if(IPAddress, isnotempty(IPAddress)),
    take_any(AccountUpn, AccountName, AccountDomain, AccountSid, AccountObjectId, AccountDisplayName, ActionType)
    by SourceEntity, TargetDeviceName, Application, Protocol
| join kind=leftanti (
    IdentityLogonEvents
    | where TimeGenerated between (ago(query_period) .. ago(query_frequency))
    | where LogonType == "Resource access" and not(Protocol == "Kerberos")// and Application == "Active Directory" and ActionType == "LogonSuccess"
    | where not(tostring(AdditionalFields["ACTOR.DEVICE"]) == tostring(AdditionalFields["TARGET_OBJECT.DEVICE"]))
    | where not(AccountUpn in (_ExpectedAccounts))
    | where not(TargetDeviceName has_any (_ExpectedTargetDevices))
    | extend SourceEntity = coalesce(AccountUpn, IPAddress, DeviceName)
    | where not(isempty(SourceEntity) or isempty(TargetDeviceName))
    ) on SourceEntity, TargetDeviceName
| summarize
    StartTime = min(StartTime),
    EndTime = max(EndTime),
    SourceDevices = make_set(SourceDevices),
    SourceIPAddresses = make_set(SourceIPAddresses),
    TargetDevices = make_set_if(TargetDeviceName, isnotempty(TargetDeviceName), 250),
    take_any(AccountUpn, AccountName, AccountDomain, AccountSid, AccountObjectId, AccountDisplayName, ActionType)
    by SourceEntity, Application, Protocol
| extend TargetDevicesCount = array_length(TargetDevices)
| where TargetDevicesCount > device_threshold
| extend SourceDevice = iff(array_length(SourceDevices) == 1, tostring(SourceDevices[0]), "")
| sort by TargetDevicesCount desc
| project
    StartTime,
    EndTime,
    Application,
    ActionType,
    Protocol,
    SourceEntity,
    SourceDevice,
    SourceDevices,
    SourceIPAddresses,
    TargetDevicesCount,
    TargetDevices,
    AccountDisplayName,
    AccountUpn,
    AccountSid,
    AccountObjectId

Explanation

This query is looking for logon events in the IdentityLogonEvents table that meet certain criteria. It filters for logon events that occurred within the last hour, have a LogonType of "Resource access" and not a Protocol of "Kerberos". It also excludes logon events where the actor device is the same as the target device, and where the account UPN is in a list of expected accounts, and where the target device name is in a list of expected target devices.

The query then summarizes the results by grouping them based on the source entity, target device name, application, and protocol. It also calculates the start and end times of the logon events, and creates sets of source devices and source IP addresses. It takes any one of the account UPN, account name, account domain, account SID, account object ID, account display name, and action type for each group.

The query then performs a left anti join with another set of logon events from the IdentityLogonEvents table, this time looking for events that occurred between 14 days ago and 1 hour ago. It applies the same filters as before and creates the same sets and calculations.

After the join, the query summarizes the results again, this time grouping them by the source entity, application, and protocol. It calculates the start and end times, creates sets of source devices, source IP addresses, and target devices. It also counts the number of target devices and filters for groups where the count is greater than a threshold value.

Finally, the query extends the results by adding a source device column that takes the first value from the source devices set if it contains only one value. It then sorts the results by the count of target devices in descending order and projects a selected set of columns for the final output.

Details

Jose Sebastián Canós profile picture

Jose Sebastián Canós

Released: June 29, 2023

Tables

IdentityLogonEvents

Keywords

IdentityLogonEvents,TimeGenerated,LogonType,Protocol,AdditionalFields,AccountUpn,_ExpectedAccounts,_ExpectedTargetDevices,IPAddress,DeviceName,Application,ActionType,SourceEntity,TargetDeviceName,SourceDevices,SourceIPAddresses,AccountName,AccountDomain,AccountSid,AccountObjectId,AccountDisplayName,StartTime,EndTime,TargetDevicesCount,SourceDevice

Operators

|,let,=,1h,;,14d,15,_,toscalar,_GetWatchlist,|,where,==,and,not,.,tostring,in,has_any,extend,summarize,by,join,kind=leftanti,between,isempty,array_length,iff,sort,desc,project

Actions