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 参考链接


  1. crowdstrike 《CrowdStrike Discovers Use of 64-bit Zero-Day Privilege Escalation Exploit (CVE-2014-4113) by Hurricane Panda》
  2. 微软 《Microsoft 安全公告 MS14-058 – 严重》
  3. MJ0011 《从Dump到POC系列一:Win32k内核提权漏洞分析》