怎么淺析CVE-2021-1647的漏洞利用技巧

蝸牛 互聯網技術資訊 2021-12-18 221 0

這期內容當中小編將會給大家帶來有關怎么淺析CVE-2021-1647的漏洞利用技巧,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。

概要

近期爆出的 CVE-2021-1647 是 Windows Defender MpEngine 模塊中的一處 rce 漏洞,下面旨在從漏洞利用層面對相關樣本所使用的技巧進行分析,筆者使用的樣本哈希為:6e1e9fa0334d8f1f5d0e3a160ba65441f0656d1f1c99f8a9f1ae4b1b1bf7d788。

漏洞原理

Windows Defender 采用模擬執行的策略,對可執行文件進行黑白判定,模擬執行分為以下兩個層面:指令模擬和運行環境模擬。指令模擬部分負責將相應平臺指令(包括 arm/x86/x64 等)轉為中間指令(IL),然后通過 jit/ 解釋執行的方式運行相應的中間指令;運行環境模擬則包括內存系統模擬/文件系統模擬/api 模擬/DLL 模擬(與 MpEngine.dll 同目錄的 vdm 文件是 dll 模擬文件的壓縮集/合),在指令模擬執行的過程中,碰到壓縮殼的情況,defender 也會模擬解壓過程(詳見 UnpackerContext::Unpack 函數),當前 defender 支持的壓縮方式有:Upxw64/Upxw/WExtract/NSPacker/Shrinker/PECompact2/Area51/Crypter1337/Aspack/PKLite/SfxCab/Asprotect 等。本次漏洞出現在 Asprotect 模擬解壓過程中(CAsprotectDLLAndVersion::RetrieveVersionInfoAndCreateObjects 函數):

怎么淺析CVE-2021-1647的漏洞利用技巧  第1張

上圖中,v2+28 代表一個 section 數組的開始,該數組包含四個元素,每個 section 元素 8 字節,前 4 字節用于描述該 section 的虛擬地址,后四個字節用于描述該 section 的大小,上圖描述的是這樣一個過程:遍歷一個包含 4 項的 section 數組,最后獲得一個 sectionva 和 sectionsize,申請一片大小為 sectionva+sectionsize 的內存用于存儲解壓后的 section 內容,但其在計算 sectionva 和 sectionsize 時存在錯誤,代碼中只考慮了 section[i+1].va>section[i].va 的情況,但并沒有考慮兩者相等的情況,倘若 section 數組中四個元素的值如下:[0,0],[0,0],[0x2000,0],[0x2000,0x3000],按照上述代碼的邏輯最終 sectionva=0x2000,sectionsize=0,那最終申請的內存大小為 0x2000+0=0x2000,因此在解壓最后一個 section 時,由于其大小為 0x3000,這樣便會產生堆溢出問題,這便是本漏洞的產生根源。

利用技巧

1. 確定版本偏移

在樣本開頭處調用了如下函數:

怎么淺析CVE-2021-1647的漏洞利用技巧  第2張

在剛開始分析該樣本時,筆者以為該處地址是 defender 中某個未開啟 ASLR 模塊的地址或是類似于利用異常處理進行反調試的措施,但其實這時筆者犯了一個巨大的錯誤,要明確的一點是,當樣本在被 defender 模擬執行時,一切內存地址并不是真實的 host 上的地址,而是 defender 模擬內存空間中的一個地址,也就是說 0x7c96c654 其實是 defender 模擬內存空間中的一段地址,該地址其實對應于模擬 dll 模塊 --ntdll.dll(模擬的 ntdll.dll 可以通過解壓與 mpengine.dll 同目錄的 mpasbase.vdm 獲得)中的一段代碼:

怎么淺析CVE-2021-1647的漏洞利用技巧  第3張

注意看函數最后兩個字節:0xf 0xff,這兩個字節說明這是一個 native api 調用,其后的四個字節 0x9E9EFDF0 是用于標識最終 native api 函數的一個 crc 校驗碼,所謂的 native api 即是有 mpengine.dll 提供的一系列功能 api,最終該函數會由 mpengine!NTDLL_DLL_NtControlChannel 實現,也就是說樣本中 call 7C96C654 其實最終是調用 mpengine!NTDLL_DLL_NtControlChannel 完成功能,該函數第一個參數代表功能號,樣本中的 3 代表的是獲取 defender 版本信息,樣本就是通過該函數獲取版本信息,然后根據不同的版本信息硬編碼關鍵偏移。

2. 內存占位/修改關鍵字段

在樣本中包含了大量的 SuspendThread 和 ResumeThread 的調用代碼,這部分代碼其實是用來進行內存布局和占位的,在堆溢出發生后,會修改布局在堆內存后的 lfind 對象,lfind 對象中的兩個關鍵字段分別被修改為 2f9b 和 2f9c(原始值為 107e 和 107f),這兩個字段在 lfind_switch::switch_in(在模擬執行 ResumeThread 函數時會觸發該函數調用)函數中被引用:

怎么淺析CVE-2021-1647的漏洞利用技巧  第4張

上圖中的 v20 即是會被引用的 2f9b 和 2f9c,很明顯由于被修改之后的值比正常的大,這會造成一個越界寫的行為,上圖中的 *(v20+*(v16+144))|=3 是漏洞利用過程的關鍵,該部分代碼修改的是 vmmcontrol 中的一個關鍵字段,我們將在第三部分說明這個字段的用途。

3. 獲取任意讀寫能力

在 defender 進行內存空間模擬的過程中涉及到這樣幾個比較重要的結構:

怎么淺析CVE-2021-1647的漏洞利用技巧  第5張

該結構用于維持模擬內存地址和真實內存地址之間的映射關系,該結構在內存中以數組的形式存在。

為了實現高效的地址轉換,defender 還引入了一個索引數組(每個索引用 2 字節存儲),該數組中存儲的是 EmuVaddrNode 結構數組的索引,并且是按照 EmuPagenum 從小到大進行排序的,也就是說假設此時 EmuVaddrNode 數組中包含三個元素,且三個元素的 EmuPageNum 字段內容為 0x2000,0x1000,0x5000,那么正常情況下此時索引數組內容為1,0,3(1、0、3 都代表 EmuVaddrNode 數組的索引),并且 EmuVaddrNode 數組和索引數組在真實內存中的布局如下(假設從左到右代表地址從低到高):

怎么淺析CVE-2021-1647的漏洞利用技巧  第6張

也就是說,索引數組后頭就是 EmuVaddrNode 數組,EmuVaddrNode 數組緊跟著的是 Page,Page 代表的是 defender 申請的用于映射模擬內存空間的真實內存,即 EmuVaddrNode 中的 Vaddr 都是從 page 中切割出來的。

最后,我們回顧一下第二部分中提到的修改了 vmmcontrol 中的關鍵字段,這個關鍵字段描述的是索引數組一共有多少個元素。如果我們將該數值改的盡可能的大,使得索引數組的起始地址+索引數組數目*2>Page 地址,而 Page 中的內容是我們可控的,我們通過讓 defender 模擬執行 *p=value 的方式,就能在 Page 中布置我們想要的內容。首先,我們在 Page 中偽造索引數組,并且該索引遠大于 EmuVaddrNode 數組的項數,那么當 defender 模擬執行 *p=value 這類指令時,先是從我們在 Page 中偽造的索引數組中取到一個偽造的索引(該索引遠大于 EmuVaddrNode 數組的項數);接著,我們在 Page 中繼續偽造一個 EmuVaddrNode 結構,那么 defender 通過偽造的索引便會訪問到我們在 Page 中偽造的 EmuVaddrNode 結構,這時 EmuVaddrNode 結構的 Vaddr 是我們可控的,那么我們便獲得了任意地址讀寫能力,“寫”通過讓 defender 模擬執行 *p=value 來實現,“讀”通過讓 dfender 模擬執行 value=*p 來實現。有瀏覽器或者內核漏洞相關經驗的同事應該很熟悉這種場景,通過修改長度字段來偽造對象及其 pointer 字段最終獲得任意地址讀寫的能力。

4. 獲取代碼執行能力

在 defender 中會將常用的代碼片段進行 jit 處理,通常 jit 內存中存放的是 prolog 和 epilog 片段,在取得任意地址讀寫能力后,樣本中先將通過硬編碼偏移獲取到了 jit 部分的真實地址,將某個 EmuVaddrNode 的 vaddr 設置為 jit 的真實地址,并且利用模擬執行 memcpy(EmuPageNum,shellcode, sizeof (shellocde))向 jit 地址寫入了 shellcode,最終只要 jit 功能一使用便會執行 shellcode。

檢測原理

由于樣本是在 defender 模擬執行的過程中觸發的漏洞,那么,如果我們僅僅簡單取樣本中的幾個特征字串作為匹配規則,顯然是十分容易被繞過的。筆者建議可以綜合以下幾方面信息作為特征:

1. asprotect 殼的特征

怎么淺析CVE-2021-1647的漏洞利用技巧  第7張

2. 上圖所示內容是 MpEngine 中對解壓后的內容做的一個校驗,只有滿足條件才會觸發堆溢出操作,因此可以對類似于 ”*(memory)=0x8d; *(memory+1)=0x85;? *(memory+6)=0x50; *(memory+7)=0xc3” 的賦值操作進行特征匹配。

3. 樣本通過 NtControlChannel 獲得版本信息以確定偏移信息,因此可以把 NtControlChannel 函數的調用特征作為匹配依據。

4. 樣本中其他為了實現穩定的內存布局而進行的模擬調用的特征。

上述就是小編為大家分享的怎么淺析CVE-2021-1647的漏洞利用技巧了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注蝸牛博客行業資訊頻道。

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:niceseo99@gmail.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

評論

日本韩欧美一级A片在线观看