POC详情: beba64dc44a7388e31cdf9b2ce81a4c1f1504630

来源
关联漏洞
标题: TechPowerUp ThrottleStop 安全漏洞 (CVE-2025-7771)
描述:TechPowerUp ThrottleStop是TechPowerUp公司的一款用于监控和调整CPU性能的软件。 TechPowerUp ThrottleStop 3.0.0.0版本存在安全漏洞,该漏洞源于允许物理内存读写,可能导致权限提升。
描述
CVE-2025-7771: Arbitrary physical memory and I/O port read/write via ThrottleStop driver
介绍
# ThrottleStopPoC
**CVE-2025-7771**: Arbitrary physical memory and I/O port read/write via ThrottleStop driver

ThrottleStop is a small legitimate application used to monitor and correct CPU throttling. It has a driver that faciliates these tasks and it mostly doesn't have any sort of input validation.

## Vulnerable IOCTLs
| IOCTL         | Vulnerability             |
| --------------| --------------------------|
| 0x80006498    | Arbitrary memory read     |
| 0x8000649C    | Arbitrary memory write    |
| 0x80006430    | Arbitrary port read       |
| 0x80006434    | Arbitrary port write      |

There also seems to be arbitrary MSR read and write but I wasn't able to get them working.
Feel free to look it yourself.
Read MSR is at `0x80006448` and write at `0x8000644C`.

If you were able to get it working, please submit an issue describing the procedure.

---
> All of the IOCTL calls mentioned below are implemented in [Exploit.c](src/Exploit.c) file. 
---

### Arbitrary memory read
`0x80006498` IOCTL maps any provided physical address into kernel space using `MmMapIoSpace` and reads 1, 2, 4, or 8 bytes from it. The data is then copied back into user space. 

To trigger this IOCTL, `DeviceIoControl` with physical address as input and output buffer size as read size (1, 2, 4, or 8).

Simplified code for this IOCTL in driver:
```cpp
case 0x80006498: {
    size_t readSize = inputBuffer->Size;   // must be 1,2,4,8
    PHYSICAL_ADDRESS physAddr = inputBuffer->PhysAddr;
    void* mappedAddr = MmMapIoSpace(physAddr, readSize, MmNonCached);

    if (mappedAddr) {
        if (readSize == 1)
            *outputBuffer = *(uint8_t*)mappedAddr;
        else if (readSize == 2)
            *(uint16_t*)outputBuffer = *(uint16_t*)mappedAddr;
        else if (readSize == 4)
            *(uint32_t*)outputBuffer = *(uint32_t*)mappedAddr;
        else if (readSize == 8)
            *(uint64_t*)outputBuffer = *(uint64_t*)mappedAddr;

        MmUnmapIoSpace(mappedAddr, readSize);
    }
}
```

### Arbitrary memory write
Similar to read, `0x8000649C` IOCTL maps provided physical address into kernel space using `MmMapIoSpace` and reads 1, 2, 4, or 8 bytes from it.

To trigger this IOCTL, `DeviceIoControl` with the following input buffer layout:
```cpp
struct {
    ULONGLONG PhysicalAddress;  // 8 bytes
    union {
        BYTE  Value8;
        WORD  Value16;
        DWORD Value32;
        QWORD Value64;
    };
};
```
Input buffer size will be 8 + (1, 2, 4, or 8) depending on write size.

Output buffer and output buffer size are unused.

Simplified code for this IOCTL in driver:
```cpp
case 0x8000649C: {
    size_t writeSize = inputBuffer->Size;  // must be 1,2,4,8
    PHYSICAL_ADDRESS physAddr = inputBuffer->PhysAddr;
    void* mappedAddr = MmMapIoSpace(physAddr, writeSize, MmNonCached);

    if (mappedAddr) {
        if (writeSize == 1)
            *(uint8_t*)mappedAddr = inputBuffer->Value8;
        else if (writeSize == 2)
            *(uint16_t*)mappedAddr = inputBuffer->Value16;
        else if (writeSize == 4)
            *(uint32_t*)mappedAddr = inputBuffer->Value32;
        else if (writeSize == 8)
            *(uint64_t*)mappedAddr = inputBuffer->Value64;

        MmUnmapIoSpace(mappedAddr, writeSize);
    }
}
```

### Arbitrary port read
`0x80006430` IOCTL allows a user to specify an IO port and read from it directly using `__inbyte`, `__inword`, or `__indword`.

Input buffer is a `USHORT` and Input buffer size should be `sizeof(USHORT)`.

Output buffer will hold the result (1, 2, or 4 bytes depending on requested size) and output size can be 1, 2, or 4.

Simplified code for this IOCTL in driver:
```cpp
case 0x80006430: {
    uint16_t port = inputBuffer->PortNumber;
    uint8_t size  = inputBuffer->AccessSize; // 1, 2, or 4

    if (size == 1)
        *outputBuffer = __inbyte(port);
    else if (size == 2)
        *(uint16_t*)outputBuffer = __inword(port);
    else if (size == 4)
        *(uint32_t*)outputBuffer = __indword(port);
}
```

### Arbitrary port write
Similar to port read, `0x80006434` IOCTL allows a user to specify an IO port and write arbitrary values to it with `__outbyte`, `__outword`, or `__outdword`.
The input buffer layout is:
```cpp
struct {
    USHORT PortNumber;
    BYTE   Padding[2];   // alignment
    union {
        BYTE  Value8;
        WORD  Value16;
        DWORD Value32;
    };
};
```
Input buffer size should be sizeof(USHORT) + sizeof(Value) (+ padding).
Output buffer and its size are unused.

Simplified code for this IOCTL in driver:
```cpp
case 0x80006434: {
    uint16_t port = inputBuffer->PortNumber;
    uint8_t size  = inputBuffer->AccessSize; // 1, 2, or 4

    if (size == 1)
        __outbyte(port, inputBuffer->Value8);
    else if (size == 2)
        __outword(port, inputBuffer->Value16);
    else if (size == 4)
        __outdword(port, inputBuffer->Value32);
}
```
---

### Translation of virtual addresses to physical addresses
This translation is possible by abusing Superfetch, a legitimate kernel module that exposes virtual to physical address translation using undocumented APIs.
The code for this is implemented in [vtop.c](src/vtop.c)

## Build 
This project can be compiled using Meson. It reads the `UniqueProcessId` field by resolving the EPROCESS structure of the System process using `PsInitialSystemProcess` and checks if it's `4` (imeplemented in [Main.c](src/Main.c) and the functions for finding EPROCESS of a specific PID are implemented in [EProcess.c](src/EProcess.c)). Additionally, it asks the user if they want to force-restart their system. This is possible by writing `0x0E` value to port `0xCF9`.

> **Warning**: Everything was tested on **Windows 11 build 24H2**. The offsets in the EPROCESS structure might be different on your system.

Build the project by
```
meson setup build
```
It will create the build directory. Now compile the project with
```
meson compile -C build
```

The driver is available at `Drivers` directory of the repository. ThrottleStop drivers can be directly extracted from `ThrottleStop.exe` program via Resource Hacker. You'll find 2 drivers - x64 and x86. `DriverObject->MajorFunction[14]` holds the dispatch function where all the IOCTLs have been implemented.

Create and start driver using:
```
sc create ThrottleStop binPath="<Path>" type=kernel
sc start ThrottleStop
```

## References
https://github.com/jonomango/superfetch

This driver hasn't yet been added to Microsoft driver block list nor [loldrivers](https://loldrivers.io).
文件快照

[4.0K] /data/pocs/beba64dc44a7388e31cdf9b2ce81a4c1f1504630 ├── [4.0K] Drivers │   ├── [ 49K] ThrottleStop.sys │   └── [ 45K] ThrottleStop_x86.sys ├── [1.0K] LICENSE ├── [ 374] meson.build ├── [6.4K] README.md └── [4.0K] src ├── [1.9K] EProcess.c ├── [ 191] EProcess.h ├── [5.2K] Exploit.c ├── [1.3K] Exploit.h ├── [2.4K] Main.c ├── [7.6K] vtop.c └── [3.9K] vtop.h 2 directories, 12 files
神龙机器人已为您缓存
备注
    1. 建议优先通过来源进行访问。
    2. 如果因为来源失效或无法访问,请发送邮箱到 f.jinxu#gmail.com 索取本地快照(把 # 换成 @)。
    3. 神龙已为您对POC代码进行快照,为了长期维护,请考虑为本地POC付费,感谢您的支持。