Windows Pool OverFlow漏洞利用

作者: 360 Vulcan Team 晏子霜 分类: Windows安全 发布时间: 2021-07-19 08:51

前言:

2021 年 4 月 14 日至 15 日,卡巴斯基技术检测到一波针对多家公司的高度针对性攻击。更仔细的分析表明,所有这些攻击都利用了一系列 Google Chrome 和 Microsoft Windows 零日漏洞(CVE-2021-31956)。虽然我们无法在 Chrome 网络浏览器中检索用于远程代码执行 (RCE) 的漏洞,但我们能够找到并分析用于逃离沙箱并获取系统权限的特权提升 (EoP) 漏洞,并且它利用了两个不同的Microsoft Windows 操作系统内核。

——引用自卡巴斯基[1]

该漏洞使用了WNF模块来完成任意地址读写以及越界读写操作,所以笔者最近对Windows Kernel的 WNF 模块进行了一系列研究,发现WNF模块对于漏洞利用有非常大的帮助(Paged Pool)。

本文对 Windows 中的 WNF 在实用功能上不做讨论,仅对我们关心的漏洞利用进行讨论。

漏洞利用:

在逆向NtosKrnl.exe 后笔者发现,WNF_Object结构是保存在Paged Pool中的一个固定大小 (0xC0|0xD0) 的内核池,该结构由函数Nt!ExpWnfCreateNameInstance 创建并初始化,该函数在R3中也可以通过Ntdll!NtCreateWnfStateName调用。

  

在WNF_Object结构中最重要的就是WNF_Object+0x58处的StateData结构指针,该指针在WNF_Object结构初始化时并未定义,而是在后续使用nt!ExpNtUpdateWnfStateData函数更新StateData时使用了nt! ExpWnfWriteStateData函数更新StateData数据时经过一些判断,来确定是否 创建 Or 修改 StateData的内容。

StateData结构的大小为我们传入的数据内容+0x10,这里的0x10为方便管理Data所创建的,结构如下。(其中 StateData为动态长度)

Struct StateDataObject {

   +0x00 UINT Flag;

   +0x04 UINT MaxLength;

   +0x08 UINT UseLength;

   +0x0c UINT NON;

   +0x10 CHAR StateData[1];

};

有限制的任意地址读写以及相对应的越界读写:

也就是说只要修改了WNF_Object+0x58处的StateData指针,即可获取一个有限制的任意地址读写。

有限制的任意地址写:

       修改StateData指针之后获取一个有限制的任意地址读写的原因是因为WNF_Object+0x58 处保存的是 StateData的结构指针,而不是单纯的数据,其结构在前几节已经介绍过了,具体修改StateData的代码如下。(nt! ExpWnfWriteStateData)

   可以看到复制时不单单复制了StateData的内容,并且会相对应的修改目前使用的长度以及其他信息,所以笔者认为这是获取到了一个有限制的任意地址写。

有限制的任意地址读:

既然任意地址写都有限制了,那任意地址读是否也是如同任意地址写一样,是有限制的呢? 答案是,确实是这样的,任意地址读也有一些相应的限制,请看代码。(nt!ExpWnfReadStateData)

   在读取时,虽然不会修改当前StateData结构的任何属性,但是该函数会完整的读取StateData数据段的全部内容。

也就是说如果我们将StateData的指针修改后用其进行任意地址读则需要注意StateData的UseLength,他的长度则代表了复制的总长度,如果我们Copy的长度低于UseLength,则会返回错误代码。

StateData Object的越界读写:

   与此同时笔者也发现既然任意地址读写的限制都由StateData 结构中MaxLength 、UseLength的引发,但是换一种思路思考的话,也可以推断出如果修改了MaxLength以及UseLength,可以获取一个无限制的越界读写(OOBRW)。

如果布局得当则可以在Ntoskrnl模块中复现Win32k经典利用手法BitMap以及Palette在Windows10 1709之前的骄傲成绩。

WNF_Object 信息泄露造成的危害:

       在WNF_Object创建时,会在WNF_Object + 0x98处 存放当前进程EPROCESS的地址,只要布局得当,则可以使用前几节的内容StateData的越界读并联合其任意地址读写,读出当前进程EPROCESS的地址,并使用任意地址读来读取EPROCESS->Token的指针来获取当前进程Token的地址,对其使用任意地址写来覆盖Token中的SEP_TOKEN_PRIVILEGES结构位来开启当前进程所有的权限,来完成一次完整的漏洞利用,甚至不需要任何一个信息泄露的漏洞!!!!

[1]卡巴斯基对该漏洞的介绍:https://securelist.com/puzzlemaker-chrome-zero-day-exploit-chain/102771/