Detection rules › Kusto

WinRM Plugin Lateral Movement

Author
FalconForce
Source
github.com/FalconForceTeam/FalconFriday

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

Event coverage

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.

FieldKindExcluded values
FolderPathstarts_withC:\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.

FieldKindValues
ActionTypein
  • FileCreated corpus 8 (kusto 8)
  • FileModified
  • FileRenamed
GlobalPrevalencelt
  • 100 transforms: coalesce_default:0 corpus 4 (kusto 4)
InitiatingProcessFileNameeq
  • wsmprovhost.exe corpus 6 (elastic 2, splunk 2, kusto 2)
ProfileAvailabilityne
  • Error

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.

FieldSource
FolderPathextend