首页
社区
课程
招聘
[原创]CVE-2016-7255提权漏洞学习笔记
发表于: 2022-6-16 18:11 20711

[原创]CVE-2016-7255提权漏洞学习笔记

2022-6-16 18:11
20711

该漏洞存在于win32k中的xxxNextWindow函数中,该函数没有对tagWND对象的spmenu成员的合法性进行验证,就直接将其作为合法地址进行读写,导致了BSOD的产生。通过将spmenu设置为特定的值,可以让tagWND对象获得越界写入的能力,从而修改其他tagWND的strName->Buffer的值,实现任意地址写入,最终实现提权。

操作系统:Win 7 x86 sp1 专业版

编译器:Visual Studio 2017

调试器:IDA Pro, WinDbg

xxxNextWindow函数的第一个参数指向tagQ结构体,该结构体定义如下:

tagQ结构体中有许多成员指向tagWND结构体,该结构体定义如下:

xxxNextWindow会从tagQ中取出偏移0x28的spwndActive作为参数调用GetNextQueueWindow,spwndActive代表当前活跃的窗口,函数GetNextQueueWindow会将spwndActive偏移0x38保存的子窗口spwndChild返回:

验证GetNextQueueWindow返回的tagWND偏移0x78处保存的spmenu成员是否为0,如果不为0,将对spmenu偏移0x14处指向的地址进行或运算:

spmenu是一个tagMENU对象,该对象部分成员如下,所以上面的代码其实是想对tagMENU的flags成员进行或运算。

在进行或运算之前,函数只是验证了tagWND->spmenu是否为0,却没有验证tagWND->spmenu所指的内存是否有效,而spmenu可以通过函数SetWindowLong修改,该函数定义如下:

SetWindowLong函数会调用内核的xxxSetWindowLong函数实现功能,在xxxSetWindowLong函数中会判断nIndex是否小于0:

如果nIndex小于0,则会调用xxxSetWindowData函数:

xxxSetWindowData函数会判断nIndex是否等于-12:

如果nIndex为-12,继续判断tagWND->style的最高位是否为0x40,如果是,则将dwNewLong赋值给窗口的spmenu:

根据以下定义可以知道,当对带有WS_CHILD标记的窗口调用SetWindowLong的时候,如果第二个参数传入GWL_ID,第三个参数的值就会写入到窗口的spmenu中:

因此,用户可以修改窗口的spmenu,如果将它修改为一个非法的地址,再调用xxxNextWindow函数,就会因为对一个非法地址进行或运算导致BSOD的产生。

对上述内容的总结如下:

漏洞函数xxxNextWindow的执行流程是:1) 获取当前活跃窗口;2) 从当前活跃窗口中获取子窗口;3) 对子窗口的spmenu成员0x14所指的内存地址进行或运算

想要在用户层修改窗口的spmenu成员,要满足的条件:1) 被修改的窗口具有WS_CHILD标记. 2) 调用SetWindowLong的时候第二个参数指定为GWL_ID

xxxNextWindow函数需要通过发送Alt + Esc的按键信息来调用,因此漏洞触发的步骤如下:

获取桌面窗口句柄作为父窗口

创建一个用来触发漏洞的攻击窗口,该窗口的父窗口需要指定为桌面窗口

设置攻击窗口带有WS_CHILD标记,通过SetWindowLong修改攻击窗口的spmenu,将其指向非法内存地址

将桌面窗口置于最顶层,即将其变成活跃窗口

模拟Alt + Esc按键调用xxxNextWindow函数

相应的POC代码如下:

在xxxNextWindow函数验证spmenu是否为0处下断点,编译运行POC,可以看到此时的spmenu已经被修改为指定的值:

由于是非0的,所以函数会继续向下执行,将spmenu的值取出,并对其+0x14的内存地址进行或操作,但是该地址是非法地址,所以会触发BSOD错误:

利用该漏洞可以实现对指定的内存地址与4进行或运算,因此可以将spmenu赋值为tagWND偏移0x93,这样就可以扩大tagWND偏移0x90的cbwndExtra。之所以扩大这个地址,是因为在xxxSetWindowLong中,当nIndex大于0的时候,函数会判断nIndex + 4是否小于等于cbwndExtra,如果大于,就会设置错误码再退出函数:

如果nIndex + 4小于等于cbwndExtra,函数会对将dwNewLong的值写入到tagWND窗口之后的nIndex处的地址。这里的esi指向tagWND的首地址,0xB0是tagWND的大小,edx则是nIndex:

如果利用该漏洞将cbwndExtra扩大了,此时就可以直接通过SetWindowLong来实现越界写入操作。如果可以在可写的范围内在布置一个tagWND结构体,这样就可以通过SetWindowLong函数修改新布置的tagWND结构体中的成员来实现任意地址读写。

由于要获取tagWND的cbwndExtra地址来对其进行扩大,所以要首先获取窗口对象的tagWND地址。tagWND的获取可以通过HMValidateHandle函数实现,该函数定义如下:

当第二个参数type指定为TYPE_WINDOW(0x1)的时候,函数会返回第一个参数指定的窗口句柄的THREADESKEAD结构体,该结构体定义如下,其中pSelf成员保存了tagWND对象在内核中的地址。

有了HMValidateHandle函数就可以获取需要的窗口的tagWND在内核中的地址,但是该函数是未导出的函数,需要通过user32.dll中的导出函数IsMenu来获取,因为IsMenu函数有对HMValidateHandle的调用:

这里可以将0xE8作为特征码找到HMValidateHandle的相对地址,根据相对地址得出实际的函数地址,相应的代码如下:

通过HMValidateHandle可以获取cbwndExtra,在调用SetWindowLong修改spmenu的时候,可以将写入值指定为cbwndExtra  + 3  - 0x14的地址,这样就可以利用或操作扩大cbwndExtra,相应代码如下:

此时在xxxNextWindow对spmenu是否为0处下断点,查看此时的tagWND地址为0xFEA1C200,那么cbwndExtra的地址就是0xFEA1C290:

spmenu为0xFEA1C27F,等于0xFEA1C200 + 0x90 + 0x3 - 0x14,成功指向cbwndExtra + 0x3处的地址,此时的cbwndExtra为0。

继续向下运行,会对tagWND中成员cbwndExtra + 0x3地址处的内容对4进行或运算:

可以看到此时成功将cbwndExtra值扩大到0x04000000:

现在可以利用漏洞实现扩大cbwndExtra成员的方式来实现越界写入,需要在被扩大的tagWND对象的可写入的范围内布置另一个tagWND结构体作为用来修改的窗口对象,通过对该对象成员的修改实现任意地址读写,所以此时需要首先创建一部分窗口,在释放掉其中的一部分,这样触发漏洞的时候创建的窗口之后就会存在另一个tagWND对象,相应代码如下:

此时,在触发漏洞的时候,加入以下代码用来查找位于被扩大cbwndExtra的tagWND对象高地址中最近的一个tagWND对象用来作为攻击窗口此时,就可以利用越界写入修改攻击窗口对象tagWND中的成员。

任意地址的读取要用到GetAncestor函数,该函数的定义如下:

该函数会调用内核中的NtUserGetAncestor,NtUserGetAncestor函数将_GetAncestor函数返回值指向的地址中的值作为返回值:

参数gaFlags为1的时候,_GetAncestor函数会返回tagWND中偏移0x34的spwndParent:

所以,在用户层调用GetAncestor函数的时候,如果第二个参数指定为GA_PANT,函数就会将第一个参数对应的tagWND对象的spwndParant所指的内存地址中的数据返回。

因为可以利用越界写入操作将tagWND偏移0x34的spwndParent修改为任意地址,所以,可以通过调用GetAncestor就可以实现任意地址的读取。

对于任意地址写入,需要用到tagWND对象偏移0x84处的strName成员:

该成员用来是一个_LARGE_UNICODE_STRING结构体,结构体定义如下:

在用户层调用如下定义的SetWindowTextW函数的时候,函数会将参数lpString中的数据写入到tagWND->strName的Buffer保存的地址中。同理,因为此时可以利用越界写入操作将Buffer修改为任意地址,所以,可以通过SetWindowTextW实现任意地址写入。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

最后于 2022-6-29 15:27 被1900编辑 ,原因:
收藏
免费 5
支持
分享
最新回复 (6)
雪    币: 239
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
2
老师我想学二进制漏洞,怎么入门
2022-6-22 09:49
0
雪    币: 22411
活跃值: (25361)
能力值: ( LV15,RANK:910 )
在线值:
发帖
回帖
粉丝
3
t1n9 老师我想学二进制漏洞,怎么入门
汇编和C会的话,可以直接看0day和漏洞战争
2022-6-22 15:39
0
雪    币: 239
能力值: ( LV1,RANK:0 )
在线值:
发帖
回帖
粉丝
4
好的感谢
2022-6-26 10:17
0
雪    币: 8175
活跃值: (6399)
能力值: ( LV12,RANK:207 )
在线值:
发帖
回帖
粉丝
5
补充一个细节,初始化用来攻击的窗口时,一定要设置WindowName,不能设置为NULL。否则tagWNd->StrName.MaximumLength为0,导致在调用SetWindowText时会写入任意地址
2023-2-3 15:05
0
雪    币: 22411
活跃值: (25361)
能力值: ( LV15,RANK:910 )
在线值:
发帖
回帖
粉丝
6
Ally Switch 补充一个细节,初始化用来攻击的窗口时,一定要设置WindowName,不能设置为NULL。否则tagWNd->StrName.MaximumLength为0,导致在调用SetWindowText ...
提醒一句,二进制方向,特别win内核漏洞这一块 是红海,工作特别特别不好找 具体可以去招聘软件看看。想学的师傅们三思。。。
2023-3-29 16:04
0
雪    币: 8175
活跃值: (6399)
能力值: ( LV12,RANK:207 )
在线值:
发帖
回帖
粉丝
7
1900 提醒一句,二进制方向,特别win内核漏洞这一块 是红海,工作特别特别不好找 具体可以去招聘软件看看。想学的师傅们三思。。。
哈哈,早已转行金融,只是偶尔想学点技术
2023-5-10 11:09
0
游客
登录 | 注册 方可回帖
返回
//