CVE-2024-38063 — Windows TCP/IP IPv6 Integer Underflow → Kernel Heap Overflow
Last updated: 2026-04-15
Severity: Critical (CVSS 9.8)
Component: tcpip.sys (IPv6 stack)
Bug Class: Integer Underflow → Heap-Based Buffer Overflow
Privilege Escalation: Remote → Kernel (RCE / DoS)
Patch: KB5041578, August 13 2024
Related: Tcpip Stack, Integer Overflows, Cve 2021 24086, Cve 2020 16898
Tags:kernel-mode,integer-overflow,oob-write,tcpip,aslr-bypass,remote
Vulnerability Summary
Pre-authentication, zero-click, wormable RCE/DoS in the Windows TCP/IP IPv6 stack. Any system with IPv6 enabled (default on all modern Windows) is reachable from the adjacent network or internet with no user interaction. Credited to Xiao Wei / Kunlun Lab. CVSS 9.8. Affects Windows 10, 11, Server 2008 through 2022. Patch Tuesday August 2024.
The vulnerability is a two-stage integer arithmetic flaw in tcpip.sys:
- Integer underflow: A 16-bit subtraction where
packet_size = 0wraps around to0xFFD0(65,488). - Allocation/copy mismatch: The allocator uses a 16-bit overflow calculation (→ 48 bytes) while the copy operation uses the full underflowed value (65,488 bytes) → controllable kernel pool heap overflow.
Root Cause Analysis
Stage 1: Packet State Corruption via IppSendErrorList()
The vulnerable function is Ipv6pProcessOptions() in tcpip.sys. Under normal operation, malformed IPv6 extension header packets are handled by IppSendError() on a per-packet basis. However, IppSendErrorList() iterates the entire coalesced linked list and calls IppSendError() on every packet in the list — including packets that were not erroneous.
Within IppSendError(), when called with always_send_icmp = true (triggered by setting the option type > 0x80, e.g., 0x81), a code path is reached that sets packet->packet_size = 0 for all packets in the list. This corrupts the state of any fragment packets that happen to be coalesced with the malformed option packet.
// Vulnerable (pre-patch): IppSendErrorList called for entire coalesced list
IppSendErrorList(param); // zeroes packet_size for ALL packets in list
// Fixed (post-patch): IppSendError called for the single erroneous packet
if (IsEnabledDeviceUsage_3 == 0) {
IppSendErrorList(param); // old path, gated behind feature flag (KIR rollback)
} else {
IppSendError(param); // correct path
}
The patch is a single line change in Ipv6pProcessOptions(). Microsoft retained the old code behind Feature_2660322619__private_IsEnabledDeviceUsage_3() — a Known Issue Rollback flag. If the flag is disabled (via registry or Group Policy), the vulnerability re-emerges. This is a significant residual risk.
Stage 2: Integer Underflow in Ipv6pReceiveFragment()
Once packet->packet_size = 0, subsequent fragment packets with Next Header = 44 are processed by Ipv6pReceiveFragment(). The allocation size is computed as:
; AX = LOWORD(packet->packet_size) = 0
; Subtract header size 0x30:
sub ax, 0x30 ; AX = 0 - 0x30 = 0xFFD0 (16-bit underflow!)
; Result: fragment_size = 0xFFD0 = 65,488
The critical architectural detail: the ax register is 16-bit. The underflow is confined to 16 bits. This is convenient for the attacker: a 32-bit underflow would yield ~4GB which would cause ExAllocatePoolWithTagPriority to fail; the 16-bit underflow produces a “large but feasible” 65,488-byte value.
The underflowed fragment_size (0xFFD0) is stored in reassembly->packet_length / reassembly->fragment_size.
Stage 3: Allocation/Copy Mismatch in Ipv6pReassemblyTimeout()
IPv6 fragment reassembly state persists for 60 seconds before timing out. The timeout handler Ipv6pReassemblyTimeout() performs the actual buffer overflow:
// Allocation size calculation (16-bit arithmetic, overflows):
// fragment_list->net_buffer_length ≈ 0x38
// reassembly->packet_length = 0xFFD0
// DX = 0x38 + 0xFFD0 + 8 = 0x0010 (16-bit overflow wraps to 0x10)
// After + 0x28: allocation = 0x38 bytes ≈ 48 bytes
alloc_buf = ExAllocatePool(tiny_calculated_size); // 48 bytes
// Copy operation uses FULL underflowed size:
memmove(alloc_buf, reassembly->payload, 0xFFD0); // copies 65,488 bytes into 48-byte buffer!
The fragment payload is attacker-controlled, making this a controllable kernel pool overflow of ~65KB.
Exploitation Technique
Triggering Packet Coalescing
The exploit requires multiple packets to be in a coalesced linked list simultaneously when Ipv6pProcessOptions() is called. Packet coalescing is a NIC performance optimization — at high throughput, the NIC delivers multiple packets as a single interrupt/batch.
Reliable coalescing strategies:
- Extreme NIC interrupt moderation mode: maximally batches packets (test environment;
bcdedit /set debug onas workaround) - Single CPU target: fewer cores → less parallelism → more coalescing
- High packet volume: flood with 2,400+ packets under normal NIC settings; 2–8 suffice under heavy-load NIC mode
Attack Packet Sequence (ynwarcs PoC)
Three packets are required in one coalesced batch:
- Malformed destination options — IPv6 header + Destination Options Extension Header (type 60) + invalid option with type > 0x80 (e.g., 0x81). Triggers
IppSendErrorList()withalways_send_icmp = true, zeroingpacket_sizeof subsequent packets. - Fragment #1 — IPv6 fragment with Next Header = 44. Gets corrupted
packet_size = 0→fragment_sizeunderflows to 0xFFD0. - Fragment #2 — Optional; provides attacker-controlled payload data.
Then wait 60 seconds for Ipv6pReassemblyTimeout() to fire.
PoC Code Structure (Python/Scapy)
def build_malicious_option(next_header, header_length, option_type, option_length):
dest_options_header = 60
options_header = struct.pack('BBBB', next_header, header_length, option_type, option_length) + b'AAAA'
return Ether(dst=mac_addr) / IPv6(dst=ip_addr, nh=dest_options_header) / raw(options_header)
# Packet 1: malformed dest options (option_type=0x81 > 0x80 → triggers always_send_icmp=true)
pkt1 = build_malicious_option(next_header=44, header_length=0, option_type=0x81, option_length=0)
# Packet 2: fragment (Next Header already 44 in pkt1's nh field)
pkt2 = Ether(dst=mac_addr) / IPv6(dst=ip_addr, nh=44) / IPv6ExtHdrFragment(...) / payload
# Send in burst to force coalescing; wait 60s for timeout → crash/overflow
RCE Path (Theoretical)
Reliable RCE requires:
- KASLR bypass: The overflow corrupts kernel pool memory, but arbitrary code execution needs the kernel base. An information leak (e.g., uninitialized pool memory returned in ICMPv6 echo reply — ~65KB of uninitialized kernel pool is allocated by
ExAllocatePoolWithTagPriority) could provide this. - Heap grooming: Place a victim object (function pointer, EPROCESS token, etc.) adjacent to the 48-byte buffer before the overflow fires.
- Overwrite control: The fragment payload is attacker-controlled, providing ~65KB of controllable overwrite data.
As of public research: DoS (BSOD) is reliably achieved; full RCE has not been publicly demonstrated. The HAU paper (Kerutt et al., 2025) recalculates CVSS as 7.5–8.2 given the practical difficulty of RCE.
Key Primitives Used
- 16-bit integer underflow (
packet_size = 0, subtract0x30) →0xFFD0large fragment size - 16-bit integer overflow (in
Ipv6pReassemblyTimeoutallocation math) → 48-byte buffer - Controllable kernel pool overflow (~65KB of attacker-controlled data)
- Uninitialized pool data leak (via
ExAllocatePoolWithTagPrioritywithout zero-init — potential KASLR defeat)
Mitigations Bypassed
- Pre-auth / zero-click: No authentication or user interaction
- Network reachability only: Any host with IPv6 reachable is vulnerable
- KASLR: Not bypassed in public PoC; theoretically defeatable via the uninitialized pool allocation
Proof-of-Concept Notes
| Repository | Author | Type | Notes |
|---|---|---|---|
| github.com/ynwarcs/CVE-2024-38063 | @ynwarcs (Miloš Ynwarcs) | DoS PoC | Primary reference; 39-line Python/Scapy; three-packet chain; reliable DoS |
| github.com/ThemeHackers/CVE-2024-38063 | ThemeHackers | Extended toolkit | ICMP flood, SYN flood, traffic analysis, PDF reports; targets DoS |
Requirements: Python 3 + Scapy; Linux attacker (Windows blocks raw IPv6 packet construction); root; configure iface, ip_addr, mac_addr.
Patch Analysis
- Changed function:
Ipv6pProcessOptions()intcpip.sys - Change: Replace
IppSendErrorList(param)withIppSendError(param) - Feature flag:
Feature_2660322619__private_IsEnabledDeviceUsage_3()— if this returns 0 (flag disabled), the old vulnerableIppSendErrorListpath is executed. Flag controllable via registry/Group Policy = Known Issue Rollback mechanism. - Risk: Vulnerable code path is never removed, only gated. If the flag is disabled (e.g., by admin for “compatibility”), vulnerability re-emerges.
Workaround (if patching is not immediately possible): Disable IPv6 via registry or netsh interface ipv6 set global:
netsh interface ipv6 set global defaultcurhoplimit=0 # Not a real fix; patch is required
# Real workaround: Disable IPv6 on external-facing interfaces
References
- Xiao Wei / Kunlun Lab — discovery (credited by MSRC)
- Marcus Hutchins, “CVE-2024-38063 - Remotely Exploiting The Kernel Via IPv6”, malwaretech.com, August 2024
- Kerutt et al., “Critical Analysis of CVE-2024-38063: The Microsoft IPv6-Vulnerability”, HAW Hamburg / Bavarian LSI, 2025
- OPSWAT Fellowship, “Comprehensive Breakdown of CVE-2024-38063”, opswat.com, April 2025
- @ynwarcs, PoC, github.com/ynwarcs/CVE-2024-38063, 2024
- MSRC, “CVE-2024-38063 Security Update Guide”, 2024
