使用Afl-fuzz (American Fuzzy Lop) 進行fuzzing測試(二)——詳細使用說明(README.txt)

來源:互聯網
上載者:User

不完全譯自:http://lcamtuf.coredump.cx/afl/README.txt
轉載請註明出處。

隨手翻譯的筆記,還有待繼續整理。 AFL演算法

1) 把使用者提供的初始測試案例載入到隊列(queue)中;
2) 從隊列中擷取下一個測試輸入檔案;
3) 在保持程式行為的前提下,嘗試修剪(trim)測試案例(體積)到最小;
4) 使用傳統的模糊測試策略中的各種已有的研究方法,重複變異檔案;
5) 如果產生的變異結果能夠驅動新的狀態轉換(通過插樁記錄),則把這一測試案例加入到隊列中;
6) 調到第2步。

已經發現的測試案例也會周期性地被新的、能驅動更高程式碼涵蓋範圍的測試案例替代,或者使用若干其他插樁層驅動的最小化的措施刪除。

作為模糊測試步驟的副作用(side effect),工具產生比較小的,自足的測試案例語料。這些是非常有用的。

因為以上的措施,使得AFL能比盲fuzz或者只有程式碼涵蓋範圍驅動的工具具有更好地效能。 使用AFL對程式插樁

在有被測試程式源碼的前提下,可以直接使用AFL替代gcc或者clang作為編譯器,AFL的插樁具有非常低的效能影響。加上其他的afl-fuzz效能最佳化措施,大部分程式能被快速fuzzed,甚至會比傳統的工具更快。

重新編譯目標程式的配置可能會因不同程式而不同,但通用的步驟是:

$ CC=/path/to/afl/afl-gcc ./configure$ make clean all

對C++程式,設定為CXX=/path/to/afl/afl-g++

對clang編譯的程式,可以用同樣的方式設定,如afl-clang和afl-clang++。clang使用者同樣可以選擇利用llvm_mode/README.llvm提到的高效能的插樁模式。

當測試lib庫的時候,需要找到或者寫入簡單程式,從stdin或者從檔案讀取資料,傳入到被測試的lib庫中。所以,以把被插樁的lib庫以靜態方式串連到可執行檔顯得至關重要。或者確保正確的.so檔案在程式運行時載入(通過LD_LIBRARY_PATH)。最簡單的選擇是使用靜態編譯,通常採用以下方式:

$ CC=/path/to/afl/afl-gcc ./configure --disable-shared

在使用make命令時設定AFL_HARDEN=1的時候,可以促使CC自動化代碼加固選項,使得檢測簡單的記憶體bug更加容易。Libdislocator是一個AFL提供的協助者lib(具體詳見libdislocator/README.dislocator),能協助發現堆崩潰問題。 對二進位程式插樁

在沒有原始碼的時候,可以使用QUMU中的“user space emulation”模式對二進位進行插樁。具體操作:

$ cd qemu_mode$ ./build_qemu_support.sh

關於QEMU插樁的說明及注意事項,可以參見qemu_mode/README.qemu 選擇初始測試案例

為了正常操作,fuzzer要求一個或多個包含測試輸入資料的好的初始檔案,有兩個基本規則:
1) 減小檔案的大小。低於1kB的檔案是比較理想的,雖然並沒有嚴格要求。至於為什麼初始檔案大小會影響測試效果,詳見perf_tips.txt;
2) 只有在每個測試案例都能驅動程式中的不同功能的情況下才有必要使用多個測試案例。在AFL中使用50個不同的圖片fuzz圖片處理類lib庫並沒有什麼意義。

可以在本工具的testcases/目錄下找到非常多好的測試案例作為初始種子檔案。

如果有比較大的資料語料庫,可以使用afl-cmin工具鑒別功能不同(驅動程式走不同的代碼路徑)的子集檔案,即最小集處理。 對二進位進行模糊測試

使用afl-fuzz工具對目標二進位程式進行fuzz。在運行前,需要唯讀許可權的包含初始測試案例的目錄,分開的目錄用於存放測試過程中的findings,以及被測試二進位程式的路徑。

對直接從stdin中接收輸入的目標二進位程式,常用的文法為

$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program [...params...]

其中params被測試程式接受的命令列參數。

如果從檔案中讀取輸入,則在命令列中使用@@標記,在實際執行的時候afl-fuzz會把“@@”替換成測試樣本目錄(testcase_dir )下的測試樣本。對應的命令為:

$ ./afl-fuzz -i testcase_dir -o findings_dir /path/to/program @@

可以使用-f參數,把已經變異過的資料寫入特定的檔案。這對需要指定特定副檔名的需求特別有用。

沒有插樁過得二進位能被QEMU模式fuzz(在命令列中添加-Q參數),或者以傳統的盲fuzz的模式測試(以-n參數指定)。
可以使用-t和-m改寫程式執行過程中預設的timeout和memory limit。但有這種需求的情況比較少見(包括在編譯器和視頻轉碼器等)。

關於最佳化fuzzing效能的一些措施詳見perf_tips.txt

afl-fuzz從數組fuzz開始,可能會需要幾天的時間。但會產生比較整潔的測試案例。如果短時間內想要迅速和比較髒的結果,可以使用zzuf和其他傳統的模糊測試工具(添加-d參數)。 輸出解釋

從status_screen.txt中可以找到顯式介面中各欄位的含義,以及監控被測試程式的健康狀態。在介面中如果出現任何欄位被紅色高亮顯式,可以查閱此檔案確認情況。

fuzzing進程會一直持續知道使用者按下Ctrl-C,即使想要fuzzer完成一個隊列周期的測試,也可能會需要幾小時到一周的時間。
在輸出目錄中有三個子目錄,分別是:

-queue/ 每一條不同的執行路徑對應的測試案例,包括所有由使用者提供的初始化測試案例檔案。這是之前提到的綜合語料庫。在使用這些語料到任意程式之前,可以使用afl-cmin工具對其大小進行緊縮。這一工具將尋找更小的測試集檔案(保持相同的代碼、邊覆蓋)。

-crashes/ 能導致被測試程式獲得致命訊號(fatal signal)(如SIGSEGV, SIGILL, SIGABRT等)的唯一性的測試案例。

-hangs/ 能導致被測試程式逾時的唯一性測試案例。預設的時間限制。執行時間限制超過預設的1秒或者以-t參數設定的數值之後,改測試案例就會被記錄在這個檔案夾下。這些值也可以使用AFL_HANG_TMOUT設定,但通常很少會有這樣的需求。

如果相關的執行路徑包含的任意狀態轉換並沒有包含在之前記錄的錯誤相關的記錄中,則crashes和hangs被當做是唯一的(unique)。如果單一的bug能通過多重路徑觸發,則count計算會臨時有所膨脹,但會在後續的操作中逐漸層少。

crashes和hangs的檔案名稱和父節點以及沒出錯的隊列節點相關。這樣能協助調試。

當不能使用afl-fuzz重現crash的時候,最有可能的原因是沒有設定相同的記憶體限制。可以嘗試以下命令:

$ LIMIT_MB=50$ ( ulimit -Sv $[LIMIT_MB << 10]; /path/to/tested_binary ... )

在以上命令中,更改LIMIT_MB參數與-m參數相匹配。

任何已經存在的output目錄對應的工作能被重新恢複:

$ ./afl-fuzz -i- -o existing_output_dir [...etc...]

如果安裝了gnuplot,可以使用afl-plot為正在fuzzing的程式產生一些漂亮的圖片,詳見http://lcamtuf.coredump.cx/afl/plot/. 並行模糊測試

每個afl-fuzz執行個體只佔用一個cpu的核。這對使得在多核系統中使用並行化來來增加對硬體的利用率顯得很重要。
並行Fuzzing模式同時還提供簡單的方式的介面給其他的測試載入器,包括符號執行工具。具體詳見parallel_fuzzing.txt 測試字典(fuzzing dictionaries)

預設情況下,AFL更適合對緊湊資料格式的fuzzing,包括映像、多媒體、壓縮資料、Regex文法,或者shell指令碼等;對一些格式繁瑣、冗餘的資料,如HTML,SQL和JavaScript等,支援並不好。

為了避免構建文法敏感型的工具所帶來的麻煩,afl-fuzz提供了一種方式可以對語言關鍵字、magic headers或者其他特殊的符號和目標資料類型相關的符號。可選擇字典的fuzzing進程。使用上面這種方式重建潛在的文法,目前正在開發中。詳見:
http://lcamtuf.blogspot.com/2015/01/afl-fuzz-making-up-grammar-with.html

如果要使用以上的特性,首先需要為dictionaries/README.dictionaries中說明的一種或兩種格式建立一個字典,然後在命令中以-x參數選項指定。(一些通用的字典已經在子目錄下提供)。

對潛在的文法(syntax),afl-fuzz並沒有辦法提供更加複雜的描述,但fuzzer將可能通過插樁層的反饋解決部分問題。詳見:
http://lcamtuf.blogspot.com/2015/04/finding-bugs-in-sqlite-easy-way.html

另外,即使在沒有詳細字典提供的情況下,afl-fuzz將嘗試通過觀察插樁的形式從輸入語料中抽取已有的文法標識。這些工作對一些類型的解析和文法有效,但效果不如上面提到的-x參數指定的模式。

如果字典非常難得到,另一個選擇是讓AFL先運行一段時間,然後使用標識(token)捕獲作為AFL工具的庫。具體詳見libtokencap/README.tokencap 崩潰分類(Crash triage)

基於程式碼涵蓋範圍的崩潰分類常常能產生小的資料集,能被快速手動分類,或者使用簡單的GDB或Valgrind指令碼分類。每個crash還是對其在隊列中相應的非崩潰測試案例可追蹤的,這樣能更容易診斷錯誤。

一些fuzzing出來的crash很難被快速評估其可利用性,而需要大量的調試和程式碼分析工作。為了協助解決這一問題,afl-fuzz支援以比較獨創的“crash exploration”模式,具體在命令中以-C參數指定。

在這種模式下,fuzzer採用一個或多個崩潰測試案例作為輸入,然後使用反饋驅動的fuzzing策略,快速枚舉所有能達到崩潰點的代碼路徑。

對編譯中產生的不會導致崩潰的樣本將被丟棄,同時,沒有觸發新路徑的測試輸入也同樣會被丟棄。
輸出是包含崩潰樣本的小的語料庫(corpus),這些能被快速檢查通過崩潰點能多大程度上被控制,或者是否可能通過越界讀,查看其它記憶體中的資訊。

對測試集最小化,仍然可以使用afl-tmin工具:

$ ./afl-tmin -i test_case -o minimized_result -- /path/to/program [...]

這一工具對崩潰樣本集和普通樣本集同樣適用,在崩潰模式下,將接收以插樁和非插樁二進位的形式。在非崩潰模式,最小化處理依賴於標準的AFL插樁,這使得在沒有更改執行路徑的前提下讓檔案變的更簡單。
另一項最近添加到AFL的功能是afl-analyze工具。這一工具在有測試輸入的情況下,驅動程式執行,嘗試連續地改變位元組,然後觀察被測試程式的行為。然後對比較重要(critical)的節區(sections)的代碼標註顏色,這樣通常能快速查看複雜檔案格式。更多詳情移步:technical_details.txt

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.