Skip to content

CodeByLM/CVE-2025-24990_POC

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

16 Commits
 
 
 
 
 
 
 
 

Repository files navigation

Windows Agere Modem Driver (ltmdm64.sys). This driver is very old and is not loaded by default on my test machine, so I will exploit it in a BYOVD scenario. Interestingly, according to my research this driver has existed on Windows 7 and has at least one bug. here

At that time, MSRC didn't take any action 🤡

Vulnerabilities

Some IOCTLs within this driver use METHOD_NEITHER but do not check whether the address buffer supplied by the caller is from user-mode or kernel-mode. Here is an example IOCTL code that I decoded with OSR :

This means you can supply a kernel address to the DeviceIoControl API and the driver will handle it normally.

Note that you have to bypass kASLR first to leak the kernel address, I will use EnumDeviceDrivers (On Windows 24h2 you need SeDebugPriv to do this).

Null Dereference

The issue is in IOCTL 0x802b200f (ud_response). Again, this IOCTL dispatch does not validate the address I supply from user-mode, but I will leverage it later.

The ud_response calls ll_load_diagnostics, and I will reach the following code:

At the beginning the global variable eeprom isn't initialized, so it will contain NULL. Here is a simple code that will trigger this.

I will leverage this later.

Exploit entry point 0x802b2003

This IOCTL simply converts the driver version string "8.36" to the number 0x836 (a DWORD) and writes it to the address supplied by the caller (thanks to METHOD_NEITHER). Technically, I can write these four bytes (36 08 00 00) to an arbitrary kernel address. I will leverage this to overwrite the driver’s global variables and change the execution flow.

I will call this 0x802b2003 is IOCTL_GET_VERSION

Exploit

Arbitrary null 1 byte:

Going back to the NULL-dereference case, I use the VirtualAlloc API to allocate a fixed address (0x083600000000). I then use the IOCTL_GET_VERSION to write to *(eeprom + 4) the four bytes described above. When the driver later dereferences eeprom, it will read from the address I allocated.

After fix the NULL dereference, the IOCTL writes a string to the address I supply from user-mode, based on the buffer size.

This code simply demonstrates what I described above, allocate a buffer and fill it with 0xAA, fix the NULL dereference, then call the driver. Note that I allocate 11 bytes but only provide a buffer size of 10 to the driver to see how it behaves.

It writes a fixed sequence of bytes to my buffer and then nulls out the final byte (the 11th), even though I only provide a size of 10. It replaces the last 0xAA in my buffer with 0x00. This indicates that if I provide a size of 0, the driver still writes a single 0x00 byte at the target address.

Arbitrary decrement

Now I have the null and arbitrary with fixed 4 bytes let craft other primitive.

This IOCTL will set the global LtMsgEvent to my user buffer then check WDM is null then set zero again.

Then in 0x802b2207 it will call ObfReferenceObject API.

At inital state the WDM is null but with the help of IOCTL_GET_VERSION I can set WDM to 0x36 (it's size only 1 byte) and the LtMsgEvent is still my buffer. Then I will null out WDM and call 0x802b2207. Finally reach the ObfReferenceObject. I will call this two ioctl is IOCTL_SET_LtMsgEvent and IOCTL_DEREF_LtMsgEvent.

The exploit technique using ObfReferenceObject changes the PreviousMode of our KTHREAD from UserMode to KernelMode you can read about it here. However, Windows has fixed this exploit, so we cannot use it.

But the primitive in ObfReferenceObject still exists. The API subtracts 0x30 from the address we provide, casts the result to an 8-byte integer, and then subtracts 1.

    *(signed long long)(LtMsgEvent-0x30) -= 1

But the problem is it checks whether the next value is 0 or whether the current value is < 1 (interpreted as an 8-byte signed integer). If either condition is true, it jumps to KeBugCheckEx and crashes the system.

Arbitrary write

With Arbitrary decrement in hand I need to find somewhere else to write the byte 0xFF then decreate it to the byte I want and I found this ioctl 0x802b2243:

We will focus on the flip branch. pbVar5 is the address I supply from user-mode and can be any target address I choose. I write the byte 0x0C to DAT_TARGET_EX (with the help of IOCTL_GET_VERSION and the arbitrary-decrement primitive), and I also null out 1 byte at the target address. The first call to this IOCTL sets 0xC0 at the target address, which is then decremented to 0xBF. A second call sets 0xFF at the target address (0xBF | 0xC0 = 0xFF). Once the target contains 0xFF, I just decrement it to the desired value.

I will write one byte one and be careful of the KeBugCheckEx inObfReferenceObject .

Arbitrary read

For the read primitive I use the technique described here (@carrot_c4k3). I simply overwrite the UNICODE_STRING object in the kernel (ExpManufacturingInformation) and then call NtQuerySystemInformation. Because of ObfReferenceObject calls KeBugCheckEx, I will null out 8 bytes adjacent to ExpManufacturingInformation.

That’s it, now we have arbitrary R/W, we can use those primitives to do many things. The driver is not loaded by default, so I will exploit it in a BYOVD scenario and set the PPL of a process.

Exploit in Windows 11 22H2+:

The exploit I have decribe above is work in all windows version but unstable due to the KeBugCheckEx. But In Windows 11 22h2+ there is a technique called ioring. This technique simply overwrites ioring->Buffer with a controllable address. Concretely, we can overwrite ioring->Buffer and its size with 0x083600000000 and 0x836 respectively (using IOCTL_GET_VERSION). Using this technique I only perform 2 write and then use the R/W primitive very stably. Note that this approach requires leak kernel address.

Exploit Run

Windows doesn't load the driver at default state. So you need to load it manually. The file ltmdm64.sys is located at C:\Windows\System32\DriverStore\...\ltmdm64.sys, run this command as admin and run the exploit:

sc create ltmdm64_srv binPath="C:\Windows\System32\DriverStore...\ltmdm64.sys" type=kernel && sc start ltmdm64_srv

The exploit will use ioring technique to turn off PPL of lsass.exe and use my data-only technique to set PPL to notepad.exe (win 11 24h2 need SeDebugPriv is enabled)

poc1.mp4

CVE Authors

I reported this bug to ZDI. But seem like it duplicate with the submission of Fabian Mosch and Jordan Jay to MSRC, so this PoC just shows the bug and appreciate their work. Almost my first CVE 😍

About

Proof of Concept CVE-2025-24990 (Agere Systems's driver)

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors

Languages

  • C 86.0%
  • C++ 14.0%