支持本站 — 捐款将帮助我们持续运营

目标: 1000 元,已筹: 1000

100.0%

POC详情: ac2f66a3967b1af2087e7e8d9b22abed072b05bd

来源
关联漏洞
标题:Microsoft Windows 安全漏洞 (CVE-2025-24990)
Description:Microsoft Windows是美国微软(Microsoft)公司的一套个人设备使用的操作系统。 Microsoft Windows Agere Modem Driver存在安全漏洞,该漏洞源于攻击者利用该漏洞可以提升权限。
Description
Proof of Concept CVE-2025-24990 (Agere Systems's driver) 
介绍
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](https://github.com/int0/ltmdm64_poc)

<p align="center">
  <img src="pics/pic1.png"/>
</p>
  
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](https://www.osronline.com/article.cfm%5Earticle=229.htm) :

<p align="center">
  <img src="pics/pic2.png"/>
</p>

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](https://learn.microsoft.com/en-us/windows/win32/api/psapi/nf-psapi-enumdevicedrivers) (On Windows 24h2 you need SeDebugPriv to do this).

<p align="center">
  <img src="pics/pic3.png"/>
</p>

## 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.

<p align="center">
  <img src="pics/pic4.png"/>
</p>

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

<p align="center">
  <img src="pics/pic5.png"/>
</p>

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

<p align="center">
  <img src="pics/pic6.png"/>
</p>

I will leverage this later.

## Exploit entry point 0x802b2003

<p align="center">
  <img src="pics/pic7.png"/>
</p>

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.

<p align="center">
  <img src="pics/pic8.png"/>
</p>

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.

<p align="center">
  <img src="pics/pic9.png"/>
</p>

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. 

<p align="center">
  <img src="pics/pic10.png"/>
</p>

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

<p align="center">
  <img src="pics/pic11.png"/>
</p>

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]((https://hnsecurity.it/blog/from-arbitrary-pointer-dereference-to-arbitrary-read-write-in-latest-windows-11/)). 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

<p align="center">
  <img src="pics/pic12.png"/>
</p>

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`:

<p align="center">
  <img src="pics/pic13.png"/>
</p>

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` in`ObfReferenceObject` . 

**Arbitrary read**

For the read primitive I use the technique described [here]([Mastodon](https://exploits.forsale/pwn2own-2024/)) ([@carrot_c4k3](https://x.com/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](https://windows-internals.com/one-i-o-ring-to-rule-them-all-a-full-read-write-exploit-primitive-on-windows-11/). 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`)


https://github.com/user-attachments/assets/05a35b38-d26c-484f-9fb7-137f8fe8c079

## CVE Authors

I reported this bug to ZDI. But seem like it duplicate with the submission of [Fabian Mosch](https://x.com/shitsecure) and [Jordan Jay](https://x.com/0xLegacyy) to MSRC, so this PoC just shows the bug and appreciate their work.
Almost my first CVE 😍





文件快照

[4.0K] /data/pocs/ac2f66a3967b1af2087e7e8d9b22abed072b05bd ├── [4.0K] pics │   ├── [ 25K] pic10.png │   ├── [9.0K] pic11.png │   ├── [ 20K] pic12.png │   ├── [ 12K] pic13.png │   ├── [100K] pic1.png │   ├── [ 14K] pic2.png │   ├── [ 30K] pic3.png │   ├── [ 12K] pic4.png │   ├── [ 11K] pic5.png │   ├── [ 28K] pic6.png │   ├── [ 25K] pic7.png │   ├── [ 44K] pic8.png │   └── [9.0K] pic9.png ├── [8.0K] README.md ├── [4.0K] src_data_only │   ├── [4.0K] capstone-4.0.2-win64 │   │   ├── [5.3M] capstone.dll │   │   ├── [5.2K] capstone_dll.lib │   │   ├── [7.0M] capstone.lib │   │   ├── [ 20K] ChangeLog │   │   ├── [2.6K] CREDITS.TXT │   │   ├── [5.4M] cstool.exe │   │   ├── [4.0K] include │   │   │   ├── [4.0K] capstone │   │   │   │   ├── [ 28K] arm64.h │   │   │   │   ├── [ 18K] arm.h │   │   │   │   ├── [ 29K] capstone.h │   │   │   │   ├── [4.3K] evm.h │   │   │   │   ├── [ 12K] m680x.h │   │   │   │   ├── [ 14K] m68k.h │   │   │   │   ├── [ 17K] mips.h │   │   │   │   ├── [3.9K] platform.h │   │   │   │   ├── [ 25K] ppc.h │   │   │   │   ├── [ 11K] sparc.h │   │   │   │   ├── [ 14K] systemz.h │   │   │   │   ├── [8.1K] tms320c64x.h │   │   │   │   ├── [ 42K] x86.h │   │   │   │   └── [4.8K] xcore.h │   │   │   ├── [3.1K] platform.h │   │   │   └── [4.0K] windowsce │   │   │   ├── [ 315] intrin.h │   │   │   └── [2.9K] stdint.h │   │   ├── [3.3K] LICENSE_LLVM.TXT │   │   ├── [1.6K] LICENSE.TXT │   │   ├── [2.1K] README.md │   │   ├── [ 177] RELEASE_NOTES │   │   └── [ 857] SPONSORS.TXT │   ├── [ 214] common.h │   ├── [ 428] debug.h │   ├── [4.8K] demo.cpp │   ├── [5.2M] demo.exe │   ├── [4.5K] exploit.cpp │   ├── [ 516] exploit.h │   ├── [7.4K] utils.cpp │   └── [ 586] utils.h └── [4.0K] src_ioring ├── [ 177] common.h ├── [ 428] debug.h ├── [ 834] exploit.cpp ├── [ 241] exploit.h ├── [ 11K] io_ring.cpp ├── [9.6K] io_ring.h ├── [5.6K] main.cpp ├── [1.7K] ntdll.h ├── [5.8K] utils.cpp └── [ 869] utils.h 8 directories, 60 files
神龙机器人已为您缓存
备注
    1. 建议优先通过来源进行访问。
    2. 如果因为来源失效或无法访问,请发送邮件到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
    3. 神龙已为您对 POC 代码进行快照,为了长期维护,请考虑为本地 POC 付费/捐赠,感谢您的支持。