摘要
自動生成漏洞利用樣本(AEG)已成為評估漏洞的最重要的方式之一, 但現有方案在目標系統部署有漏洞緩解機制時受到很大阻礙. 當前主流的操作系統默認部署多種漏洞緩解機制, 包括數據執行保護(DEP)和地址空間布局隨機化(ASLR)等, 而現有AEG方案仍無法面對所有漏洞緩解情形. 提出了一種自動化方案EoLeak, 可以利用堆漏洞實現自動化的信息泄露, 進而同時繞過數據執行保護和地址空間布局隨機化防御. EoLeak通過動態分析漏洞觸發樣本(POC)的程序執行跡, 對執行跡中的內存布局進行畫像并定位敏感數據(如代碼指針), 進而基于內存畫像自動構建泄漏敏感數據的原語, 并在條件具備時生成完整的漏洞利用樣本. 實現了EoLeak原型系統, 并在一組奪旗賽(CTF)題目和多個實際應用程序上進行了實驗驗證. 實驗結果表明, 該系統具有自動化泄露敏感信息和繞過DEP及ASLR緩解機制的能力.
自動生成漏洞利用樣本(automatic exploit generation, AEG)[1,2]已經成為評估漏洞的最重要方式之一. 給定一個有漏洞的二進制程序以及觸發漏洞的POC (proof-of-concept)樣本, AEG系統可以自動分析目標二進制程序并生成漏洞利用樣本. AEG不僅可以輔助生成攻擊, 同樣可以輔助防御. 例如, 軟件供應商可以使用AEG工具來評估軟件漏洞的威脅級別, 并確定漏洞修復的緊迫性.
近年來, 研究人員已提出許多AEG方案. 早期工作[3?8]主要關注對棧和格式化字符串漏洞的分析, 其漏洞利用模式相對固定、有效. 而近年來的工作[9?15]更注重堆等復雜類型漏洞, 需要更復雜的利用技巧, 例如堆內存布局操控, 以構建可行的漏洞利用樣本. 然而, 現有AEG工作很少考慮目標環境中部署有漏洞緩解等防御機制的場景, 這些漏洞緩解機制為漏洞利用帶來極大的挑戰. 事實上, 隨著現代操作系統廣泛部署各種漏洞緩解機制, 若攻擊者想在如今的生產服務環境中進行實際攻擊, 突破目標環境中的防御機制是必須解決的重要問題.
現代操作系統中廣泛部署了3種著名的防御機制, 包括數據執行保護(NX/DEP)[16]、棧保護變量(Canary/ Cookie)[17]和地址空間布局隨機化(address space layout randomization, ASLR)[18]. 數據執行保護DEP的目標是, 防止內存中寫入的數據被當作代碼來執行. 設置棧保護變量Canary可以在棧緩沖區溢出漏洞覆蓋棧幀中的函數返回地址時檢測到該破壞行為. 地址空間布局隨機化ASLR則將內存中的代碼段、數據段、堆棧等的基地址隨機化, 使攻擊者難以找到可用的重要數據和代碼的地址, 從而使得攻擊變得更加困難. 除此之外, 還有一些其他漏洞利用緩解措施, 包括控制流完整性解決方案[19?21]等, 也可以有效緩解漏洞利用. 但是由于性能和兼容性等各種問題, 廠商尚未廣泛部署這些保護措施. 因而, 自動生成漏洞利用樣本的AEG方案目前主要需要考慮DEP、ASLR、Canary等防御機制繞過即可.
在當前的AEG工作中, 部分方案[4,5,22,23]假設目標環境和程序沒有啟用防御機制, 部分方案[8,12?14]可以繞過數據執行保護但無法對抗地址空間布局隨機化, 部分方案[3,6,7,24?26]可以通過棧漏洞繞過地址空間布局隨機化保護, 或在沒有數據執行保護的情況下通過堆漏洞繞過地址空間布局隨機化. 目前, 尚未有工作研究通過堆漏洞繞過數據執行保護和地址空間布局隨機化的防御.
繞過地址空間布局隨機化防護的關鍵在于泄漏被隨機化的內存地址. 目前部署在現代操作系統中的地址空間布局隨機化防御基于大尺寸的內存段, 包括棧、堆和共享庫, 粒度相對較粗. 其中, 每個段內的偏移是不受隨機化影響的固定值. 繞過地址空間布局隨機化的最有效策略是泄漏某個段的地址, 從這個地址可以推斷出攻擊者所需的所有在同一段內的其他地址, 其位于固定偏移處. 因此, 我們需要找到一個包含隨機化后地址的指針進行泄漏. 常見的方法包括借用目標二進制程序本身的語義或構建新的輸出功能, 觸發輸出函數以打印出該地址. 通過這個泄漏的隨機地址, 攻擊者可以推斷其他代碼地址并基于此完成漏洞利用.
本文提出了一種面向緩解機制評估的自動化信息泄漏系統EoLeak, 可以通過堆漏洞同時繞過數據執行保護和地址空間布局隨機化, 達成利用效果. EoLeak首先通過對觸發漏洞的POC的運行時內存執行過程進行動態分析, 定位敏感信息的變量位置, 然后自動地為敏感信息變量構建信息泄漏, 并根據泄漏的信息生成漏洞利用樣本. 為了定位內存中的重要變量, 方案通過構建內存畫像來記錄所有有關信息并搜索可能的泄漏路徑. 為了構建泄漏能力, 方案通過堆漏洞分析模型來實現對堆漏洞的初步攻擊, 擴展了內存利用能力. 方案還執行了一種輕量級動態污點策略, 通過監控內存緩沖區的傳輸操作來搜索具有用戶可控參數的庫函數調用, 降低了插樁開銷. 對于最終的漏洞利用, 方案遵循相似的策略來構建用戶可控的庫函數調用, 并妥善處理了泄漏失敗的特殊情形.
我們在基于QEMU的記錄和重放平臺PANDA[27]上實現了該系統, 并通過17個CTF堆漏洞二進制程序和5個真實世界軟件對其進行了評估. 結果表明, 系統成功生成了15個自動泄漏樣本和14個最終利用樣本.對于真實軟件, 系統可以自動分析、定位敏感信息的運行時內存地址和相關指針.
1 研究案例
針對堆漏洞繞過數據執行保護和地址空間布局隨機化的AEG解決方案面臨著與分析人員手工構造利用樣本相同的問題. 本節中, 我們通過對一個實際的堆漏洞利用案例進行研究, 來概述所面臨的挑戰和本文所提出的泄漏系統解決方案.
1.1堆漏洞利用案例
如圖 1所示, 目標程序邏輯簡化后可以表示為圖 1所示代碼(level參數確保合法), 其中存在一個釋放后使用(use after free)的堆漏洞. 程序在第20行調用堆塊釋放函數時未檢查指向目標堆塊的buf指針是否合法, 也未在堆塊被釋放后將指向堆塊的buf指針置零.
圖 1堆漏洞示例代碼
POC通過構造重疊的堆塊內存布局來觸發漏洞. 如圖 2所示, 矩形代表堆塊頭部和堆塊區域, 側方的矩形條代表對應堆塊指針buf的當前指向區域. 當依次執行: (a) 創建小堆塊; (b) 釋放小堆塊; (c) 創建大堆塊; (d) 釋放小堆塊; (e) 創建小堆塊; (f) 創建中堆塊之后, 不僅所有堆塊所對應的存在指示都被置為真, 且大堆塊指針和小堆塊指針發生了重疊, 都指向了(f)中小堆塊的起始地址, 還讓大堆塊指針指向的區域可以對包括小堆塊區域、中堆塊頭部、中堆塊區域在內的內存區域進行覆蓋. 這樣, 對大堆塊的寫入可以造成對中堆塊頭部的堆溢出.
圖 2輸入漏洞觸發樣本時程序執行過程中堆內存布局變化示意
當攻擊者試圖利用這類啟用了地址空間布局隨機化防護的漏洞時, 其首先嘗試泄漏libc庫的隨機化后的地址. 通過在小堆塊中創建一個偽造的堆塊并執行safe unlink攻擊, 指向小堆塊的指針將被篡改為一個略低于該指針本身地址的值, 小堆塊包含了指向大堆塊的指針. 此時, 便可以通過依次修改小堆塊和大堆塊的內容, 先后篡改大堆塊指針的值及其指向內存區域的數據, 實現任意地址寫. 攻擊者可以借助任意地址寫原語用輸出庫函數的過程鏈接表地址替換全局偏移表中的某個libc庫函數地址, 并在觸發該函數調用時以任意libc庫函數指針為第1個參數, 從而實現了泄漏libc庫函數地址. 借助該泄漏地址, 攻擊者可以計算libc庫中system函數和“/bin/sh”字符串等信息的實際運行時地址, 將其寫回堆塊中并觸發system函數調用, 以完成漏洞利用.
1.2攻擊模型
本文假定在目標環境中啟用了3種廣泛部署的防御機制, 包括數據執行保護[16]、棧保護變量[17]和地址空間布局隨機化[18]. 同時還假定目標二進制程序中存在一個常見的堆漏洞可以利用, 例如釋放后使用或堆溢出.
此外, 本文假定攻擊者擁有一個可以觸發堆漏洞的漏洞觸發樣本, 廣泛發展的漏洞發現工具可以滿足這一要求. 由于現代AEG解決方案通常都允許用戶提供對應的漏洞利用輸入模板[28], 本文允許攻擊者對漏洞觸發樣本做一些劃分以輔助跟蹤分析. 本文還假定攻擊者可以通過最近的一些堆布局操縱工作[9?11]掌握堆風水能力, 以便通過漏洞觸發樣本提供一個相對方便而確定的堆布局, 輔助進一步分析.
1.3研究挑戰
在漏洞利用過程中, 攻擊者需要找到一個隨機化后的libc庫函數地址進行泄漏, 然后依據泄漏的地址信息生成漏洞利用樣本. 泄漏和利用生成都要求以攻擊者控制的參數調用某些特定的庫函數(包括打印數據和系統函數). 為了實現這一目標, 需要解決以下多個挑戰.
(1) 挑戰1: 哪些重要的敏感信息值得泄漏, 又如何定位其在內存中的位置? 例如, 要繞過地址空間布局隨機化, 需要通過信息泄漏來獲得一個隨機化后的地址. 在僅給定目標二進制文件和POC時, 需要對運行過程中的內存結構構建內存畫像;
(2) 挑戰2: 如何泄漏所定位的敏感信息? 用戶只能通過向程序提供輸入來影響二進制程序的執行過程. 為了實現信息泄漏, 攻擊者需要確定正確的輸入以觸發打印特定位置數據的功能;
(3) 挑戰3: 如何根據泄漏的信息生成漏洞利用樣本? 即便信息遭到泄漏, 仍與漏洞利用存在一定的距離, 需要額外工作來跨越這其中的障礙.
1.4自動泄漏方案
為了解決上述挑戰, 本文提出了一種新穎的解決方案EoLeak, 來自動執行面向漏洞利用的敏感信息泄漏和相應的漏洞利用樣本生成. 總的來說, 方案對二進制程序執行跡進行動態分析, 對運行時內存結構構建內存畫像, 定位有價值的數據變量, 構建用戶可控的讀寫能力, 并生成繞過地址空間布局隨機化和數據執行保護的堆漏洞利用樣本.
方案使用給定的POC來分析二進制文件的運行過程, 并識別參與計算的指針和敏感變量, 將相關內存信息及時間戳記錄在圖中, 從而可以找到通往指定內存位置的一條嵌套指針鏈條.
為了構建泄漏能力, 方案首先基于堆內存模型, 利用堆漏洞來獲得更廣泛的內存操縱能力. 通過執行輕量級動態污點分析來跟蹤用戶輸入字節, 方案分析用戶可控內存區域, 從二進制程序執行路徑中提取抽象的堆操作信息, 并從預先設定的堆利用模板列表中檢查相符合的堆漏洞利用條件是否被滿足. 為了減少污點分析性能開銷, 并直接獲得用戶輸入和內存數據之間的聯系, 本文采用的污點分析只考慮內存傳輸操作作為傳播策略.
構建漏洞利用樣本遵循與構建泄漏能力相似的策略. 方案通過任意或可控的內存寫來以指定的參數調用目標庫函數, 執行漏洞利用. 對于自動泄漏失敗或二進制文件受到其他高級防御機制保護的情形, 方案還嘗試使用相應的堆漏洞利用技術來直接生成漏洞利用樣本.
2 系統設計
本節介紹了EoLeak方案的設計細節. 如圖 3所示, 主要有3個步驟.
圖 3自動化信息泄漏系統總覽
1、敏感信息定位. 給定一個有漏洞的二進制程序和一個觸發堆漏洞的POC, 方案首先分析程序執行跡, 提取指令語義, 通過恢復指針和有價值的內存對象來定位它們的位置. 我們通過內存畫像來記錄變量地址并維護一個指針圖來搜索到特定地址的泄漏路徑;
2、構建信息泄漏. 方案利用堆模型, 通過堆漏洞利用模板來實現漏洞推斷, 以擴展內存操縱能力并執行輕量級動態污點分析, 來研究用戶輸入與庫函數調用參數之間的關系. 通過構建讀寫功能來實現參數受控, 方案可以構建泄漏原語來打印出敏感信息;
3、生成利用樣本. 方案通過與構建泄漏能力類似的策略來依據泄漏信息生成目標二進制文件的最終利用樣本. 如果無法觸發選定參數的漏洞利用庫函數調用, 方案還會使用相應的模板來處理特定的堆漏洞利用情形作為補充.
2.1敏感信息定位
EoLeak方案的第1步是使用POC運行給定的有漏洞的二進制程序, 并在執行過程中探索敏感信息.
2.1.1重要數據
在程序的整個執行過程中會產生許多指針和內存對象參與計算. 其中, 我們認為以下3種信息值得注意.
1、程序執行中使用的代碼指針, 尤其是位于可寫內存區域的代碼指針;
2、內存對象指針, 包括由堆分配函數返回的堆塊指針;
3、程序執行中頻繁訪問的變量, 或作為函數調用參數的變量.
可寫代碼指針在漏洞利用中非常寶貴, 因為通過篡改這些指針, 攻擊者可以劫持控制流. 并且可寫代碼指針在隨機化后的代碼空間中為推理共享庫的基地址提供了參考. 敏感數據通常作為成員變量被存儲在內存對象中, 內存對象的地址空間在堆管理器控制之下, 我們通過堆塊指針來掌握運行時堆的狀態, 從而推理內存對象在內存空間中的分布. 部分變量, 如數據結構的起始指針經常參與后續數據結構的運算, 或常作為參數被應用程序接口調用. EoLeak方案認為這些變量對漏洞利用生成也很重要, 記錄了這類變量的訪問頻率.
2.1.2內存畫像
為了識別和定位上述敏感信息, EoLeak方案在執行動態程序執行跡分析時構建了內存畫像: 對每條指令進行反匯編以獲取其操作碼和操作數信息, 并從執行跡中提取對應操作數的運行時變量值. 通過分析寄存器和內存操作數的尋址模式, 方案識別指針并對訪問進行計數, 然后將數據添加到全局內存指向映射中, 該映射保存了所有記錄的內存位置和變量聲明周期時間戳.
為了定位保存libc等庫函數地址的指針, EoLeak方案首先查找所有屬于該庫內存段的運行時地址變量值.通過一個單獨的進程監控器來獲取內存段的地址區域信息后, EoLeak方案記錄所有運行時間接調用和跳轉目標, 檢查并過濾出屬于該內存段的那些地址, 并執行一個單獨的驗證過程來比對確認每個庫地址確實對應于一個庫函數符號.
如圖 4所示, 樣例程序的指針內存畫像中包含了兩個指針的嵌套: 位于0x6020b0處的pS指針指向包含指針pM和pH的內存區域0x602098, 而pM和pH這兩個指針又分別指向單獨的內存區域. 當pH指向的以0x175e010為起始地址的內存區域中包含一個有價值的敏感數據時, 便可以通過使用兩個連續的泄漏讀取來構建對該重要數據的泄漏: 先讀取*pS+0x10處pH指針的值, 再讀取*pH+0x8處的敏感信息變量. 由于內存中的偏移量是相對固定的, 只要知道第1個位于0x6020b0處的pS指針地址, 就可以沿著鏈條打印出整個鏈上的每一個節點.
圖 4樣例漏洞程序部分運行時指針內存畫像
在收集到的內存分析圖中, 我們將內存描述為一系列由指針指向的嵌套內存區域, 每個指針都位于特定內存區域的某個偏移處. 給定一個用戶可以讀取的已知地址指針和一個漏洞時間范圍, EoLeak方案可以自動搜索到指定目標變量的指針泄漏鏈條, 從而通過連續任意讀功能應用這條泄漏路徑.
2.2構建信息泄漏
定位敏感信息的位置后, EoLeak方案構建泄漏能力來打印出敏感信息. 正如在上一小節中所闡釋的, 對特定變量的泄漏可以被拆分為沒有沖突的連續任意讀取. 因此, 方案首先構造單個任意讀取的泄漏功能, 然后將其拼接以形成任意讀取鏈條. 更具體地說, 方案分析目標二進制程序的語義, 結合堆漏洞構建泄漏能力, 以目標變量地址作為參數調用打印輸出庫函數, 最后觸發函數調用完成泄漏過程.
2.2.1擴展內存操縱能力
開發者編寫的程序通常對用戶輸入的數據有嚴格的校驗, 避免其破壞內存造成漏洞攻擊, 導致目標二進制程序本身往往沒有足夠的執行語義來實現可控的庫函數調用. 因此, 必要的步驟是通過結合堆漏洞攻擊來提供更多的可利用原語以擴展可用的內存操縱范圍. 攻擊者可以手動調整POC輸入來實現對堆漏洞的初始攻擊, EoLeak也提供了一套通過簡單的堆模型和漏洞利用模板來自動推導和構建這類堆利用攻擊的方案.
現有的堆漏洞攻擊基本上來源于成熟的堆漏洞利用技術, 針對各堆管理器的攻擊方案也在發展中變得特化. glibc當前采用的ptmalloc2為最常用的堆管理器之一, 通過arena結構及其中的bin數組為堆上動態分配的內存提供高效的管理. 在ptmalloc2中, 每個malloc分配出來的內存都有統一的chunk堆塊結構, 其中包含頭部數據用于管理堆結構, 存儲了前一堆塊的大小prev_size和該堆塊的大小size. 空閑的堆塊復用了主體部分的首段字節作為FD和BK指針(分別指向下一個和上一個空閑的堆塊). 每個分配出來的內存堆塊依據其大小和使用狀態被歸為以下4類之一: (1) fast bin; (2) small bin; (3) large bin; (4) unsorted bin.
EoLeak針對ptmalloc2堆管理器抽象出了典型堆漏洞利用方案的模板, 包括觸發漏洞攻擊所需的條件和執行攻擊后的利用效果. 具體來說, EoLeak提供了一個堆漏洞利用模板列表, 每個模板對應一種堆利用攻擊方案, 包含了所需條件(如堆塊分配大小限制、堆塊頭部溢出可能性)和攻擊效果(如任意地址的堆分配).
表 1中列出了當前支持的主要利用模板. 我們以樣例程序中執行的safe unlink攻擊為例. 在未執行safe unlink攻擊之前, 目標二進制程序內存中沒有攻擊者可寫的指針, 無法實現進一步的泄漏. safe unlink攻擊是一種釋放后使用攻擊, 它通過可控的FD和BK指針錯誤地釋放一個已經被釋放的small bin或unsorted bin.在堆利用模板中, EoLeak要求必須滿足以下條件才能實現攻擊.
表 1EoLeak當前支持的堆漏洞利用模板列表
1、在已知地址處有一個指向某堆塊的指針;
2、該堆塊可布置為一個可以通過檢查的被釋放的堆塊, 其FD和BK對應于偏移處都可具有的受控的內容;
3、該堆塊的相鄰堆塊可以觸發釋放操作.
對于目標二進制程序而言, 條件(1)是靜態內存狀態, 可以通過內存畫像的簡單檢查來獲得. 條件(2)要求該堆塊具有滿足約束條件的寫能力. 條件(3)則需要對相鄰的堆塊執行釋放, 可以通過對程序執行跡進行分析而獲得.
該模板的攻擊效果則可被總結為: 已知指針被設置為指向略低于指針所在地址處.
在分析階段, EoLeak方案已經記錄了指針及對應的內存區域. 通過分析包括堆塊頭部信息和雙向鏈表指針結構的堆塊元數據, EoLeak方案維護了一個表示運行時堆布局結構的簡易堆模型. 方案通過分析程序執行跡來提取抽象的堆操作信息, 收集程序路徑中對堆狀態的修改語義, 并將這些修改與堆模型結合起來進行比較, 以檢查其是否滿足任何堆漏洞攻擊模板的條件. 如果某個堆漏洞攻擊模板的所有條件都成立, 方案便會根據模板執行堆攻擊, 驗證這一攻擊的有效性, 并更新POC輸入和程序追蹤狀態. 若后續的分析表明此攻擊無效, 則方案回退到攻擊之前, 并以此嘗試其他攻擊模板.
在執行完POC后, 樣例程序執行到了如圖 2(f)所示的堆布局狀態, 方案開始檢查其是否滿足safe unlink堆攻擊模板的條件. 對于條件(1), 方案在bss段找到了幾個固定地址的堆塊指針. 對于條件(2), 方案發現了程序路徑, 其中存在圖 4所示的pS指針, 指向的小堆塊中可以填充用戶偽造的假堆塊, 且其長度可以大于小堆塊容許的大小, 允許通過堆溢出覆蓋后續相鄰堆塊頭部的大小字段和存在標識比特. 雖然小堆塊和大堆塊都可以填充用戶可控的內容, 但只有pS滿足從指向內存區域起始的可寫長度大于剩余塊大小的要求, 因此, prev_size字段和prev_in_use比特可以根據需要被覆蓋為指定內容(標明前一偽造塊為已釋放狀態, 同時通過大小匹配檢查). 對于第3個條件, 另一條程序路徑滿足了觸發堆塊釋放的要求. 3個條件都得以滿足, 因此EoLeak方案根據模板構造對應的攻擊輸入, 依次執行相應的程序路徑, 成功更新了當前程序狀態.
2.2.2污點分析可控庫函數調用
收集更多內存操縱原語后, EoLeak方案嘗試著構造單個泄漏能力. 在獲得庫函數實際地址之前, 我們仍然依靠目標二進制程序本身來完成泄漏過程. 因此, 需要找到目標二進制程序中已經存在的輸出能力, 并以欲將泄漏的數據地址為參數進行觸發.
EoLeak方案首先在目標二進制程序中查找具有打印輸出語義的庫函數, 這在構建內存畫像的過程中已經收集獲得. 進而, 方案分析程序執行跡以確定是否存在合適的程序路徑來用可控的參數調用該輸出庫函數, 這包括兩種可控參數情形: 參數直接來源于當前POC輸入中的某些字節, 或參數來源于當前程序路徑中某些可控內存區域的變量傳播. 前者可以通過修改當前輸入進行簡單的調整, 而后者則需要額外的寫入程序路徑來將所需的地址數據寫入相應的內存區域. 另一方面, 如果沒有合適的程序路徑來調用庫函數, 則EoLeak方案必須首先通過劫持其他庫函數符號來構造泄漏原語, 然后再以可控參數對該函數進行調用. 總之, EoLeak方案需要了解用戶輸入可以影響哪些內存區域, 也需要了解函數參數來源于哪些內存區域.
為了跟蹤來自用戶輸入的數據流, 除了反匯編二進制指令并獲取運行時數據外, EoLeak方案還根據指令語義執行一個輕量級的污點傳播分析來跟蹤用戶輸入. 用戶輸入庫函數的結果被標記為污點源, 目標庫函數調用參數被標記為污點接受器. 由于動態污點傳播是一個比較繁重的過程, 分析工作量大而無法保證精度, 為了降低性能開銷并專注于由用戶輸入字節直接控制的內存區域, EoLeak方案僅以不超過一階的算術或位操作的內存傳輸操作作為污點傳播策略. 其背后的思路在于: 如果目標地址完全被攻擊者所控制, 則構成該地址的連續字節有很高的概率會作為一個整體在內存中進行傳輸或執行偏移操作. 在這種情況下, 污點分析僅跟蹤原始用戶輸入, 降低了維護的開銷, 并且使后續漏洞利用生成分析更加簡潔.
2.2.3構建泄漏語義
EoLeak方案對上述內容的分析結果存在多種可能性, 包括可能存在多個讀取語義的程序路徑可以實現泄漏能力, 打印庫函數的參數可能來源于多個可控內存區域, 而每個內存區域也可以支持多種寫入方式.
方案在這些候選組成部分中進行選取, 拼接出一個完整的泄漏原語. 由于通過指針鏈條的連續任意讀取泄漏能力要求每個任意讀取泄漏之間不能發生沖突, 方案在拼接泄漏路徑后對其執行跡進行分析, 計算其帶來的副作用, 包括其他內存位置的寫入、對堆布局的額外操作等, 對每個生成的庫函數調用給予一個副作用評分, 用以衡量副作用的影響, 優先選擇副作用較小的泄漏路徑. 具體而言, 方案提取每個執行跡中的內存讀寫和分配釋放操作, 并分成兩部分進行處理. 對于執行跡中的內存讀寫, 方案對每個不同地址的內存寫入計3分, 并對每一組逆序的執行跡中內存讀寫(即存在某個地址執行跡先讀后寫)計1分. 對于執行跡中的內存分配和釋放操作, 方案對每個內存分配和釋放計1分, 并對每一組不匹配的分配和釋放(匹配即一對分配釋放操作目標地址相同)計1分. 在選擇泄漏路徑時, 方案按內存分配釋放分數和內存讀寫分數依次優先選擇分數較小的泄漏路徑.
目標程序的內存畫像中記錄了所有與隨機化后庫函數地址相關的指針位置, EoLeak方案自動地為每個庫函數指針計算可能的泄漏鏈條, 嘗試對任一指針進行泄漏, 以獲得在地址空間布局隨機化后的運行時庫函數地址. 分析人員也可以在內存畫像圖中手動標記目標敏感信息, EoLeak方案可以嘗試為該變量構建相應的泄漏路徑.
2.3生成利用樣本
在完成信息泄漏之后, 我們嘗試利用泄漏出來的libc庫函數地址和此前通過模板擴展出的可控內存范圍來實現目標二進制程序的利用, 通過使用和構建泄漏語義相似的策略來構建利用語義中的庫函數調用, 例如system(“/bin/sh”), 在下文中將以此作為示例. 也有其他可用的庫函數, 如execve, 只需要不同的參數組合. 自動構建利用樣本過程同樣可以分為兩個步驟: 使一個可被調用的代碼指針具有隨機化后的運行時system函數地址, 并確保第1個或相應的參數被填充為“/bin/sh”的地址.
由于在不同的隨機化基地址中, 相同庫中的兩個符號之間總具有相同的偏移量, 所以,system函數的運行時地址可以通過泄漏出的libc庫函數地址進行計算. 被調用的代碼指針可以選取典型代表, 如全局偏移表, 其保存程序中使用的真實庫函數地址. libc庫中包含“/bin/sh”這一字符串, 其地址亦可通過泄漏的地址進行計算. 在某些情形下,system庫函數調用的第1個參數無法由用戶輸入值直接控制, EoLeak方案則尋求替代選項: 將參數設置為指向具有可寫內存區域的指針, 通過在原始POC中附加或修改字節來觸發寫入過程, 將“/bin/sh”字符串本身寫入目標內存區域而非其運行時所在地址. 當system函數地址和參數都準備好后, 便可通過篡改libc庫函數符號來觸發對system函數的庫函數調用, 實現對目標二進制文件的利用.
EoLeak方案基于泄漏函數地址的方案來繞過地址空間布局隨機化防護. 在泄漏和生成利用樣本階段, 無需注入shellcode, 而是基于最初堆漏洞利用模板對可用內存范圍的擴展, 通過對可控庫函數調用目標地址和參數進行分析劫持庫函數調用, 通過復用代碼以實現攻擊, 可以對抗數據執行保護. 在堆漏洞利用的過程中, 一般不依賴于棧溢出功能, 且可以通過內存畫像指定棧保護變量來構造對應的泄漏路徑, 因此可以對抗棧保護變量的防護.
3 實現方案
本文基于PANDA項目實現了EoLeak系統. 具體來說, 我們用C++實現了部分分析代碼, 并將整個系統包裝為一個基于Python的服務器/客戶端架構.
3.1記錄和重放
針對隨機化保護的分析, 一直是一項艱巨的工作. 隨機化值僅在實際執行過程中生成, 在此之前無法觀察到相關的隨機化程序行為. 動態分析解決了這個問題, 但每次執行時產生的隨機結果有所不同, 從而給研究人員帶來了新的困難.
EoLeak系統借助了記錄程序執行跡并以確定方式進行重放的技術. 在記錄階段, 所有運行時的環境變量照常生成并被記錄在日志文件中. 當重放執行跡時, 每條指令都具有與最初記錄時完全相同的執行行為. 一致的運行環境有助于研究人員輕松地比較和分析多次重放之間同一程序執行跡的執行過程, 并準確識別隨機化后的庫函數地址和相應的內存結構.
3.2PANDA插件
PANDA基于QEMU模擬器, 在TCG生命周期中有多個回調函數點, 如PANDA_CB_INSN_TRANSLATE在基本塊首次轉換為TCG IR之前被調用, 而PANDA_CB_AFTER_INSN_EXEC在一條指令執行后被觸發. 通過這些回調函數有選擇地插入分析邏輯代碼, EoLeak系統能夠記錄和分析特定用戶輸入的目標二進制程序的執行過程. 例如: 在Capstone反匯編工具的幫助下, 將指令在執行前進行反匯編, 并在全局指針映射結構中記錄識別到的指針. 污點和傳播分析在這里進行.
3.3服務器/客戶端架構
PANDA是一個構建在QEMU之上的分析平臺, 其在啟動目標操作系統鏡像實例的新虛擬機時面臨嚴重的性能問題和時間開銷. EoLeak系統需要動態決定目標二進制程序的下一個用戶輸入, 無法承擔頻繁的啟動和關閉虛擬機的時間成本. 為此, 我們將EoLeak設計為服務器/客戶端架構, 客戶端是一個Python控制器, 用戶控制PANDA虛擬機并接受來自服務器的命令. 其包裝了常見的PANDA操作, 例如記錄給定目標二進制程序和對應輸入的新程序執行過程記錄、重放程序執行跡并運行分析插件進行分析以及將服務器傳來的ISO文件注入/彈出虛擬機等. 當分析操作完成后, 客戶端將分析結果發送回服務器. 為了降低虛擬機啟動的時間開銷, 客戶端在后臺保留一個運行中的客戶操作系統實例來接受和執行來自服務器的命令, 并根據需要自動重啟虛擬機.
EoLeak系統的服務器則是另一個Python項目, 也是系統的核心分析器. 它向客戶端發送PANDA操作和分析指令, 從客戶端接收分析結果, 并驅動自動構建泄漏和生成漏洞利用樣本過程. 當生成新的程序輸入時, 服務器將輸入和二進制文件一起發送給客戶端, 以進行另一次執行跟蹤分析. 通過將漏洞利用分析模塊和PANDA執行模塊拆分為服務器和客戶端架構, EoLeak系統可以通過連接一個服務器和多個執行器客戶端來并行加速.
4 評估驗證
本節介紹針對EoLeak系統的實驗評估和驗證, 主要回答了如下幾個研究問題.
1、研究問題1: EoLeak系統能否成功定位敏感信息?
2、研究問題2: EoLeak系統采用的堆攻擊模板是否有效?
3、研究問題3: EoLeak系統能否為堆漏洞程序生成自動泄漏敏感信息以及能否自動實現利用的樣本?
4.1敏感信息定位
如表 2所示, 我們從著名的CTF賽事和網站中收集了17個堆漏洞程序. 所有案例提供的POC都不可利用. 系統的libc版本為2.23, 啟用的防御類型在表中以SNP表示(S表示棧保護變量, N表示數據執行保護, P表示PIE, 字母存在表示目標程序部署了對應防御, ?表示3種防御均不存在), 系統采用全隨機模式地址空間隨機化保護.
表 2EoLeak測試的CTF堆漏洞二進制程序
為了回答研究問題1, 我們收集了EoLeak在動態分析過程中記錄的libc庫函數地址指針作為敏感信息的代表. 如表 3所示, EoLeak在所有CTF二進制文件中都成功定位到了可供泄漏的libc庫函數地址. 左列的libc地址識別數代表原始POC下識別到的存儲隨機化后libc庫函數相關地址值的內存位置數量, 由動態分析模塊給出. 右列的攻擊后libc地址識別數則代表在實現了初步堆攻擊后識別到的對應內存位置數量, 體現了堆攻擊對內存操縱能力的提升. libc庫相關指的是與libc庫基址有固定偏移量的地址, 其不僅包括libc函數符號, 也包括了libc數據段內部的某些內存結構字段, 這些字段也可以起到泄漏libc運行時地址的作用.
表 3EoLeak當前支持的堆漏洞利用模板列表
我們還評估了5個真實世界程序的敏感信息定位能力. 從表 4的結果可以看出, EoLeak成功地在所有應用程序中定位到了libc地址. 值得注意的是: 原始POC下識別到的libc庫相關地址數量與目標二進制文件的大小沒有明顯關系, 但與目標二進制文件中引用的libc符號數量大致相同. 這表明, 幾乎所有可能的用于繞過地址空間布局隨機化的libc相關地址都僅來自于全局偏移表. 另一方面, 通過初步堆攻擊所擴展得到的libc相關地址不受此限制, 是穩定的泄漏來源選項.
表 4真實軟件中對libc庫相關地址的識別
4.2堆攻擊模板
為了回答研究問題2, 我們在17個CTF堆漏洞程序上驗證EoLeak方案所采用的攻擊模板列表的有效性.結果見表 5. 17個程序中, 有5個程序可以成功匹配Fastbin攻擊模板; 有8個程序可以匹配Unlink攻擊模板; 有2個程序可以通過偽造數據結構來實現內存寫; 還有2個程序無法匹配到對應的攻擊模板. 即, 有88.2%的目標程序可以由EoLeak自動探索從堆布局不過分復雜的漏洞觸發點到遵循模板的堆漏洞初步攻擊.表 3中, 初步攻擊后新增識別到的libc庫相關地址體現了這一初步攻擊所帶來的內存可利用性的提升. 我們也調研了2個無法成功匹配初步攻擊模板的程序案例以及在真實軟件中的情形, 具體緣由在下一小節中加以分析.
表 5CTF堆漏洞二進制程序適用的堆攻擊模板
4.3泄漏和漏洞利用生成
為了回答研究問題3, 我們使用17個CTF堆漏洞程序來評估EoLeak系統, 嘗試生成泄漏和漏洞利用樣本. 對于每個堆漏洞程序, 會準備一個能夠觸發堆漏洞但未能利用的POC.
如表 6所示: EoLeak系統為17個堆漏洞程序中的15個成功構建了泄漏, 其中14個生成了最終利用樣本.也就是說, EoLeak系統在構建libc庫函數地址泄漏方面成功率達到了88.2%, 而82.4%的目標程序得到了利用.
表 6CTF堆漏洞二進制程序的信息泄漏構建和利用樣本生成效果
我們進一步調查了無法構建泄漏的3個案例和未能生成漏洞利用的1個案例, 分析了失敗的原因.
1、多線程. vote程序是一個多線程程序, 對于當前的分析模塊來說過于復雜. 目前, EoLeak僅支持對單線程的漏洞程序進行分析. 出于同樣的原因, EoLeak暫時無法理解條件競爭類漏洞;
2、自定義堆結構. minesweeper程序實現了自定義的堆結構和管理器. EoLeak的堆模型推斷依賴于標準的ptmalloc2實現, 因此目前無法處理自定義堆, 也無法為程序順利生成泄漏或最終漏洞利用;
3、尚未支持的堆利用技術. mario程序需要利用_IO_file結構來實現堆利用攻擊, 當前堆模型推斷機制尚未能支持該類利用技巧. 因此, 雖然可以正常使用FD指針構造泄漏, 但在生成漏洞利用樣本時仍是失敗的;
4、利用窗口. 實際中, 軟件路徑復雜, 大多漏洞僅允許有限的攻擊窗口, 通常僅有1次寫入的能力, 很難復用. 即使部分漏洞符合利用模板條件, 后續亦因復雜的堆布局變化而難以構造無沖突的連續讀取鏈條, 因而難以自動實現泄漏.
5 相關工作
5.1自動生成漏洞利用樣本
早期的自動生成漏洞利用樣本解決方案沒有考慮防御機制. APEG[22]是第一個AEG解決方案, 它將補丁前后出現差異的條件檢查與目標二進制文件進行比較, 使用符號執行來自動構建在補丁之前未能通過條件檢查的輸入. AEG[4]基于棧上的控制流劫持對源代碼進行符號執行, 以利用棧溢出和格式化字符串漏洞. Mayhem[5]設法為二進制文件中的棧溢出和格式化字符串漏洞生成漏洞利用, 通過控制流劫持符號執行實現執行ret2stack-shellcode和ret2libc攻擊. PolyAEG[23]通過污點分析用戶可控的控制流方向, 為具有一個異常輸入的二進制文件生成多種漏洞利用. 這些AEG解決方案都無法繞過數據執行保護或地址空間布局隨機化.
一些研究工作設法突破防御機制, 但仍無法自動繞過地址空間布局隨機化. HI-CFG[8]將良性輸入轉換為緩沖區之間的漏洞點, 生成帶有緩沖區信息的控制流圖(control flow graph), 并通過讀寫操作搜索緩沖區傳輸.該工作的核心目標是生成可以造成異常狀態的POC樣本, 如果想繞過地址空間布局隨機化防御的利用樣本, 則需要人工引導的介入. Revery[12]、KOOBE[13]和FUZE[14]研究如何使用模糊測試技術生成針對堆漏洞的攻擊. Revery在用戶態程序中搜索與崩潰執行路徑相似的內存布局, 嘗試縫合替換程序路徑. KOOBE專注于Linux內核中的越界寫入漏洞. 另一方面, FUZE分析用于創建和取消引用懸空指針的時間戳. 這些解決方案將繞過地址空間布局隨機化, 被視為超出研究范圍的內容, 因而未予考慮.
一些研究工作試圖繞過地址空間布局隨機化, 但只能通過對棧漏洞的利用實現繞過, 而無法在堆漏洞上成功繞過. Heelan[3]提出了一種使用符號執行來生成已知棧溢出漏洞的解決方案, 通過跳轉寄存器引導向未隨機地址來繞過地址空間布局隨機化. Q[6]使用少量非隨機代碼強化現有漏洞利用, 以繞過地址空間布局隨機化. 它通過二進制分析平臺BAP[29]構建面向返回編程(return-oriented programming)的配件, 并匹配所提出的QooL語言以進行棧利用. CRAX[7]通過對用戶控制的程序計數器進行污染, 為大型真實世界的二進制文件生成漏洞利用. 盡管它可以使用ret2libc和jmp2reg技術繞過棧上的地址空間布局隨機化, 但它無法實現堆漏洞上的繞過. ShellSwap[24]通過使用符號跟蹤以及漏洞利用代碼布局修復和路徑拼接的組合, 將現有的舊漏洞利用移植到一個有效的新漏洞利用中. 其通過一個具有可控寄存器的特定jmp指令覆蓋指令指針來繞過地址空間布局隨機化, 因而無法同時繞過數據執行保護. R2dlAEG[26]利用符號執行探索利用return2dl-resolve攻擊技術來為棧溢出漏洞生成繞過數據執行和地址空間布局隨機化的利用樣本. KEPLER[25]通過發現多個漏洞利用鏈來生成繞過現代緩解技術的面向返回編程的漏洞利用. 它需要劫持控制流并利用控制流劫持原語(control- flow hijacking primitive)來構建漏洞利用的POC.
數據流分析自然可以對抗地址空間布局隨機化保護. FLOWSTITCH[30]自動生成面向數據的漏洞利用, 在不違反控制流完整性的情況下, 拼接信息泄漏或特權升級. DOP[31]更進一步, 通過構建數據流配件來執行面向數據的編程, 但是它們沒有在堆漏洞上繞過地址空間布局隨機化. BOPC[32]假設所有控制流緩解都已啟用.它在給定的入口點上搜索內存布局, 通過多個任意內存寫入原語來設置內存布局(如果繞過地址空間布局隨機化, 則亦需要讀取原語), 使得后續數據流滿足所需的SPL邏輯.
解釋器上的AEG研究工作也受到了一些關注. SHRIKE[9]對PHP進行回歸測試以提取堆操作. 此外, 它會搜索溢出塊與目標塊相鄰的特定內存布局. Gollum[10]自動解決了尋找數據結構溢出并以某種特定方式使用的問題. 它首先檢查可利用的堆布局, 然后以惰性方法搜索相應的堆操作過程. 由于需要確定的堆分配地址, 它不能繞過地址空間布局隨機化.
5.2污點分析
污點分析技術是用于分析程序數據流的一種重要方法, 可以直接判斷輸入源和目標點之間是否存在關聯性, EoLeak執行輕量級動態污點分析來研究用戶輸入與庫函數調用參數之間的關系. 靜態污點分析很難保證結果的正確性, 現行的污點分析系統往往采用動態分析的方法, 并與動態符號執行和模糊測試等方法相結合.
Dytan[33]給出了一個通用的污點分析框架, 并采用動態插樁的方法進行污點分析, 但它在污點標記和插樁效率上存在很大的局限性. Libdft[34]使用影子內存(shadow memory)方法, 提高了動態數據流追蹤的效率, 加強了動態污點分析技術的實用性. 現行的動態污點分析方法都不可避免地存在過污染(over-taint, 污點標記過多, 污點變量大量擴散)或欠污染(under-taint, 污點傳播分析不當, 本應被標記的變量沒有被標記)的問題[35]. 并且, 由于污點分析需要對每一條指令指定污點傳播規則, 它們對目標程序的運行平臺有著很強的依賴, 遷移到不同的平臺需要付出很大的工程代價. 迄今為止, 沒有一個動態污點分析系統可以同時在x86和x86-64平臺上分別對32位和64位程序進行分析. 為了緩解過污染和欠污染問題, 從而加強動態污點分析的可靠性和完備性, TaintInduce[36]可以只利用對應架構最少的語義信息來自動分析得到傳播規則, 具有較好的跨平臺遷移能力. 另外, 還有一些結合二進制分析的動態污點分析工具, 比如TEMU[37]和Triton[38].
傳統的污點分析方法工程量大, 運行效率低, 因此一些前沿的研究嘗試使用機器學習的手段, 用神經網絡模擬指令的輸入和輸出, 嘗試為指令自動建立傳播規則, 從而達到降低工程量和跨平臺的目的. 如Neutaint[39]利用神經網絡來直接估計輸入源和目標點之間的關聯性.
6 總結
對于自動生成漏洞利用樣本解決方案來說, 將部署在目標系統中的緩解策略涵蓋進考慮范圍是一個現實的挑戰. 我們提出了一種有效的自動解決方案EoLeak, 用于通過堆漏洞同時繞過地址空間布局隨機化和數據執行保護. 通過使用漏洞觸發樣本對程序執行跡進行動態分析, EoLeak方案利用對內存傳輸的輕量級污點分析和簡單的堆利用模型來推斷可能的庫函數指針和漏洞利用目標. 我們在17個奪旗賽堆漏洞二進制程序上測試了EoLeak, 其中15個可以自動構建泄漏, 14個可以生成最終利用樣本. EoLeak還可以成功分析真實世界程序中的敏感信息和內存可控性.
審核編輯:湯梓紅
-
信息
+關注
關注
0文章
406瀏覽量
35536 -
PoC
+關注
關注
1文章
69瀏覽量
20513 -
AEG
+關注
關注
0文章
4瀏覽量
1896
發布評論請先 登錄
相關推薦
評論