漏洞简介
漏洞公告相关信息:
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数组中的偏移。相关代码如下所示:
...
if (w == MFMWFP_NOITEM)
w = pMenu->cItems;
w--;
pItemWalk = pMenu->rgItems + w;
#ifdef MEMPHIS_MENUS
while (w && (pItemWalk->hbmp) && (pItemWalk->hbmp < (HBITMAP)MENUHBM_MAX))
#else // MEMPHIS_MENUS
while (w && (pItemWalk->fType & MFT_BITMAP) && (pItemWalk->hTypeData < (HANDLE)MENUHBM_MAX))
#endif // MEMPHIS_MENUS
{ wIndex = w--;
pItemWalk--;
}
...
在调用AppendMenuA函数后,Menu中的Item数据刚好达到了8个,而由下面的代码可以看出,内核中Item数据的分配刚好是以8个Item为分配粒度的。于是如下代码中的pMenu->cItems >= pMenu->cAlloced的条件正好成立,于是win32k!MNLookUpItem会被再次调用,在新分配的Item数据中通过wIndex偏移找到需要插入的内存地址并保存在pItem中。
#define CMENUITEMALLOC 8
...
...
if (pMenu->cItems >= pMenu->cAlloced) {
if (pMenu->rgItems) {
pNewItems = (PITEM)DesktopAlloc(pMenu->head.rpdesk->hheapDesktop,
(pMenu->cAlloced + CMENUITEMALLOC) * sizeof(ITEM));
...
} else {
pNewItems = (PITEM)DesktopAlloc(pMenu->head.rpdesk->hheapDesktop,
sizeof(ITEM) * CMENUITEMALLOC);
}
...
pMenu->cAlloced += CMENUITEMALLOC;
pMenu->rgItems = pNewItems;
...
/*
* Now look up the item again since it probably moved when we realloced the
* memory.
*/
if (wIndex != MFMWFP_NOITEM)
pItem = MNLookUpItem(pMenu, wIndex, fByPosition, &pMenuItemIsOn);
}
然而win32k!MNLookUpItem函数会在所有的Item以及子菜单的Item中递归寻找,由于之前已经有7个Item数据存在,在调用InsertMenuA函数后wIndex被改写为7,而此时由于notepad的第一个File的子菜单中的最后一个Item(Exit)的id正好是7,于是win32k!MNLookUpItem函数遍会把此Item的内核地址返回。之后在计算memmove移动长度时便会出现不可预料的情况,并在移动数据时发生访问异常。
...
memmove(pItem + 1, pItem, (pMenu->cItems - 1) *
sizeof(ITEM) - ((char *)pItem - (char *)pMenu->rgItems));
...
typedef struct tagITEM
{
UINT fType;
UINT fState;
UINT wID;
struct tagMENU* spSubMenu; /* Pop-up menu. */
HANDLE hbmpChecked;
HANDLE hbmpUnchecked;USHORT* lpstr; /* Item text pointer. */
ULONG cch;
DWORD_PTR dwItemData;
ULONG xItem; /* Item position. left */
ULONG yItem; /* " top */
ULONG cxItem; /* Item Size Width */
ULONG cyItem; /* " Height */
ULONG dxTab; /* X position of text after Tab */
ULONG ulX; /* underline.. start position */
ULONG ulWidth; /* underline.. width */
HBITMAP hbmp; /* bitmap */
INT cxBmp; /* Width Maximum size of the bitmap items in MIIM_BITMAP state */
INT cyBmp; /* Height " */
} ITEM, *PITEM;
从上面代码可以看出,win32k!xxxInsertMenuItem中触发漏洞的memmove所用到的pItem地址正好是之前win32k!MNLookUpItem函数返回的内存地址。结合内存数据和PITEM数据结构可以看出,此时的pItem地址所指向的是notepad中File的子菜单中的最后一个Item(Exit)(数据结构如上图红色所示),而pMenu->rgItems为DesktopAlloc新分配的内存地址指针,这两个地址分别属于不同的Item数组中,所以相减的值是不可预料的,精确操作内核堆分配可控制memmove长度,从而控制特定的内存区域。
漏洞利用
漏洞利用主要用到两个数据结构如下:
typedef struct tagPROPLIST {
UINT cEntries;
UINT iFirstFree;
tagPROP aprop[1];
} PROPLIST, *PPROPLIST;
typedef struct tagMENU
{
...
UINT cItems;
/* Number of items in the menu */
...
PITEM rgItems;
/* Array of menu items */
...
} MENU, *PMENU;
通过构造数据覆盖tagPROPLIST中的cEntries和iFirstFree便可以实现对tagPROPLIST结构之后的一段数据进行控制。
漏洞触发过程中tagPROPLIST在内存中的变化:
漏洞触发前
fce2f240 00000002 00000002 fb10afe0 0001c033 tagPROPLIST
fce2f250 00000000 0002c04a 00010002 08000004
fce2f260 00410041 00000041 00010002 08000002
fce2f270 00410041 00000041 00010002 08000002
fce2f280 00410041 00000041 00010002 08000002
fce2f290 00410041 00000041 00010002 08000002
fce2f2a0 00410041 00000041 00010002 08000002
fce2f2b0 00410041 00000041 00010002 08000002
漏洞触发后
fce2f240 08000002 88888888 88888888 88888888 tagPROPLIST
fce2f250 88888888 88888888 88888888 88888888
fce2f260 88888888 88888888 88888888 88888888
fce2f270 88888888 88888888 88888888 88888888
fce2f280 88888888 88888888 88888888 88888888
fce2f290 88888888 88888888 88888888 88888888
fce2f2a0 00008888 00010004 0800000d 00000002
fce2f2b0 00000002 fb10afe0 0001c033 00000000
漏洞利用过程大概可以分为如下步骤:
1. 构造数据覆盖tagPROPLIST中的cEntries和iFirstFree;
2. 通过SetProp函数对tagPROPLIST对分布在其后的tagMENU结构中的cItems和rgItems字段进行控制;
3. 通过SetMenuItemInfo实现对任意地址的写操作;
4. 改写内核HalDispatchTable+4的数据实现EIP控制。
漏洞演示
测试环境: Windows 7 SP1 x86 (更新于2016-07-16)
聚圣源八字土起名商标起名名称测试公安部副部长颜氏家字辈起名伤物语冷血篇陈姓女宝宝起名大全2021官路风流红帆酒店时尚中黑简体华为x5哈利波特全集下载车用尿素品牌起名起名姓王名字女孩洋气阴阳师姑获鸟御魂服务公司起名怎么起英语名字男生排列五走势图综合版周易八字算命起名属马起什么名字好猪年张姓的宝宝起名大全msecache注册个体户名字怎么起起名劳务建筑公司名称八字起名测试打分免费店面的起名集团有限公司公司起名字珊字起名字蜗居是什么意思微微一笑很倾城网盘景起名寓意淀粉肠小王子日销售额涨超10倍罗斯否认插足凯特王妃婚姻让美丽中国“从细节出发”清明节放假3天调休1天男孩疑遭霸凌 家长讨说法被踢出群国产伟哥去年销售近13亿网友建议重庆地铁不准乘客携带菜筐雅江山火三名扑火人员牺牲系谣言代拍被何赛飞拿着魔杖追着打月嫂回应掌掴婴儿是在赶虫子山西高速一大巴发生事故 已致13死高中生被打伤下体休学 邯郸通报李梦为奥运任务婉拒WNBA邀请19岁小伙救下5人后溺亡 多方发声王树国3次鞠躬告别西交大师生单亲妈妈陷入热恋 14岁儿子报警315晚会后胖东来又人满为患了倪萍分享减重40斤方法王楚钦登顶三项第一今日春分两大学生合买彩票中奖一人不认账张家界的山上“长”满了韩国人?周杰伦一审败诉网易房客欠租失踪 房东直发愁男子持台球杆殴打2名女店员被抓男子被猫抓伤后确诊“猫抓病”“重生之我在北大当嫡校长”槽头肉企业被曝光前生意红火男孩8年未见母亲被告知被遗忘恒大被罚41.75亿到底怎么缴网友洛杉矶偶遇贾玲杨倩无缘巴黎奥运张立群任西安交通大学校长黑马情侣提车了西双版纳热带植物园回应蜉蝣大爆发妈妈回应孩子在校撞护栏坠楼考生莫言也上北大硕士复试名单了韩国首次吊销离岗医生执照奥巴马现身唐宁街 黑色着装引猜测沈阳一轿车冲入人行道致3死2伤阿根廷将发行1万与2万面值的纸币外国人感慨凌晨的中国很安全男子被流浪猫绊倒 投喂者赔24万手机成瘾是影响睡眠质量重要因素春分“立蛋”成功率更高?胖东来员工每周单休无小长假“开封王婆”爆火:促成四五十对专家建议不必谈骨泥色变浙江一高校内汽车冲撞行人 多人受伤许家印被限制高消费
发表评论
您还未登录,请先登录。
登录