Skip to content
KitploitKITPLOIT
ToolsExploitsBlog
Log in
Submit
ToolsExploitsBlog
Submit

Hacking, PenTest, and Cybersecurity Tools for Your Security Arsenal!

Kitploit is a directory of hacking, cybersecurity, and pentesting tools. Discover the latest project updates to find vulnerabilities, analyze systems, automate testing, and strengthen your security.

··Feeds·Contact·Privacy·© 2026 Kitploit

Tool Directory

Categories

View all categories
Loading categories
CVE-2024-38063- — Remotely Exploiting The Kernel Via IPv6 | Kitploit
Tools/GitHubGitHub/adminpentester/cve-2024-38063-
Memory ForensicsVulnerability AnalysisExploitationReverse EngineeringLearning & EducationBinary Exploitation
GitHubadminpentester/cve-2024-38063-

CVE-2024-38063-

Remotely Exploiting The Kernel Via IPv6

View Repository
21112 years agoNot yet reviewed

Most Popular

View all →

Discover the most used tools by our community.

Explore all tools

Browse our collection of tools

View all tools →
Share

CVE-2024-38063-

Remotely Exploiting The Kernel Via IPv6

CVE-2024-38063 - Remotely Exploiting The Kernel Via IPv6 Marcus Hutchins

Since the latest Windows patch dropped on the 13th of August I’ve been deep in the weeds of tcpip.sys (the kernel driver responsible for handling TCP/IP packets). A vulnerability with a 9.8 CVSS score in the most easily reachable part of the Windows kernel was something I simply couldn’t pass up on. I’ve never really looked at IPv6 before (or the drivers responsible for parsing it), so I knew trying to reverse engineer this vulnerability was going to be extremely challenging, but a good learning experience.

For the most part, tcpip.sys is largely undocumented. I was able to find a couple of exploit write-ups for older bugs: here, here, and here, but little else. When the top search result for my English Google search is written in Chinese, I immediately know I’m way out of my depth and in for a bad time, but learn we must. Despite Google Translate doing a mediocre job, the post provided some incredibly detailed insight into how IPv6 fragmentation works, and gave me a good head start.

Later on, while Googling some function names, I came across another analysis of the same 2021 vulnerability, written by Axel Souchet (AKA 0vercl0k), which went even deeper into the internals of tcpip.sys and gave me enough information to define several undocumented structures. The easiest patch analysis ever

Usually, even just reverse engineering the patch to figure out which code change corresponds to the vulnerability can take days or even weeks, but in this case it was instant. It was so easy in fact, that multiple people on social media told me I was wrong and that the bug was somewhere else. Did I actually listen to them and then waste an entire day reversing the wrong driver? We may never know.

There was exactly one change made in the entire driver file, which it turns out, actually was the bug after all.

A bindiff overview of tcpip.sys before and after installing the patch.

Only a single function in the whole driver has been modified. Typically, I could spend a whole day going through 20+ different function changes just to figure which is the one I should be looking at, but not this time.

Ipv6pProcessOptions() before the patch.

Ipv6pProcessOptions() after the patch.

Not only was it just a single function that was changed, but a single line of code.

The extremely long-named Feature_2660322619__private_IsEnabledDeviceUsage_3() function is something Microsoft sometimes adds to enable partial patch rollbacks. The call checks for the presence of a global flag, or registry setting, which if set, will cause the function to return false, resulting in the original code being executed instead of the patched version.

The reason Microsoft does this is because security patches sometimes unintentionally break things, so this setting enables an administrator to unpatch a single vulnerability, without uninstalling the entire monthly patch rollup and drastically weakening their system security.

Taking this into account, it’s clear that all this patch does is replace a call to IppSendErrorList() with IppSendError(), giving us a clue that the issue is with some kind of list. Easiest patch diff ever (or so I thought). Vulnerabilities optional, exploitation mandatory

Reverse engineering the patch to find the altered code is only half of the challenge (or in this case less than 0.1%). The rest of the process consists of reverse engineering enough of the codebase to understand what is even going on, figuring out what kind of vulnerability was patched, how to craft a request to reach the target code, and what state results in an exploitable condition.

The first part is easy enough. The change is in Ipv6pProcessOptions(), which tells us it’s IPv6 and involves processing options. So, a quick call to the RFC tells us exactly what an IPv6 option is and where we can find one.

The destination options header layout from Wikipedia.

Ok, cool. What we’re looking for appears to be the destination options header, which sits directly after the main IPv6 header. Let’s use the Python library ‘scapy’ to craft a test IPv6 packet.

Note: To mitigate DDoS attacks using spoofed IP addresses, Windows restricts the ability to construct raw IP packets. For this reason, I opted to use Linux to develop my proof-of-concept. Whilst Linux does allow users to construct and send raw layer 2 and layer 3 packets, it requires the Python script to be run as root.

import sys import struct from scapy.all import *

def send_ipv6_option_packet(dest_ip): ethernet_header = Ether() ip_header = IPv6(dst=dest_ip) options_header = IPv6ExtHdrDestOpt() sendp(ethernet_header / ip_header / options_header)

if len(sys.argv) < 2: print('Use: python3 script.py <target_ipv6_address>') exit(-1)

send_ipv6_option_packet(sys.argv[1])

After setting a breakpoint on tcpip!Ipv6pProcessOptions, then running the script, it was clear that all that was needed to reach the vulnerable function was sending an IPv6 packet with an empty options structure. I then tried adding some invalid options to the structure to see if I could reach the call to IppSendErrorList().

A brief code review indicated that almost any invalid option formatting could trigger the call to IppSendErrorList. So, I decided on using the Jumbo Packet option with an invalid length (less than 65535 bytes).

options_header = IPv6ExtHdrDestOpt(options=[Jumbo(jumboplen=0x1337)])

So, what does IppSendErrorList() actually do? Well, the code is pretty simple.

The entire IppSendErrorList function.

The code iterates a linked list and calls IppSendError() on every item in the list. Again, the stars have aligned and things have been easy thus far. If IppSendErrorList just calls IppSendError for each item in a list, and the patch replaces the call to IppSendErrorList with IppSendError, then the problem occurs when IppSendError is called on a list item other than the first.

So, what is this a list of, and how do we make one? He’s making a list, he’s checking it….52,567 times

This is where things went from obvious to abnormally difficult, though I think a large part of this was due to one of my two available brain cells being preoccupied with fighting a bad covid infection. I lost a couple of days to understanding parts of the code, falling asleep, then forgetting what it was I had figured out. The whole process required over a week of reverse engineering parts of tcpip.sys to figure out what was going on. But Axel’s blog post was extremely helpful.

By looking at the functions and structure Axel reverse engineered, and which other functions they’re passed to, It’s clear that the one and only argument passed to Ipv6pProcessOptions() is the same packet_t structure defined in the article. Essentially, the pointer passed to Ipv6pProcessOptions, and iterated by IppSendErrorList, is a linked-list of packets.

So, I set a breakpoint on Ipv6pProcessOptions() and inspected the list.

The list->Next entry is NULL.

Every time my breakpoint was hit, the list contained only one packet. I spent way longer than I’d like to admit trying to figure out why and how to get my list to actually be a list. My first thought was IPv6 fragmentation: IPv6 allows senders to split large packets into separate smaller packets, which it would make sense to keep together in a list.

After extensive reverse engineering, I confirmed my assumptions were correct, though the fragment list is not related to the one we’re dealing with here.

Download Tool