<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/7816

                    Black Hat USA 2015正在進行,在微軟安全響應中心公布的最新貢獻榜單中,綠盟科技安全研究員張云海位列第6位,綠盟科技安全團隊(NSFST)位列28位,綠盟科技安全團隊(NSFST)常年致力于發現并解決計算機以及網絡系統中存在的各種安全缺陷。這篇《Windows 10執行流保護繞過問題及修復》是團隊在此次大會上分享的主要內容

                    0x00 Content


                    0x01 內容摘要


                    Black Hat USA 2015正在進行,在微軟安全響應中心公布的最新貢獻榜單中,綠盟科技安全研究員張云海位列第6位,綠盟科技安全團隊(NSFST)位列28位,綠盟科技安全團隊(NSFST)常年致力于發現并解決計算機以及網絡系統中存在的各種安全缺陷。這篇《Windows 10執行流保護繞過問題及修復》是團隊在此次大會上分享的主要內容。

                    1. 1月22日,微軟發布Windows 10技術預覽版,Build號9926;
                    2. 2月,綠盟科技安全團隊(NSFST)展開對其安全機制的研究,發現并與微軟一起解決了CFG繞過問題;
                    3. 3月,微軟發布補丁修復了CFG繞過問題;
                    4. 7月21日,在綠盟科技Techworld技術大會上分享了此次研究成果;
                    5. 8月7日,在Black Hat US 2015上進行演講并發布分析文章。
                    

                    綠盟科技安全團隊NSFST一直努力發現及修復計算機以及網絡系統中存在的各種安全缺陷,如果您需要了解更多信息,請聯系:

                    0x02 執行流保護(CFG)


                    攻擊者常常溢出覆蓋或者直接篡改寄存器EIP的值,篡改間接調用的地址,進而控制了程序的執行流程。執行流保護(CFG,Control Flow Guard)是微軟從Windows 8.1 update 3及Windows 10技術預覽版開始,默認啟用的一項緩解技術。這項技術通過在間接跳轉前插入校驗代碼,檢查目標地址的有效性,進而可以阻止執行流跳轉到預期之外的地點,最終及時并有效的進行異常處理,避免引發相關的安全問題。

                    這種思想及技術在業界有了較為成熟的應用,此次Windows 10將其引入,以便提高其安全性。但是綠盟科技安全團隊(NSFST)在分析CFG的實現機制過程中,發現了CFG存在全面繞過的方法,隨即向微軟提報,并在隨后的一段時間內,配合微軟修復了這個問題。

                    0x03 CFG原理


                    在編譯啟用了CFG的模塊時,編譯器會分析出該模塊中所有間接函數調用可達的目標地址,并將這一信息保存在Guard CF Function Table中。

                    :006> dds jscript9!\_load\_config\_used + 48 l5
                    62b21048 62f043fc jscript9!\_\_guard\_check\_icall\_fptr Guard CF Check Function Pointer
                    62b2104c 00000000 Reserved
                    62b21050 62b2105c jscript9!\_\_guard\_fids\_table Guard CF Function Table
                    62b21054 00001d54 Guard CF Function Count
                    62b21058 00003500 Guard Flags
                    

                    同時,編譯器還會在所有間接函數調用之前插入一段校驗代碼,以確保調用的目標地址是預期中的地址。這是未啟用CFG的情況:

                    jscript9!Js::JavascriptOperators::HasItem+0x15:
                    66ee9558 8b03 mov eax,dword ptr [ebx]
                    66ee955a 8bcb mov ecx,ebx
                    66ee955c 56 push esi
                    66ee955d ff507c call dword ptr [eax+7Ch]
                    66ee9560 85c0 test eax,eax
                    66ee9562 750b jne jscript9!Js::JavascriptOperators::HasItem+0x2c (66ee956f)
                    

                    這是啟用CFG的情況:

                    ript9!Js::JavascriptOperators::HasItem+0x1b:
                    62c31e13 8b03 mov eax,dword ptr [ebx]
                    62c31e15 8bfc mov edi,esp
                    62c31e17 52 push edx
                    62c31e18 8b707c mov esi,dword ptr [eax+7Ch]
                    62c31e1b 8bce mov ecx,esi
                    62c31e1d ff15fc43f062 call dword ptr [jscript9!\_\_guard\_check\_icall\_fptr (62f043fc)]
                    62c31e23 8bcb mov ecx,ebx
                    62c31e25 ffd6 call esi
                    62c31e27 3bfc cmp edi,esp
                    62c31e29 0f8514400c00 jne jscript9!Js::JavascriptOperators::HasItem+0x33 (62cf5e43)
                    

                    操作系統在創建支持CFG的進程時,將CFG Bitmap映射到其地址空間中,并將其基址保存在ntdll!LdrSystemDllInitBlock+0x60中。

                    CFG Bitmap是記錄了所有有效的間接函數調用目標地址的位圖,出于效率方面的考慮,平均每1位對應8個地址(偶數位對應1個0x10對齊的地址,奇數位對應剩下的15個非0x10對齊的地址)。

                    提取目標地址對應位的過程如下: * 取目標地址的高24位作為索引i; * 將CFG Bitmap當作32位整數的數組,用索引i取出一個32位整數bits; * 取目標地址的第4至8位作為偏移量n; * 如果目標地址不是0x10對齊的,則設置n的最低位; * 取32位整數bits的第n位即為目標地址的對應位。

                    操作系統在加載支持CFG的模塊時,根據其Guard CF Function Table來更新CFG Bitmap中該模塊所對應的位。同時,將函數指針\_guard\_check\_icall\_fptr初始化為指向ntdll!LdrpValidateUserCallTarget

                    ntdll!LdrpValidateUserCallTarget從CFG Bitmap中取出目標地址所對應的位,根據該位是否設置來判斷目標地址是否有效。若目標地址有效,則該函數返回進而執行間接函數調用;否則,該函數將拋出異常而終止當前進程。

                    ll!LdrpValidateUserCallTarget:
                    774bd970 8b1570e15377 mov edx,dword ptr [ntdll!LdrSystemDllInitBlock+0x60 (7753e170)]
                    774bd976 8bc1 mov eax,ecx
                    774bd978 c1e808 shr eax,8
                    774bd97b 8b1482 mov edx,dword ptr [edx+eax\*4]
                    774bd97e 8bc1 mov eax,ecx
                    774bd980 c1e803 shr eax,3
                    774bd983 f6c10f test cl,0Fh
                    774bd986 7506 jne ntdll!LdrpValidateUserCallTargetBitMapRet+0x1 (774bd98e)
                    ntdll!LdrpValidateUserCallTargetBitMapCheck+0xd:
                    774bd988 0fa3c2 bt edx,eax
                    774bd98b 730a jae ntdll!LdrpValidateUserCallTargetBitMapRet+0xa (774bd997)
                    ntdll!LdrpValidateUserCallTargetBitMapRet:
                    774bd98d c3 ret
                    ntdll!LdrpValidateUserCallTargetBitMapRet+0x1:
                    774bd98e 83c801 or eax,1
                    774bd991 0fa3c2 bt edx,eax
                    774bd994 7301 jae ntdll!LdrpValidateUserCallTargetBitMapRet+0xa (774bd997)
                    ntdll!LdrpValidateUserCallTargetBitMapRet+0x9:
                    774bd996 c3 ret
                    

                    0x04 繞過問題


                    通過上面的原理分析,我們發現CFG的實現中存在一個隱患,校驗函數ntdll!LdrpValidateUserCallTarget是通過函數指針\_guard\_check\_icall\_fptr來調用的。

                    如果我們修改\_guard\_check\_icall\_fptr,將其指向一個合適的函數,就可以使任意目標地址通過校驗,從而全面的繞過CFG。通常情況下,\_guard\_check\_icall\_fptr是只讀的:

                    06> x jscript9!___guard_check_icall_fptr
                    62f043fc          jscript9!__guard_check_icall_fptr = <no type information>
                    0:006> !address 62f043fc
                    Usage:                  Image
                    Base Address:           62f04000
                    End Address:            62f06000
                    Region Size:            00002000
                    State:                  00001000    MEM_COMMIT
                    Protect:                00000002    PAGE_READONLY
                    Type:                   01000000    MEM_IMAGE
                    Allocation Base:        62b20000
                    Allocation Protect:     00000080    (null)
                    Image Path:             C:\Windows\System32\jscript9.dll
                    Module Name:            jscript9
                    Loaded Image Name:      C:\Windows\System32\jscript9.dll
                    Mapped Image Name:
                    

                    但如果利用jscript9中的CustomHeap::Heap對象將其變成可讀寫的,那么就會出現問題了。

                    0x05 CustomHeap::Heap對象


                    CustomHeap::Heap是jscript9中用于管理私有堆的類,其結構如下:

                    stomHeap::Heap
                    +0x000  HeapPageAllocator           :    PageAllocator
                    +0x060  HeapArenaAllocator          :    Ptr32 ArenaAllocator
                    +0x064  PartialPageBuckets          :    [7] DListBase<CustomHeap::Page>
                    +0x09c  FullPageBuckets             :    [7] DListBase<CustomHeap::Page> 
                    +0x0d4  LargeObjects                :    DListBase<CustomHeap::Page>
                    +0x0dc  DecommittedBuckets          :    DListBase<CustomHeap::Page>
                    +0x0e4  DecommittedLargeObjects     :    DListBase<CustomHeap::Page>
                    +0x0ec  CriticalSection             :    LPCRITICAL_SECTION
                    

                    CustomHeap::Heap對象析構時,其析構函數會調用CustomHeap::Heap::FreeAll來釋放所有分配的內存。

                     __thiscall CustomHeap::Heap::~Heap(CustomHeap::Heap *this)
                    {
                      CustomHeap::Heap *v1; // [email protected]
                      v1 = this;
                      CustomHeap::Heap::FreeAll(this);
                      DeleteCriticalSection((LPCRITICAL_SECTION)((char *)v1 + 0xEC));
                      \'eh vector destructor iterator\'((int)((char *)v1 + 0x9C), 8u, 7, sub_10010390);
                      \'eh vector destructor iterator\'((int)((char *)v1 + 0x64), 8u, 7, sub_10010390);
                      return PageAllocator::~PageAllocator(v1);
                    }
                    

                    CustomHeap::Heap::FreeAll 為每個Bucket對象調用CustomHeap::Heap::FreeBucket

                    d __thiscall CustomHeap::Heap::FreeAll(CustomHeap::Heap *this)
                    {
                      CustomHeap::Heap *v1; // [email protected]
                      signed int v2; // [email protected]
                      int v3; // [email protected]
                      int v4; // [email protected]
                      v1 = this;
                      v2 = 7;
                      v3 = (int)((char *)this + 0x9C);
                      do
                      {
                        CustomHeap::Heap::FreeBucket(v1, v3 - 0x38, (int)this);
                        CustomHeap::Heap::FreeBucket(v1, v3, v4);
                        v3 += 8;
                        --v2;
                      }
                      while ( v2 );
                      CustomHeap::Heap::FreeLargeObject<1>(this);
                      CustomHeap::Heap::FreeDecommittedBuckets(v1);
                      CustomHeap::Heap::FreeDecommittedLargeObjects(v1);
                    }
                    

                    CustomHeap::Heap::FreeBucket 遍歷Bucket的雙向鏈表,為每個節點的CustomHeap::Page 對象調用CustomHeap::Heap::EnsurePageReadWrite<1,4>

                     __thiscall CustomHeap::Heap::FreeBucket(PageAllocator *this, int a2, int a3)
                    {
                      PageAllocator *v3; // [email protected]
                      int result; // [email protected]
                      int v5; // [email protected]
                      int v6; // [sp+8h] [bp-8h]@1
                      int v7; // [sp+Ch] [bp-4h]@1
                      v3 = this;
                      v6 = a2;
                      v7 = a2;
                      while ( 1 )
                      {
                        result = SListBase<Bucket<AddPropertyCacheBucket>,FakeCount>::Iterator::Next(&v6);
                        if ( !(_BYTE)result )
                          break;
                        v5 = v7 + 8;
                        CustomHeap::Heap::EnsurePageReadWrite<1,4>(v7 + 8);
                        PageAllocator::ReleasePages(v3, *(void **)(v5 + 0xc), 1u, *(struct PageSegment **)(v5 + 4));
                        DListBase<CustomHeap::Page>::EditingIterator::RemoveCurrent<ArenaAllocator>(*((ArenaAllocator **)v3 + 0x18));
                      }
                      return result;
                    }
                    

                    CustomHeap::Heap::EnsurePageReadWrite<1,4> 用以下參數調用VirtualProtect:

                    將內存頁面標記為PAGE_READWRITE, 這正是出現問題的關鍵地方。

                    0x06 繞過CFG


                    通過修改CustomHeap::Heap對象,我們可以將一個只讀頁面變成可讀寫的,從而可以改寫函數指針\_guard\_check\_icall\_fptr的值。觀察ntdll!LdrpValidateUserCallTarget在目標地址有效時執行的指令:

                    mov     eax,ecx
                    shr     eax,8
                    mov     edx,dword ptr [edx+eax*4]
                    mov     eax,ecx
                    shr     eax,3
                    test    cl,0Fh
                    jne     ntdll!LdrpValidateUserCallTargetBitMapRet+0x1 (774bd98e)
                    bt      edx,eax
                    jae     ntdll!LdrpValidateUserCallTargetBitMapRet+0xa (774bd997)
                    ret
                    

                    從調用者的角度來看,上述指令與單條ret指令之間并沒有本質區別。因此,將函數指針\_guard\_check\_icall\_fptr改寫為指向ret指令,就可以使任意的目標地址通過校驗,從而全面的繞過CFG。

                    0x07 問題修復


                    綠盟科技安全團隊(NSFST)發現這一問題后,立即向微軟報告了相關情況。微軟很快修復了這一問題,并在2015年3月發布了相關的補丁。在該補丁中,微軟引入了一個新的函數HeapPageAllocator::ProtectPages

                    0x08 HeapPageAllocator::ProtectPages函數


                     __thiscall HeapPageAllocator::ProtectPages(HeapPageAllocator *this, LPCVOID lpAddress, unsigned int a3, struct Segment *a4, DWORD flNewProtect, unsigned __int32 *a6, unsigned __int32 a7)
                    {
                      unsigned __int32 v7; // [email protected]
                      unsigned int v8; // [email protected]
                      int result; // [email protected]
                      struct _MEMORY_BASIC_INFORMATION Buffer; // [sp+Ch] [bp-20h]@4
                      DWORD flOldProtect; // [sp+28h] [bp-4h]@7
                      v7 = (unsigned __int32)this;
                      if ( (unsigned __int16)lpAddress & 0xFFF
                        || (v8 = *((_DWORD *)a4 + 2), (unsigned int)lpAddress < v8)
                        || (unsigned int)((char *)lpAddress - v8) > (*((_DWORD *)a4 + 3) - a3) << 12
                        || !VirtualQuery(lpAddress, &Buffer, 0x1Cu)
                        || Buffer.RegionSize < a3 << 12
                        || a7 != Buffer.Protect )
                      {
                        CustomHeap_BadPageState_fatal_error(v7);
                        result = 0;
                      }
                      else
                      {
                        *a6 = Buffer.Protect;
                        result = VirtualProtect((LPVOID)lpAddress, a3 << 12, flNewProtect, &flOldProtect);
                      }
                      return result;
                    }
                    

                    這個函數是VirtualProtect的一個封裝,在調用VirtualProtect之前對參數進行校驗,如下:

                    任何一個檢查項未通過,都會調用CustomHeap_BadPageState_fatal_error拋出異常而終止進程。

                    0x09 修復機制


                    CustomHeap::Heap::EnsurePageReadWrite<1,4>改為調用HeapPageAllocator::ProtectPages而不再直接調用VirtualProtect。

                    1  unsigned __int32 __thiscall CustomHeap::Heap::EnsurePageReadWrite<1,4>(HeapPageAllocator *this, int a2)
                    2  {
                    3    unsigned __int32 result; // [email protected]
                    4    unsigned __int32 v3; // [sp+4h] [bp-4h]@5
                    5  
                    6    if ( *(_BYTE *)(a2 + 1) || *(_BYTE *)a2 )
                    7    {
                    8      result = 0;
                    9    }
                    10    else
                    11    {
                    12      v3 = 0;
                    13      HeapPageAllocator::ProtectPages(this, *(LPCVOID *)(a2 + 12), 1u, *(struct Segment **)(a2 + 4), 4u, &v3, 0x10u);
                    14      result = v3;
                    15      *(_BYTE *)(a2 + 1) = 1;
                    16    }
                    17    return result;
                    18  }
                    

                    這里參數中指定的訪問權限是PAGE_EXECUTE,從而防止了利用CustomHeap::Heap將只讀內存頁面變成可讀寫內存頁面。

                    0x10 參考文獻


                    1 MJ0011. Windows 10 Control Flow Guard Internals

                    http://www.powerofcommunity.net/poc2014/mj0011.pdf

                    [2] Jack Tang. Exploring Control Flow Guard in Windows 10

                    http://sjc1-te-ftp.trendmicro.com/assets/wp/exploring-control-flow-guard-in-windows10.pdf

                    [3] Francisco Falcón. Exploiting CVE-2015-0311, Part II: Bypassing Control Flow Guard on Windows 8.1 Update 3

                    https://blog.coresecurity.com/2015/03/25/exploiting-cve-2015-0311-part-ii-bypassing-control-flow-guard-on-windows-8-1-update-3/

                    [4] Yuki Chen. The Birth of a Complete IE11 Exploit under the New Exploit Mitigations

                    https://www.syscan.org/index.php/download/get/aef11ba81927bf9aa02530bab85e303a/SyScan15%20Yuki%20Chen%20-%20The%20Birth%20of%20a%20Complete%20IE11%20Exploit%20Under%20the%20New%20Exploit%20Mitigations.pdf

                      <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>

                                      这里只有精品视频