EDR-Freeze Puts Your Sensor in a Coma With a Signed Windows Dumper. The Detection Is a Gap in Your Own Telemetry

WerFaultSecure.exe is Microsoft’s signed secure crash-dump component, and EDR-Freeze launches it as a WinTCB-level protected process (PPL) so it can read the memory of your most sensitive processes — LSASS, Defender’s MsMpEng.exe, your third-party EDR sensor — the way Windows itself dumps a protected process. EDR-Freeze, published by the researcher behind Zero Salarium in September 2025, turns that dumper into an off switch. Point WerFaultSecure at the sensor’s PID, wait for MiniDumpWriteDump to suspend the target’s threads while it snapshots memory, then suspend the dumper itself mid-write before it can resume them. The target’s threads stay parked for as long as the operator keeps the dumper suspended — the PoC holds it for a chosen interval and then terminates WerFaultSecure, which lets the target resume, so the freeze ends when the dumper is terminated or resumed, the sensor is otherwise recovered, or the box restarts. The targeted sensor isn’t dead; its threads are suspended. It remains present but stops executing. Kernel callbacks or companion components may stay registered, but the practical effect on them varies by product architecture. No kernel driver loaded. No vulnerable-driver blocklist entry tripped. No code-integrity event. The whole thing runs in user mode against binaries that ship with the OS.

TL;DR

  • EDR-Freeze abuses WerFaultSecure.exe — a Microsoft-signed WinTCB/PPL crash dumper — to suspend a security sensor’s threads mid-dump, then suspends the dumper itself before it can resume them, leaving the sensor frozen entirely in user mode with no driver load, blocklist trip, or code-integrity event.
  • The dangerous part is forensic: a frozen sensor keeps a live PID and — depending on the vendor’s watchdog and management-plane logic — may keep reporting “healthy” until a heartbeat timeout expires, all while the targeted user-mode sensor stops emitting its normal telemetry, so post-freeze ransomware, credential theft, or lateral movement runs against a primary detection surface that’s asleep.
  • Filename/IMPHASH Sigma rules are a canary at best — trivially evaded by anyone who renames and recompiles, so keep them low-severity and don’t mistake them for a control; the durable detection is behavioral — Sysmon EID 1 for WerFaultSecure spawned outside the WER service chain with the full flag set (/h, /pid, /tid, /encfile, /cancel, /type, 268310) and a /pid targeting a security process, correlated with EID 10 showing another process open a PROCESS_SUSPEND_RESUME handle against WerFaultSecure itself.
  • Tune out benign protected-process crashes by requiring the full flag combination plus a parent outside your baselined WER chain, and split it into two tiers — a high-severity analytic that also requires the external suspension of the dumper (legitimate WER dumps and resumes the target, so an unrelated process requesting suspend rights against the active secure dumper isn’t part of that workflow and reads as highly suspicious), and a medium-severity one on the launch-plus-heartbeat-gap for when that EID 10 event isn’t collected. Baseline local debuggers and security tooling first.
  • Without EID 10 process-access telemetry and command-line auditing the analytic loses its strongest confirmation and falls back to weaker signals; since the frozen agent may be your own log path, route telemetry off-box (Sysmon shipped via native Windows Event Forwarding or another forwarder the endpoint agent doesn’t control) and treat a sensor heartbeat gap plus a WerFaultSecure spawn as the most durable composite signal.

That is the part that should worry a SOC lead more than the technique itself: the forensic signature of a frozen sensor is the absence of the sensor’s own telemetry, and absence is the hardest thing in the world to alert on. Whatever the operator does after the freeze — ransomware staging, credential theft, lateral movement — happens in a window where your primary detection surface is asleep and, depending on the vendor’s watchdog and management-plane logic, may still be reading “healthy” to the console until its heartbeat or health-check timeout expires. The process exists. It has a PID. It just isn’t executing — and whether the console notices depends entirely on whether that product treats process existence, a kernel component, or a live heartbeat as its health signal.

The mechanism, and why it dodges the usual tripwires

Most prominent EDR-killer tooling of the last several years has favored one of two doors. Bring Your Own Vulnerable Driver — load a signed-but-broken driver, get kernel execution, tear the sensor’s callbacks out from the inside. Or direct process-handle abuse that requires sufficiently elevated rights and usually collides with the sensor’s own self-protection. Both can leave artifacts in layers defenders commonly monitor. BYOVD in particular can light up the Microsoft vulnerable-driver blocklist, Sysmon EID 6 driver loads, and code-integrity telemetry — though only when the specific driver or certificate is actually covered, the blocklist is current and enforced, and you’re collecting driver-load events in the first place. The point isn’t that BYOVD is always caught; it’s that it touches layers where you at least have a chance.

EDR-Freeze walks through neither door. The trick is a race condition against a legitimate Windows behavior. MiniDumpWriteDump, when it snapshots a process, suspends the target process’s threads so it can read a consistent memory image, then resumes them when the dump completes. WerFaultSecure is the component Windows uses to dump protected processes, so it runs as a PPL at the WinTCB level — which is precisely what lets it touch a PPL-protected EDR that normal tooling can’t. The attack spawns WerFaultSecure as a PPL, hands it arguments telling it to dump the sensor’s PID, polls until the target’s threads go suspended, and at that instant opens a handle to WerFaultSecure with PROCESS_SUSPEND_RESUME and calls NtSuspendProcess on the dumper. Now the dumper is frozen before it can issue the resume. The sensor’s threads stay parked. Deadlock, by design, using two Microsoft components doing exactly what they were built to do.

The precise prerequisite is an elevated token that already holds SeDebugPrivilege — normally obtained through local administrator or SYSTEM under standard Windows policy. “User mode” (as bleepingcomputer frames it) is not the same as “low privilege”: no kernel driver loads, but AdjustTokenPrivileges can only enable a privilege the token already has, not grant one it lacks, and the PoC’s own EnableDebugPrivilege() call exits if it can’t turn SeDebugPrivilege on. So “local admin” and “has SeDebugPrivilege” aren’t identical conditions — the second is the operative one. Any post-exploitation foothold that’s already SYSTEM or admin-with-SeDebug clears that bar trivially. The significance was never the privilege level. It’s that the technique produces none of the attacker-driver, vulnerable-driver-blocklist, or callback-removal artifacts defenders normally associate with EDR killers. A sufficiently capable vendor self-protection layer may still observe or prevent the handle abuse — Microsoft says Defender detects and blocks it, and that’s the right question for your bake-off below — but the conventional BYOVD telemetry you’d reach for first has nothing to show you.

Microsoft’s response, given to bleepingcomputer, was that Defender customers “are not impacted by this tool, and any attempt will be detected and blocked before execution.” Defender now ships two detections for it — a behavioral one, Behavior:Win32/EDRFreeze.A, and a tampering one, Tampering:Win32/EDRFreeze!rfn. Microsoft documents EDRFreeze.A explicitly as “a detection for specific malicious behavior rather than traditional persistent malware,” and the write-up names the sequence it keys on: the SeDebugPrivilege enablement, the PPL creation with PROC_THREAD_ATTRIBUTE_PROTECTION_LEVEL and CREATE_PROTECTED_PROCESS, and the WerFaultSecure abuse. That’s behavioral, not a hash on one compiled binary. A rename and a recompile will dodge static, artifact-based indicators — and the Detect.FYI author reportedly did exactly that to shake trivial AV signatures — but there is no public evidence that recompilation alone beats Microsoft’s behavioral coverage. Don’t assume the signature layer is a speed bump; do assume it isn’t the whole answer, which is why you still want the behavioral analytic below.

The filename Sigma rule everyone shipped first is a canary, not a control

The reflexive detection — and the one that hit SigmaHQ within days — matches the tool. Image path contains \EDR-Freeze or \EDRFreeze, or one of eight known IMPHASH values. The rule rates its own false-positive likelihood as “Unlikely,” which is true and also completely beside the point. Anyone deploying this in anger renames the binary and rebuilds. The IMPHASH isn’t guaranteed to move on any recompile — it’s derived from the PE import table (imported DLLs and function names, and their order), so a build that only changes optimization or code generation can leave it unchanged — but it’s easy to shift deliberately by altering the imported functions, their ordering, or the runtime linkage. A rename defeats the filename branch; a suitably altered rebuild defeats the known-IMPHASH branch. So the rule detects the PoC, not the technique: it’s genuine coverage for unmodified commodity use — and threat actors do run public tooling with minimal changes, which is why it earns a slot as a low-severity canary — but it is not a control you can lean on.

The detection that survives contact with a real intrusion is behavioral, and it lives on the abuse of WerFaultSecure itself. ARC Labs’ teardown calls out a high-fidelity command-line shape: WerFaultSecure.exe carrying /encfile, /cancel, and /type 268310 together. Two caveats on that /type value: 268310 is a constant the PoC hardcodes and its own source comments as “dump full” — treat it as a PoC implementation detail, not a documented, semantically stable Windows API contract. And those three flags are the high-value pivots, not the complete invocation: the current SigmaHQ command-line rule requires the full set — /h, /pid, /tid, /encfile, /cancel, /type, and 268310 — so if you author your own, either match the full combination or knowingly trade some precision for variant tolerance with a reduced subset. Combined with a /pid pointing at a security process, it’s a strong signal. In Sysmon terms you want two correlated events:

  • EID 1 (process creation) for WerFaultSecure.exe where the parent falls outside your locally baselined WER chain, and the command line carries /pid referencing MsMpEng.exe, MsSense.exe, or your EDR’s sensor binary. Don’t hardcode “svchost.exe hosting the WER service, or WerFault.exe” as the complete legitimate ancestry — WER parentage shifts with Windows build, protected-process type, and whether reporting was service- or application-initiated, so baseline the expected chain for each supported build before you alert on “unusual parent.”
  • EID 10 (process access) where the target is WerFaultSecure.exe and GrantedAccess includes PROCESS_SUSPEND_RESUME (0x0800). Be precise about what this proves: an external process (the launcher, or any non-WER process) opening a handle to the crash dumper with suspend rights is the prerequisite handle acquisition for the freeze step — WerFaultSecure as the target, something else as the source. It is not “self-suspension” (WerFaultSecure never suspends itself), but neither is the handle open itself the freeze; the actual primitive is the subsequent NtSuspendProcess call, which standard Sysmon EID 10 doesn’t directly report. So correlate the handle acquisition with the characteristic dumper launch, the target’s thread suspension or heartbeat loss, and tight timing rather than treating the open as proof on its own. External suspend-rights against the active secure dumper aren’t part of the normal WER dump-and-resume workflow, so treat it as highly suspicious — subject to local validation for debuggers and security tooling.

A word on the shipped rules, because they don’t all cover the same relationship and the naming invites conflation. SigmaHQ currently carries three EDR-Freeze rules. “Hacktool – EDR-Freeze Execution” is the filename/IMPHASH rule above — canary only. “PPL Tampering Via WerFaultSecure” matches the full WerFaultSecure command-line argument set — that’s the stronger process-creation detection, and the one to promote to production (reserve “durable” for the multi-source correlation; the exact argument set is still PoC-specific). “Suspicious Process Access of MsMpEng by WerFaultSecure – EDR-Freeze” is a process-access (EID 10) rule, but look closely at which relationship it matches: SourceImage WerFaultSecure.exe accessing TargetImage MsMpEng.exe with dbgcore.dll/dbghelp.dll in the CallTrace. That’s the dumper reading Defender’s memory — the dump step — not the external suspension of the dumper. The suspend-the-dumper analytic in the EID 10 bullet above is a custom analytic you have to write yourself; no published SigmaHQ rule currently matches it, so don’t ship it expecting a stock rule to cover it. Omar Tarek Zayed’s Detect.FYI build guide walks the correlation logic in more depth. One mapping note before you tune severities: all three of those SigmaHQ rules tag the behavior attack.t1685 under attack.defense-impairment, and that’s the current, correct ATT&CK mapping. ATT&CK v19 moved this behavior into the new Defense Impairment tactic (TA0112) and revoked the former T1562.001 sub-technique in favor of the top-level T1685 – Disable or Modify Tools, whose description explicitly covers disabling, degrading, or tampering with EDR, antivirus, and logging agents — a clean fit for temporarily rendering a sensor nonfunctional without deleting or modifying its files. Expect both IDs in the wild: the revoked T1562.001 still turns up in historical detections and downstream products, but this post uses the current T1685.

In Splunk, if you’re normalizing Sysmon through the Add-on, the join is roughly: EID 1 Image="*\\WerFaultSecure.exe" where ParentImage isn’t in your WER allowlist and CommandLine matches the flag set, correlated against EID 10 TargetImage="*\\WerFaultSecure.exe" where GrantedAccess carries the PROCESS_SUSPEND_RESUME bit, inside a short window on the same host. Match the bit, not the literal string GrantedAccess="0x800" — Sysmon reports the field in hex and the attacker’s handle can carry additional access bits, so an exact-string filter silently misses a handle opened with, say, 0x1800 (which contains both 0x1000 and 0x0800; if your pipeline normalizes to decimal, that’s 6144, and the bit you want is 2048). Splunk can’t bitwise-test a raw hex string without converting it first, so the test is roughly — and treat this as illustrative, not drop-in SPL, since field names and function support vary by version and data model:

| eval granted_access_dec=tonumber(replace(GrantedAccess,"^0x",""),16)
| where bitand(granted_access_dec, 2048) = 2048

A transaction or stats correlation works here: the process-local sequence is immediate — the suspend follows the spawn almost instantly — so start with a 10-to-30-second event-time window and widen only for known timestamp-granularity, batching, or forwarding delays in your pipeline.

Where the false positives come from, and the first tuning pass

WerFaultSecure is not exotic. It fires whenever a protected process actually crashes, and on a fleet of any size, protected processes crash — Defender’s own MsMpEng.exe throws faults, LSASS throws faults under certain auth stacks, and WER dutifully dumps them. So a naive “WerFaultSecure touched a security PID” rule will page you every time Defender hiccups. Per the ARC Labs analysis, legitimate WerFaultSecure runs use overlapping command-line options, which is exactly why the single-flag version of this rule is noisy.

The first tuning pass has to do two things. Constrain on the full flag combination (the complete /h /pid /tid /encfile /cancel /type 268310 set, not any one of them), and require the parent process to fall outside your baselined WER service chain. That alone drops the bulk of the noise. The residual false positives you’ll still see come from genuine crashes of a security process where WER legitimately spawns the secure dumper — and the discriminator there is the external suspension of the dumper. Real WER dumps and resumes the target; an unrelated process requesting suspend rights against the active secure dumper isn’t part of that workflow, so it reads as highly suspicious once you’ve baselined out local debuggers and security tooling. If you’re only alerting on the EID 1 spawn you’ll have a bad first week. The clean way to handle this is two analytics rather than one strict rule. A high-severity analytic requires the EID 10 PROCESS_SUSPEND_RESUME-against-WerFaultSecure event alongside the command line — that’s the confirmed sequence, and it’s nearly silent-until-it-matters. A medium-severity analytic fires on the characteristic WerFaultSecure launch against a security PID with an out-of-baseline parent, corroborated by a subsequent sensor heartbeat gap, without requiring the suspend-access event. You want that second tier because the EID 10 event isn’t guaranteed to be there: ProcessAccess collection may be filtered or dropped, Sysmon may have started after the handle op, the product may record the action through different telemetry, or the EDR may block the operation before the expected sequence completes. Don’t make the highest-confidence event a universal prerequisite for any alert — make it the thing that separates “wake someone now” from “investigate.”

Volume is environment-specific, and I’m not going to hand you a fleet-wide “X per day” figure — anyone who does without telling you the estate size, Windows build mix, WER policy, and developer/debugging workload is guessing. The honest guidance is to baseline it yourself: measure your own unfiltered WerFaultSecure.exe creation and the relevant ProcessAccess events before you assign severity or suppression logic. Expect the raw WerFaultSecure spawn rate to be non-trivial on any real Windows estate (protected processes do crash), a sharp drop after the parent-process and flag-combination constraints, and something close to silence once the external-suspension requirement is in. If it fires then, it’s worth waking someone.

The assumptions that decide whether any of this works

The strongest confirmation in this whole analytic rests on having EID 10 process-access telemetry, and that is not a safe default. Sysmon’s ProcessAccess event is heavy — it’s one of the noisiest events Sysmon emits, and plenty of shops either don’t run Sysmon at all or run it with a config that excludes EID 10 to control volume. If you’ve got the SwiftOnSecurity config or a derivative that filters process access aggressively, check whether WerFaultSecure is even in scope before you trust the rule. Lose EID 10 and you don’t lose the detection outright — you lose its most conclusive signal (the external suspension of the dumper) and fall back to weaker, less specific evidence: the characteristic command line, the parent ancestry, the SeDebugPrivilege enablement, the temporary dump-file create/delete, and the heartbeat gap below. That’s a real downgrade in confidence, not a collapse.

Second assumption: you can see WerFaultSecure’s command line at all. That means process-creation command-line auditing is on (Sysmon EID 1, or Event ID 4688 with the command-line inclusion GPO enabled). A depressing number of Windows fleets still run 4688 without command-line capture, which reduces this to “WerFaultSecure ran,” useless for discrimination.

Third, and this is the one people miss: the frozen sensor is the thing generating your telemetry. If EDR-Freeze targets your only EDR and that EDR is also your log-forwarding path, the post-freeze activity may never reach the SIEM. This is the argument for a detection stack that doesn’t route everything through the agent that’s about to get put to sleep — Windows Event Forwarding to a collector the endpoint agent doesn’t control, or a Sysmon-to-SIEM path independent of the EDR’s own uplink. Be clear about what that buys you, though: it reduces shared fate with the EDR agent, but it isn’t immunity — an attacker who also disables Sysmon, the Windows Event Log service, the WEF subscription, or network egress blinds it too, so off-box forwarding is a layer, not a guarantee. Agent-health monitoring belongs here too: a sensor whose process exists but has stopped heartbeating past the product’s normal heartbeat interval and your locally established health threshold, correlated against a WerFaultSecure spawn on the same host in the same window, is a high-confidence composite even if you missed the suspend event itself. That heartbeat-gap-plus-WER-spawn correlation is one of the most durable detections in this whole piece, because it doesn’t depend on the operator being sloppy with flags.

Hardening, and the control mapping

Detection buys you the alert. Prevention narrows the door, and here it’s genuinely hard. Be careful who you attribute the hardening advice to: Microsoft’s on-record statement was only that Defender customers “are not impacted… any attempt will be detected and blocked before execution” — it did not, in that reporting, recommend WDAC or AppLocker. The application-control idea comes from the surrounding hardening discussion, not from Microsoft, so don’t cite it as vendor guidance.

Application control can still help, but only at one end. A WDAC or AppLocker policy can block the untrusted launcher — an unsigned binary, or one executing from a user-writable path — before it ever spawns the dumper. What it can’t do is discriminate the malicious WerFaultSecure invocation from the legitimate one, because application control keys on a binary’s identity (path, publisher, hash), not its command line, and WerFaultSecure is a Microsoft-signed Windows component: allow signed Microsoft binaries and the abuse stays available; block WerFaultSecure by path/publisher/hash and you break Windows crash handling the first time a genuine protected-process fault needs the dumper. Treat direct blocking of the dumper as a tested exception strategy for a specific locked-down enclave, not a general hardening recommendation.

The other end is the vendor’s. The right question to put on your next EDR bake-off scorecard isn’t “do you block WerFaultSecure” — it’s whether the product’s kernel self-protection prevents or detects an untrusted process obtaining PROCESS_SUSPEND_RESUME (or terminate) rights against the sensor, its watchdog, or a trusted intermediary like WerFaultSecure that’s being used to impair it. A driver can register an ObRegisterCallbacks handler that filters process-handle creation and duplication and inspects the requested access mask — but note the mechanics honestly: that callback observes the handle request, it doesn’t directly announce that NtSuspendProcess was later called, so turning “a handle with PROCESS_SUSPEND_RESUME was opened against my dumper” into “someone froze the dump” still takes correlation. And remember the direction of the critical step: it’s an external process opening WerFaultSecure, not WerFaultSecure opening the EDR. Ask the vendor directly whether they’ve shipped that self-protection.

The NIST SP 800-53 mapping is straightforward. This is squarely SI-4 (system monitoring) — the whole point is monitoring for defensive-tool impairment, MITRE ATT&CK T1685, Disable or Modify Tools (historically T1562.001 in pre-v19 ATT&CK). The agent-health and heartbeat-gap piece is SI-4 monitoring; I’d only stretch it to SI-7 (software/firmware integrity) if your implementation actually validates the sensor’s binaries, configuration, or running state rather than just watching for a heartbeat — a missing heartbeat is a monitoring signal, not an integrity check. Application-control hardening around the untrusted launcher is CM-7 (least functionality), with AC-6 (least privilege) the stronger control for constraining which accounts and tokens can obtain SeDebugPrivilege in the first place. Routing telemetry off-box so a frozen agent can’t blind you is AU-6 (audit review) and AU-9 (protection of audit information) — your logging path shouldn’t share fate with the process an attacker is trying to silence. And Defender’s own behavioral coverage, Behavior:Win32/EDRFreeze.A, is SI-3 (malicious code protection) — useful, and more than a filename signature, but not something to lean on as the sole control.

Treat the signature layer as the floor and the behavioral correlation as the actual control. A frozen sensor that can still read healthy to the console is the exact failure mode your monitoring exists to catch, and — where the suspend event itself slips past you — one of the strongest signals left is the shape of the hole where the telemetry used to be.

Sources


This post was engineered and validated through a multi-agent AI workflow — drafted, adversarially reviewed by several independent models, checked against primary sources, and given a human review before publishing. See an inaccuracy, or found this useful? Leave a comment below — corrections and feedback are read and shape what comes next.

Leave a comment