Detection rules › Kusto
DCOM Lateral Movement
This detection looks for cases of close-time proximity between incoming network traffic on RPC/TCP, followed by the creation of a DCOM object, followed by the creation of a child process of the DCOM object. The query first identifies incoming network traffic over RPC/TCP, followed by the creation of a DCOM object (process) within 2 seconds, followed by the creation of a child process of this DCOM object.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Lateral Movement |
Telemetry coverage
Rule body
id: d58035ff-0bac-4c61-a7f4-f58939ff9764
name: DCOM Lateral Movement
description: |
This detection looks for cases of close-time proximity between incoming network traffic on RPC/TCP, followed by the creation of a DCOM object, followed by the creation of a child process of the DCOM object.
The query first identifies incoming network traffic over RPC/TCP, followed by the creation of a DCOM object (process) within 2 seconds, followed by the creation of a child process of this DCOM object.
severity: Medium
status: Available
requiredDataConnectors:
- connectorId: MicrosoftThreatProtection
dataTypes:
- DeviceProcessEvents
- DeviceNetworkEvents
queryFrequency: 1h
queryPeriod: 1h
triggerOperator: gt
triggerThreshold: 0
tactics:
- LateralMovement
relevantTechniques:
- T1021.003
query: |
let allowListedExecs = dynamic(["TiWorker.exe", "dllhost.exe", "backgroundTaskHost.exe", "mobsync.exe", "WmiPrvSE.exe", "RuntimeBroker.exe", "smartscreen.exe", "SppExtComObj.Exe", "usocoreworker.exe", "browser_broker.exe", "ssoncom.exe"]);
let rpcNetwEvents = materialize(DeviceNetworkEvents
| where InitiatingProcessFileName =~ "svchost.exe" and InitiatingProcessCommandLine has "rpcss" and LocalPort == 135
| where LocalIP !~ RemoteIP and ActionType != "ListeningConnectionCreated"
| project TimestampNetwEvent=bin(Timestamp, 5s),TimestampNetwEventExact=Timestamp, DeviceId, DeviceName, RPCHostID=InitiatingProcessId, RPCHostFileName=InitiatingProcessFileName, LocalIP, RemoteIP);
let dcomProcEvents = materialize (DeviceProcessEvents
| where InitiatingProcessFileName =~ "svchost.exe" and InitiatingProcessCommandLine has "dcomlaunch"
| project TimestampProcEvent=bin(Timestamp, 5s),TimestampProcEventExact=Timestamp, DeviceId, DeviceName, DCOMHostPID=InitiatingProcessId, DCOMHostFileName=InitiatingProcessFileName, DCOMPID=ProcessId, DCOMFileName=FileName, DCOMCmdLine=ProcessCommandLine);
let lastBootTime = materialize(DeviceProcessEvents
| where FileName =~ "services.exe"
| summarize LastBootTime=max(Timestamp) by DeviceId);
let RemoteDcomProcs = materialize(rpcNetwEvents
| join kind=inner dcomProcEvents on DeviceId
| join kind=leftouter lastBootTime on DeviceId
| where TimestampProcEvent > LastBootTime+5m // Ignore first 5 min after boot.
// Avoiding < 2 since if the time between netw and proc creation is negative, they can't be related. Network event must come first.
| where datetime_diff("second", TimestampProcEventExact, TimestampNetwEventExact) between (0 .. 2)
// Allow-listing some usual suspects which create lot of noise. This is dangerous though...huge gap for bypass.
| where DCOMFileName !in~ (allowListedExecs));
RemoteDcomProcs
| join kind=inner hint.strategy=broadcast (
DeviceProcessEvents
| where InitiatingProcessParentFileName =~ "svchost.exe" and InitiatingProcessFileName in ((RemoteDcomProcs | project DCOMFileName)))
on $left.DCOMHostPID == $right.InitiatingProcessParentId, DeviceId, $left.DCOMPID == $right.InitiatingProcessId
| where InitiatingProcessParentFileName =~ "svchost.exe" and InitiatingProcessFileName =~ DCOMFileName
// Allow-listing the magic of Defender.
| where FileName !in~ ("csc.exe")
| summarize make_set(ProcessCommandLine) by TimestampNetwEventExact, TimestampProcEventExact, DeviceId, DeviceName, InitiatingProcessId, LocalIP, RemoteIP, LastBootTime, DCOMCmdLine
entityMappings:
- entityType: Host
fieldMappings:
- identifier: FullName
columnName: DeviceName
- entityType: IP
fieldMappings:
- identifier: Address
columnName: RemoteIP
- entityType: Process
fieldMappings:
- identifier: CommandLine
columnName: DCOMCmdLine
version: 1.0.0
kind: Scheduled
Stages and Predicates
let rpcNetwEvents and let RemoteDcomProcs are inlined into the numbered stages below.
Let binding: allowListedExecs
let allowListedExecs = dynamic(["TiWorker.exe", "dllhost.exe", "backgroundTaskHost.exe", "mobsync.exe", "WmiPrvSE.exe", "RuntimeBroker.exe", "smartscreen.exe", "SppExtComObj.Exe", "usocoreworker.exe", "browser_broker.exe", "ssoncom.exe"]);
Let binding: dcomProcEvents
let dcomProcEvents = materialize (DeviceProcessEvents
| where InitiatingProcessFileName =~ "svchost.exe" and InitiatingProcessCommandLine has "dcomlaunch"
| project TimestampProcEvent=bin(Timestamp, 5s),TimestampProcEventExact=Timestamp, DeviceId, DeviceName, DCOMHostPID=InitiatingProcessId, DCOMHostFileName=InitiatingProcessFileName, DCOMPID=ProcessId, DCOMFileName=FileName, DCOMCmdLine=ProcessCommandLine);
Let binding: lastBootTime
let lastBootTime = materialize(DeviceProcessEvents
| where FileName =~ "services.exe"
| summarize LastBootTime=max(Timestamp) by DeviceId);
Stage 1: source
let rpcNetwEvents
Stage 2: source
let dcomProcEvents
Stage 3: source
let lastBootTime
Stage 4: source
let RemoteDcomProcs
Stage 5: source
DeviceNetworkEvents
Stage 6: where
where InitiatingProcessCommandLine contains "rpcss" and InitiatingProcessFileName =~ "svchost.exe" and LocalPort == 135
Stage 7: where
where ActionType !~ "ListeningConnectionCreated" and LocalIP != RemoteIP
Stage 8: project
project DeviceId, DeviceName, LocalIP, RPCHostFileName, RPCHostID, RemoteIP, TimestampNetwEvent, TimestampNetwEventExact
Stage 9: join
join kind=inner (dcomProcEvents) on DeviceId
Stage 10: join
join kind=leftouter (lastBootTime) on DeviceId
Stage 11: where TimestampProcEvent - LastBootTime > 5m
where TimestampProcEvent - LastBootTime > 5m
Stage 12: where TimestampProcEventExact - TimestampNetwEventExact >= 0s AND TimestampProcEventExact - TimestampNetwEventExact <= 2s
where TimestampProcEventExact - TimestampNetwEventExact >= 0s AND TimestampProcEventExact - TimestampNetwEventExact <= 2s
Stage 13: where
where not (DCOMFileName in~ ("RuntimeBroker.exe", "SppExtComObj.Exe", "TiWorker.exe", "WmiPrvSE.exe", "backgroundTaskHost.exe", "browser_broker.exe", "dllhost.exe", "mobsync.exe", "smartscreen.exe", "ssoncom.exe", "usocoreworker.exe"))
Stage 14: join
join kind=inner (DeviceProcessEvents) on DCOMHostPID, InitiatingProcessParentId, DeviceId, DCOMPID, InitiatingProcessId
Stage 15: where
where InitiatingProcessFileName =~ DCOMFileName and InitiatingProcessParentFileName =~ "svchost.exe"
Stage 16: where
where not (FileName =~ "csc.exe")
Stage 17: summarize
summarize by TimestampNetwEventExact, TimestampProcEventExact, DeviceId, DeviceName, InitiatingProcessId, LocalIP, RemoteIP, LastBootTime, DCOMCmdLine
Exclusions
The rule actively suppresses these predicates.
| Field | Kind | Excluded values | Search |
|---|---|---|---|
DCOMFileName | in | RuntimeBroker.exe, SppExtComObj.Exe, TiWorker.exe, WmiPrvSE.exe, backgroundTaskHost.exe, browser_broker.exe, dllhost.exe, mobsync.exe, smartscreen.exe, ssoncom.exe, usocoreworker.exe | excludes:DCOMFileName |
FileName | eq | csc.exe | excludes:FileName field:"FileName" value:"csc.exe" |
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActionType | ne |
| field:"ActionType" kind:ne value:"ListeningConnectionCreated" |
FileName | eq |
| field:"file_name" kind:eq value:"services.exe" |
InitiatingProcessCommandLine | match |
| field:"CommandLine" kind:match |
InitiatingProcessFileName | cross_field_compare |
| field:"parent_process_name" kind:cross_field_compare value:"DCOMFileName" |
InitiatingProcessFileName | eq |
| field:"parent_process_name" kind:eq value:"svchost.exe" |
InitiatingProcessParentFileName | eq |
| field:"ParentImage" kind:eq value:"svchost.exe" |
LocalIP | cross_field_compare |
| field:"SourceIp" kind:cross_field_compare value:"RemoteIP" |
LocalPort | eq |
| field:"SourcePort" kind:eq value:"135" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DCOMCmdLine | summarize |
DeviceId | summarize |
DeviceName | summarize |
InitiatingProcessId | summarize |
LastBootTime | summarize |
LocalIP | summarize |
RemoteIP | summarize |
TimestampNetwEventExact | summarize |
TimestampProcEventExact | summarize |