<span id="7ztzv"></span>
<sub id="7ztzv"></sub>

<span id="7ztzv"></span><form id="7ztzv"></form>

<span id="7ztzv"></span>

        <address id="7ztzv"></address>

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

            Author:[email protected]

            0x00 簡介


            內存的讀、寫、執行屬性是系統安全最重要的機制之一。通常,如果要改寫內存中的數據,必須先確保這塊內存具有可寫屬性,如果要執行一塊內存中的代碼,必須先確保這塊內存具有可執行屬性,否則就會引發異常。然而,Windows系統的異常處理流程中存在一些小小的特例,借助這些特例,就可以知其不可寫而寫,知其不可執行而執行。

            0x01 直接改寫只讀內存


            我在CanSecWest 2014的演講《ROPs are for the 99%》中介紹了一種有趣的IE瀏覽器漏洞利用技術:通過修改JavaScript對象中的某些標志,從而關閉安全模式,讓IE可以加載類似WScript.Shell這樣的危險對象,從而執行任意代碼而完全無需考慮DEP。

            不過,修改SafeMode標志并非是讓IE可以加載危險對象的唯一方法。

            IE瀏覽器的某些界面實際上是用HTML實現的,這些HTML通常存儲在ieframe.dll的資源中,例如:打印預覽是res://ieframe.dll/preview.dlg,整理收藏夾是res://ieframe.dll/orgfav.dlg,頁面屬性則是res://ieframe.dll/docppg.ppg

            IE瀏覽器會為這些HTML創建獨立的渲染實例,以及獨立的JavaScript引擎實例。而為這些HTML創建的JavaScript引擎實例中,SafeMode本身就是關閉的。

            所以,只需將JavaScript代碼插入到ieframe.dll的資源中,然后觸發IE的相應功能,被插入的代碼就會被當作IE自身的功能代碼在SafeMode關閉的JavaScript實例下執行。

            不過,PE的資源節是只讀的,如果試圖用某個能對任意地址進行寫入的漏洞直接改寫ieframe.dll的資源,會觸發寫訪問違例:

            #!bash
            eax=00000041 ebx=1e2e31b0 ecx=00000000 edx=00000083 esi=1e2e31b0 edi=68b77fe5
            eip=69c6585f esp=0363ac00 ebp=0363ac84 iopl=0         nv up ei pl nz na pe cy
            cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010207
            jscript9!Js::JavascriptOperators::OP_SetElementI+0x117:
            69c6585f 88040f          mov     byte ptr [edi+ecx],al      ds:002b:68b77fe5=76
            0:008> !exchain
            0363b0f0: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1)
            0363b648: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1)
            0363bab8: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+1570 (69b421d1)
            0363bb78: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+28c0 (69c71564)
            0363bbc0: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+2898 (69c7150f)
            0363bc44: jscript9!DListBase<CustomHeap::Page>::DListBase<CustomHeap::Page>+276a (69d0dedd)
            0363c588: MSHTML!_except_handler4+0 (66495fa4)
              CRT scope  0, filter: MSHTML! ... Omitted... (6652bbe8) 
                            func:   MSHTML!... Omitted... (6652bbf1)
            0363c62c: user32!_except_handler4+0 (7569a61e)
              CRT scope  0, func:   user32!UserCallWinProcCheckWow+123 (75664456)
            0363c68c: user32!_except_handler4+0 (7569a61e)
              CRT scope  0, filter: user32!DispatchMessageWorker+15e (756659b7)
                            func:   user32!DispatchMessageWorker+171 (756659ca)
            0363f9a8: ntdll!_except_handler4+0 (776a71f5)
              CRT scope  0, filter: ntdll!__RtlUserThreadStart+2e (776a74d0)
                            func:   ntdll!__RtlUserThreadStart+63 (776a90eb)
            0363f9c8: ntdll!FinalExceptionHandler+0 (776f7428)
            

            在上面的異常處理鏈中,mshtml.dll中的異常處理函數最終會調用kernel32!RaiseFailFastException()。如果g_fFailFastHandlerDisabled標志是false,就會終止當前進程:

            #!cpp
            int __thiscall RaiseFailFastExceptionFilter(int this) {
              signed int **v1; // [email protected]
              CONTEXT *v2; // [email protected]
              signed int v3; // [email protected]
              UINT v4; // [email protected]
              HANDLE v5; // [email protected]
            
              v1 = (signed int **)this;
              if ( !g_fFailFastHandlerDisabled )
              {
                v2 = *(CONTEXT **)(this + 4);
                g_fFailFastHandlerDisabled = 1;
                RaiseFailFastException(*(PEXCEPTION_RECORD *)this, v2, 2u);
                v3 = 1653;
                if ( *v1 )
                  v3 = **v1;
                v4 = v3;
                v5 = GetCurrentProcess();
                TerminateProcess(v5, v4);
              }
              return 0;
            }
            

            但是,如果g_fFailFastHandlerDisabled標志為true,異常處理鏈就會執行到kernel32!UnhandledExceptionFilter(),并最終執行kernel32!CheckForReadOnlyResourceFilter():

            #!cpp
            int __stdcall CheckForReadOnlyResourceFilter(int a1) {
              int result; // [email protected]
            
              if ( BasepAllowResourceConversion )
                result = CheckForReadOnlyResource(a1, 0);
              else
                result = 0;
              return result;
            }
            

            如果BasepAllowResourceConversion 也為true,CheckForReadOnlyResource()函數就會將試圖寫入的那個內存分頁的屬性設為可寫,然后正常返回。

            也就是說,如果先將g_fFailFastHandlerDisabled和BasepAllowResourceConversion這兩個標志改寫為true,之后就可以直接修改ieframe.dll的資源,而不必擔心其只讀屬性的問題,操作系統會處理好一切。

            另外還有個小問題。如果像上面所說的那樣觸發了一次CheckForReadOnlyResource()中的修改內存屬性的操作,內存屬性的RegionSize也會變成一個內存分頁的大小,通常是0x1000。而IE在以ieframe.dll中的HTML資源創建渲染實例前,mshtml!GetResource()函數會檢查資源所在內存的RegionSize屬性,如果該屬性小于資源的大小,就會返回失敗。然而,只需將要改寫的資源從頭到尾全部改寫一遍, RegionSize就會相應變大,從而繞過這個檢查。

            這樣,利用Windows寫訪問異常對PE文件資源節開的綠燈,就可以寫出非常奇妙的漏洞利用代碼。

            0x02 直接執行不可執行內存


            我在VARA 2009的演講《漏洞挖掘中的時間維度》中介紹了一種較為少見的模塊地址釋放后重用漏洞。比如一個程序中線程A調用了模塊X的函數,模塊X又調用了模塊Y的函數。模塊Y的函數由于某種原因,耗時比較長才能返回。在它返回前,如能讓線程B將模塊X釋放,那么模塊Y的函數返回時,返回地址將是無效的。當時發現在Opera瀏覽器中可以利用Flash模塊觸發這種漏洞,一款國產下載工具也有類似問題。

            p1

            另外還有不少其它類型的漏洞,最終表現也和上述問題一樣,可以執行某個固定的指針,但無法控制該指針的值。在無DEP環境下,這些漏洞并不難利用,只要噴射代碼到會被執行的地址即可。而在DEP環境下,這些漏洞通常都被認為是不可能利用的。

            但如果在預期會被執行到的地址噴射下面這樣的數據:

            #!cpp
            typedef struct _THUNK3 {
                UCHAR MovEdx;       // 0xba         mov edx, imm32
                LONG EdxImmediate; 
                UCHAR MovEcx;       // 0xb9         mov ecx, imm32
                LONG EcxImmediate; // <- put your Stack Pivot here
                USHORT JmpEcx;      // 0xe1ff       jmp ecx
            } Thunk3;
            

            即使在DEP環境下,盡管堆噴射的內存區域確定無疑不可執行,但你會驚奇地發現系統似乎還是執行了這些指令,跳到ecx所設定的地址去了。只要把ecx設為合適的值,就可以跳往任何地址,繼而執行ROP鏈。

            這是因為Windows系統為了兼容某些老版本程序,實現了一套叫ATL thunk emulation的機制。系統內核在處理執行訪問異常時,會檢查異常地址處的代碼是否符合ATL thunk特征。對符合ATL thunk特征的代碼,內核會用KiEmulateAtlThunk()函數去模擬執行它們。

            ATL thunk emulation機制會檢查要跳往的地址是否位于PE文件中,在支持CFG的系統上還會確認要跳往的地址能否通過CFG檢查。同時,在Vista之后的Windows默認 DEP policy 下,ATL thunk emulation機制僅對沒有設置 IMAGE_DLLCHARACTERISTICS_NX_COMPAT的程序生效。如果程序編譯時指定了/NXCOMPAT參數,就不再兼容ATL thunk emulation了。不過還是有很多程序支持ATL thunk emulation,例如很多第三方應用程序,以及32 位的 iexplore.exe。所以,類似Hacking Team泄露郵件中的CVE-2015-2425,如能用某種堆噴成功搶占內存,也可借此技巧實現漏洞利用。

            這樣,利用系統異常處理流程中的ATL thunk emulation能直接執行不可執行內存的特性,就可以讓一些通常認為無法利用的漏洞起死回生。

            (本文大部分內容完成于2014年10月,涉及的模塊地址、符號信息等基于Windows Technical Preview 6.4.9841 x64 with Internet Explorer 11。)

            0x03 參考


            1. ROPs are for the 99%, CanSecWest 2014
            2. Bypassing Browser Memory Protections
            3. (CVE-2015-2425) “Gifts” From Hacking Team Continue, IE Zero-Day Added to Mix
            4. 《漏洞挖掘中的時間維度》,VARA 2009

            <span id="7ztzv"></span>
            <sub id="7ztzv"></sub>

            <span id="7ztzv"></span><form id="7ztzv"></form>

            <span id="7ztzv"></span>

                  <address id="7ztzv"></address>

                      亚洲欧美在线