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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2025-24990_POC — Доказательство концепции CVE-2025-24990 (драйвер Agere Systems) | Kitploit
Инструменты/GitHubGitHub/moiz-2x/cve-2025-24990_poc
Повышение привилегийФреймворки для эксплойтовАнализ уязвимостейЭксплуатацияЭксплуатация Бинарных Файлов
GitHubmoiz-2x/cve-2025-24990_poc

CVE-2025-24990_POC

Доказательство концепции CVE-2025-24990 (драйвер Agere Systems)

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

Популярное

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

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

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

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

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

Драйвер модема Agere для Windows (ltmdm64.sys). Этот драйвер очень старый и не загружается по умолчанию на моей тестовой машине, поэтому я буду эксплуатировать его в сценарии BYOVD. Интересно, что, согласно моим исследованиям, этот драйвер существовал на Windows 7 и имеет как минимум одну ошибку. здесь

В то время MSRC не предпринял никаких действий 🤡

Уязвимости

Некоторые IOCTL в этом драйвере используют METHOD_NEITHER, но не проверяют, находится ли буфер адреса, предоставленный вызывающим абонентом, в пользовательском или режиме ядра. Вот пример кода IOCTL, который я декодировал с помощью OSR:

Это означает, что вы можете передать адрес ядра в API DeviceIoControl, и драйвер обработает его обычным образом.

Обратите внимание, что сначала нужно обойти kASLR, чтобы утечь адрес ядра. Я буду использовать EnumDeviceDrivers (в Windows 24h2 для этого нужен SeDebugPriv).

Разыменование NULL

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

ud_response вызывает ll_load_diagnostics, и я достигну следующего кода:

В начале глобальная переменная eeprom не инициализирована, поэтому она будет содержать NULL. Вот простой код, который вызовет это.

Я воспользуюсь этим позже.

Точка входа эксплойта 0x802b2003

Этот IOCTL просто преобразует строку версии драйвера "8.36" в число 0x836 (тип DWORD) и записывает его по адресу, предоставленному вызывающим абонентом (благодаря METHOD_NEITHER). Технически я могу записать эти четыре байта (36 08 00 00) по произвольному адресу ядра. Я воспользуюсь этим, чтобы перезаписать глобальные переменные драйвера и изменить поток выполнения.

Я буду называть этот 0x802b2003 IOCTL_GET_VERSION

Эксплойт

Произвольный нулевой 1 байт:

Возвращаясь к случаю разыменования NULL, я использую API VirtualAlloc для выделения фиксированного адреса (0x083600000000). Затем я использую IOCTL_GET_VERSION, чтобы записать в *(eeprom + 4) четыре байта, описанные выше. Когда драйвер позже разыменует eeprom, он прочитает данные по адресу, который я выделил.

После исправления разыменования NULL, IOCTL записывает строку по адресу, который я передаю из пользовательского режима, на основе размера буфера.

Этот код просто демонстрирует то, что я описал выше: выделяет буфер и заполняет его 0xAA, исправляет разыменование NULL, затем вызывает драйвер. Обратите внимание, что я выделяю 11 байт, но передаю драйверу размер буфера только 10, чтобы посмотреть, как он себя поведет.

Он записывает фиксированную последовательность байтов в мой буфер, а затем обнуляет последний байт (11-й), даже если я предоставляю размер только 10. Он заменяет последний 0xAA в моем буфере на 0x00. Это указывает на то, что если я укажу размер 0, драйвер все равно запишет один байт 0x00 по целевому адресу.

Произвольное уменьшение

Теперь у меня есть нулевой и произвольный с фиксированными 4 байтами, давайте создадим другой примитив.

Этот IOCTL установит глобальный LtMsgEvent в мой пользовательский буфер, затем проверит, является ли WDM нулевым, и снова установит ноль.

Затем в 0x802b2207 он вызовет API ObfReferenceObject.

В начальном состоянии WDM равен нулю, но с помощью IOCTL_GET_VERSION я могу установить WDM в 0x36 (его размер всего 1 байт), а LtMsgEvent все еще мой буфер. Затем я обнулю WDM и вызову 0x802b2207. Наконец, достигну ObfReferenceObject. Я буду называть эти два ioctl IOCTL_SET_LtMsgEvent и IOCTL_DEREF_LtMsgEvent.

Техника эксплойта с использованием ObfReferenceObject изменяет PreviousMode нашего KTHREAD с UserMode на KernelMode. Вы можете прочитать об этом здесь. Однако Windows исправила этот эксплойт, поэтому мы не можем его использовать.

Но примитив в ObfReferenceObject все еще существует. API вычитает 0x30 из предоставленного нами адреса, приводит результат к 8-байтовому целому числу, а затем вычитает 1.

root@kitploit:~
*(signed long long)(LtMsgEvent-0x30) -= 1

Но проблема в том, что он проверяет, является ли следующее значение 0 или текущее значение < 1 (интерпретируется как 8-байтовое целое число со знаком). Если какое-либо из условий истинно, он переходит к KeBugCheckEx и вызывает сбой системы.

Произвольная запись

Имея в руках произвольное уменьшение, мне нужно найти другое место для записи байта 0xFF, а затем уменьшить его до нужного мне байта, и я нашел этот ioctl 0x802b2243:

Мы сосредоточимся на ветке flip. pbVar5 — это адрес, который я передаю из пользовательского режима, и он может быть любым целевым адресом, который я выберу. Я записываю байт 0x0C в DAT_TARGET_EX (с помощью IOCTL_GET_VERSION и примитива произвольного уменьшения), а также обнуляю 1 байт по целевому адресу. Первый вызов этого IOCTL устанавливает 0xC0 по целевому адресу, который затем уменьшается до 0xBF. Второй вызов устанавливает 0xFF по целевому адресу (0xBF | 0xC0 = 0xFF). Как только цель содержит 0xFF, я просто уменьшаю его до желаемого значения.

Я буду записывать по одному байту за раз и быть осторожным с KeBugCheckEx в ObfReferenceObject.

Произвольное чтение

Для примитива чтения я использую технику, описанную здесь (@carrot_c4k3). Я просто перезаписываю объект UNICODE_STRING в ядре (ExpManufacturingInformation), а затем вызываю NtQuerySystemInformation. Из-за того, что ObfReferenceObject вызывает KeBugCheckEx, я обнулю 8 байт, смежных с ExpManufacturingInformation.

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

Эксплойт в Windows 11 22H2+:

Эксплойт, который я описал выше, работает во всех версиях Windows, но нестабилен из-за KeBugCheckEx. Но в Windows 11 22h2+ есть техника, называемая ioring. Эта техника просто перезаписывает ioring->Buffer управляемым адресом. Конкретно, мы можем перезаписать ioring->Buffer и его размер значениями 0x083600000000 и 0x836 соответственно (используя IOCTL_GET_VERSION). Используя эту технику, я выполняю только 2 записи, а затем использую примитив чтения/записи очень стабильно. Обратите внимание, что этот подход требует утечки адреса ядра.

Запуск эксплойта

Windows не загружает драйвер в состоянии по умолчанию. Поэтому вам нужно загрузить его вручную. Файл ltmdm64.sys находится в C:\Windows\System32\DriverStore\...\ltmdm64.sys. Выполните эту команду от имени администратора и запустите эксплойт:

sc create ltmdm64_srv binPath="C:\Windows\System32\DriverStore...\ltmdm64.sys" type=kernel && sc start ltmdm64_srv

Эксплойт будет использовать технику ioring для отключения PPL процесса lsass.exe и мою технику, основанную только на данных, для установки PPL для notepad.exe (в win 11 24h2 требуется, чтобы SeDebugPriv был включен)

https://github.com/user-attachments/assets/05a35b38-d26c-484f-9fb7-137f8fe8c079

Авторы CVE

Я сообщил об этой ошибке в ZDI. Но, похоже, она дублируется с заявкой Fabian Mosch и Jordan Jay в MSRC, поэтому этот PoC просто демонстрирует ошибку и ценит их работу. Почти мой первый CVE 😍

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