```yaml
title: Per-Target Primitive Co-occurrence (Ransomware Spread-Module Signature)
id: corr-ransomware-spread-multi-primitive
status: experimental
description: >
Correlation rule flagging a single target host receiving lateral-movement
indicators from two or more of the four Windows code-execution primitives
(WMI, Task Scheduler, SCM, WinRM) within a 60-second window. Modern
ransomware spread modules (e.g. TheGentlemen's --spread, documented by
Check Point Research in April 2026) fire all four primitives in parallel
against every discovered host. Operator-driven lateral movement by
contrast touches one primitive per host at a time, separated by seconds
to minutes of operator decision-making. Primitive-mixing at a single
target is a near-unambiguous signal of binary-driven spread.
references:
- https://research.checkpoint.com/2026/dfir-report-the-gentlemen/
- https://attack.mitre.org/techniques/T1021/
author: ShroudCloud
date: 2026/04/20
tags:
- attack.lateral_movement
- attack.execution
- attack.t1021
logsource:
category: correlation
product: windows
detection:
primitive_wmi:
any_of:
- ParentImage|endswith: '\wmiprvse.exe'
filter:
Image|endswith:
- '\svchost.exe'
- '\WmiApSrv.exe'
- Image|endswith: '\wmic.exe'
CommandLine|contains: '/node:'
- Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
CommandLine|contains|all:
- '-ComputerName'
- 'Win32_Process'
primitive_taskscheduler:
any_of:
- Image|endswith: '\schtasks.exe'
CommandLine|contains: '/S '
- EventID: 4698
TaskContent|contains: '\\\\'
primitive_scm:
any_of:
- Image|endswith: '\sc.exe'
CommandLine|contains|all:
- '\\\\'
- 'create'
- 'binpath='
- Image|endswith:
- '\psexec.exe'
- '\paexec.exe'
- '\psexesvc.exe'
- '\csexesvc.exe'
- Image|endswith:
- '\python.exe'
- '\python3.exe'
- '\pythonw.exe'
CommandLine|contains:
- 'psexec.py'
- 'smbexec.py'
- 'crackmapexec'
- 'netexec'
- 'nxc '
- 'cme '
- EventID: 7045
ImagePath|contains:
- '\\\\'
- '%COMSPEC%'
- 'cmd.exe /Q /c'
primitive_winrm:
any_of:
- ParentImage|endswith:
- '\wsmprovhost.exe'
- '\winrshost.exe'
filter:
Image|endswith:
- '\svchost.exe'
- Image|endswith:
- '\powershell.exe'
- '\pwsh.exe'
CommandLine|contains|all:
- 'Invoke-Command'
- '-ComputerName'
- Image|endswith: '\winrs.exe'
CommandLine|contains: '-r:'
clustering:
timeframe: '60s'
group_by:
- 'TargetHost'
distinct_primitives_threshold: 2
condition: |
count_distinct(primitive_*) by TargetHost within 60s >= 2
severity_tiers:
- distinct_primitives: 2
level: critical
label: "Ransomware-grade alert — spread module likely"
- distinct_primitives: 3
level: critical
label: "P0 — burn the network; spread module confirmed"
- distinct_primitives: 4
level: critical
label: "P0 — full primitive saturation; contain immediately"
falsepositives:
- Fleet management tools executing multiple remote primitives against the same host for patching/inventory (SCCM, Intune, Tanium) — baseline and exclude by source
- Security tooling that legitimately uses multiple remote execution methods (rare; baseline)
level: critical
```
## Detection Logic Notes
### What "TargetHost" means
The correlation is per-target, not per-source. The key derivation is:
- **WMI source-side:** `wmic /node:<target>` or `Invoke-WmiMethod -ComputerName <target>` → `TargetHost = <target>`
- **WMI target-side:** the host producing the `wmiprvse.exe` parent → `TargetHost = ComputerName`
- **Task Scheduler:** `schtasks /S <target>` or Event ID 4698 host → `TargetHost = <target>` or `ComputerName`
- **SCM:** `sc \\<target>` or `psexec \\<target>` or Event ID 7045 host → `TargetHost = <target>` or `ComputerName`
- **WinRM:** `Invoke-Command -ComputerName <target>` or the host running `wsmprovhost.exe` → `TargetHost = <target>` or `ComputerName`
Your SIEM field mapping layer needs to normalize source-side `<target>` arguments and target-side `ComputerName` into a single `TargetHost` field. Without this normalization the correlation fails.
### Why 60 seconds
TheGentlemen's `--spread` module fires all four primitives against a single target within milliseconds — it's a single binary running the invocations in parallel. Operator-driven lateral movement rarely hits the same target through two different primitives within a minute because a human at the keyboard picks one method, tries it, sees if it worked, then moves on.
60s is the sweet spot:
- Too tight (< 10s) and you miss the spread module if the binary serializes its invocations
- Too loose (> 5min) and you start catching legitimate sequential admin work (e.g., admin uses RDP to connect, then via RDP uses PsExec to push a patch)
### Severity tiers — why 2 primitives = Critical
| Distinct primitives at one target in 60s | Conditional probability of benign |
|---|---|
| 1 | High — ordinary admin work, baseline and suppress |
| 2 | Low — rare in legitimate admin; most common non-ransomware cause is fleet management tools (baseline as exclusion) |
| 3 | Near-zero — ransomware spread module or red-team `--spread` equivalent |
| 4 | Zero-grade signal — full primitive saturation, active ransomware deployment |
The jump from "1" to "2" is the discriminator. Operators generally don't mix primitives on the same target in the same minute. Binaries do.
### Implementation notes
- **Sigma correlation is still an evolving spec.** The `distinct_primitives_threshold` field isn't native Sigma — implement this via your SIEM's aggregation language (Splunk `stats dc(primitive_type) by TargetHost`, Elastic `cardinality` aggregation, S1QL `groupby TargetHost, unique(primitive_type)`, etc).
- **Feed with per-primitive sub-rules.** Rather than re-implementing all primitive detection inside this rule, wire the `primitive_*` blocks to route the *output* of the existing per-road rules:
- `primitive_wmi` ← alerts from `edr-win-lat-wmic-remote-node` + `edr-win-lat-impacket-wmiexec (wmiexec selection)`
- `primitive_taskscheduler` ← alerts from `edr-win-lat-schtasks-remote` + `edr-win-lat-impacket-wmiexec (atexec selection)`
- `primitive_scm` ← alerts from `edr-win-lat-remote-psexec`
- `primitive_winrm` ← alerts from `edr-win-lat-winrm-abuse`
- **Don't double-count.** One primitive firing multiple times at the same target inside the window is still one primitive — the cardinality count is on `primitive_type`, not on event count.
### Known limitations
- **Visibility prerequisite:** this rule only works if your EDR/SIEM normalizes target host identity across source-side and target-side events. If source-side commands reference targets by IP and target-side events reference them by hostname, normalize first (DNS resolve or asset-inventory join).
- **Fleet tools will false-positive.** SCCM, Intune, Tanium, Ansible, and similar management tools legitimately use multiple remote primitives against the same host during a deployment. Baseline these explicitly by source host or service account and exclude from this rule — do NOT loosen the threshold.
- **Operator-side speed-up.** A sophisticated operator using a custom toolkit that chains multiple primitives could mimic the spread signature. This rule catches the common case (binary-driven spread) but is not a full substitute for per-primitive rules — run them in parallel.