作者:啟明星辰ADLab
原文鏈接:https://mp.weixin.qq.com/s/xy4SA9MDe5cPchoc8TJQ0w
1.背景
2023年9月7日,Citizen Lab [1]宣布早在一周前,他們發現工作在華盛頓一國際辦事處機構員工的設備上存在活躍的iMessage 0-click攻擊,該利用通過發送包含惡意圖片的Apple PassKit部署著名軍火商NSO 研發的Pegasus 間諜軟件。漏洞利用鏈由于可以繞過BlastDoor的沙箱,因此被稱之為BLASTPASS。當天Apple 發布了兩條漏洞的修復公告[2]。其中漏洞CVE-2023-41061存在于Apple Wallet中,惡意構造的附件可使得任意代碼執行。另一漏洞CVE-2023-41064存在于ImageIO中,當解析惡意的圖片可導致任意代碼執行。這兩個漏洞在iOS 16.6.1 和iPadOS 16.6.1 中修復。截止目前,漏洞細節并未公開。
Apple ImageIO框架中包含了對WebP數據的支持,9月6日Apple安全團隊向Google報告了WebP安全漏洞(CVE-2023-4863)。9月11日,Google緊急發布一則關于WebP的安全修復[3],并指出Google已經意識到該漏洞存在在野利用。該漏洞極有可能就是BLASTPASS攻擊中使用的漏洞。據不完全統計,WebP組件的下游軟件可能超過百萬款,或將使其成為下一個Log4Shell漏洞,建議使用WebP組件的廠商及時更新到最新版。本文主要對漏洞CVE-2023-4863進行分析復現。
2.漏洞分析
使用address sanitizer選項編譯WebP代碼(7ba44f80f3b94fc),當加載惡意圖片時,程序在解析WebP圖片時因堆溢出崩潰:

WebP容器文件格式基于RIFF(Resource Interchage File Format)文件格式,支持無損壓縮(VP8L)。基本的文件格式由WebP頭(綠色部分)和VP8L(藍色部分)塊組成。文件頭由RIFF標識、文件大小以及容器名WEBP文件標識組成,VP8L塊包括VP8L標識以及其數據部分(bitsream)[5]:

結合poc構造,可以看到VP8L的數據流頭部包含特征(0x2f)、width、height、has_alpha(false)、version等信息。

在函數DecodeImageStream中,將transform(line1426)和 color cache(line1432)設置為0,并且在函數ReadHuffmanCodes中繞過if判斷(line381),以便于直接進入哈夫曼編碼的解析(ReadHuffmanCodes):


哈夫曼編碼是一類帶權路徑長度(WPL)最短的樹,是一種傳輸效率最高的二進制編碼。在實現中使用表代替樹。其核心思想是使用變長編碼表對源符號進行編碼,出現頻率高的符號使用較短的編碼,出現頻率低的符號使用較長的編碼,這使得字符串的平均長度、期望值降低[4]。
在poc中,對(1-15)進行哈夫曼編碼,每個值出現的情況使用二維數組(code_lengths_counts)統計,創建5個哈夫曼編碼,每個哈夫曼編碼使用的符號集大小分別為{280, 256, 256, 256, 40}:

在創建哈夫曼樹的過程中,先按照使用頻次對節點排序,然后調用函數calculate_code_lengths計算每個節點編碼長度(code_lengths):

在函數ConvertBitDepthsToSymbols中,根據獲得編碼長度(code_lengths)和編碼深度計數(depth_count)計算出每個節點的key值(存儲在codes):

就第一個哈夫曼編碼計算出的每個節點的編碼長度以及每個節點的key值如下:


在ReadHuffmanCodes函數中開始了哈夫曼編碼解析之旅,前述的5個哈夫曼編碼將存儲到表中,這里簡稱哈夫曼表(huffman_tables )。在ReadHuffmanCodes函數中首先確定表的大小(table_size),該值由color_cache_bits(這里為0)索引數組(kTableSize)確定(line377),即數組的第一個元素。

當給定符號集的大小、根表的大小以及最大的編碼長度,數組(kTableSize)中的大小可使用工具enough.c提前確定,該工具可根據前面給定的參數生成最大有效的完全的哈夫曼編碼表[6]。kTableSize 的值如下:

在ReadHuffmanCodes函數中根據上述確定的表的大小分配huffman_tables 緩存(line432):

然后調用函數ReadHuffmanCode依次解析5個haffman編碼:

函數ReadHuffmanCode調用VP8LBuildHuffmanTable構建哈夫曼表,該表使用2級存儲,根表的大小是8位,多余8位的存儲到二級表中。


前述的key值作為哈夫曼表的索引,當編碼長度大于根表的大小(8bits),key值的低位用來索引根表的位置,高位值用來索引二級表來確定存儲的位置。調用ReplicateValue對哈夫曼編碼(HuffmanCode)存儲:


解析前4個哈夫曼編碼時,哈夫曼表都可如常構建,當對第5個哈夫曼編碼解析時,生成的key值索引二級表的存儲位置時,超出哈夫曼表(haffman_tables)預先分配緩存大小,導致程序出現崩潰。
第5個哈夫曼編碼的key值如下:

造成這種情況的原因是開發者使用enough工具預測緩存的大小,該工具預測的緩存的大小是根據完全有效的哈夫曼樹計算出來的,并未考慮不平衡的編碼情況。在poc中給定{0, 1, 1, 1, 1, 1, 0, 0, 0, 11, 5, 1, 10, 4, 2, 2},并設定最大的編碼長度為15,根表的大小為8時,許多內部節點作為葉節點,創建的是一棵無效的哈夫曼樹。

結合前述分析,key值是根據節點的深度的計數以及編碼長度計算得出,當使用無效的哈夫曼樹計算時得到的key值去索引預定的緩存時,就超出了預期。
3. 漏洞補丁
漏洞補丁[7]對于每個哈夫曼編碼,在函數VP8LBuildHuffmanTable中,兩次調用函數BuildHuffmanTable,第一次將參數root_table 設置為NULL計算需要編碼的段的總大小(total_size),如果大小不滿足,將重新分配緩存。第二次調用函數BuildHuffmanTable才執行實際的哈夫曼表的建立。

當創建完哈夫曼表后,如果是無效的哈夫曼樹,返回的大小為0,后續直接拋出錯誤。


4. 漏洞復現
使用chrome加載構造的WebP圖像,瀏覽器因為堆溢出崩潰。WebP解析庫應用廣泛,在實際測試中,沒有崩潰不代表沒有影響,受影響的廠商應及時更新到最新版本。

5. 參考鏈接
-
https://chromereleases.googleblog.com/2023/09/stable-channel-update-for-desktop_11.html
-
https://developers.google.com/speed/webp/docs/riff_container
-
https://github.com/madler/zlib/blob/v1.2.5/examples/enough.c
-
https://chromium.googlesource.com/webm/libwebp/+/902bc9190331343b2017211debcec8d2ab87e17a%5E%21/
本文由 Seebug Paper 發布,如需轉載請注明來源。本文地址:http://www.qqdpw.com/3056/
暫無評論