當前位置:
首頁 > 新聞 > 一款更快的 libFuzzer:libFuzzer-gv

一款更快的 libFuzzer:libFuzzer-gv

最近 ,我花費了一些時間去了解並研究了libFuzzer以及其技術。目前針對其我已經提出了一些相關補充,我預計這將大大提升我找到案例的時間。

首先我對Micha?Zalewski和libFuzzer背後的研究人員以及各種對Sanitizers 所做的工作表示讚賞。模擬器可以附加到任意軟體從而能夠提升發現影響數百萬設備的世界級漏洞的方便性,這一點在我看來應該與技術基礎一樣值得稱讚。毫無疑問這是一項站在巨人肩膀上的工作。

你可以在這裡找到我的fuzzer:https://github.com/guidovranken/libfuzzer-gv

請記住,這些功能都是非常具有實驗性質的。當然我非常鼓勵libFuzzer和其他fuzzer的開發人員將這些功能合并到他們的工作中,如果他們喜歡這些的話。

代碼覆蓋只是改變fuzzer的一種方式

代碼覆蓋率是像libFuzzer這樣的fuzzing程序用來增加找到導致錯誤的代碼路徑的可能性的主要指標。但代碼執行的確切過程由許多因素決定。這些因素並不僅僅由代碼覆蓋率指標來解釋。所以我實現了一些額外的程序狀態信號器,可以幫助快速發現錯誤的代碼。沒有這些的話就只有在很長時間的fuzzing之後才會發現某些錯誤。

在輸入中給出足夠的0xAA,由於堆棧溢出(遞歸太深),程序將崩潰。使用-stack_depth_guided = 1 -use_value_profile = 1,我的系統通常需要大約0.5 - 5秒鐘才能崩潰。

(是的,這個具體的實現只適用於x86-64,如果它不適合你,請注釋或修改它以適應你的架構。)

如果您需要一個超過某一堆棧深度的fuzzer輸入作為文件,則可以在運行fuzzer之前,使用ulimit -s來降低堆棧大小。它會崩潰並且libFuzzer會將fuzzer輸入寫入磁碟。

我認為由於過度遞歸而導致的崩潰是一種不足的漏洞。對於伺服器應用程序而言,不可信任的客戶端可以在伺服器上執行堆棧溢出這一點很重要。這一類的漏洞相對較少,但是我確實設法在一個知名度較高的軟體(Apache httpd CVE-2015-0228)中找到一個遠程的,未經身份驗證的crasher。

有很多解析與上下文無關語法的應用程序,比如編程語言(一個表達式可以包含一個表達式,該表達式再包含一個表達式..)、序列化格式(JSON:數組可以包含一個數組,該數組再包含一個數組..)

從理論上來講這是容易的。

PS:您可以使用我的工具來查找二進位文件中的調用圖循環。

改變fuzzing的強度

此功能可量化在單次運行中擊中檢測位置的數量。訪問非唯一位置的總和。因此,如果1次迭代的某個循環導致覆蓋回調被調用5次,則5次迭代的相同循環導致總和值為5 * 5 = 25。

這樣就能很好的去找慢輸入了。

改變fuzzing的分配

在輸入中給出足夠的0xAA,程序將執行-1位元組的分配。AddressSanitizer完全不能容忍這一點,所以這裡會導致它崩潰。

我比較期望這個功能可以有助於找到某些閾值限制的問題。例如,一個應用程序如果涉及的東西少於8192個元素,那麼它會運行正常。而一旦超出該閾值,它就會採用不同的錯誤邏輯(可能是使用realloc())。該功能可以引導fuzzers指向該核心。

除了發現崩潰之外,該功能還能夠深入了解應用程序的最高內存使用情況,並且根據堆使用情況自動找到最壞情況的輸入(因為fuzzing由malloc()引導)。如果您發現一個輸入可以導致伺服器應用程序預留50MB內存,而正常請求的平均內存使用量為100KB,那麼這個在傳統意義上可能不是漏洞的情況就會變成一個漏洞(儘管這可能是一個非常便宜的DoS機會),但它可能會使你考慮重構一些代碼。

改變fuzzing的慣例

libFuzzer希望LLVMFuzzerTestOneInput返回0,而如果返回其他內容,它就會停止下來。目前這一點還沒有被用於其他任何事情。所以我認為這裡我很好的通過使用-custom_guided = 1來利用了它。

現在你可以連接libFuzzer到任何東西了。我正在嘗試連接到LLVMFuzzerTestOneInput中的一個刪除伺服器,哈希這個伺服器返回的內容,並返回到目前為止生成的唯一哈希數。所以我實際上是fuzzing了一個遠程的,未測量的應用程序。

引導fuzzing禁用覆蓋

使用-no_coverage_guided = 1來引導fuzzing禁用覆蓋。這一點對於如果您想純粹依賴分配指導來說,會很有用。

技術的嘗試與拋卻

我試著用一個柱狀圖來展示mutator的功效。所以每當某個mutator(如EraseBytes,InsertBytes,...)負責增加代碼覆蓋率時,我會增加其柱狀圖的值。然後,當需要選擇下一個迭代的mutator時,我總是喜歡選擇最有效的mutator(但是也可以選擇較低效率的mutator,只有較小的可能性)。

在對類解釋時,我創建了一個lin-log查找表。對於5個變體,它看起來像這樣:

每次迭代,我都會對柱狀圖進行排序並保存索引的順序。所以柱狀圖如下所示:

然後,(反向)排序的索引序列為:

選擇一個新的mutator:

所以目前mutator 3是非常受青睞的(3/3的機會),但是仍然有1/5的機會選擇mutator 4。

不幸的是,這個努力是徒勞的,這似乎只是減緩了fuzzing而已。顯然,fuzzers需要進行不斷的開發多樣性才能達到新的覆蓋範圍。也或者是我一直在忽視某些東西,所以在你可以自由發表評論來和我進行探討。

我認為,嵌入堆棧深度指導和代碼強度指導的方法是在一次運行中保留應用程序命中的代碼位置數組,散列數組,並使用唯一散列數作為指導。不幸的是,這個數字對於幾乎每一個輸入都是遞增的,並且很快內存就會耗盡。也許一個不那麼細緻的覆蓋工具可以進行此工作。

fuzzing的秘訣

Sanitizers 和fuzzers是不同的技術。您可以在沒有Sanitizers 的情況下進行fuzzing(並且無需fuzzingSanitiz):將語料庫生成加速一個數量級 - >然後用Sanitizers 測試語料庫。

開發人員:您可以使用fuzzing來驗證應用程序邏輯。當你認為絕對不會失敗的assert() 失敗時,在通常列印調試消息的地方放入一個abort(),好了現在開始fuzzing。

有時優化和編譯器版本很重要。gcc + ASAN使用-O0檢測以下程序中的問題,但不能使用-O1及更高版本:int main()。clang沒有找到任何優化標誌。相反(與-O3崩潰,不與-O1崩潰)也可能發生。另外,依賴於特定的編譯器版本和標誌的安全性可能是向開放源代碼軟體提供後門代碼的好方法,因此如果我是一個壞人的話,我想我可能會這麼做。而維護者用自己的 clang -O2構建系統+回歸測試+fuzzing鑽機測試您的代碼仍然可能不會檢測到您的惡意代碼隱藏在明顯的地方,但儘管如此它仍然會被衍生進入一定百分比的二進位文件。

點擊展開全文

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 嘶吼RoarTalk 的精彩文章:

看著電影電腦怎麼就被黑了?給你技術細節分析
工具解析篇:高效利用JS載入.Net程序
國內研究人員發現GMR-2漏洞,可實時解密衛星電話通訊
超級間諜軟體SpyDealer:可同時監視40餘款安卓應用,包括微信、淘寶、百度網盤等
繞過AppLocker系列之MSBuild的利用

TAG:嘶吼RoarTalk |