IE遠程代碼執行漏洞(CVE-2020-0674)分析

發布時間 2020-03-09

2020年1月17日,微軟發布了針對IE遠程代碼執行漏洞(CVE-2020-0674)的Security Advisory(ADV200001),并指出該0day漏洞已經被運用于針對性攻擊。目前,微軟已經發布相關補丁進行修復。


該漏洞影響組件為jscript.dll,該動態鏈接庫是微軟Internet Explorer瀏覽器的Javascript引擎之一,其中IE8及以下使用jscript.dll,IE9及以上默認使用jscript9.dll,但網頁可以通過<script>標簽指定在IE8兼容性模式下加載jscript.dll,因此IE9、IE10、IE11都受到此漏洞影響。從操作系統范圍來看,本漏洞影響范圍橫跨Windows 7至Windows 10中所有的個人操作系統和服務器操作系統。


該漏洞是一個Use-After-Free漏洞,攻擊樣本使用UAF達成類型混淆,進而獲取全局內存讀寫能力并繞過ASLR等漏洞利用緩解技術,并從指定ip地址請求下一步攻擊載荷,最終達到遠程代碼執行。


啟明星辰ADLab安全研究員根據反病毒廠商捕獲到的樣本對此漏洞進行了分析,發現漏洞CVE-2020-0674其實與CVE-2019-1429從漏洞原理上是同一個漏洞,但觸發漏洞的樣本截然不同,兩次推出的補丁也不完全相同。


應對措施


使用Windows更新和補丁修復此漏洞。

禁用jscript.dll,Security Advisory(ADV200001)中已經給出:



漏洞和補丁分析


PART1


在開啟頁堆的IE瀏覽器中調試,崩潰現場如下:



根據?;厮菘梢詫絟tml樣本的typeof調用。在樣本中,經過復雜的引用操作,在arr3中,前一部分元素應該為undefined,后一部分元素應為RegExp對象,但使用typeof訪問某元素時報錯為“已釋放的頁堆空間”,可以看出這是一個由垃圾回收機制引起的問題。在用戶默認設置下,即未開啟頁堆時,arr3中的某一個元素i會導致arr3[i]) === "number"成立,此時即引發類型混淆。


IE jscript的垃圾回收(Garbage Collect, GC)基于Mark-Sweep算法,即從定義為“根”的數據結構開始,尋找其所有引用到的對象標記為正在使用,而沒有在標記的對象被當作不再使用,其內存空間將在垃圾回收過程中被釋放。因此從崩潰現場看,本漏洞的成因是Mark-Sweep的標記過程出現了問題,也就是對象之間的引用出現了問題。


補丁分析的結論支持了上述猜測。安裝補丁后,對新舊jscript.dll進行bin diff,可以看到垃圾回收算法在多個對象的標記過程(Scavenge)著重處理了一個值為0x400C的特殊情況,以NameList對象為例:



根據逆向分析和文檔,這個枚舉類型的值是VARIANT->VarType域。其中,0x400C代表該對象是一個指針類型的對象,指向另一個VARIANT,其指針域位于offset 8的位置,也即*((_DOWORD *)i + 2)??梢钥吹?,此處的修補是取出指針值,傳遞給VAR::Scavenge函數。而VAR::Scavenge再次對0x400C的枚舉型變量添加了特殊處理:



VAR::Scavenge函數對傳入對象迭代地解引用,直到獲得非指針的對象,也即若干層指針的最終指向,將其傳入GcContext::ScavengeVar。GcContext::ScavengeVar函數邏輯較為簡單,該函數通過與0xF7FF的與操作對傳入對象進行標記,該與操作是將第12位清零。


經過測試,CVE-2019-1429與CVE-2020-0674的樣本在各個“未修復”和“已修復”版本中表現完全一致。其UAF的對象的標記過程確實經由NameList::ScavengeCore,在CVE-2019-1429中是Array索引的Object對象,在CVE-2020-0674中是Array索引的RegExp對象,NameList::ScavengeCore決定了其是否被標記。


因此對于本漏洞的成因得出結論:在Mark-Sweep標記算法中,遇到指針類型的對象時應該解引用并標記對應對象;本例中,缺乏解引用的過程導致了漏洞的產生。


PART2


進一步分析可以發現,針對CVE-2019-1429和CVE-2020-0674微軟先后推出了兩個patch,以Windows 10 Version 1903 for 32-bit Systems為例,分別是KB4524570和KB4532693,但最終都升級到后者:



KB4524570和KB4532693都包含了對上述漏洞核心原理的修復,其中前者對jscript.dll有較大改動,而后者改動則簡潔很多。KB4532693還包含另一個改進,使用“冗余容災”的思路提供了另一處加強;此處加強位于Javascript引擎中call和dispatch的基礎設施中,而不是對各種對象逐個補救。


KB4532693對jscript.dll中的ScrFncObj::Call函數進行了重新組織,對于CallWithFrameOnStack和CallWithFrameOnHeap(自定義名稱)這兩種情況,用ScrFncObj::PerformCall統一。在ScrFncObj::PerformCall中,把調用使用的函數參數加入垃圾回收的“根”中:



經過驗證,在PerformCall的加固下,即使NameList等對象出現問題,在函數調用中作為參數的對象仍然被正確標記,不會觸發漏洞。因而雖然兩個補丁都可以完全抵御兩個CVE的exploit,仍可以認為KB4532693是比KB4524570稍微高明一點的修補。



PART3


除此之外,兩個補丁雖然能夠在默認配置下抵御上述漏洞,對應jscript.dll仍然有一個稱為LegacyGC的兼容項,已修補代碼中仍然根據GcContext::IsLegacyGCEnabled()的函數查詢結果來判斷檢查是否介入。根據逆向分析可知,該函數查詢一個注冊表項:

HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Policies\ee1ca8aa-4402-4da1-bbe2-69a09c483a56

在此項為1時意為“兼容使用老的GC機制”,將使KB4532693中的加強失效,對于KB4524570則會完全失效。因此該注冊表項的內容也涉及IE瀏覽器的安全性,需要予以注意。


參考鏈接:

1.https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/ADV200001

2.https://portal.msrc.microsoft.com/en-US/security-guidance/advisory/CVE-2019-1429

3.https://www.virustotal.com