Skip to content
KitploitKITPLOIT
ИнструментыБлог
Отправить
ИнструментыБлог
Отправить

Инструменты для хакинга, пентеста и кибербезопасности — ваш арсенал защиты!

Kitploit — это каталог инструментов для хакинга, кибербезопасности и пентестинга. Находите последние обновления проектов для поиска уязвимостей, анализа систем, автоматизации тестирования и усиления вашей безопасности.

··Ленты·Контакты·Конфиденциальность·© 2026 Kitploit

Каталог инструментов

Категории

Все категории
Loading categories
CVE-2026-29923 — Эксплойт Proof-of-concept для CVE-2026-29923, повышение привилегий BYOVD в pstrip64.sys. Демонстрирует чтение/запись физической памяти через IOCTL для кражи токена SYSTEM и запуска оболочки с повышенными привилегиями. | Kitploit
Инструменты/GitHubGitHub/athenasec16/cve-2026-29923
Повышение привилегийАнализ уязвимостейЭксплуатацияОбучение и ОбразованиеЭксплуатация Бинарных ФайловЛаборатории и Практика
GitHubathenasec16/cve-2026-29923

CVE-2026-29923

Эксплойт Proof-of-concept для CVE-2026-29923, повышение привилегий BYOVD в pstrip64.sys. Демонстрирует чтение/запись физической памяти через IOCTL для кражи токена SYSTEM и запуска оболочки с повышенными привилегиями.

Репозиторий
2534 месяцев назадПроверено Kitploit

Популярное

Смотреть все →

Откройте для себя самые используемые инструменты нашего сообщества.

Изучить все инструменты

Просмотрите нашу коллекцию инструментов

Смотреть все инструменты →
Поделиться

CVE-2026-29923 - Атака локального повышения привилегий через pstrip64.sys

Отказ от ответственности: Этот код предоставлен только для образовательных целей и исследований в области защиты. Он был написан для углубления понимания эксплуатации ядра и помощи защитникам в предотвращении подобных уязвимостей. Любое несанкционированное, незаконное или злонамеренное использование этого проекта строго запрещено.


Описание

Хеш: ab01485bb7c8bc1a9c86096eeea6d31d8fad557bf4d44072b46373d2203faa6e

Имя драйвера: pstrip64.sys

CVE: CVE-2026-29923

Атака «Принеси свой собственный уязвимый драйвер» (BYOVD) — старый, но по-прежнему эффективный способ обойти современные средства защиты Windows, используя устаревший драйвер, которому операционная система всё ещё официально доверяет. После загрузки драйвера злоумышленник использует его недостатки, чтобы преодолеть разрыв между стандартным непривилегированным процессом и полным контролем над системой.

Ранее на этой неделе была раскрыта новая уязвимость в драйвере pstrip64.sys, отслеживаемая под идентификатором CVE-2026-29923. Эта запись в блоге подробно описывает весь жизненный цикл эксплойта: от моих первоначальных исследований уязвимости и разработки доказательства концепции (PoC) до практических стратегий смягчения последствий для защитников, обеспечивающих безопасность своих сред.

Драйвер pstrip64.sys — это устаревший компонент режима ядра, связанный с EnTech Taiwan PowerStrip (до версии 3.90.736). Хотя его законное назначение — обеспечение расширенных возможностей настройки отображения графических карт, его глубокие системные привилегии делают его весьма привлекательной целью для атакующих.


Уязвимость

Когда уязвимость была впервые раскрыта, я начал с анализа её функции DriverEntry. Она служит основной процедурой инициализации драйвера ядра, создавая объект устройства \Device\PSTRIP64 и открывая его для пользовательских приложений через символическую ссылку \DosDevices\PSTRIP64. Что ещё более важно, она настраивает диспетчерскую таблицу драйвера. Запись, которая сразу привлекла моё внимание, находилась под индексом 14 (IRP_MJ_DEVICE_CONTROL), которая направляет все предоставленные пользователем запросы IOCTL непосредственно в функцию-обработчик sub_11340 — нашу основную область интереса.

IDA DriverEntry

Функция sub_11340 служит основным диспетчером IOCTL, интерпретируя запросы из пользовательского режима.

Из всех доступных IOCTL, 0x80002008, несомненно, самый интересный. В то время как стандартные случаи обрабатывают незначительные взаимодействия с портами ввода-вывода, 0x80002008 действует как шлюз к sub_11000, передавая SystemBuffer напрямую в эту функцию.

IDA ioctl

Эта процедура sub_11000 — неопровержимая улика. Сначала она использует HalTranslateBusAddress для преобразования предоставленного пользователем адреса в действительный системный физический адрес. Затем она открывает \Device\PhysicalMemory и отображает его с помощью ZwMapViewOfSection. Жёстко прописав дескриптор целевого процесса как (HANDLE)0xFFFFFFFFFFFFFFFFLL (что соответствует ZwCurrentProcess()), драйвер отображает эту физическую память непосредственно в адресное пространство виртуальной памяти вызывающего процесса. Критически важно, что затем он записывает этот только что отображённый виртуальный адрес обратно в SystemBuffer для возврата пользователю, официально передавая нашему приложению прямой указатель на чтение и запись физической памяти.

IDA MapViewofSection

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


Доказательство концепции (PoC)

Примечание: Это PoC было специально разработано и протестировано в среде Windows 10 22H2. Поскольку эксплойт основан на манипуляции сырой физической памятью, смещения структур ядра и границы физической памяти в данный момент жёстко прописаны для моей конфигурации. Чтобы протестировать это на вашей машине, необходимо обновить смещения ядра Windows и настроить диапазоны сканирования физических адресов в соответствии с вашей конкретной сборкой ОС и конфигурацией ОЗУ.

Первым шагом в моём эксплойте было установление связи с драйвером. Я сделал это, вызвав CreateFileA для символической ссылки драйвера (\\.\PSTRIP64). Получив действительный дескриптор, мне понадобился чистый способ злоупотребить ранее проанализированным IOCTL 0x80002008. Я создал функцию-обёртку под названием MapPhysicalMemory(). Эта функция заполняет мой пользовательский структур PSTRIP_MAP_REQUEST целевым физическим адресом и длиной фрагмента памяти, который я хочу прочитать.

Затем я отправляю эту структуру напрямую драйверу через DeviceIoControl. В случае успеха драйвер отображает эту физическую память непосредственно в моё пользовательское приложение и возвращает базовый виртуальный адрес в поле OutputResult. Теперь я могу привести этот возвращённый адрес к стандартному указателю C++, что даёт мне необработанный непривилегированный доступ к физической ОЗУ системы.

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

Windows выделяет структуры EPROCESS в пуле ядра, используя определённый 4-байтовый идентификатор, называемый тегом пула. Для процессов этот тег — строка Proc (которая в шестнадцатеричном виде преобразуется в 0x636F7250). Сканируя физическую ОЗУ системы, я мог найти эту точную строку.

Мой эксплойт циклически перебирает пространство физической памяти от 0x10000000 до 0x140000000, отображая память блоками по 2 МБ (STEP_SIZE = 0x200000). Каждый отображённый блок я привожу к сырому массиву байтов и сканирую его блоками по 16 байт (sizeof(_POOL_HEADER)).

Однако простого поиска тега Proc в физической памяти недостаточно. Память неоднородна; этот тег может быть остаточным артефактом завершённого процесса или просто случайными данными, которые совпадают с шестнадцатеричным значением. Если бы я слепо предполагал, что каждый тег Proc является действительной структурой EPROCESS, и начал изменять память, я бы немедленно вызвал BSOD.

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

  • PriorityClass: Я проверяю, что это значение равно 0x2 (Normal Priority).
  • ProcessLock: Я проверяю, что это значение равно 0x0.
  • ImageFileName: Я проверяю, что первый символ имени процесса является допустимым печатным символом ASCII.

Если все эти эвристики проходят, я могу с высокой степенью уверенности утверждать, что смотрю на действительный активный процесс. Затем я читаю его уникальный идентификатор процесса (PID). Если PID совпадает с PID моего собственного процесса эксплойта, я сохраняю физический адрес его указателя на токен. Если PID равен 4 (системный процесс Windows System), я извлекаю и сохраняю фактическое значение его высокопривилегированного токена.

Наконец, я выравниваю сохранённый физический адрес указателя токена моего процесса до ближайшей границы 4 КБ и использую MapPhysicalMemory() в последний раз, чтобы отобразить только эту конкретную страницу.

Затем я перехожу к точному смещению и перезаписываю свой токен значением токена System. Мгновенно ядро Windows начинает рассматривать мой процесс эксплойта как NT AUTHORITY\SYSTEM.

После отображения страницы для обеспечения стабильности системы я просто вызываю CreateProcessA для запуска cmd.exe. Поскольку мой текущий процесс повышен, новая командная строка наследует эти привилегии высшего уровня, успешно завершая атаку!


Примечания

Примечание: Критическая деталь, которую я обнаружил в ходе ранней фазы отладки, касается того, как драйвер обрабатывает отображённый указатель. Выполняя SystemBuffer->LowPart = (unsigned int)BaseAddress;, драйвер приводит 64-битный базовый виртуальный адрес к 32-битному значению перед возвратом. Это усечение теряет старшие биты адреса, что вызывает немедленные нарушения доступа при попытке разыменовать его в моём 64-битном эксплойте. Чтобы чисто обойти эту проблему, я просто скомпилировал своё пользовательское PoC как 32-битное приложение, гарантируя, что возвращаемый указатель остаётся полностью действительным.

IDA MapViewofSection - Copy

Примечание: Во время начального тестирования я столкнулся с интересным пограничным случаем: моё PoC успешно находило мой процесс эксплойта в памяти, но не могло найти процесс System (PID 4).

Чтобы понять причину, мне нужно было напрямую исследовать физическую память. Я подключил отладчик ядра (WinDbg) и использовал команды для получения виртуального адреса и базового каталога процесса System. Затем я использовал !vtop для преобразования этого виртуального адреса в его точный физический адрес в ОЗУ.

windbg kernel debbuger system physical address windbg kernel debbuger db system address

Я переключился обратно на свой отладчик пользовательского режима, подключённый к PoC. Я установил условную точку останова на цикле сканирования памяти, указав приостановить выполнение в тот момент, когда моя функция MapPhysicalMemory() захватит 2-мегабайтный блок, содержащий физический адрес процесса System.

windbg breakpoint

Как только точка останова сработала, я начал вручную проверять сырые байты отображённой памяти. Именно здесь я обнаружил важную деталь о выделении пула ядра Windows.

windbg eprocessBase offset 88000

Когда Windows выделяет память для процесса, она начинается с _POOL_HEADER (содержащего наш тег Proc), за которым следуют _OBJECT_HEADER и, наконец, сама структура EPROCESS. Для стандартных пользовательских приложений эти заголовки содержат дополнительные данные отслеживания, что означает, что фактическая структура EPROCESS начинается на 0x80 байт после тега пула.

offest for use mode process

Однако исследование памяти процесса System показало другую компоновку. У процесса System отсутствуют некоторые из этих стандартных заголовков отслеживания. Смещение от тега Proc до начала структуры EPROCESS было всего 0x40 байт!

windbg db 88000 offset windbg db 88000 - 0x40 offset offset for system process

Исправление было тривиальным. Я обновил своё PoC для обработки обоих размеров заголовков пула, перебирая массив возможных смещений (0x40 и 0x80) всякий раз, когда встречается тег Proc.

posibileoffset

Смягчение и обнаружение

Кибербезопасность — это бесконечная игра в кошки-мышки между атакующими и защитниками. Пока атакующие постоянно ищут уязвимые драйверы, современные средства безопасности и «синие команды» имеют несколько надёжных способов обнаружить и заблокировать эту конкретную операцию.

Самый эффективный способ остановить атаку BYOVD (Принеси свой собственный уязвимый драйвер) — предотвратить загрузку драйвера в первую очередь.

  • Защитники должны убедиться, что хеш pstrip64.sys добавлен в их списки блокировки.
  • Кроме того, организации должны применять список блокировки уязвимых драйверов Microsoft через Windows Defender Application Control (WDAC) и включать Hypervisor-Protected Code Integrity (HVCI), чтобы строго ограничить, какие компоненты ядра могут быть загружены.
  • Отслеживайте новые события создания служб, обращая внимание на неожиданные установки драйверов режима ядра.

Если драйвер уже загружен, средства безопасности всё равно могут обнаружить эксплойт на этапе манипуляции токенами.

  • Расширенный мониторинг аномалий в токенах процессов. Повышение привилегий стандартного пользовательского процесса до NT AUTHORITY\SYSTEM без легитимной цепочки аутентификации является огромным «красным флагом».
  • Кроме того, команды безопасности могут создавать правила для обнаружения случаев, когда процесс с низким или средним уровнем целостности порождает дочерний процесс с высокими привилегиями (например, cmd.exe), особенно если родительский процесс не имеет причин работать как SYSTEM.

Демонстрация

poc_demo

Скачать инструмент