漏洞简介
漏洞公告相关信息:
ZDI-16-453 CVE-2016-3308
CloverSec Labs成员bear13oy在七月中旬也发现该内核漏洞,由于当时比较忙,本想在八月微软的补丁周过后再对其进行分析和利用,不巧的是微软八月份的补丁修复了该漏洞。再次撞洞!
附上当时精简后的poc代码截图:
内核崩溃后栈回溯信息截图:
漏洞原理
由于函数win32k!xxxInsertMenuItem在处理新增菜单插入时,获得了错误的插入偏移,导致函数在计算MenuItem内核数据长度时发生错误,进而在调用memmove移动MenuItem数据时,发生越界操作。
win32k!xxxInsertMenuItem函数在调用memmove移动MenuItem内核数据前,两次调用函数win32k!MNLookUpItem来获取相关Item数据的内存地址。在此漏洞中,第一次调用win32k!MNLookUpItem时,由于传入的wIndex不存在,函数会返回NULL,于是win32k!xxxInsertMenuItem会默认把新Item数据放到原Item数组的末尾,并把wIndex更新为新Item数据在原Item数组中的偏移。相关代码如下所示:
在调用AppendMenuA函数后,Menu中的Item数据刚好达到了8个,而由下面的代码可以看出,内核中Item数据的分配刚好是以8个Item为分配粒度的。于是如下代码中的pMenu->cItems >= pMenu->cAlloced的条件正好成立,于是win32k!MNLookUpItem会被再次调用,在新分配的Item数据中通过wIndex偏移找到需要插入的内存地址并保存在pItem中。
然而win32k!MNLookUpItem函数会在所有的Item以及子菜单的Item中递归寻找,由于之前已经有7个Item数据存在,在调用InsertMenuA函数后wIndex被改写为7,而此时由于notepad的第一个File的子菜单中的最后一个Item(Exit)的id正好是7,于是win32k!MNLookUpItem函数遍会把此Item的内核地址返回。之后在计算memmove移动长度时便会出现不可预料的情况,并在移动数据时发生访问异常。
漏洞利用主要用到两个数据结构如下:
通过构造数据覆盖tagPROPLIST中的cEntries和iFirstFree便可以实现对tagPROPLIST结构之后的一段数据进行控制。
漏洞触发过程中tagPROPLIST在内存中的变化:
漏洞利用过程大概可以分为如下步骤:
1. 构造数据覆盖tagPROPLIST中的cEntries和iFirstFree;
2. 通过SetProp函数对tagPROPLIST对分布在其后的tagMENU结构中的cItems和rgItems字段进行控制;
3. 通过SetMenuItemInfo实现对任意地址的写操作;
4. 改写内核HalDispatchTable+4的数据实现EIP控制。
漏洞演示
测试环境: Windows 7 SP1 x86 (更新于2016-07-16)
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论