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.
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:
mskssrv
driverThe 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
With the root cause found, let’s analyze the vulnerability.
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).
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
.
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.
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:
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.
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
}
Kali Linux 2024.4, the final release of 2024, brings a wide range of updates and…
This Go program applies a lifetime patch to PowerShell to disable ETW (Event Tracing for…
GPOHunter is a comprehensive tool designed to analyze and identify security misconfigurations in Active Directory…
Across small-to-medium enterprises (SMEs) and managed service providers (MSPs), the top priority for cybersecurity leaders…
The free and open-source security platform SecHub, provides a central API to test software with…
Don't worry if there are any bugs in the tool, we will try to fix…