Detection rules › Kusto
ADWS Connection from Process Injection Target
The query first collects all network connections to the Active Directory Web Services (ADWS) service. It then searches for processes that inject into a process that makes a connection to ADWS. This can be used to detect process injection into a process that is used to query Active Directory.
Known false positives
- None expected.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Stealth | |
| Discovery | |
| Collection |
References
Telemetry coverage
Rule body
let timeframe = 2*1h;
let ADWSConnections=(
DeviceNetworkEvents
| where ingestion_time() >= ago(timeframe)
| where ActionType == "ConnectionSuccess"
| where RemotePort == 9389
| extend InitiatingProcessFileName=tolower(InitiatingProcessFileName)
);
let ADWSFileNames=materialize(
ADWSConnections
| distinct InitiatingProcessFileName
);
// Look for processes that inject into a process that makes an ADWS connection.
let InjectorProcesses=materialize(
DeviceEvents
| where ingestion_time() >= ago(timeframe)
| where not(isempty(FileName))
// Look for actions associated with process injection.
| where ActionType in~ ("CreateRemoteThreadApiCall", "MemoryRemoteProtect","NtAllocateVirtualMemoryApiCall", "NtAllocateVirtualMemoryRemoteApiCall", "NtMapViewOfSectionRemoteApiCall", "NtProtectVirtualMemoryApiCall", "SetThreadContextRemoteApiCall", "QueueUserApcRemoteApiCall")
| where FileName in~ (ADWSFileNames)
| where not(InitiatingProcessFolderPath startswith @"c:\program files\vmware\vmware tools" and InitiatingProcessFileName =~ "vmtoolsd.exe")
| where not(InitiatingProcessFolderPath =~ @"C:\Windows\System32" and InitiatingProcessFileName =~ "csrss.exe")
| where not(InitiatingProcessFolderPath =~ @"C:\Windows\System32\csrss.exe")
| where not(InitiatingProcessFolderPath startswith @"c:\program files\microsoft azure ad sync\" and InitiatingProcessFileName =~ "miiserver.exe")
| extend FileName=tolower(FileName)
| lookup kind=inner ADWSConnections on DeviceId, $left.ProcessId == $right.InitiatingProcessId, $left.FileName == $right.InitiatingProcessFileName
// Begin environment-specific filter.
// End environment-specific filter.
| project DeviceId, ProcessId, FileName, InjectorProcessId=InitiatingProcessId, InjectorFileName=InitiatingProcessFileName, InjectorActionType=ActionType
);
// Find ADWS connections from processes that were injected into by another process.
ADWSConnections
| lookup kind=inner InjectorProcesses on DeviceId, $left.InitiatingProcessId == $right.ProcessId, $left.InitiatingProcessFileName == $right.FileName
| summarize arg_min(Timestamp,*), InjectionMethods=make_set(InjectorActionType) by DeviceId, DeviceName, InitiatingProcessId, InitiatingProcessFileName
| extend HostName=tostring(split(DeviceName,".")[0]),DnsDomain=iif(DeviceName contains ".", substring(DeviceName, indexof(DeviceName, ".") + 1, strlen(DeviceName)),"")
// Begin environment-specific filter.
// End environment-specific filter.
Stages and Predicates
Parameters
let timeframe = 2*1h;
let ADWSConnections is inlined into the numbered stages below.
Let binding: ADWSFileNames
let ADWSFileNames = materialize(
ADWSConnections
| distinct InitiatingProcessFileName
);
Let binding: InjectorProcesses
let InjectorProcesses = materialize(
DeviceEvents
| where ingestion_time() >= ago(timeframe)
| where not(isempty(FileName))
| where ActionType in~ ("CreateRemoteThreadApiCall", "MemoryRemoteProtect","NtAllocateVirtualMemoryApiCall", "NtAllocateVirtualMemoryRemoteApiCall", "NtMapViewOfSectionRemoteApiCall", "NtProtectVirtualMemoryApiCall", "SetThreadContextRemoteApiCall", "QueueUserApcRemoteApiCall")
| where FileName in~ (ADWSFileNames)
| where not(InitiatingProcessFolderPath startswith @"c:\program files\vmware\vmware tools" and InitiatingProcessFileName =~ "vmtoolsd.exe")
| where not(InitiatingProcessFolderPath =~ @"C:\Windows\System32" and InitiatingProcessFileName =~ "csrss.exe")
| where not(InitiatingProcessFolderPath =~ @"C:\Windows\System32\csrss.exe")
| where not(InitiatingProcessFolderPath startswith @"c:\program files\microsoft azure ad sync\" and InitiatingProcessFileName =~ "miiserver.exe")
| extend FileName=tolower(FileName)
| lookup kind=inner ADWSConnections on DeviceId, $left.ProcessId == $right.InitiatingProcessId, $left.FileName == $right.InitiatingProcessFileName
| project DeviceId, ProcessId, FileName, InjectorProcessId=InitiatingProcessId, InjectorFileName=InitiatingProcessFileName, InjectorActionType=ActionType
);
Stage 1: source
let ADWSConnections
Stage 2: source
let ADWSFileNames
Stage 3: source
let InjectorProcesses
Stage 4: source
DeviceNetworkEvents
Stage 5: where
where ...
Stage 6: where
where ActionType =~ "ConnectionSuccess"
Stage 7: where
where RemotePort == 9389
Stage 8: extend
extend InitiatingProcessFileName
Stage 9: kusto:lookup
lookup kind=inner (InjectorProcesses) on DeviceId, InitiatingProcessId, ProcessId, InitiatingProcessFileName, FileName
Stage 10: summarize
summarize InjectionMethods by DeviceId, DeviceName, InitiatingProcessId, InitiatingProcessFileName
Stage 11: extend
extend DnsDomain, HostName
Exclusions
The rule actively suppresses these predicates.
Indicators
These rows show field, operator, and value matches.
| Field | Kind | Values | Search |
|---|---|---|---|
ActionType | eq |
| field:"ActionType" kind:eq value:"ConnectionSuccess" |
ActionType | in |
| field:"ActionType" kind:in |
FileName | in |
| field:"file_name" kind:in value:"ADWSFileNames" |
RemotePort | eq |
| field:"DestinationPort" kind:eq value:"9389" |
Output fields
These fields are emitted when the rule matches.
| Field | Source |
|---|---|
DeviceId | summarize |
DeviceName | summarize |
InitiatingProcessFileName | summarize |
InitiatingProcessId | summarize |
InjectionMethods | summarize |
DnsDomain | extend |
HostName | extend |