360分析 看雪分析
关于漏洞的成因,以上两篇引用文章对漏洞的成因已经介绍的很详细,这里不再赘述.本文主要分析漏洞复现的调试过程,和漏洞利用方式的讨论. 在poc中先创建大小为0x350的AcceleratorTable,计算公式为:
然后又创建了0xcb0大小的AcceleratorTable,这么多个0x350之间的存在空隙,由于其他线程会创建对象占用池的原因,那些创建的小块一般不会大于0xcb0,所以会在多个0x350之间的存在空隙之间堆积,而之后创建的0xcb0大小的AcceleratorTable正好以0xcb00+0x350和方式占满整个一页也就是0x1000大小的空间,又因为0xcb0大小的块数量多余0x350的块,最后0xcb0下方方空余部分可以被同样0x350大小的bitmap和gdi对象占位即图中标识为free的块,占位后池排序方式如下图: poc中出现了2种类型对象,一种是CreateAcceleratorTableW产生的user object对象,还有一种是通过CreateBitmap或GetCurrentObject产生的gdi对象. 在用户态只返回了产生对象的句柄,但是可以通过如下2中方式找到对象的内核泄露地址, user object可以在user32.dll的导出函数gSharedInfo中找到泄露内核地址,具体计算公式为(SHAREDINFO->aheList+sizeOf(HANDLEENTRY)*(AcceleratorTabl句柄&0xffff))
对于gdi对象可以在PEB结构体中的GdiSharedHandleTable中找到泄露内核地址,具体计算公式为(PEB->GdiSharedHandleTable+ sizeof(HANDLEENTRY) *(gdi对象句柄&0xffff)),下面我们来看调试验证过程. 笔者使用在exsi上用windbg和vs双虚拟机调试内核和用户态的2种方法,具体方法见我的另一篇文章 . 对win32k的NtUserCreateAcceleratorTable和win32k!HMAllocObject下断点得到到创建的AcceleratorTable泄露内核地址为fffff900c2877630.
在用户态查看栈变量
在内核态验证这个AcceleratorTable泄露内核地址
接下来验证gdi对象hgdiObj=00000000`0F050D4E,内核地址为FFFFF900C3041CC0,在内核态验证
在ddclient进程退出后再次查看gdi对象的池分布情况
之后poc中把后方存在大量0xcb0的AcceleratorTable和0x350的bitmap占满整个一页池布局中的bitmap清除,此时这个gdi对象必定在这些bitnap中一个位置,马上使用0x350的CreateAcceleratorTableW占位,再来看下池布局
池风水情况如图: poc使用SetDIBColorTable对这个uaf的gdi对象进行操作,实现了任意地址3字节的写,原poc采用了写入Window的cbWNDExtra字段操作的buff指针和方式替换systemtoken实现提权,笔者认为太麻烦,改为hookhal函数至shellcode方式实现提权,可以实现相同效果.下面分析uaf的利用过程. SetDIBColorTable会调用ZwGdiDoPalette进入内核态调用NtGdiDoPalette
NtGdiDoPalette接着又调用了GreSetDIBColorTable
这里xp是一个PALETTE64结构正确逆向结果如下,vCopy_rgbquad函数向xp的+0x80+(4*iStartRef)处写入3个字节也就是PALETTEENTRY的rbg3种颜色,可以由用户控制,这里iStartRef是索引值为0
下面我们看调试来验证这个结果: surf->xpobj就是uaf的gdi对象相对于AcceleratorTableW+0x78偏移量位置的对,也就是最终被任意位置写入内存的对象, 在内核态查看:
继续运行程序至以下代码,然后在用户态查看:
再回到内核态查看
此时可以看到hal地址+8位置的内存数据已经被修改成target地址也就是shellcode地址 接下去调用NtQueryIntervalProfile执行eshellcode,最后成功在win7x64机器上弹出system的cmd,经测试成功率在50%左右,如图:
引用
我的poc地址
作者来自ZheJiang Guoli Security Technology
[招生]科锐逆向工程师培训(2024年11月15日实地,远程教学同时开班, 第51期)
最后于 2019-8-9 09:01
被王cb编辑
,原因: