CVE-2022-21907 — Windows HTTP Protocol Stack Uninitialized MDL (http.sys)
Last updated: 2026-04-15
Severity: Critical (CVSS 9.8)
Component: http.sys (Windows HTTP kernel driver, IIS)
Bug Class: Uninitialized Memory Use (MDL) → Kernel Crash / Potential RCE
Privilege Escalation: Remote → DoS; theoretical RCE with additional primitive
Patch: January 11, 2022 (KB5009543 / Patch Tuesday)
Related: Tcpip Stack, Heap Grooming, Primitives
Tags:kernel-mode,remote,oob-read,aslr-bypass,iis
Vulnerability Summary
A remote code execution / denial-of-service vulnerability in http.sys, the Windows kernel-mode HTTP server component used by IIS. An unauthenticated attacker sends multiple malformed HTTP requests to crash the server kernel via nt!MmUnmapLockedPages accessing an uninitialized Memory Descriptor List (MDL).
Affected platforms: Windows Server 2022, Server 2019, Windows 10 (IIS not default-enabled on Win10, reducing risk). IIS is default-enabled on Windows Server — making this wormable across exposed IIS servers.
Analyzed by FortiGuard Labs (Tim Lau). PoC by antx (ZZ-SOCMAP). CVSS 9.8.
Root Cause Analysis
The Tracker Structure
http!UlFastSendHttpResponse() processes HTTP responses via a “Tracker” object allocated by http!UlpAllocateFastTracker(). The Tracker is allocated from either:
nt!ExAllocatePool3()(fresh allocation — attacker can spray)ExpInterlockedPopEntrySList()(recycled from LookAside list)
The Tracker contains multiple MDL pointers at offsets 0x68, 0x70, 0x80, 0x88. Only Tracker->0x68 is initialized by http!UlInitializeFastTrackerPool() via MmBuildMdlForNonPagedPool. The MDL at Tracker->0x80 is never initialized — it resides in the uninitialized tail of the allocation (pool allocation is for 0xC85 bytes, far beyond the Tracker struct itself).
The Patched Fix
The patch in http!UlpAllocateFastTracker() adds memset() to zero out 0x50 bytes starting at offset 0x2E of the Tracker:
// Patch: zero out Tracker[0x2E..0x7E] even for LookAside recycled buffers
// This ensures Tracker->0x50 and Tracker->0x80 are zeroed
memset(Tracker + 0x2E, 0, 0x50);
The field Tracker->0x50 is the trigger: if non-zero, the vulnerable code path is taken. The field Tracker->0x80 is the uninitialized MDL that causes the crash.
The Vulnerable Code Path
In http!UlFastSendHttpResponse(), the cleanup phase:
// Pseudo-code of vulnerable cleanup:
if (Tracker->0x50 != NULL) { // non-zero stale value from recycled pool
some_mdl = Tracker->0x80; // uninitialized MDL pointer
if (some_mdl->MdlFlags & 0x0001) { // MDL_MAPPED_TO_SYSTEM_VA
MmUnmapLockedPages(
some_mdl->MappedSystemVa, // attacker-controlled (uninitialized pool content)
some_mdl // uninitialized MDL
); // → crash or potential code exec
}
}
// Eventually calls UlpFreeFastTracker(Tracker)
nt!MmUnmapLockedPages is the Windows kernel routine that releases a virtual-to-physical mapping described by an MDL. Passing an invalid MDL (uninitialized pool bytes) causes it to access invalid memory → BSOD.
Triggering the Bug
The trigger requires a specific code path where Tracker->0x50 is non-zero AND UlGenerateFixedHeaders() returns early (skipping initialization of some_mdl). This path is reached when:
- Multiple malformed HTTP packets are sent in rapid succession.
- IIS’s internal caching/DUO_COLLECTION mechanism transitions: on the second allocation call,
UlH3ExtraHeaderCount/_UX_DUO_COLLECTIONchanges from0x200to0x0. - With second argument
0x0,UlGenerateFixedHeaders()hits an early return (error0xC000000D). - Execution jumps straight to cleanup, invoking the vulnerable
MmUnmapLockedPagescall.
Attacker control of MDL content: Since Tracker->0x80 is uninitialized pool memory from ExAllocatePool3, an attacker with memory spray capability can pre-populate the pool with fake MDL data. However, reliably placing controlled data in the exact Tracker allocation is difficult without an additional primitive.
Exploitation Technique
Minimal PoC (DoS)
Send malformed HTTP requests in rapid bursts:
import socket, time
def send_malformed(target, port=80, count=20):
for _ in range(count):
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.connect((target, port))
# Malformed HTTP — rapid-fire to trigger DUO_COLLECTION path
s.send(b"GET / HTTP/1.1\r\nHost: " + target.encode() + b"\r\n" * 50)
s.close()
except:
pass
Almost any form of malformed HTTP packet that triggers the DUO_COLLECTION code path works — the surface is broad.
RCE Path (Theoretical)
Full RCE would require:
- Kernel info leak / KASLR defeat: Knowing a valid mapped virtual address to place in
MappedSystemVa. - Fake MDL spray: Pre-populate
ExAllocatePool3pool allocations with a crafted MDL whereMdlFlags |= MDL_MAPPED_TO_SYSTEM_VAandMappedSystemVapoints to a useful location. - What happens next:
MmUnmapLockedPageswith an attacker-controlled MDL could potentially be weaponized, but the specific exploitation path remains unclear without a proven chain.
The low probability is due to: unpredictable pool allocation position, difficulty placing exactly the right data at Tracker->0x80, and the need for a pre-existing KASLR bypass.
Key Primitives Used
- Uninitialized pool memory exposure:
Tracker->0x80MDL never initialized in vulnerable code path - Pool spray (attacker-influenced): Fresh
ExAllocatePool3allocation = attacker-sprayable memory MmUnmapLockedPagesabuse: Potential for controlled virtual address unmap via fake MDL
Mitigations Bypassed
- Pre-authentication (no credentials needed)
- Default IIS on Windows Server = default attack surface on internet-exposed servers
- Wormable: can be automated across network
Proof-of-Concept Notes
| Repository | Author | Notes |
|---|---|---|
| github.com/ZZ-SOCMAP/CVE-2022-21907 | antx | Python PoC; resembles CVE-2021-31166 pattern |
Requirements: Python 3 + requests; target must have IIS with affected http.sys version running.
Patch Analysis
- Patched function:
http!UlpAllocateFastTracker() - Fix: Added
memset(Tracker + 0x2E, 0, 0x50)for both fresh allocations and LookAside recycled buffers. This zerosTracker->0x50(the gate condition) andTracker->0x80(the uninitialized MDL). UlFastSendHttpResponse()also modified — large code changes suggest additional hardening beyond the minimal MDL fix.
Workaround (Windows Server 2019 / Windows 10 v1809 only):
reg delete HKLM\System\CurrentControlSet\Services\HTTP\Parameters /v EnableTrailerSupport /f
This mitigation only applies to 1809/Server 2019. Newer versions require the patch.
Note: Windows Server 2019 and Windows 10 v1809 are not vulnerable by default (the EnableTrailerSupport registry value must be present and set for the vulnerable code path to be active). Newer versions (Server 2022, Win10 20H2+, Win11) are vulnerable by default.
References
- Tim Lau (FortiGuard Labs), “Analysis of Microsoft CVE-2022-21907”, fortinet.com, February 2022
- antx / ZZ-SOCMAP, PoC, github.com/ZZ-SOCMAP/CVE-2022-21907, January 2022
- MSRC, “CVE-2022-21907 — HTTP Protocol Stack Remote Code Execution Vulnerability”, January 2022
- Microsoft Documentation,
nt!MmUnmapLockedPages, WDK - Microsoft Documentation, MDL flags (
MDL_MAPPED_TO_SYSTEM_VA = 0x0001), wdm.h
