AFL--模糊測試使用淺析

合天網安實驗室 發佈 2022-05-31T12:57:06.445259+00:00

Zalewski開發的一款基於覆蓋引導的模糊測試工具,它通過記錄輸入樣本的代碼覆蓋率,從而調整輸入樣本以提高覆蓋率,增加發現漏洞的概率。

一、AFL簡介

AFL(American Fuzzy Lop)是由安全研究員Micha? Zalewski(@lcamtuf)開發的一款基於覆蓋引導(Coverage-guided)的模糊測試工具,它通過記錄輸入樣本的代碼覆蓋率,從而調整輸入樣本以提高覆蓋率,增加發現漏洞的概率。

①從源碼編譯程序時進行插樁,以記錄代碼覆蓋率(Code Coverage);②選擇一些輸入文件,作為初始測試集加入輸入隊列(queue);③將隊列中的文件按一定的策略進行「突變」;④如果經過變異文件更新了覆蓋範圍,則將其保留添加到隊列中; ⑤上述過程會一直循環進行,期間觸發了crash的文件會被記錄下來。

【——全網最全的網絡安全學習資料包分享給愛學習的你,關注我,私信回復「領取」獲取——】

1.網絡安全多個方向學習路線

2.全網最全的CTF入門學習資料

3.一線大佬實戰經驗分享筆記

4.網安大廠面試題合集

5.紅藍對抗實戰技術秘籍

6.網絡安全基礎入門、Linux、web安全、滲透測試方面視頻


二、AFL安裝、測試

*1.安裝AFL*

下載源碼

Make

llvm_mode安裝

之後輸入以下命令進行安裝

*2.AFL測試*

下載一個有缺陷的c文件

使用 afl-gcc/afl-clang 編譯

生成一些種子語料庫

開始fuzz

提示修改/proc/sys/kernel/core_pattern

再次運行之前的代碼可看到fuzz進度

現在就表示我們的ACL已經安裝成功了,注意出現(odd,check syntax!)是表示樣例根本沒有進入到測試中去,需要調整語料庫。

Ctrl+C打斷可以在out文件里看見我們的測試信息

*3.並行fuzz測試*

每個afl-fuzz進程占用CPU的一個核,實際上如果是多核的主機,AFL就可以並行工作

首先先看自己有多少內核

以上可以看出有四個內核意味著可以同時運行4個實例

首先指定主實例 -M 用於主實例,將 -S 添加到所有從屬實例。它們可以相互同步

主實例:afl-fuzz -M master -i in/ -o out/ -m none -- ./imgRead_afl @@

從實例:afl-fuzz -S slave1 -i in/ -o out/ -m none -- ./imgRead_afl @@

在之前的out文件夾會多出倆個不同的文件夾masterh和slave1

現在嘗試假如我們一次性運行5個實例會怎麼樣

在運行第5個實例後報錯,其他實例不受影響,也可以確定4個核在運行中

三、AFL模糊測試libjpeg-turbo

libjpeg是專門處理Jpeg解碼、編碼、轉碼的自由軟體庫。libjpeg-turbo是其fork版本,還有一個基於libjpeg-turbo的fork的版本是MozJpeg。

*1.編譯libjpeg-turbo*

首先下載libjpeg-turbo

之後需要修改cmakelist.txt,進行插樁編譯

在cmakelist.txt中,在cmake_minimum_required命令下添加編譯器選項,在前面添加,免得被覆蓋,進行插樁編譯


之後在libjpeg-turbo文件夾下

mkdir build

cd build

cmake ..

make

sudo make install

安裝好之後build的內容如下


之後利用程序的示例對是否成功安裝libjpeg-turbo庫進行測試

該函數有倆個參數 一個輸入文件名,一個作為輸出文件名

具體作用就是調用了turbojpeg.h這個庫函數對輸入的jpg圖片進行壓縮

因為修改了cmake中的編譯器設置,應該庫函數裡已經是被插過樁的,所以在編譯時是可以不用afl-gcc編譯也可以進行檢測

這樣是可以生成可執行文件,也可以實現壓縮圖片的功能,這裡也對之前的樣例進行了修改,只接收一個變量,並且不對壓縮文件進行保存

但在進行模糊測試時出現以下問題

沒有插樁信息,無法進行測試

發現它是動態編譯的,雖然應該其動態連結庫是插過樁的。但最後已知沒有實現。這裡最後考慮是想通過連結靜態庫實現。也是在網上查詢未果後,發現在根目錄下輸入 make test,可以調用他自己的樣例進行測試,這其中就包括了靜態連結的測試

在一個靜態連結測試的項目下,查看其ling.txt,得到靜態編譯的方式

最後對自己的編譯自己的樣例

之後開始模糊測試

總共測試次數超過1億次,開了4個並行

4個樣例的的最開始輸入都是不一樣的,可以從路徑速度和總量上看出明顯的區別,確實libjpeg-turbo在更新2.0之後,其安全性能得到了極大的提升,沒有收到一個報錯信息。

*2.內存錯誤檢查工具*

這裡有很多的內存檢查工具,這裡舉個大概,只大概研究ASAN (-fsanitize=address)的使用和與AFL測試的結合

這裡測試了幾個漏洞文件以此來明晰ASAN的作用

編譯文件模板如下

g++ -fsanitize=address -fno-omit-frame-pointer -o t xxx.cpp

這裡只對幾種漏洞進行展示

use-after-fee

可以看到漏洞的名稱和發生的內存地址

stack buffer overflow


還有很多其他類型的漏洞可以進行檢測

Address Sanitizer 用法 - 簡書 (jianshu.com)

https://www.jianshu.com/p/3a2df9b7c353

在AFL中啟用ASAN的方式也比較簡單

在make時加上AFL_USE_ASAN=1

注意之後編譯文件時需要加上啟用asan的參數,不然會報錯


*3.構造自己的字典*

AFL自帶自己的一個字典庫,主要用於各種變異操作的

如下是AFL的jpeg的字典

為了符合jpeg圖片的實際,需要分析在jpeg中出現次數多且固定的字符

這裡挑選一些頻率較高的字符加入字典

這裡挑選的字符主要來源自各種jpeg的開頭部分

之後如果要使用字典需要使用-x參數進行指定字典文件

https://paper.seebug.org/496/#dictionary

*4.語料庫蒸餾*

afl-cmin的核心思想是:嘗試找到與語料庫全集具有相同覆蓋範圍的最小子集。舉個例子,假設有多個文件,都覆蓋了相同的代碼,那麼就丟掉多餘的文件。

最後只留下一個文件

afl-tmin(減小單個輸入文件的大小)

afl-tmin有兩種工作模式,

instrumented mode和crash mode。默認的工作方式是instrumented mode

後面查資料得到tmin只能處理文件,文件夾需要修改腳本

精簡到0bytes,後面在網上看到了相似的例子,這和tmin的精簡策略有關,確實存在這種情況。

如果加上了參數-x,就會調用crash mode模式,會把導致程序非正常退出的文件直接剔除。這裡測試的樣例並沒有crash例子,所以不進行測試。

*5.持久模式*

在持久模式下,AFL 僅模糊部分程序,而不是整個程序。當只想模糊複雜軟體中的特定功能時,這很有用。與分叉伺服器模式相比,這提供了許多速度改進。

具體例子如下:

對想要進行的部分進行修改

此時修改的文件是turbojpeg.c

再修改cmakelist.txt如下

之後對庫進行重新編譯

編譯方式

再進行afl-fuzz(與之前一致)

速度上確實比之前的速度要快,最快時比之前要快上倆倍多

*6.Afl-cov使用*

可以快速幫助我們調用lcov和gcov處理來自afl-fuzz測試用例的代碼覆蓋率結果

安裝

GCOV,它隨gcc一起發布,所以不需要再單獨安裝,和afl-gcc插樁編譯的原理一樣,gcc編譯時生成插樁的程序,用於在執行時生成代碼覆蓋率信息

LCOV,它是GCOV的圖形前端,可以收集多個源文件的gcov數據,並創建包含使用覆蓋率信息注釋的原始碼HTML頁面。

這裡也可以使用apt-install afl-cov來安裝,不過看網上建議這個版本實際使用上會有問題,所以這裡還是直接下載源碼

為了實現檢查覆蓋率需要修改cmakelist.txt如下

再次編譯庫

編譯文件

這裡的afl-cov選擇實時監控 也就是添加--live,先啟動afl-cov,後啟動afl-fuzz,當afl-fuzz退出時,afl-cov就會跟著退出

啟動afl-cov的命令

/home/user/Desktop/afl-cov/afl-cov -d afl-cc --live --enable-branch-coverage -c . -e "cat AFL_FILE | ./ttt AFL_FILE" --overwrite

-d是之後afl-fuzz的輸出文件,-c是直向源碼文件的,在編譯.c文件後,會生成一個.gno文件,-c 後面跟該文件的目錄

啟動afl-fuzz(與之前一致)

Afl-fuzz退出後,afl-cov需要等一會才能正常退出,此時就可以看見生成分析的網頁了

也可以針對已經生成的數據直接開啟afl-cov,但要求編譯已經加上了-fprofile-arcs -ftest-coverage

網頁首頁

也可以進入到文件里,查看具體語句的執行次數


*7.afl_postprocess使用*

它最主要的作用就是可以規定生成種子的格式

作者在github上的樣例的作用是讓每個測試用例開頭的標頭都是

GIF89ahttps://github.com/mirrorer/afl/blob/master/experimental/post_library/post_library.so.c

編譯方法

gcc -shared -wall -O3 post_library.so.c -o post_library.so

可以看看afl-fuzz.c對該方法的支持

獲取AFL_POST_LIBRARY環境變量的值,自動加載afl_postprocess函數

這裡推薦使用export設定環境變量,需要說明的是export的環境變量只在當前的shell(BASH)或其子shell(BASH)下是有效的,shell關閉了,變量也就失效了,再打開新shell時就沒有這個變量,需要使用的話還需要重新定義。如果需要一直使用,需要修改配置文件,方法推薦

https://blog.csdn.net/wx_it/article/details/118450790

加載後處理器庫成功

也可以看到我們的測試樣例變成了GIF格式,後處理庫有效。

測試其他的例子

這部分需要注意的是對源碼的處理,確保樣例格式的滿足輸入的要求

參考資料

Fuzzing open source softwares with AFL

AFL 漏洞挖掘技術漫談(一):用 AFL 開始你的第一次 Fuzzing

AFL 漏洞挖掘技術漫談(二):Fuzz 結果分析和代碼覆蓋率

Fuzzing software: common challenges and potential solutions (Part 1)

Fuzzing software: advanced tricks (Part 2)

AFL 源碼分析

實操推薦:Fuzz之AFL

測試用例來探索二進位程序內部新的執行路徑。通過該實驗了解AFL的使用方法,能夠通過AFL模糊測試一些簡單的軟體,明白fuzz的基本方法和思想。

關鍵字: