TripleDoggy:程式碼漏洞自動化分析外掛快速入門專案
題圖來源:( ofollow,noindex">別樣網-沙沙野|免費背景圖片素材_網頁設計圖片素材網站 )
如何自動化分析原始碼中存在的安全漏洞,一直是電腦保安研究領域的熱門問題。但是,開發一款原始碼分析工具,門檻往往很高,也存在諸多相容性問題(特別是分析一些奇怪的程式碼時),因此想要快速進入這個領域,,沒有大量的程式語言和編譯原理的知識預備,往往難以快速入門。儘管如此,當時間已經進入到2018年,摩爾定律都快要撞上物理學的南牆了,難道我們還會因為原始碼分析的困難而止步不前嗎?
解決這個問題,我們可以從LLVM這個強大的專案中去挖掘寶藏,還記得我們之前釋出的孤挺花(Armariris)LLVM混淆框架嗎( GoSSIP安全研究專案:孤挺花(Armariris) LLVM混淆框架 )?今天,我們向大家介紹基於LLVM的Clang Project中另一個優秀框架Clang static analyzer(以下簡稱CSA):CSA 是一個基於Clang的c/c++/object-c原始碼分析框架,它首先對原始檔進行預處理得到關於某個模組的完整的控制流程圖(CFG),然後可以支援使用符號執行來遍歷整個原始檔。開發者可以開發自己的外掛,通過hook的方式在符號執行過程中與框架進行互動。具體地,在CSA中,所有的值都是一個符號(如函式返回值,區域性變數,全域性變數等),通過符號執行,每條執行路徑上都對應著某個符號不同的約束範圍,當靜態分析執行到程式某個點上,開發者可利用框架提供的hook介面與符號執行引擎進行互動(例如在函式呼叫後詢問該函式的返回值對應的符號值,該函式的原型如引數個數,引數型別,返回值型別等)。由於CSA本身提供了大量的api介面,開發者可在不同位置的hook接入,並利用這些介面得到大量有用的資訊,進而可以分析和發現潛在的安全問題。
為了幫助大家更好地理解基於CSA的開發,我們 上海交通大學蜚語安全小組(G.O.S.S.I.P) 的程式安全分析研究員 王健強 實現了三個基於CSA的原始碼符號執行漏洞檢測外掛原型(我們將其命名為 TripleDoggy ^_^):
1. NewDereferenceChecker ,用於檢測空指標解引用漏洞。
2. DoubleFreeChecker ,用於檢測doublefree,use-after-free,memroy leak漏洞。
3. OverflowChecker ,用於檢測整形溢位漏洞
感興趣的研究人員可以通過訪問我們的Github頁面( GoSSIP-SJTU/TripleDoggy )獲取相關原始碼,同時也歡迎大家與我們聯絡(email loccs at sjtu dot edu do cn ),一起交流開發更好的功能。
下面我們對這三個外掛原型的實現做一些簡單的介紹,具體的程式碼實現請查考Github上公佈的程式碼內容
0x01 NewDereferenceChecker
CSA本身之前其實已經包含了一個prototype DereferenceChecker(空指標解引用)外掛,但是該外掛效果較差,為此我們設計了自己新的NewDereferenceChecker。
我們的設計思路比較簡單:首先我們收集了一些在2017年評分高於7.5的CVE,並手工確認後得出一個結論,絕大部分的空指標解引用bug來源於未對記憶體分配函式的返回值作校驗。於是我們提出的檢測思路是:
1. 識別所有的記憶體分配函式。
2. 獲得所有的記憶體分配函式與new操作符的返回值並加入集合A。
3. 在地址被訪問或者被寫入時插入hook函式
4. 檢檢視被訪問的地址指向的記憶體區是否是A中任何一個地址指向記憶體的子記憶體,如是則對該地址進行約束求解,如果為0則報告空指標解引用錯誤。
我們在8個CVE上進行測試,並獲得87%的檢測成功率,對於每個CVE檔案平均產生6個warning,我們甚至找到一個由於不正確初始化導致的空指標解引用bug,目前還未被公開報道。對於一個未被檢測出來的CVE,我們手工除錯了該過程,發現導致該錯誤的原因為符號執行的路徑爆炸。


這裡我們的外掛還有一些有待改進的地方:
1. 記憶體分配函式檢測準確率不高。
2. 檢測模式單一,對於一些並非記憶體分配函式返回空指標的情況沒有考慮到。
接下來,我們會嘗試使用自然語言理解(NLP)對函式名進行解析從而更加準確的認識記憶體分配函式。
0x02 DoubleFreeChecker
Double free漏洞的成因顧名思義,就是指一塊記憶體被重複的釋放兩次以上。Clang static analyzer中的自己實現的檢測演算法為通過hook對應的記憶體分配釋放函式來記錄一塊記憶體的狀態,當發現有釋放同一塊記憶體的操作時,報告漏洞。然而在實際使用的原始檔中,情況要比描述的複雜,主要由以下兩個情況導致:
1. 記憶體分配釋放函式為該庫自己實現或者經過封裝後的標準庫函式,僅僅使用標準庫函式名稱匹配並不能準確的識別所有的記憶體分配釋放函式。
2. 某塊記憶體可能是經過外部函式分配後,通過引數傳入到該C檔案中的某個頂層函式中,因此不能捕獲到該塊記憶體的形成位置,從而不能記錄該記憶體的狀態。
基於以上兩點,我們提出的double free、記憶體洩漏及USE AFTER FREE的分析方法為:
- 基於此前我們使用的啟發式的記憶體分配函式的識別方法識別出記憶體分配函式和釋放函式。定義兩個集合,分別為已經分配未釋放的記憶體集合A,已釋放的記憶體集合B。
- 通過符號執行,分析遇到記憶體分配函式時將該記憶體記錄到A中,分析遇到釋放函式時,將該塊記憶體記錄到B集合中並且刪除A中對應的記憶體(如果存在的話),再次遇到對該塊記憶體的釋放操作時報告漏洞。
- 在符號dead時檢測是否存在A集合中的元素,存在則報告記憶體洩漏。在訪問記憶體資料 時,檢測所在記憶體是否在B集合中,在則報告UAF漏洞。


0x03 OverflowChecker
Integer Overflow的漏洞檢測較為複雜,導致該種漏洞複雜的原因在於:
1. 算術運算溢位不一定導致溢位漏洞,即該程式所需要的即為溢位後的結果。
2. 原始碼中新增的檢測程式碼通常位於算術運算結果之後,因此不能在算術運算處報告漏洞,否則產生誤報。
3. 整型溢位型別多樣,包含無符號溢位有符號溢位,不同位數的溢位。
我們提出的Integer Overflow檢測方法基於汙點分析(Taint Analysis)技術,具體的分析方法如下:
1. 在top frame函式的開始處,將全域性變數,輸入引數標記為汙點源,並在接下來的分析中,將標準輸入函式的輸入資料和未被定義的函式的返回值,指標形引數標記為汙點源。
2. 在進行算術運算(目前定義為加法,減法,乘法)時,檢查左值或者右值是否被汙染,如果其中一個值被汙染,則根據運算的值的型別檢查算術運算結果是否溢位,如果溢位則將運算結果的符號值及產生溢位的條件記錄下來。
3. 符號執行行至陣列索引訪問操作或者記憶體分配函式時,檢測引數(陣列索引 ,記憶體分配函式的整形引數)是否包含在記錄中,如果存在,則將該溢位條件取出,再次檢查該條件是否滿足,如果滿足則報告溢位漏洞。


總結
利用CSA框架可以開展許多有趣的原始碼分析,CSA本身基於Clang前端的強大程式碼分析處理能力,對現有程式碼的支援相當完善,這也是其主要的優勢之一。接下來我們將嘗試使用CSA框架來檢測密碼學庫中的一些經典的密碼學誤用,這是一個很有意思的方向。另外 ,對於TripleDoggy專案中的三個checker,其實現尚有許多不足之處,我們也會陸續進行完善改進(例如由於符號執行原生的缺陷,即路徑爆炸和約束求解效能差等還有待繼續探索)。歡迎有興趣的研究人員同我們一起合作,也歡迎有興趣的同學加入我們 上海交通大學蜚語安全小組(G.O.S.S.I.P) 參與這項研究工作!