DCOM Lateral Movement
Id | d58035ff-0bac-4c61-a7f4-f58939ff9764 |
Rulename | 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 |
Tactics | LateralMovement |
Techniques | T1021.003 |
Required data connectors | MicrosoftThreatProtection |
Kind | Scheduled |
Query frequency | 1h |
Query period | 1h |
Trigger threshold | 0 |
Trigger operator | gt |
Source Uri | https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/FalconFriday/Analytic Rules/DCOMLateralMovement.yaml |
Version | 1.0.0 |
Arm template | d58035ff-0bac-4c61-a7f4-f58939ff9764.json |
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
relevantTechniques:
- T1021.003
name: DCOM Lateral Movement
requiredDataConnectors:
- dataTypes:
- DeviceProcessEvents
- DeviceNetworkEvents
connectorId: MicrosoftThreatProtection
entityMappings:
- fieldMappings:
- identifier: FullName
columnName: DeviceName
entityType: Host
- fieldMappings:
- identifier: Address
columnName: RemoteIP
entityType: IP
- fieldMappings:
- identifier: CommandLine
columnName: DCOMCmdLine
entityType: Process
triggerThreshold: 0
id: d58035ff-0bac-4c61-a7f4-f58939ff9764
tactics:
- LateralMovement
version: 1.0.0
OriginalUri: https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/FalconFriday/Analytic Rules/DCOMLateralMovement.yaml
queryPeriod: 1h
kind: Scheduled
queryFrequency: 1h
severity: Medium
status: Available
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.
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
triggerOperator: gt
{
"$schema": "https://schema.management.azure.com/schemas/2019-04-01/deploymentTemplate.json#",
"contentVersion": "1.0.0.0",
"parameters": {
"workspace": {
"type": "String"
}
},
"resources": [
{
"apiVersion": "2024-01-01-preview",
"id": "[concat(resourceId('Microsoft.OperationalInsights/workspaces/providers', parameters('workspace'), 'Microsoft.SecurityInsights'),'/alertRules/d58035ff-0bac-4c61-a7f4-f58939ff9764')]",
"kind": "Scheduled",
"name": "[concat(parameters('workspace'),'/Microsoft.SecurityInsights/d58035ff-0bac-4c61-a7f4-f58939ff9764')]",
"properties": {
"alertRuleTemplateName": "d58035ff-0bac-4c61-a7f4-f58939ff9764",
"customDetails": null,
"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. \nThe 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. \n",
"displayName": "DCOM Lateral Movement",
"enabled": true,
"entityMappings": [
{
"entityType": "Host",
"fieldMappings": [
{
"columnName": "DeviceName",
"identifier": "FullName"
}
]
},
{
"entityType": "IP",
"fieldMappings": [
{
"columnName": "RemoteIP",
"identifier": "Address"
}
]
},
{
"entityType": "Process",
"fieldMappings": [
{
"columnName": "DCOMCmdLine",
"identifier": "CommandLine"
}
]
}
],
"OriginalUri": "https://github.com/Azure/Azure-Sentinel/blob/master/Solutions/FalconFriday/Analytic Rules/DCOMLateralMovement.yaml",
"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\"]);\nlet rpcNetwEvents = materialize(DeviceNetworkEvents\n| where InitiatingProcessFileName =~ \"svchost.exe\" and InitiatingProcessCommandLine has \"rpcss\" and LocalPort == 135\n| where LocalIP !~ RemoteIP and ActionType != \"ListeningConnectionCreated\"\n| project TimestampNetwEvent=bin(Timestamp, 5s),TimestampNetwEventExact=Timestamp, DeviceId, DeviceName, RPCHostID=InitiatingProcessId, RPCHostFileName=InitiatingProcessFileName, LocalIP, RemoteIP);\nlet dcomProcEvents = materialize (DeviceProcessEvents\n| where InitiatingProcessFileName =~ \"svchost.exe\" and InitiatingProcessCommandLine has \"dcomlaunch\"\n| project TimestampProcEvent=bin(Timestamp, 5s),TimestampProcEventExact=Timestamp, DeviceId, DeviceName, DCOMHostPID=InitiatingProcessId, DCOMHostFileName=InitiatingProcessFileName, DCOMPID=ProcessId, DCOMFileName=FileName, DCOMCmdLine=ProcessCommandLine);\nlet lastBootTime = materialize(DeviceProcessEvents\n| where FileName =~ \"services.exe\"\n| summarize LastBootTime=max(Timestamp) by DeviceId);\nlet RemoteDcomProcs = materialize(rpcNetwEvents\n| join kind=inner dcomProcEvents on DeviceId \n| join kind=leftouter lastBootTime on DeviceId\n| where TimestampProcEvent > LastBootTime+5m // Ignore first 5 min after boot.\n// Avoiding < 2 since if the time between netw and proc creation is negative, they can't be related. Network event must come first. \n| where datetime_diff(\"second\", TimestampProcEventExact, TimestampNetwEventExact) between (0 .. 2) \n// Allow-listing some usual suspects which create lot of noise. This is dangerous though...huge gap for bypass. \n| where DCOMFileName !in~ (allowListedExecs));\nRemoteDcomProcs\n| join kind=inner hint.strategy=broadcast (\n DeviceProcessEvents \n | where InitiatingProcessParentFileName =~ \"svchost.exe\" and InitiatingProcessFileName in ((RemoteDcomProcs | project DCOMFileName))) \non $left.DCOMHostPID == $right.InitiatingProcessParentId, DeviceId, $left.DCOMPID == $right.InitiatingProcessId\n| where InitiatingProcessParentFileName =~ \"svchost.exe\" and InitiatingProcessFileName =~ DCOMFileName \n// Allow-listing the magic of Defender.\n| where FileName !in~ (\"csc.exe\") \n| summarize make_set(ProcessCommandLine) by TimestampNetwEventExact, TimestampProcEventExact, DeviceId, DeviceName, InitiatingProcessId, LocalIP, RemoteIP, LastBootTime, DCOMCmdLine\n",
"queryFrequency": "PT1H",
"queryPeriod": "PT1H",
"severity": "Medium",
"status": "Available",
"subTechniques": [
"T1021.003"
],
"suppressionDuration": "PT1H",
"suppressionEnabled": false,
"tactics": [
"LateralMovement"
],
"techniques": [
"T1021"
],
"templateVersion": "1.0.0",
"triggerOperator": "GreaterThan",
"triggerThreshold": 0
},
"type": "Microsoft.OperationalInsights/workspaces/providers/alertRules"
}
]
}