Cyber security

CVE-2023-29360: Kernel DMA Exploit For Direct R/W Access To kernel Virtual Memory

When looking for vulnerabilities of interest, it’s always a good option to look for vulnerabilities used at pwn2own. Indeed, these vulnerabilities are exploited during the competition, meaning they have a practical impact.

  • Thomas is recognized as one of the several highly skilled researchers in the French exploit scene, and is certainly knowledgeable
  • The vulnerability, teased in the HITB’s upcoming conference, is described as: “a logical bug that defeats most mitigations by allowing direct read and write access to kernel virtual memory.

Finding The Root Cause

Starting with the ZDI’s advisory of the vulnerability, it is possible to get enough details to look for the root cause. Typically, the important information is:

  • The vulnerability is present in the mskssrv driver
  • The issue results from the lack of proper validation of a user-supplied value prior to dereferencing it as a pointer

The next step is to patch-diff the driver for the update, correcting the vulnerability. Only one function—named FsAllocAndLockMdl—was modified.

Within that function, the AccessMode parameter of the call to MmProbeAndLockPages was changed from KernelMode to UserMode, as shown in the following

Screenshot:

With the root cause found, let’s analyze the vulnerability.

Understanding The Vulnerability

MDL, What is that?

An I/O buffer that occupies a contiguous virtual memory range can be non-contiguously distributed over several physical pages in memory.

The Windows OS utilizes memory descriptor list (MDL) structures at the kernel level to describe a single virtual memory buffer’s physical page layout.

MDLs vary in size, are semi-opaque, and are composed of a header that describes the MDL’s properties and a variable-size array of pointers—called the page frame number (PFN) array—describing the physical addresses used by the MDL.

Inside the header, the virtual address (VA) of the memory buffer that is physically described by the MDL is present, as well as its length.

The following schematics illustrates the concept of MDL:

MDL creation and interaction are reserved for the components operating in kernel mode, like drivers, even though a user-facing process may be able to do so via a communication channel with a driver.

It should be noted that an address that is already mapped and potentially in use by the OS can have its physical page layout described by a new MDL.

In this case, the component accessing this MDL will be able (overly simplified) to directly access the physical memory pointed to by this buffer VA.

This creates a communication channel between this component and the OS component that is already interacting with the VA.

As a consequence, MDLs can allow drivers for the Windows OS to implement Direct Memory Access (DMA) operations and permit memory-copy operations between the user land and the kernel land (Direct I/O).

Inner Workings of IoAllocateMdl and MmProbeAndLockPages

In the vulnerable functionFsAllocAndLockMdl, two APIs permitting interaction with MDLs are used: IoAllocateMdl and MmProbeAndLockPages.

The first API—IoAllocateMdl—allocates the MDL structure’s storage to the virtual memory, sets the buffer VA that the MDL describes in its header, but does not initialize the PFN array describing the physical memory that will be used for the buffer.

In fact, it should be coupled with a second API call that is responsible for establishing this array, thus acquiring the correct physical memory to describe it.

The second API—MmProbeAndLockPages— first probes the buffer VA described by the MDL—i.e., it will check if this buffer VA can be accessed—in case the the AccessMode parameter is set to UserMode.

Next, this function locks the physical pages, making them unable to be paged, reallocated, or freed while setting the access operation (read and/or write).

Let’s describe what the probing consists of:

As already described, new MDLs can be created to get the physical description of a given virtual address’s buffer already in use by the OS and potentially to directly interact with the physical memory associated with this buffer.

In particular, it can be used against various data already in use at the kernel level.

This is a problem when the MDL parameters come from the user-land (for instance, because that user-land process aims to perform a DMA operation), for example, through a DeviceIO control message made to a driver.

Indeed, if the user-land process passes in kernel pointers for the creation of the MDL, and is then able to interact with it, that means this user-land process would be able to interact with kernel data.

As a consequence, the user/kernel barrier is broken. To avoid this problem, the probing simply checks that the buffer VA in the MDL is not in the land, by checking that the address is not superior to 0x7FFFFFFF0000.

Explaining The Root Cause

The FsAllocAndLockMdl function is reachable through a DeviceIO control message with code 0x2f0408 . In particular, the parameters for the MDL creation are directly taken from the user-supplied SystemBuffer.

As the AccessMode parameter of MmProbeAndLockPages was not correctly set to UserMode, no probing of the MDL occurs. As a consequence, the user can create a MDL pointing to critical kernel data.

As CVE-2023-29360 was exploited, it means there is a way for the user to interact later with the arbitrarily created MDL, especially to directly modify the kernel data pointed at by it.

In particular, it appears that a second DeviceIO control message with code 0x2f0410, permits to map the previously created MDL’s physical memory directly in the user-land process’s memory, inside a variable with read and write access.

This mapping is realized through the MmMapLockedPagesSpecifyCache API. As a consequence, accessing this variable as a pointer allows the physical pages used in the MDL to be accessed and modified directly.

Exploiting The Vulnerability

One approach to exploit CVE-2023-29360 is to first obtain a MDL describing the kernel VA where the current process privileges are defined (the kernel VA being simply obtained through a NtQuery leak), using the first DeviceIO control message. Subsequently, this MDL is mapped through the second DeviceIO control message.

As a consequence, the values located at the kernel VA, where the current process privileges are defined are now directly accessible and modifiable in the current process’s virtual memory.

The process can now freely modify its own privileges and achieve privilege escalation, for example by getting the SeDebugPrivilege.

The following steps highlight how the identified exploit approach works:

  1. The exploit process is launched. After launching, the memory layout is as follows:

2. The exploit process sends the first DeviceIO control message to mskssrv, inducing the creation of a MDL pointing to its own privileges in the kernel address space, thanks to the absence of check. The memory layout is now the following:

3. The exploit process sends the second DeviceIO control message to mskssrv, mapping the physical memory pointed by the MDL in its own virtual address space. The memory layout becomes:

4. The exploit process can now directly modify the physical memory values tied to its own privileges, to make itself highly privileged.

Conclusion

This logical vulnerability is really powerful as it may allow for direct kernel read/write. As stated by Thomas, no mitigation currently halts a similar exploit for it.

This might change soon with the modification of the NtQuery leaks in-the-works, as such exploits will necessitate a first vulnerability to leak the kernel address of interest.

Finally, I would like to thanks Thomas Imbert one more time for having found it as I learnt a lot while analyzing it.

By the way, this attack surface might have been underlooked. Setting up the following bad yara rule for variants leads to a few results, eheh:

rule search_cve_2023_29360_variant
{
    meta:
        version = "102947593"

    strings:
        $api1 = "MmProbeAndLockPages"
        $api2 = "MmMapLockedPagesSpecifyCache"
        $s2 = { 33 D2 44 8D 42 01 } //xor edx, edx, lea r8d, [rdx+1]

    condition:
        uint16(0) == 0x5a4d and all of them
}

Tamil S

Tamil has a great interest in the fields of Cyber Security, OSINT, and CTF projects. Currently, he is deeply involved in researching and publishing various security tools with Kali Linux Tutorials, which is quite fascinating.

Recent Posts

Shadow-rs : Harnessing Rust’s Power For Kernel-Level Security Research

shadow-rs is a Windows kernel rootkit written in Rust, demonstrating advanced techniques for kernel manipulation…

2 weeks ago

ExecutePeFromPngViaLNK – Advanced Execution Of Embedded PE Files via PNG And LNK

Extract and execute a PE embedded within a PNG file using an LNK file. The…

3 weeks ago

Red Team Certification – A Comprehensive Guide To Advancing In Cybersecurity Operations

Embark on the journey of becoming a certified Red Team professional with our definitive guide.…

3 weeks ago

CVE-2024-5836 / CVE-2024-6778 : Chromium Sandbox Escape via Extension Exploits

This repository contains proof of concept exploits for CVE-2024-5836 and CVE-2024-6778, which are vulnerabilities within…

4 weeks ago

Rust BOFs – Unlocking New Potentials In Cobalt Strike

This took me like 4 days (+2 days for an update), but I got it…

4 weeks ago

MaLDAPtive – Pioneering LDAP SearchFilter Parsing And Security Framework

MaLDAPtive is a framework for LDAP SearchFilter parsing, obfuscation, deobfuscation and detection. Its foundation is…

4 weeks ago