```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.