- A+
http://drops.wooyun.org/papers/3324
0x00 漏洞背景
近日CrowdStrike团队发现Win64bit2008 R2服务器系统上存在可疑攻击行为,并捕获到相关样本。百度安全攻防实验室根据外界放出的poc进行了研究,漏洞成因和利用细节如下。 此类提权漏洞曾经出现在2011年的8个CVE中(CVE-2011-1878~CVE-2011-1885),由挪威安全公司Norman的内核漏洞达人TarjeiMandt(@kernelpool)报告的(微软公告编号MS11-054),其相关的细节未被公开。 2013年,MJ0011曾经因分析蓝屏崩溃dump文件,重现了此类漏洞并编写了poc和分析文章。
此次漏洞poc运行后的截图如下:
以普通用户权限运行poc成功后,一个system权限的cmd进程被创建出来,说明提权成功,已从普通用户权限提升到了系统system最高权限。
0x01 漏洞分析
漏洞主要发生在win32k!xxxTrackPopupMenuEx函数中,该函数用于弹出一个菜单,是同步的,也就是说只有等菜单弹出并选择之后才返回的,漏洞发生的根本原因在于可以让该函数执行过程中中断一次并执行ring3代码再返回继续执行;
以下是来自win32k!xxxTrackPopupMenuEx函数中部分代码:
1.经过一系列的初始化工作后,调用win32k!xxxMNLoop进入菜单循环等待选择:
2.跟进win32k!xxxMNLoop ,win32k!xxxMNLoop在进入真正的while循环之前会调用win32k!xxxHandleMenuMessages :
3.继续跟进win32k!xxxHandleMenuMessages ,其会事先调用win32k!xxxMNFindWindowFromPoint来得到菜单窗口对象指针ptagWND,之后再调用win32k!xxxSendMessage给菜单窗口发送消息:
4.继续跟进win32k!MNFindWindowFromPoint,其会调用win32k!xxxSendMessage给句柄窗口发送消息来确定菜单窗口坐标,可以看到消息值为:0x1EB(MN_FINDWINDOWFROMPOINT)
5.POC在应用层安装了一个WH_WNDPROC钩子,将这个消息(MN_FINDWINDOWFROMPOINT)给拦截下来,并在其窗口处理线程上下文中调用了EndMenu让菜单窗口销毁,下面是样本中的应用层代码:
Wh_wnd_proc:
Wnd_proc_long:
之所以在钩子函数还要多一步通过SetWindowLong设置窗口函数,在窗口函数里再调用EndMenu是因为得在窗口处理函数线程的上下文空间中调用EndMenu才有意义(每个窗口都有与之关联的pti--tagTHREADINFO).
6.可以看到,由于win32k!xxxSendMessage是异步的,调用完应用层代码(即菜单窗口已经销毁)返回到win32k!xxxMNFindWindowFromPoint, 此时由于失败,win32k!xxxMNFindWindowFromPoint返回0xFFFFFFFB, 回到win32k!xxxHandleMenuMessages
7.回到win32k!xxxHandleMenuMessages之后,问题来了,原因就在于其在检查win32k!xxxMNFindWindowFromPoint函数的返回值ptagWnd的合法性时的不严谨,便直接调用win32k!xxxSendMessage(ptagWnd …….);
8.由于调用xxxSendMessage(ptagWnd ,….)的参数ptagWnd为0xFFFFFFFB, 在函数内会取tagWND.lpfnWndProc字段,并调用该函数,该字段的偏移为: 0x60 , 即地址0Xfffffffb+0x60=0x5B,所有在样本中事先申请了0页面内存,并向0x5B处写入了shellcode地址,从而实现了exploit.
至此,上面就是整个漏洞的流程分析了。
9.最后给出一份直观的流程图:
下面通过调试来重现整个情景;
0x02 漏洞重现与调试
1.应用层与内核层同时进行调试,内核层下条件断点
win32k!xxxFindWindowFromPoint :
bpwin32k!xxxFindWindowFromPoint ".if poi(poi(poi(fs:0x124)+0x50)+0xb4) = 0x130 {} .else {gc}" ----0x130为进程ID
应用层单步到分配0页面构造Fake TagWnd时,查看0页面:
2.应用层继续单步到call TrackPopMenu时.
1.应用层F8单步步过call TrackPopMenu时, 内核层win32k!xxxFindWindowFromPoint断下,可以看到其调用栈如下
2.win32k!xxxFindWindowFromPoint单步到调用xxxSendMessage(MN_FINDWINDOWFROMPOINT)时,并在应用层的窗口函数Wnd_proc_long下断点:
3.F10 步过call xxxSendMessage时,应用层Wnd_proc_long断下:
如果是0x1EB(MN_FINDWINDOWFROMPOINT)消息,则进入到如下:
4.回到内核层单步从xxxMNFindWindowFromPoint返回到xxxHandleMenuMessages,此时:
5.xxxHandleMessages继续执行,单步到调用xxxSendMessage()时:窗口对象ptagWnd为xxxMNFindWindowFromPoint()返回值:0xFFFFFFFB :
6.此时查看patgWnd -00xFFFFFFFB:
7.下断点“ba r4 0x5c“ ,”bp 0x00d21830” , g运行 ,来到断点处:
至此可看到,ShellCode已执行成功~~~~~;
0x03 参考链接
- 我的微信
- 这是我的微信扫一扫
- 我的微信公众号
- 我的微信公众号扫一扫