Detection rules › Kusto
WinRM Plugin Lateral Movement
This query detects loading of malicious WinRM plugins. These plugins can be used for lateral movement. This tradecraft has been researched and published by Arnau Ortega at FalconForce. Refer to the references for the blog post describing the full attack chain. This detection looks at low-prevalence DLLs being loaded into the WinRM host process. To minimize false-positives, the detection looks for files that are written to disk in the last 30 days, prior to being loaded into the WinRM host process as DLL. Such DLLs are likely WinRM plugins that are being loaded. Since the use of WinRM plugins is extremely scarce in real environments, we assume that any such DLL is malicious and warrants an investigation.
MITRE ATT&CK coverage
| Tactic | Techniques |
|---|---|
| Lateral Movement | T1021.006 Remote Services: Windows Remote Management |
Event coverage
| Provider | Event/ActionType | Title |
|---|---|---|
| Sysmon | Event ID 2 | A process changed a file creation time |
| Sysmon | Event ID 7 | Image loaded |
| Sysmon | Event ID 11 | FileCreate |
| Security-Auditing | Event ID 4663 | An attempt was made to access an object. |
| Defender-DeviceFileEvents | FileCreated | File created |
| Defender-DeviceFileEvents | FileModified | File modified |
| Defender-DeviceFileEvents | FileRenamed | File renamed |
| Defender-DeviceImageLoadEvents | any | Image load (any) |
| Defender-DeviceImageLoadEvents | ImageLoaded | Image loaded |
Rule body kusto
let timeframe = 2*1d;
let default_global_prevalence = 0;
let lookback = 30d;
let PotentialPlugins = materialize(
DeviceImageLoadEvents
| where ingestion_time() >= ago(timeframe)
| where InitiatingProcessFileName =~ "wsmprovhost.exe"
| where FolderPath !startswith @"C:\windows\assembly\nativeimages_" // Excluding .NET GAC as these are irrelevant for WinRM plugins and generate false positives.
| invoke FileProfile(SHA1, 1000)
| where ProfileAvailability !~ "Error"
| where coalesce(GlobalPrevalence, default_global_prevalence) < 100
| extend FolderPath=tolower(FolderPath)
);
let PotentialWrites = (
DeviceFileEvents
| where Timestamp >= ago(lookback)
| where ActionType in~ ("FileCreated", "FileRenamed", "FileModified")
| where SHA1 in~ ((PotentialPlugins | project SHA1))
| extend FolderPath=tolower(FolderPath)
);
PotentialPlugins
| join kind=inner PotentialWrites on SHA1, DeviceId, FolderPath
// Begin environment-specific filter.
// End environment-specific filter.
Stages and Predicates
Parameters
let timeframe = 2*1d;
let default_global_prevalence = 0;
let lookback = 30d;
Let binding: PotentialWrites
let PotentialWrites = (
DeviceFileEvents
| where Timestamp >= ago(lookback)
| where ActionType in~ ("FileCreated", "FileRenamed", "FileModified")
| where SHA1 in~ ((PotentialPlugins | project SHA1))
| extend FolderPath=tolower(FolderPath)
);
Derived from lookback, PotentialPlugins.
The stages below define let PotentialPlugins (the rule's main pipeline source).
Stage 1: source
DeviceImageLoadEvents
Stage 2: where
| where ingestion_time() >= ago(timeframe)
Stage 3: where
| where InitiatingProcessFileName =~ "wsmprovhost.exe"
Stage 4: where
| where FolderPath !startswith @"C:\windows\assembly\nativeimages_"
Stage 5: invoke
| invoke FileProfile(SHA1, 1000)
Stage 6: where
| where ProfileAvailability !~ "Error"
Stage 7: where
| where coalesce(GlobalPrevalence, default_global_prevalence) < 100
Stage 8: extend
| extend FolderPath=tolower(FolderPath)
The stages below run on PotentialPlugins (the outer pipeline).
Stage 9: join
PotentialPlugins
| join kind=inner PotentialWrites on SHA1, DeviceId, FolderPath
Exclusions
Top-level NOT(...) conjuncts: predicates this rule actively suppresses.
| Field | Kind | Excluded values |
|---|---|---|
FolderPath | starts_with | C:\windows\assembly\nativeimages_ |
Indicators
Each row is a field, operator, and value that the rule matches. The corpus column counts how many other rules in the catalog look for the same combination: high numbers point to widely-used, community-vetted indicators. Blank or 1 shows that the indicator is specific to this rule.
| Field | Kind | Values |
|---|---|---|
ActionType | in |
|
GlobalPrevalence | lt |
|
InitiatingProcessFileName | eq |
|
ProfileAvailability | ne |
|
Output fields
Fields the rule emits when it matches. Chronicle authors list these in the outcome block; they appear on the detection and $risk_score drives alerting. Sentinel / Defender XDR rules build them up through project / summarize / extend stages. Sentinel maps these into alert fields via entityMappings and customDetails; Defender XDR custom detections surface them as alert fields directly.
| Field | Source |
|---|---|
FolderPath | extend |