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:

  1. Multiple malformed HTTP packets are sent in rapid succession.
  2. IIS’s internal caching/DUO_COLLECTION mechanism transitions: on the second allocation call, UlH3ExtraHeaderCount / _UX_DUO_COLLECTION changes from 0x200 to 0x0.
  3. With second argument 0x0, UlGenerateFixedHeaders() hits an early return (error 0xC000000D).
  4. Execution jumps straight to cleanup, invoking the vulnerable MmUnmapLockedPages call.

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:

  1. Kernel info leak / KASLR defeat: Knowing a valid mapped virtual address to place in MappedSystemVa.
  2. Fake MDL spray: Pre-populate ExAllocatePool3 pool allocations with a crafted MDL where MdlFlags |= MDL_MAPPED_TO_SYSTEM_VA and MappedSystemVa points to a useful location.
  3. What happens next: MmUnmapLockedPages with 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->0x80 MDL never initialized in vulnerable code path
  • Pool spray (attacker-influenced): Fresh ExAllocatePool3 allocation = attacker-sprayable memory
  • MmUnmapLockedPages abuse: 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

RepositoryAuthorNotes
github.com/ZZ-SOCMAP/CVE-2022-21907antxPython 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 zeros Tracker->0x50 (the gate condition) and Tracker->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