近日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最高權限。
漏洞主要發生在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已執行成功~~~~~;