關於 CVE-2024-0517
CVE-2024-0517 是 Google Chrome 120.0.6099.224 之前版本的 V8 JavaScript 引擎中的越界寫入漏洞,遠端攻擊者可透過製作的 HTML 頁面利用堆損毀。此漏洞最早由 Qrious保護 的 Toan (Suto) Pham 報告。
當應用程式使用一種類型分配或初始化指針、物件或變數等資源,但之後使用與原始類型不相容的類型存取該資源時,即會發生類型混淆(CWE-843)。在此 CVE 中,類型混淆是在稱為折疊式分配 (folded allocation) 的記憶體分配過程中觸發的,而 Maglev (V8 JavaScript 引擎的最佳化編譯器) 則採用此過程進行記憶體最佳化。
攻擊者可利用類型混淆,並透過 WebAssembly 寫入任意 shellcode,在受害者的機器上執行指令。
攻擊階段
攻擊者可以寄存一個包含精心製作的 HTML 頁面的網站,並誘騙使用者透過釣魚電子郵件或社交網路存取該網站。當使用者使用有漏洞版本的 Google Chrome 瀏覽器造訪網站時,內嵌的惡意程式碼就會執行任意指令。
V8 JavaScript 引擎
攻擊者可以寄存一個包含精心製作的 HTML 頁面的網站,並誘騙使用者透過釣魚電子郵件或社交網路存取該網站。當使用者使用有漏洞版本的 Google Chrome 瀏覽器造訪網站時,內嵌的惡意程式碼就會執行任意指令。
磁浮與折疊分配
Maglev 是 V8 中的優化編譯器,可增強程式碼執行和記憶體分配。Maglev 只會在程式碼經常執行並標示為 「熱 」時執行,這表示需要透過編譯加快執行速度,而不是逐行解釋較慢。
通常,分配發生在非連續的記憶體區域,導致記憶體使用稀疏且效率不高。為了解決這個問題,V8 採用了一種稱為折疊式分配的技術,可連續且同時分配多個變數。Maglev 也在其進程中使用折疊式分配來優化分配。
世代垃圾收集
為了清理未使用的記憶體區域,V8 採用了世代垃圾回收 (GC) 技術,將記憶體分成兩個空間:年輕世代和年老世代。此外,還有兩個垃圾回收器:次要垃圾回收器負責清理年輕空間,而主要垃圾回收器則處理舊空間的清理工作。新世代是新建立物件初始分配的記憶體區域,舊世代則是儲存長效物件的記憶體區域。在年輕一代中經過多次次要 GC 循環的物件,最後會升級到舊一代。
漏洞分析
概述
當從沒有明確定義構造器 (base default constructor) 的基類繼承類別建立物件,而隨後又建立另一個物件時,便會產生此漏洞。由於折疊分配的關係,第一個物件的分配可能會在第二個物件的分配之後。如果在這兩個分配之間發生垃圾回收等事件,就可能產生類型混淆漏洞。
根本原因分析
OPSWAT 研究生研究員對分配過程中的 V8 工作流程進行了詳細分析,並確定在此過程中會調用以下功能:
在這個過程中,TryBuildFindNonDefaultConstructorOrConstruct 函式發現了一個問題:BuildAllocateFastObject 函式延展 current_raw_allocation_(一個指向同時分配給多個變數的記憶體區域指針)來建構子類實例,但卻無法透過將其設定為 null 來清除它。
因此,下一個建立的物件總是緊接著 current_raw_allocation_ 指向的記憶體進行分配,不論在第二次分配之前有任何事件。
如果啟動 GC,則與 current_raw_allocation_ 相鄰的記憶體區域可以被指派給其他物件。這可能會導致一種情況:在觸發 GC 並建立另一個物件之後,兩個指標會引用相同的記憶體區域,但卻具有不同的資料類型,因而產生類型混淆漏洞。
開發
為了利用此漏洞,OPSWAT 研究員建立了包含 shellcode 的 WebAssembly 實體,並嘗試透過 GC 觸發類型混淆,以控制記憶體並執行 shellcode:
觸發器類型混淆
在初始化過程中,我們首先定義一個包含空物件的陣列 (_arrayObject)。接下來,我們會建構一個子類的實體以及一個觸發垃圾收集器。最後,我們定義另一個浮點數的陣列,命名為 _arrayDouble。
這些構造必須重複執行,使程式碼多次執行,導致 V8 將其標示為 「熱 」並觸發 Maglev 編譯器。我們透過在一個循環中呼叫子類的建構器來達成這個目的,如下所示:
在循環中重複初始化這些物件後,會觸發類型混淆。
建立讀寫基元
成功觸發類型混淆後,執行 shellcode 需要讀取記憶體,並覆寫受控位址的記憶體。為此,我們建立了讀取和寫入基元。開發基元會利用物件中的元資料,為我們提供任意讀/寫記憶體區域,並利用該區域執行任意程式碼。
此步驟中的讀取和寫入原素將使我們能夠在下一步中控制 WebAssembly 實例的跳轉表指針。
建立 WebAssembly Instances
接下來,我們建立兩個 WebAssembly 實體:一個用來儲存 shellcode,另一個用來觸發 shellcode。為了避免透過讀寫原語直接將 shellcode 寫入 WebAssembly 實體的記憶體中,我們在 WebAssembly 實體中定義了一些浮點常數值。
WebAssembly 實例的控制跳轉表指標
使用讀寫原語;我們調整第二個 WebAssembly 實例的跳轉表指標,跳過第一個 WebAssembly 實例中常數的編譯碼的一些位元組,這樣浮點常數就會被解釋成我們想要的 shellcode:
執行 WebAssembly Instance 以執行 Shellcode
最後,在觸發了類型混淆並使用讀/寫原素來控制 WebAssembly 實例的跳轉表指針之後,我們調用了第二個 WebAssembly 實例的匯出函式,使得第一個 WebAssembly 實例中的 shellcode 被執行。
我們使用的 shellcode 是為了終止 Linux 機器上的所有進程而設計的,如下所示:
由浮點數轉換而來的執行此指令的組合碼如下:
模擬安全漏洞
為了在真實情境中模擬這種攻擊,OPSWAT 的研究員製作了一個惡意製作的 HTML 頁面。
受害者會收到一封釣魚電子郵件,郵件中會嵌入一個連結,連結會指向寄存這個精心製作的 HTML 頁面的網域名稱。
如果受害者使用有漏洞版本的 Google Chrome 瀏覽器存取連結,shellcode 即會執行,導致所有程序終止。結果,使用者會登出,如下圖所示:
修復
MetaDefender Endpoint™ 利用其「脆弱應用程式」功能,主動減緩此 CVE。此解決方案可有效地找出並顯示端點環境中 Google Chrome 應用程式的所有相關 CVE。若要解除威脅,使用者可立即卸載 Chrome 或套用最新的安全修補程式。只要執行其中一種對策,CVE 即會完全受到控制,大幅降低端點遭受成功網路攻擊的風險。
引用
https://nvd.nist.gov/vuln/detail/CVE-2024-0517
https://cwe.mitre.org/data/definitions/843.html
https://blog.exodusintel.com/2024/01/19/google-chrome-v8-cve-2024-0517-out-of-bounds-write-code-execution/
https://jhalon.github.io/chrome-browser-exploitation-1/
https://whenderson.dev/blog/webgl-garbage-collection/
https://v8.dev/
https://github.com/Uniguri/CVE-nday/tree/master/Chrome/V8/CVE-2024-0517