CVE-2026-68820 Anatomy: How Lazarus Group’s afd.sys Use-After-Free Race Condition Became a SYSTEM-Level Zero-Day Paired With FudModule Rootkit and ForestTiger Backdoor

A defense-sector engineer opens what looks like a routine job offer, a PDF from a recruiter at a security vendor he half-recognizes. Five weeks later, Check Point Research is telling Microsoft that the same lure quietly detonated a kernel zero-day, blinded every ETW-based sensor on the box, and dropped a backdoor that talks to its operators over OneDrive. That is the compressed story of CVE-2026-68820, and if you have followed afd.sys at all, none of it should surprise you.


Why afd.sys Is a Permanent Lazarus Target

Here is the uncomfortable thesis up front: afd.sys is not an unlucky driver that keeps catching bugs. It is a structurally inevitable target, and Microsoft keeps shipping point fixes that never touch the reason it stays exploitable.

Look at the surface it presents. The Ancillary Function Driver for WinSock sits in kernel mode on every supported build of Windows, from Server 2012 R2 through Windows 11 24H2. It is the kernel-side plumbing behind every socket() call any process ever makes. It is reachable by a completely unprivileged local user through NtDeviceIoControlFile, with no driver-signing bypass, no admin token, no elevation prerequisite. And it manages a pile of per-socket state that must be shared and mutated across threads, which is exactly the condition that breeds use-after-free and race bugs.

Put those three properties together and you get a driver that is universally present, trivially reachable, and full of synchronization-sensitive state. That is a privilege-escalation goldmine, and North Korea has mined it repeatedly.

CVEYearClassNotable exploitation
CVE-2024-381932024UAFExploited in the wild, attributed to Lazarus, paired with FudModule
CVE-2025-214182025Heap-based buffer overflowExploited in the wild, added to CISA KEV
CVE-2025-327092025UAFExploited in the wild, EoP to admin
CVE-2026-688202026UAF + race conditionExploited in the wild, Lazarus, FudModule 3.1 + ForestTiger

Four in-the-wild afd.sys elevation zero-days in three years, and the same actor keeps showing up. When you see that cadence you stop treating each one as a coincidence and start treating the component as the vulnerability.


afd.sys Internals: From a socket() Call to a Kernel IRP

To understand where CVE-2026-68820 lives, you have to know how a Winsock call actually reaches the kernel. Most developers think socket() talks to the network stack. It does, but the path runs straight through afd.sys first.

The user-mode side stacks like this: your application calls ws2_32!socket, ws2_32 routes provider calls into mswsock.dll (the Microsoft Winsock service provider), and mswsock ultimately issues NtDeviceIoControlFile syscalls against a handle to \Device\Afd. Those syscalls package their parameters into an I/O Request Packet (IRP) and hand it to the kernel I/O manager, which dispatches it to afd.sys through the driver’s IRP_MJ_DEVICE_CONTROL handler.

Application
   -> ws2_32!socket / WSASocketW
      -> mswsock.dll (Winsock SPI)
         -> ntdll!NtDeviceIoControlFile   (syscall)
            -> nt!IopXxxControlFile -> IoBuildDeviceIoControlRequest (IRP)
               -> \Device\Afd  ->  afd.sys IRP_MJ_DEVICE_CONTROL dispatch
                  -> per-socket context object (AFD endpoint)

Every socket has a kernel-side context object that afd.sys allocates from the nonpaged pool and threads through the lifetime of that socket. Public reverse-engineering work has long referred to it as AFD_ENDPOINT. Microsoft does not formally document the struct, and I want to be precise: the name and its exact field layout come from community research on earlier afd.sys bugs, not from a Microsoft advisory for this CVE. Treat it as the well-understood shape of the object, not a confirmed detail of 68820’s specific freed allocation.

You can watch the machinery live in a kernel debugger:

kd> !drvobj afd.sys 2
kd> !devobj \Device\Afd
kd> dt nt!_DEVICE_OBJECT <addr>
kd> !irp <irp_addr>
kd> dt nt!_IRP <irp_addr> Tail.Overlay.CurrentStackLocation

Set a breakpoint on the dispatch entry and issue a couple of Winsock calls from user mode, and you will see the IRP arrive carrying the IOCTL code and the input/output buffers. That IRP is the attacker’s only channel into afd.sys, and it is enough.


Flowchart showing the path from a user-mode socket() call through ws2_32, mswsock, NtDeviceIoControlFile, the I/O Manager, into afd.sys and the per-socket AFD_ENDPOINT kernel object
Every Winsock call reaches the kernel as an IRP dispatched to afd.sys, giving any unprivileged local process a direct channel into the vulnerable endpoint context.

CWE-416 Deep Dive: The Use-After-Free Root Cause

Microsoft’s advisory pins CVE-2026-68820 to CWE-416, use-after-free, triggered by a race condition. In their words, “a locally authenticated attacker could run a specially crafted application on an affected system to trigger a race condition.” Everything else about the internal code path is, as of this writing, either inferred from the class or waiting on Check Point’s full patch-diff teardown. So let me draw the mechanics of the class carefully and flag where I am reasoning from pattern rather than confirmed fact.

A use-after-free in kernel nonpaged pool works like this. afd.sys allocates the socket context with ExAllocatePoolWithTag, holds a pointer to it, and later frees it with ExFreePoolWithTag. The bug is not the free itself. The bug is that some other code path still holds a stale pointer to that allocation and dereferences it after the free. If nothing has reclaimed the pool slot yet, the stale read returns freed data. If an attacker has reclaimed that slot with a controlled allocation of the same size, the stale pointer now reads and writes attacker-shaped memory inside the kernel.

The synchronization gap is the whole game. Consider two socket operations that both touch the endpoint object:

// Illustrative of the UAF *class*, not the confirmed 68820 code path.

NTSTATUS AfdDispatchTeardown(PAFD_ENDPOINT ep) {
    // Path A: transitions/cleans up the socket, frees the context
    ExFreePoolWithTag(ep, 'DfaE');   // object goes back to the pool
    // ... no lock held across the free that path B respects ...
    return STATUS_SUCCESS;
}

NTSTATUS AfdDispatchQuery(PAFD_ENDPOINT ep) {
    // Path B: reads a field / follows a pointer inside the same object
    PDEVICE_OBJECT devobj = IoGetRelatedDeviceObject(ep->FileObject); // UAF if A already freed ep
    // devobj now points into reclaimed pool if the attacker won the race
    return devobj->DriverObject->...; // controlled dereference
}

If a lock or reference count properly guarded the object across the free-versus-use pair, there would be no bug. The vulnerability is the missing (or too-narrow) synchronization that lets Path A free while Path B is mid-reference. That is the essence of a UAF-race: correctness depends on ordering that the code fails to enforce.

The reason this class keeps recurring in afd.sys specifically is that socket teardown, information queries, and state transitions all legitimately touch the same context object from different IRP handlers, and Winsock is inherently multithreaded. Getting the locking exactly right across dozens of dispatch paths is genuinely hard, and afd.sys has now lost that bet four times in three years.


The Race Condition: Winning the Timing Window

A UAF that requires a race is probabilistic, not deterministic. You do not “call the bug,” you run two threads in a tight loop and wait for the scheduler to interleave them in your favor. That has real consequences for both exploitation reliability and detection, so it is worth understanding the model.

The canonical afd.sys race, seen across the prior CVEs, uses two threads against a single socket handle:

  • Thread A (free path): loops on a state-transition or teardown IOCTL that ends up freeing the endpoint context. In prior public analyses this has been modeled with bind/unbind churn (IOCTL_AFD_BIND / IOCTL_AFD_UNBIND). The exact IOCTLs used by 68820 are not publicly confirmed.
  • Thread B (use path): loops on a query IOCTL that dereferences a pointer inside that same context (IOCTL_AFD_GET_INFORMATION-style). If Thread B lands its dereference in the window after Thread A frees but before the pool slot is reused or zeroed, you get the UAF.

The window is small, often a handful of instructions wide. Two things make it winnable in practice. First, sheer volume: run both threads millions of times and you only need to win once. Second, CPU affinity, pinning the two threads to different logical cores so they run truly concurrently rather than time-slicing on one core. Attackers routinely SetThreadAffinityMask the racer threads onto separate cores to widen the effective window.

Winning the race is only half of reliability. The other half is making sure that when the freed slot gets reclaimed, you are the one who reclaims it. That is heap grooming.

The nonpaged pool allocates by size class and tag. If the endpoint object comes out of, say, a 0x200-byte bucket, you want to spray thousands of controlled 0x200-byte allocations so that the moment afd.sys frees the endpoint, your next spray lands in that exact slot. Two classic Windows pool-spray primitives do this well: repeated ALPC port creation (NtAlpcCreatePort) and reserve-object allocation (NtAllocateReserveObject, the technique James Forshaw popularized). Both give you attacker-sized allocations with attacker-controlled contents in the nonpaged pool.

kd> !pool <freed_addr>
kd> dt nt!_POOL_HEADER <freed_addr>
kd> !poolused 2 DfaE      // watch the tag's allocation count during spray

When grooming works, the stale pointer in the “use” path now walks a structure whose bytes you wrote. That is the pivot from a memory-safety bug to a real primitive.


Graph diagram showing Thread A freeing the AFD_ENDPOINT, an attacker spray reclaiming the slot with a fake controlled object, and Thread B dereferencing the stale pointer to yield a kernel read/write primitive
Winning the race requires Thread A and Thread B running concurrently on separate cores, with a heap spray ensuring the freed slot is reclaimed with attacker-controlled bytes before Thread B dereferences it.

From UAF to SYSTEM: The Privilege-Escalation Primitive

Once your fake object occupies the freed slot, the query IOCTL dereferences a pointer you control. Depending on what the vulnerable path does with that pointer, you get one of two primitives:

  • A kernel read, if the path reads through your controlled pointer and returns the value to user mode.
  • A kernel write, if the path writes through it, which quickly bootstraps into an arbitrary write-what-where.

Either one, iterated, gives you an arbitrary kernel read/write. That is the universal currency of Windows LPE, and from there the endgame is boringly reliable. The most durable technique is direct token theft:

1. Locate the SYSTEM process token.
   - Read nt!PsInitialSystemProcess -> the System EPROCESS.
   - Read System EPROCESS.Token (an _EX_FAST_REF, mask off the low bits).

2. Locate your own EPROCESS.
   - Walk ActiveProcessLinks from System until UniqueProcessId matches your PID.

3. Overwrite your process's Token field with System's token pointer.
   - One arbitrary write. Your process is now SYSTEM.

In WinDbg you confirm the offsets and the swap directly:

kd> dt nt!_EPROCESS Token
kd> !process 0 0 System
kd> dt nt!_EPROCESS <system_eprocess> Token
kd> dt nt!_EPROCESS <target_eprocess> Token

On Windows 11 23H2 the Token field sits in the _EX_FAST_REF at a build-specific offset you should always resolve dynamically rather than hardcode. Newer builds ship kernel mitigations (kCET, kernel CFG on supported hardware) that make control-flow hijack primitives harder, which is precisely why token overwrite via data-only corruption stays popular: it never redirects execution, it just changes a pointer, so it sails past control-flow integrity.

Impact, plainly stated:

AttributeValue
Bug classCWE-416 use-after-free, race-triggered
Access requiredLocal, low-privileged authenticated user
PrimitiveKernel read/write via reclaimed pool object
ResultNT AUTHORITY\SYSTEM
CVSS7.0 (High)
AffectedAll supported Windows versions running afd.sys
PatchedAugust 11, 2026 (Patch Tuesday), CISA KEV listed

Operation Dream Job: The Full Lazarus Kill Chain

The zero-day did not arrive naked. Check Point attributes CVE-2026-68820 to Lazarus Group under the long-running Operation Dream Job umbrella, the fake-recruiter campaign that has targeted aerospace and defense engineers for years. The 2026 iteration wired the LPE into a full intrusion chain that ran undetected against defense-sector victims for roughly five weeks before disclosure.

Two delivery chains fed the same escalation step:

  • Chain 1, the ZIP lure: a spearphished archive carrying a malicious DLL that stages MISTPEN, the Lazarus downloader that communicates through the Microsoft Graph API and OneDrive to blend C2 into legitimate cloud traffic.
  • Chain 2, the impersonation site: SEO-poisoned pages impersonating a real security firm (reported as an Enveil lookalike) serving a trojanized “SecurityPDF,” landing the victim in the same loader stage.

From either entry point, the sequence converges:

  1. MISTPEN establishes a foothold as a normal user and beacons over Graph/OneDrive.
  2. The CVE-2026-68820 exploit runs the afd.sys UAF race to elevate to SYSTEM.
  3. FudModule 3.1 deploys as a kernel rootkit to blind endpoint telemetry.
  4. ForestTiger (and the modular Troy backdoor) install for long-haul persistence and data theft.
  5. C2 relay rides on compromised legitimate infrastructure: hijacked WordPress and SharePoint sites, plus vulnerable Roundcube servers running RelayShell, many exploitable through CVE-2025-49113.

The tradecraft here is disciplined. Cloud-native C2, a real LPE instead of a noisy UAC bypass, a kernel rootkit to kill sensors, and command relay through trusted third-party hosts so that egress looks like ordinary web traffic. This is what a top-tier state operation against hardened defense targets actually looks like.


Kill chain flowchart tracing the Lazarus Operation Dream Job attack from spearphish lure through MISTPEN loader, afd.sys LPE, FudModule rootkit deployment, ForestTiger backdoor installation, and RelayShell C2 relay
The five-week undetected campaign wired the afd.sys zero-day into a disciplined kill chain where the rootkit stage blinded sensors before the backdoors ever touched disk.

FudModule 3.1: Kernel Rootkit Mechanics and EDR Blinding

FudModule is the piece that should keep defenders up at night, because it directly attacks the assumption most EDR is built on: that the kernel will honestly report what happens in it.

The rootkit family has two lineages. Early FudModule used bring-your-own-vulnerable-driver (BYOVD), loading a signed-but-buggy third-party driver to gain a kernel write. Later variants, and this campaign, favor admin-to-kernel or direct kernel object manipulation (DKOM) off the back of an LPE like 68820. Once you already hold a kernel read/write from the afd.sys bug, you do not need a vulnerable driver at all. You just edit kernel memory directly. That is cleaner, quieter, and dodges Microsoft’s vulnerable-driver blocklist entirely.

What FudModule 3.1 turns off, using that kernel write:

SensorBlinding technique
ETW (including ETW Threat Intelligence)Patch EtwpDebuggerData / neutralize provider registrations so kernel events stop flowing
Minifilter callbacksDetach or disable file-system filter callbacks EDR relies on
Registry callbacksRemove CmRegisterCallback entries so registry-based sensors go dark
Object/process/thread callbacksStrip ObRegisterCallbacks and PsSetCreateProcessNotifyRoutine entries
Smart App ControlTamper with SAC state, a capability reported as new in 3.1

The consequence is brutal and specific: on a FudModule-compromised host, any detection that depends on ETW, minifilter drivers, or registry callbacks generates no alerts. ETW Threat Intelligence (Microsoft-Windows-Threat-Intelligence), the very provider EDRs lean on to catch kernel-mode shenanigans, is itself a target for blinding. After FudModule lands, the machine will tell you everything is fine because the parts that would have said otherwise are dead.

Then FudModule re-injects MISTPEN into a SYSTEM-context process (process hollowing / replacement), so the loader runs with maximum privilege inside a trusted image.


Symbolic illustration of sensor eyes being shut off one by one representing FudModule rootkit blinding ETW providers, minifilter callbacks, and registry callbacks on a compromised host
FudModule 3.1 methodically disables ETW providers, minifilter callbacks, and registry callbacks so that any detection relying on those kernel channels generates no alerts after the rootkit lands.

ForestTiger and Troy: Post-Exploitation Persistence

With telemetry blinded and SYSTEM in hand, Lazarus installs the payloads that do the actual mission work.

ForestTiger is the primary backdoor, using web protocols over HTTP/S routed through the compromised legitimate sites, and reachable through cloud service C2. It handles the standard operator toolkit: command execution, file collection, staging for exfiltration.

Troy is the modular workhorse, reported with a 17-command architecture spanning file theft, remote command execution, and in-memory DLL injection so that additional capability never touches disk. In-memory execution matters here because it dovetails with the FudModule blinding: no disk artifact, no honest kernel telemetry, no image-load event that a working sensor would flag.

RelayShell is the relay tier, a PHP web shell dropped on hijacked Roundcube servers that shuffles commands and results as files. Using compromised but legitimate mail infrastructure means victim networks see connections to ordinary-looking web hosts rather than to burnable attacker VPS ranges.


Lab Exercise: Replicating the UAF Race Against a Custom Vulnerable Driver

To actually feel how a UAF-race becomes a primitive, you build the bug yourself. What follows targets VulnAfd_lab.sys, an intentionally vulnerable teaching driver you compile with the WDK, not afd.sys and not a drop-in for the live CVE. The point is the mechanism.

The lab driver keeps a context struct holding a function pointer, exposes an IOCTL that frees it, exposes another that reads through the pointer, and deliberately holds no lock across the free/use pair.

Environment

- VM: Windows 11 23H2 with kernel debugging enabled
- Debugger: WinDbg (Preview), host/guest over network or serial
- Build: Visual Studio 2022 + WDK 11
- Harness: Python 3.x + ctypes
- Inspection: PoolMon, Process Hacker 2, WPA

Open a handle to the device

import ctypes

GENERIC_RW   = 0xC0000000
SHARE_ALL    = 7
OPEN_EXISTING = 3

k32 = ctypes.WinDLL("kernel32", use_last_error=True)
h = k32.CreateFileW(r"\\.\VulnAfd_lab",
                    GENERIC_RW, SHARE_ALL, None, OPEN_EXISTING, 0, None)
assert h != -1, ctypes.get_last_error()
print(f"[+] device handle: {hex(h)}")

Run the two-thread race

import threading, ctypes

IOCTL_FREE    = 0x222004   # lab: frees the context object
IOCTL_READ_FP = 0x222008   # lab: dereferences func ptr inside context

def free_loop(h, stop):
    br = ctypes.c_ulong()
    while not stop.is_set():
        ctypes.windll.kernel32.DeviceIoControl(
            h, IOCTL_FREE, None, 0, None, 0, ctypes.byref(br), None)

def read_loop(h, stop, out):
    buf = (ctypes.c_ubyte * 8)()
    br = ctypes.c_ulong()
    while not stop.is_set():
        ctypes.windll.kernel32.DeviceIoControl(
            h, IOCTL_READ_FP, None, 0, buf, 8, ctypes.byref(br), None)
        val = int.from_bytes(bytes(buf), "little")
        if val not in (0, 0xdeadbeefdeadbeef):   # sentinel != controlled value
            out.append(val); stop.set()

stop, out = threading.Event(), []
# Pin the racers to separate cores to widen the window.
t1 = threading.Thread(target=free_loop, args=(h, stop))
t2 = threading.Thread(target=read_loop, args=(h, stop, out))
t1.start(); t2.start(); t1.join(); t2.join()
print(f"[+] leaked kernel value: {hex(out[0]) if out else 'no win this run'}")

Groom the pool so your object lands in the freed slot

# After IOCTL_FREE releases the context, reclaim its pool slot with a
# same-size controlled allocation before IOCTL_READ_FP dereferences it.
# Classic primitives: NtAllocateReserveObject or NtAlpcCreatePort spray.
SPRAY = 0x1000
for _ in range(SPRAY):
    # allocate a same-tag/same-size object whose controlled bytes place a
    # pointer at the offset the driver reads as its function pointer
    pass  # wire in your chosen spray primitive for the lab struct size

Verify slot reuse in the debugger:

kd> !pool <freed_addr>
kd> dt nt!_POOL_HEADER <freed_addr>

Escalate via token swap and prove SYSTEM

kd> dt nt!_EPROCESS Token
kd> !process 0 0 System
kd> dt nt!_EPROCESS <system_eprocess> Token
kd> dt nt!_EPROCESS <my_eprocess> Token   ; overwrite this with System's Token
import subprocess
subprocess.Popen("cmd.exe", creationflags=subprocess.CREATE_NEW_CONSOLE)
# In the new console: whoami  ->  nt authority\system

Doing this once against your own driver teaches you more about why the race is winnable and why detection is hard than reading ten advisories.


Detection Engineering: Telemetry That Survives a Blinded Host

The hard truth of this campaign is that your best telemetry dies the moment FudModule lands. So the strategy has to be layered around a single principle: catch the LPE before the rootkit blinds the sensors, and never trust a single blindable source.

Sysmon and Windows Event Log anchors

SourceEvent IDSignal
Sysmon1 / WEL 4688SYSTEM-integrity process spawned from a Medium/Low parent
Sysmon7Unsigned image or module loaded from \Temp\ or user paths
Sysmon10Post-escalation LSASS access
Sysmon13Registry persistence / SAC tamper writes
Sysmon25Process tampering (image hollowing) consistent with MISTPEN re-injection
WEL Security4673Sensitive privilege use (SeDebugPrivilege, SeTcbPrivilege) after escalation
WEL Security4624Anomalous SYSTEM logon originating from the exploit process
WEL System7045New kernel service / driver install

ETW providers

ProviderUse
Microsoft-Windows-Kernel-NetworkHigh-rate abnormal socket IOCTL bursts, the race trigger’s fingerprint
Microsoft-Windows-WinSock-AFDAFD-layer socket state churn (bind/unbind storms)
Microsoft-Windows-Kernel-ProcessToken changes and privilege transitions
Microsoft-Windows-Threat-IntelligenceKernel-mode execution / APC injection, and a prime FudModule blinding target
Microsoft-Windows-Kernel-PnPUnexpected driver loads

Behavioral detections that map to the race

The one thing the exploit cannot hide before it succeeds is its own noise. A UAF-race hammers NtDeviceIoControlFile against \Device\Afd at rates a normal application never produces, from a process that has no business doing high-volume socket state transitions.

title: High-Rate AFD DeviceIoControl Race Pattern
logsource:
  category: process_access
detection:
  selection:
    TargetObject|contains: '\Device\Afd'
    # threshold: sustained > N IOCTLs/sec from one PID to \Device\Afd
  filter_known_good:
    Image|endswith:
      - '\svchost.exe'
      - '\lsass.exe'
      - '\System32\dns.exe'
  condition: selection and not filter_known_good
title: SYSTEM Integrity Process from Non-System Parent
logsource:
  product: windows
  category: process_creation
detection:
  selection:
    IntegrityLevel: 'System'
    ParentIntegrityLevel|in: ['Medium', 'Low']
  condition: selection
title: Unsigned Kernel Module or Process Tampering (FudModule pattern)
logsource:
  product: windows
  category: image_load
detection:
  unsigned_temp:
    Signed: 'false'
    ImageLoaded|contains: '\Temp\'
  tampering:
    EventID: 25
  condition: unsigned_temp or tampering

MITRE ATT&CK mapping

TechniqueNameUsage
T1068Exploitation for Privilege Escalationafd.sys UAF race to SYSTEM
T1014RootkitFudModule 3.1
T1055.012Process HollowingMISTPEN re-injection into SYSTEM process
T1562.001Impair Defenses: Disable/Modify ToolsETW / minifilter / registry callback blinding
T1102.002Web Service: Bidirectional CommsMISTPEN over Graph API / OneDrive
T1071.001Application Layer ProtocolForestTiger over HTTP/S via compromised sites
T1505.003Web ShellRelayShell on Roundcube
T1190Exploit Public-Facing ApplicationCVE-2025-49113 on Roundcube
T1566.001 / T1204.002Spearphishing / User ExecutionZIP lure and trojanized SecurityPDF
T1003.001LSASS MemoryPost-SYSTEM credential access

Hardening that actually moves the needle

Patch first: apply the August 2026 cumulative update everywhere, prioritizing high-value and internet-adjacent endpoints, and treat the CISA KEV two-week window as a hard deadline, not a suggestion.

After that, the single highest-leverage control against this whole chain is HVCI (Hypervisor-Protected Code Integrity). It stops unsigned kernel code from loading, which is exactly what defeats BYOVD-style FudModule deployment. Pair it with WDAC/AppLocker to keep unprivileged users from running the exploit binary in the first place, Credential Guard to protect LSASS from post-escalation dumping, and active Smart App Control with tamper monitoring, since 3.1 reportedly targets SAC directly. Alert hard on Event ID 7045 for any new kernel driver, watch for anomalous Microsoft Graph API auth from endpoints that have no reason to use it, and monitor your Roundcube/WordPress/SharePoint estate for RelayShell and CVE-2025-49113 exploitation.


Key Takeaways

  • afd.sys is a structural target, not a run of bad luck. Universal presence, unprivileged reachability, and thread-shared socket state make it a recurring UAF factory, and CVE-2026-68820 is the fourth in-the-wild afd.sys elevation zero-day since 2024.
  • The bug is a race, so it is probabilistic and noisy before it succeeds. That noise (high-rate NtDeviceIoControlFile against \Device\Afd) is your best pre-compromise signal.
  • The primitive is arbitrary kernel read/write via a reclaimed pool object, and the endgame is data-only token theft that sails past kernel control-flow integrity.
  • FudModule 3.1 turns off ETW, minifilters, and registry callbacks, so any detection built purely on those sources goes silent. Assume your telemetry can be blinded and build layered, pre-exploitation behavioral detection.
  • HVCI is the mitigation that matters most against the rootkit stage. Patching closes this specific bug; HVCI plus WDAC raises the cost of the entire class.
  • Treat the exact struct names, IOCTL codes, and offsets in public reporting as class knowledge, not confirmed 68820 internals, until Check Point’s full patch-diff teardown lands.

Related Tutorials

References