Как злоумышленники используют подписанные драйверы для захвата инфраструктуры. Использование BYOVD для обхода механизмов защиты PPL в OS Windows.

Новая эра атак на ядро

В современной экосистеме кибербезопасности атаки на ядро операционных систем представляют собой одну из наиболее серьезных угроз. Получив контроль над ядром (ring 0), злоумышленник фактически получает неограниченную власть над системой, делая тривиальными задачи обхода решений класса AV/EDR, кражи учетных данных и сокрытия своего присутствия.

Как мы рассказывали ранее, при использовании техник BYOVD, атакующие вместо того, чтобы искать уязвимости в ядре операционной системы, приносят с собой легитимный, подписанный драйвер от стороннего производителя и эксплуатируют его уязвимости для выполнения кода в режиме ядра. Это позволяет обойти такие механизмы защиты, как Driver Signature Enforcement (DSE).

В данной статье мы сфокусируемся на одном из важнейших защитных механизмов для процессов пространства пользователя ОС Windows – Protected Process Light (PPL). Посмотрим на то, как это устроено со стороны ядра операционной системы, и какие возможности есть у атакующих для манипуляций с PPL при эксплуатации техник BYOVD.

Дисклеймер

Данный материал имеет ознакомительный характер и предназначен для экспертов по информационной безопасности, исследователей и системных программистов, интересующихся вопросами защиты информации в ядре операционных систем и построения систем защиты. ООО «ПАРАНОИД СЕКЬЮРИТИ» не несет ответственности за возможный вред, причиненный с применением изложенной информации. Любая деятельность по созданию, распространению или использованию компьютерных программ, либо иной компьютерной информации, заведомо предназначенных для несанкционированного уничтожения, блокирования, модификации, копирования компьютерной информации или нейтрализации средств защиты компьютерной информации влечет за собой ответственность в соответствии с законодательством Российской Федерации.

Защита процессов в Windows: Модель PPL

Исторически модель безопасности Windows была построена на списках контроля доступа (Discretionary Access Control Lists, DACL) и токенах доступа (Access Tokens). Эта модель является фундаментальной и работает по принципу: «кто» (процесс) может выполнить «какое действие» (чтение, запись, завершение) над «чем» (файлом, другим процессом, ключом реестра). Права доступа процесса определяются его токеном доступа, который наследуется от учетной записи пользователя, его запустившего. Таким образом, пользователь с правами администратора может управлять любым процессом в системе – завершать его, отлаживать, внедрять код и т.д.

Однако у этой модели обнаружились фундаментальные ограничения:

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

  • Недостаточная изоляция критических компонентов. Даже сама операционная система не могла полноценно защитить свои ключевые процессы от «легитимного», но вредоносного использования административных привилегий.

С выходом ОС Windows Vista разработчики расширили классическую модель безопасности механизмом защищенных процессов (Protected Process). Его ключевая идея заключается в том, что он вводит новый, независимый фактор авторизации, который не основан на правах пользователя. Суть данного механизма состоит в том, что даже если у процесса есть права администратора, но он не является защищенным, то он не сможет получить полный контроль над защищенными процессами.

Изначально модель Protected Process была введена для защиты процессов, связанных с управлением цифровыми правами (Digital Rights Management, DRM), например, для защиты воспроизведения медиаконтента. Она создавала «цифровую крепость», изолируя ключевые процессы от вмешательства, включая отладку или завершение даже администратором.

Во все времена процессы с правами SYSTEM (например, winlogon.exe или lsass.exe) были главной целью атакующих. Получив доступ к таким процессам, злоумышленники могли повышать свои привилегии, обходить защитные механизмы, закрепляться в системе и получать учетные данные других пользователей. Со временем Microsoft перенесла модель Protected Process на критически важные компоненты самой ОС и программ безопасности.

С выходом Windows 8.1 (Windows Server 2012 R2) Microsoft представила усовершенствованную модель – Protected Process Light (PPL). В отличие от бинарной модели Protected Process, PPL ввела гибкую иерархию уровней доверия, определяющую, кто и кого может защищать или проверять. Ключевое улучшение – система уровней подписи, где каждый защищенный процесс и процесс, желающий получить к нему доступ, должны иметь соответствующий уровень цифровой подписи (уровень доверия). Это создает структурированную иерархию защиты, где процесс с более высоким уровнем может воздействовать на процесс с более низким, но не наоборот.

В настоящее время модель PPL активно используется для защиты критически важных компонентов Windows и стороннего программного обеспечения:

  • Защита учетных данных. Процесс lsass.exe в Windows 11 по умолчанию запущен с уровнем доверия PsProtectedSignerLsa-Light, что затрудняет процесс кражи паролей и билетов Kerberos злоумышленникам.

  • Самозащита средств защиты информации (например, решений классов AV/EDR). Процесс MsMpEng.exe запущен с уровнем доверия PsProtectedSignerAntimalware-Light, что существенно усложняет задачу атакующим по «отключению» Windows Defender.

Вся безопасность в ОС Windows строится на объектной модели, где каждый ресурс (процесс, файл, ключ реестра) – это объект, доступ к которому защищен списками контроля доступа (DACL). Прежде чем выполнить любую операцию над объектом, система требует получения хендла (handle) через соответствующий API-вызов:

HANDLE OpenProcess( [in] DWORD dwDesiredAccess, [in] BOOL bInheritHandle, [in] DWORD dwProcessId );

Ключевой параметр – dwDesiredAccess, это битовая маска, указывающая, какие именно операции процесс, запрашивающий доступ, планирует выполнять с объектом (другим процессом): PROCESS_TERMINATE, PROCESS_VM_READ, FILE_WRITE_DATA и т.д.

Механизм проверки выглядит так:

  1. При вызове OpenProcess система проверяет ACL целевого процесса.
  2. Сравнивает права вызывающего процесса (из его токена доступа).
  3. Если проверка пройдена – возвращает HANDLE с запрошенными правами.
  4. Все последующие операции через этот HANDLE считаются легитимными.

Эта модель предполагала, что проверка при открытии HANDLE достаточна для обеспечения безопасности.

С появлением моделей Protected Processes и Protected Process Light доступ к защищенным процессам (из обычного процесса), можно получить только с методом доступа PROCESS_QUERY_LIMITED_INFORMATION, что позволяет извлечь лишь базовые метаданные о процессе (PID, имя, статус), но полностью блокирует доступ к памяти процесса и возможности управления им.

Когда процесс имеет один из уровней доверия PPL, ядро Windows применяет строгие ограничения на то, какие другие процессы могут получить его HANDLE с «критичными» правами (такими как PROCESS_VM_WRITE, PROCESS_VM_READ или PROCESS_TERMINATE).

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

BYOVD: Взгляд со стороны ядра

Рассмотрим механизм PPL на примере. Если посмотреть на процесс lsass.exe в Process Explorer, то увидим следующую картину:

Как мы упомянули ранее, процесс lsass.exe имеет уровень PPL PsProtectedSignerLsa-Light. Разберем уровень PPL подробнее. В ядре, каждый процесс представлен структурой _EPROCESS. В этой структуре записана вся информация об исполняемом процессе, в том числе и уровень доверия процесса.

По смещению 0x5fa (Windows 11 25H2) находится однобайтовое поле Protection, которое и описывает уровень доверия процесса (уровень PPL). Значение PsProtectedSignerLsa-Light соответствует числовому значению 0x41.

Само поле Protection имеет тип _PS_PROTECTION и состоит из трех полей Type, Audit и Signer. Хоть поля этой структуры и не являются документированными, довольно легко догадаться что они означают.

Поле Audit включает ведение журнала аудита.

Type определяет уровень изоляции процесса. Если процесс не является защищенным, то это поле равно PsProtectedTypeNone (0x0). В большинстве же случаев, если процесс имеет защиту PPL, это поле имеет значение PsProtectedTypeProtectedLight (0x1).

Поле Signer определяет иерархию доверия (или «уровень подписанта»). Для процесса lsass.exe (в случае если он запущен, как защищенный) это значение равно PsProtectedSignerLsa (0x4), для других системных процессов (wininit.exe, smss, services.exe и т.д.) это значение равно PsProtectedSignerWinTcb (0x6), а для антивирусных программ (например, Windows Defender) это значение равно PsProtectedSignerAntimalware (0x3).

Не все PPL-процессы одинаковы. Существует иерархия уровней защиты. Процесс с более низким уровнем не может получить доступ к процессу с более высоким уровнем. Приведем некоторые из ключевых уровней (от высшего к низшему):

  • PsProtectedSignerWinTcb (Windows TCB). Используется критически важными компонентами Windows, в которые не должен вмешиваться никто.

  • PsProtectedSignerLsa (LSA) – используется для защиты процесса lsass.exe (Local Security Authority Subsystem Service). Именно это не позволяет пентестерам с административными правами использовать утилиты для дампа памяти этого процесса (например, mimikatz) напрямую.

  • PsProtectedSignerAntimalware (Antimalware) – специально разработан для решений класса EDR (Endpoint Detection and Response) и антивирусов. Когда EDR (например, процесс MsMpEng.exe Защитника Windows) запускается как PPL с этим уровнем, даже администратор не может манипулировать памятью процесса или завершить его.

Резюмируя описанное выше, можно сделать вывод, что процессы с уровнем доверия PsProtectedSignerLsa, могут получить доступ к процессам PsProtectedSignerAntimalware, но не наоборот. А процессы с уровнем доверия PsProtectedSignerWinTcb могут получить доступ и к процессам с уровнем доверия PsProtectedSignerAntimalware и PsProtectedSignerLsa, но не наоборот.

Таким образом, поле Protection в _EPROCESS ядро проверяет каждый раз, когда один процесс пытается открыть дескриптор (HANDLE) другого через системный вызов NtOpenProcess.

Также стоит отметить, что процесс не может запросить у операционной системы запустить его с требуемым ему уровнем PPL. Флаг PPL, с которым должен быть запущен исполняемый файл, зашит в его цифровой подписи, а точнее, в расширенных атрибутах (Enhanced Key Usage, EKU). Например, чтобы запуститься с уровнем PsProtectedSignerAntimalware, бинарный файл должен быть подписан специальным сертификатом, который Microsoft выдает только проверенным поставщикам антивирусного ПО, а системные процессы должны иметь запись Protected Process Light Verification (1.3.6.1.4.1.311.10.3.22) в атрибуте EKU.

Примеры эксплуатации техники BYOVD

Злоумышленники, получившие доступ к ядру через BYOVD, видят в PPL лишь одно препятствие, которое с легкостью можно обойти. Их цель – манипулировать структурой EPROCESS (точнее полем Protection) чтобы удалить PPL-защиту процесса.

Используя комбинацию примитивов чтения/записи в ядро (полученную от уязвимого драйвера), злоумышленник находит структуру EPROCESS целевого процесса и обнуляет поле Protection, в результате чего для ядра ОС этот процесс мгновенно становится обычным, незащищенным процессом. Теперь любой процесс с правами администратора может:

Для LSASS. вызвать MiniDumpWriteDump и создать полный дамп памяти lsass.exe, который затем можно проанализировать с помощью Mimikatz для извлечения учетных данных.

В этом примере с помощью команды отладчика (eb) снимаем защиту с процесса lsass.exe, в результате чего он больше не является защищенным.

Для AV/EDR после снятия защиты, у атакующих появляется возможность завершить процесс или поставить его выполнение на паузу, остановив защиту.

По аналогии с предыдущим примером снимается защиты с процесса Window Defender.

Другим, более элегантным методом манипуляции с PPL, является повышение PPL-уровня вредоносного процесса. По аналогии с первым вариантом, используя ту же комбинацию примитивов чтения/записи в ядро, злоумышленник находит структуру _EPROCESS своего атакующего процесса, после чего изменяет поля PPL, устанавливая самый высокий уровень, например, PsProtectedSignerWinTcb.

Теперь «атакующий процесс» имеет самый высокий уровень PPL в системе. Согласно правилам PPL, он может вызывать функцию OpenProcess с полным доступом (PROCESS_ALL_ACCESS) к любому другому процессу, включая EDR и lsass, поскольку его уровень теперь выше или равен любому другому.

Примеры уязвимых примитивов

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

В прошлый раз мы смотрели на примитив MmMapIoSpace, который в совокупности с примитивами чтения и записи позволял осуществлять произвольные манипуляции в ядерной памяти. В этот раз мы рассмотрим примитив ZwMapViewOfSection, который по своей сути является таким же безобидным, но предоставляет не менее значимый функционал для атакующих, чем MmMapIoSpace.

Ядерная функция ZwMapViewOfSection (в паре с ZwOpenSection), может быть использована для отображения произвольной физической памяти в виртуальное адресное пространство атакующего процесса. Если уязвимый драйвер предоставляет злоумышленнику контроль над параметрами этой функции, он может отобразить физическую память, где лежат структуры ядра (в том числе _EPROCESS) в свой процесс, и редактировать их из пространства пользователя.

Функция ZwMapViewOfSection – это примитив ядра Windows, предназначенный для проецирования (отображения) части или всего объекта секция (section) в виртуальное адресное пространство указанного процесса. Основная задача функции – обеспечить гибкий и контролируемый механизм работы с памятью. Её ключевая возможность – разделение памяти между процессами. Секция может быть спроецирована в адресные пространства нескольких процессов, позволяя им читать и записывать данные в одну и ту же область физической памяти.

Вызывая ZwMapViewOfSection можно получить прямой доступ к физической памяти, что позволяет проецировать конкретные диапазоны физической памяти. Посмотрим на определение этой функции:

NTSYSAPI NTSTATUS ZwMapViewOfSection( [in] HANDLE SectionHandle, [in] HANDLE ProcessHandle, [in, out] PVOID *BaseAddress, [in] ULONG_PTR ZeroBits, [in] SIZE_T CommitSize, [in, out, optional] PLARGE_INTEGER SectionOffset, [in, out] PSIZE_T ViewSize, [in] SECTION_INHERIT InheritDisposition, [in] ULONG AllocationType, [in] ULONG Win32Protect );

Функция работает исключительно с виртуальными адресами в контексте целевого процесса. Параметр BaseAddress – это входной/выходной виртуальный адрес в целевом процессе. На входе может содержать желаемый виртуальный адрес для отображения, или NULL – в этом случае система выбирает адрес сама. На выходе содержит фактический виртуальный адрес, по которому отображено представление секции в целевом процессе. Этот адрес является валидным указателем в контексте данного процесса.

Параметр SectionOffset – указывает на смещение в байтах от начала объекта-секции, с которого начнется проецируемое представление.

Чтобы получить секцию на основе физической памяти (\Device\PhysicalMemory), драйвер должен сначала открыть секцию (с помощью вызова ZwCreateSection), указав в качестве источника \Device\PhysicalMemory. Затем вызвать ZwMapViewOfSection, который спроецирует ее часть, заданную SectionOffset и ViewSize, в виртуальное пространство. В этом случае SectionOffset будет содержать физический адрес. Посмотрим пример реального драйвера, который предоставляет такую функциональность:

Сначала (1) с помощью вызова ZwCreateSection драйвер получает хендл на секцию физической памяти, передавая в ObjectAttributes ее имя (\Device\PhysicalMemory).

После этого (2) маппит открытую секцию в адресное пространство вызывающего процесса с физического адреса PhysicalAddress и размером в NumberOfBytes байт.

Результат в виде указателя на виртуальный возвращается в переменную BaseAddress, после чего передается в пользовательское пространство (3) вызывающего процесса с помощью SystemBuffer. Параметр 0xF001F (DesiredAccess) описывает запрашиваемые права доступа. Расшифруем данный параметр:

0xF001Fu = STANDARD_RIGHTS_REQUIRED (0xF0000) + SECTION_QUERY (0x1) + SECTION_MAP_WRITE (0x2) + SECTION_MAP_READ (0x4) + SECTION_MAP_EXECUTE (0x8) + SECTION_EXTEND_SIZE (0x10)

Передача маски 0xF001F означает запрос полного, абсолютного контроля над объектом секции.

Опасность данной реализации заключается в том, что код драйвера совершенно не проверяет диапазоны допустимых физических адресов, в результате чего атакующие могут получить доступ с максимальными правами к пространству ядра.

Защита и противодействие

Борьба с атаками уровня ядра – это игра в кошки-мышки, но у защитников есть не менее мощные инструменты, чем у атакующих.

Kernel Patch Protection

Kernel Patch Protection (KPP) или PatchGuard (PG) – в это встроенный механизм защиты Windows, который периодически проверяет целостность критических структур ядра. Если PatchGuard обнаруживает, что кто-то (например, злоумышленник) изменил ядро – например, модифицировал _EPROCESS или таблицу системных вызовов (SSDT), – он немедленно вызывает синий экран смерти (BSOD). PatchGuard проверяет, как минимум, следующие ядерные элементы:

  • Таблицы дескрипторов системных сервисов (System Service Descriptor Tables, SSDT);
  • Таблицу дескрипторов прерываний (Interrupt Descriptor Table, IDT);
  • Глобальную таблицу дескрипторов (Global Descriptor Table, GDT);
  • Код самого ядра, HAL и библиотек NDIS.

При обнаружении модификации PatchGuard останавливает систему с кодом CRITICAL_STRUCTURE_CORRUPTION.

Это мощный сдерживающий механизм. Атакуя _EPROCESS, злоумышленник рискует «уронить» систему. Однако PatchGuard не работает постоянно, он запускается по расписанию, что оставляет атакующему «временное окно» для атаки. Кроме того, PG может быть отключен, если система запущена в режиме отладки ядра, что часто используется исследователями, но этим же могут воспользоваться и злоумышленники в некоторых сценариях. Это тоже стоит учитывать. Поэтому специалистам по мониторингу стоит настроить аудит запуска процессов с параметрами командной строки (WinEventLog 4688 или Sysmon 1) и отслеживать запуск, например, включение режима отладки:

bcdedit /debug on

Kernel Mode Code Signing

Kernel Mode Code Signing (KMCS) – проверка подписи всех драйверов, загружаемых в режим ядра. Этот механизм гарантирует, что только драйверы от доверенных разработчиков могут быть загружены. Атакующие вынуждены искать уязвимости только в подписанных, легитимных драйверах, что сужает вектор атаки. Однако этот механизм можно временно отключить и, по аналоги с PatchGuard, эта функциональность активно используется не только разработчиками, но и атакующими. Поэтому стоит мониторить запуск, например, следующих процессов:

bcdedit /set testsigning off

Mitigation

Блокировка уязвимых драйверов – самый эффективный метод. Microsoft ведет «Microsoft Recommended Driver Block List» – список драйверов, которые известны как уязвимые и используются в атаках BYOVD. Активация этой политики (через Windows Defender Application Control, WDAC) предотвращает загрузку этих драйверов в ядро, лишая злоумышленника инструмента.

Hypervisor-Protected Code Integrity (HVCI) – изоляция ядра. Используя виртуализацию (Virtualization-Based Security, VBS), Windows создает защищенную среду, где проверка целостности кода ядра происходит «снаружи» самого ядра. Данная мера повышает сложность эксплуатации, изолируя код ядра от потенциально скомпрометированных процессов.

Заключение

В современном ландшафте кибербезопасности защищенные процессы представляют собой важный механизм безопасности в современных версиях Windows, обеспечивающий изоляцию критических системных процессов, в независимости от списков контроля доступа. Однако, как демонстрируют рассмотренные сценарии атак, техника BYOVD позволяет злоумышленникам обходить этот защитный механизм, используя легитимные драйверы.

Bring Your Own Vulnerable Driver (BYOVD) — это мощный вектор атаки, при котором злоумышленники используют легитимные, но уязвимые драйверы, имеющие действительную цифровую подпись, для получения несанкционированного доступа на уровне ядра операционной системы. Эти драйверы, часто разработанные для низкоуровневого мониторинга системы или оптимизации оборудования, содержат уязвимости, позволяющие выполнять произвольные операции чтения/записи в памяти ядра или получать привилегированные возможности.

Успешная атака на PPL через BYOVD состоит из нескольких этапов: получения прав администратора, загрузки уязвимого драйвера, поиска и модификации структур _EPROCESS целевых процессов, и последующего выполнения вредоносных действий.

Для защиты против таких атак необходима комплексная стратегия, включающая блокировку известных уязвимых драйверов через Microsoft Recommended Driver Block List (по умолчанию включен в Windows 11), включение HVCI (Memory Integrity), мониторинг подозрительной активности и регулярное обновление драйверов и системы.

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

Paranoid Security Анализ прошивки и механизма загрузки rootfs операционной системы FortiOS 8.0 12 января
Анализ прошивки и механизма загрузки rootfs операционной системы FortiOS 8.0
Paranoid Security Анализ обновлений Microsoft Patch Tuesday – Декабрь 2025 9 декабря
MS Patch Tuesday Анализ обновлений Microsoft Patch Tuesday – Декабрь 2025
Paranoid Security Анализ обновлений Microsoft Patch Tuesday – Ноябрь 2025 11 ноября
MS Patch Tuesday Анализ обновлений Microsoft Patch Tuesday – Ноябрь 2025