1. 程式人生 > 實用技巧 >論文分享:AURORA: Statistical Crash Analysis for Automated Root Cause Explanation

論文分享:AURORA: Statistical Crash Analysis for Automated Root Cause Explanation

這篇論文是來自RUB-SysSec小組在Usenix Security 2020 的關於分析crash的論文。之前看過他們組在ASCAC上發的PrimGen,感覺安全圈真小。
該工具已經開源,見網址:https://github.com/RUB-SysSec/aurora

文章目錄

簡介

軟體測試的自動化技術在實踐中發現了很多crash。分析這些crash的根源是很耗時的。為了解決這個問題,學術界提出了各種方法來解決,比如逆向執行,後向汙點分析。然而,這些方法侷限於特定的錯誤種類,或者只給分析人員提供彙編指令,而沒有上下文資訊或者關於錯誤的解釋。

這篇文章提出了一種自動化分析的方法,不僅能識別導致二進位制可執行檔案崩潰的crash的根源,而且能提供程式錯誤行為的上下文資訊。從一個崩潰輸入出發,我們生成相類似的輸入,可能會使得程式崩潰,或者不崩潰。然後當執行我們找到的輸入和產生predicate時,追蹤程式的狀態。然後對predicate進行資料分析,定位到根源。

作者基於以上思想做了一個工具叫AURORA,並且在25個不同的軟體錯誤上進行評估。評估結果表明AURORA能夠對複雜漏洞分析。相比於現有的方法,AURORA能夠應對在crash和root cause之間無資料依賴的漏洞,比如型別混淆漏洞。

背景

模糊測試是一個很強大的軟體測試技術,尤其是在近些年,在學術界和工業界取得了不錯的成績。本質上,模糊測試是生成各種各樣的輸入到目標程式中,並且儘可能地覆蓋不同的路徑。最近的新的模糊測試方法為軟體系統產生了很多的crash,有時導致開發者沒有時間去處理它們。許多情況下,找到一個新的導致崩潰的輸入是很容易,並且純自動化的工作。然而分析crash是一個手動,耗時耗力的工作。主要是麻煩在追蹤crash的根源。實際情況更為糟糕,一個bug就可能導致多個crash輸入。這就導致分析員需要去挖掘發現許多潛在的漏洞。也就導致開發者沒有時間去修復已知bug。

為了減少許多crash對映到同一個bug,分析員嘗試對這些輸入進行分組。也就是按照某種指標,比如覆蓋率或者呼叫棧的hash,來把崩潰的輸入分類。理論上來說,分析每一類的一個bug就夠了。然而,最近的實驗表明普通的分類方案存在2個問題:

  • 產生了太多的分類
  • 分類分得不夠準確
    即使只有一部分的輸入要去分析,分析員也不知道為什麼給定的輸入會導致崩潰。通常,真正導致crash的根本原因不是崩潰那個點,有可能在更加前面的地方。因此分析員就需要去分析從崩潰發生的地方往前去找到root cause,而這需要很多精力。

比如說,有一個型別混淆的bug,一個指標指向一個A型別的物件,然後用的時候卻指向了一個B型別物件。如果B物件的域被訪問了,就會導致A的子模組非法訪問。如果兩個結構不相容的話,就會導致記憶體損壞。在這個例子中,崩潰的位置很有可能不是falut的root cause處。論文認為這個bug的根源在於生成一個從A型別到B型別的值的那個控制流。

傳統的方法,一個分析員用偵錯程式去檢視棧和暫存器的值。從crash開始,手動地去後向追蹤到root cause。使用先進的sanitizer比如ASAN,可以檢測到離root cause很近的記憶體非法訪問。而在我們的例子中,手動分析需要從crashing的位置開始,而ASAN只會檢測到什麼位置發生記憶體損壞。分析員仍然需要手動地去識別型別混淆是root cause。而這是一個複雜的工作,因為大部分的程式碼都是正常的。

其他工作POMP,RETRACER,REPT和DEEPVSA使用自動逆向執行和後向汙點分析。這些工作在crash無法復現的時候是有用的。REPT和RETRACER通過結合core dumps和intel的PT trace來分析發生在端裝置的crash。如果沒有直接的資料依賴關係連線root cause和崩潰的指令,這些方法並不能自動地分析root cause。REPT和RETRACER更側重於為分析員提供一個在crash之前的互動式除錯環境。

難點

方法

給定一個崩潰的輸入和二進位制程式,目標是去輸出軟體錯誤的root cause的一個解釋。核心思想是通過崩潰和不崩潰輸入的行為差異來確定的root cause。
因此,我們首先建立一個多樣化的程式行為的資料集,然後監控相關的輸入行為,最後比較地分析他們。用這種方式的出發點在於崩潰的輸入必須在某種程度上,語義上與不崩潰的輸入不同。直覺上來說,在程式執行過程中第一個偏離不崩潰的輸入的行為就是root cause。
在第一步,我們建立兩個相關但不同輸入的集合,一個是crashing input , 另一個是non-crashing input。理想上,我們只包含由同一個root cause導致的crashing input。non-crashing input的集合沒有這個限制。為了獲取這些集合,我們使用crash exploration fuzzing在一個初始的crashing input上實現(seed)。

給定兩個集合的輸入,我們觀察和監控(trace)程式的行為。這些追蹤允許我們去關聯觀察的不同和執行的輸出。使用資料推斷,我們可以預測程式是否會崩潰。為了進一步格式化不同之處,我們生成了predicate來說明是否觸發了bug。理論上來說,第一個predicate就能成功預測所有執行的結果,也能解釋root cause。最終,我們為分析員提供一個列表的相關解釋和地址,以他們預測的價值排序和執行時間排序。也就是,我們更喜歡預測結果好的解釋。在所有好的解釋裡,我們更喜歡哪些能夠儘快預測crash的。

總的來說,這篇論文的方法分為三個點:
(1) 輸入多樣化,來生成兩個不同的輸入集合
(2)監控輸入的行為,來追蹤這些輸入是怎麼表現的
(3)生成解釋,生成描述性的predicate來區分crashing input 和non-crashing input

實現

主要分為三個部分的實現:

  • Input Diversification:基於AFL 2.52b修改。
  • Monitoring Input Behavior:基於PIN 3.7 修改
  • Explanation Synthesis:基於Rust語言編寫,程式碼量為5000行,同時還用到了binutils addr2line。

結果

實驗結果主要回答以下三個問題:

  • AURORA能否識別和解釋複雜和可利用bug的root cause,比如型別混淆,UAF和堆溢位?
  • 自動識別的解釋和開發者弄的補丁之間有多接近?
  • 有多少predicate是與fault相關?(其實也是在說,這個aurora工具生成結果好不好用,容不容易找到crash的root cause)

論文選取了25個比較常見的資料,從中選取了各種型別的漏洞來做實驗。說明主要實驗結果是這個表1(重點放第一個)。
在這裡插入圖片描述
說明一下漏洞有多複雜。
在這裡插入圖片描述
對假陽性的分析。
在這裡插入圖片描述
追蹤的成功率。
在這裡插入圖片描述
追蹤需要的時間。
在這裡插入圖片描述

相關工作

基於範圍的錯誤定位

這類基於範圍的錯誤定位主要是指基於程式碼覆蓋率的錯誤定位技術。換句話說,這類工作主要是定位導致bug的程式元素,比如,單一語句,基本塊,函式。

相關論文:

  • The inflection point hypothesis: a principled debugging approach for locating the root cause of a failure
  • A practical evaluation of spectrumbased fault localization
  • Localizing software faults simultaneously
  • Empirical evaluation of the tarantula automatic fault-localization technique.
  • Isolating suspiciousness from spectrum-based fault localization techniques
  • A general noise-reduction framework for fault localization of Java programs
  • Scalable statistical bug isolation
  • Statistical debugging using compound boolean predicates.
  • SOBER: statistical model-based bug localization.

逆向執行

有大量的工作去分析crash,尤其是使用core dump的。為了實現這點,通過逆向執行程式,重構導致crash的資料流。為了實現這個,CREDAL使用程式原始碼資訊去自動地分析core dump,從而輔助分析人員發現記憶體損壞類漏洞。為了進一步減少人工勞動力,POMP利用控制流追蹤和crash dump這些資訊,並使用後向汙點分析來逆向生成資料流,識別出對crash有貢獻的語句。與之相似的一個工作,不過是在OS級別,RETRACER使用後向汙點分析(沒有使用追蹤)來在棧上重構對bug有貢獻的函式。Cui等人在RETRACER做了改進,開發了一個REPT,一個逆向的debugger,引入了錯誤糾正機制來重構執行理事。從而能夠恢復導致crash的資料流。為了克服不準確性,Guo等人提出了深度學習的值集分析來解決記憶體別名問題。

相關論文:

  • CREDAL: towards locating a memory corruption vulnerability with your core dump.
  • REPT: Reverse debugging of failures in deployed software.
  • RETracer: Triaging crashes by reverse execution from partial memory dumps.
  • DEEPVSA: Facilitating value-set analysis with deep learning for postmortem program analysis
  • POMP++: Facilitating postmortem program diagnosis with value-set analysis
  • Postmortem program analysis with hardware-enhanced post-crash artifacts

討論

實驗結果顯示,我們的方法可以識別和解釋root cause,甚至是root cause和crashing 沒有直接關係的情況。然而,這個方法也不是銀彈。仍然會報告一些predicate是與root cause無關的情況。這是由於crash exploration的資料量不夠的情況。這實際上也是基於語法的fuzzer的一個問題,即AFL的突變種類不足以為目標產生足夠的不同輸入。作者期望更好的fuzzing技術出現去生成更合適的語料。不管fuzzer有多好,定位root cause的自動化方法仍然是一個複雜的目標,即使一個人類專家,也經常不能識別一個bug的根源。
依賴模糊測試還有一個問題,bugs在模糊測試setup時是可以復現的。因此,該方法不能分析分散式或者高度關聯的bug。然而,這個是fuzzer的問題,不是aurora的問題。aurora的優勢在於其資料模型可以很好地移植到別的複雜的系統,比如network,database。而傳統的分析技術,比如汙點追蹤是不行的。

某些情況下,我們生成的predicate是不夠準確的。比如,有可能存在一個使用未初始化值的bug,要觸發需要滿足兩個特定條件:程式一開始不經過初始化值的路徑,然後經過訪問了那個值的路徑。(聽的怪繞的,本質上就是一個單一位置的predicate沒法表示基於兩個位置的bug行為。)這裡的問題感覺和另外一篇文章講資料流攻擊的BOPC的很像。也是因為粒度問題所導致的。

最後,系統需要一定時間去識別和解釋root cause。某些情況下,Aurora執行時間高達17小時(12h在crash exploration)。作者認為這不是問題,因為我們的系統是和傳統的fuzzing的結合。因此,在測試setup階段的額外的17h的fuzzing幾乎不會導致很嚴重的開銷。

總結

這篇文章主要是提出了一種針對二進位制程式的自動分析崩潰原因的系統。研究的意義是幫助分析員定位crash,從而修復漏洞。因為現在模糊測試工具產生的crash太多了,而且很多crash都是指向同一個漏洞。這個工作的很多侷限性都在於fuzzer自身的問題。另外,這個工作只是輔助開發者去定位漏洞,還是需要開發者去手工分析一下。
論文寫作上也有很多可以借鑑的。文章的寫作思路也有很多值得學習的地方。實驗怎麼設計的也可以再細看一下。總的來說,是篇不錯的文章~(要是多點圖就好了)