Fuzzing初學者指南:教你如何使用zzuf(一)
模糊測試(Fuzzing),是一種通過向目標系統提供非預期的輸入并監視異常結果來發現軟件漏洞的方法,通常情況下我們會使用一個有效的輸入和添加隨機誤差來完成。在今天,很多軟件項目潛在的漏洞都可以使用模糊測試檢測出來。而我寫這篇教程的目的就是希望去告訴大家模糊測試是非常簡單的,并且希望模糊測試可以在多數項目中成為不可或缺的一部分。
如何進行模糊測試
首先我們需要生成一些輸入樣本,建議這里選擇一些小文件來進行模糊測試。在這里我們可以創建一個任意格式的小圖片文件,比如3*3的PNG文件,命名為“example.PNG”.現在我們嘗試將其轉換為其他格式,使用 ImageMagick即可(本次教程中我將以 ImageMagick 為例,這是一個命令行工具,它能夠轉換圖像文件的格式):
convert example.png example.gif convert example.png example.xwd convert example.png example.tga
盡可能多的去轉換成你喜歡的格式(-list可以顯示出所有支持的格式)。然后我們需要生成這些example的畸形樣本。
這時我們可以使用工具zzuf,這是一款簡單的模糊測試工具,并且在大多數Linux環境下可用。Zzuf有很多不同的使用方法,但在這里我們只需要讓它從我們的example中創建出大量的畸形文件。可以用一個簡單的bash循環:
for i in {1000..3000}; do for f in example.*; do zzuf -r 0.01 -s $i < "$f" > "$i-$f"; done; done
每個example我都創建了大約2000個畸形文件,這里我都是以“[數字]-example.[擴展名]”的形式進行命名的。
在zzuf中,參數-r可以改變你想要的數量,0.01意味著1%的文件會被隨機改變。參數-s則是種子值,每一個不同的s值都會得到一個不同的輸出。當然,你可以換成其他數字試試,但經驗告訴我們2000是比較合適的。
接下來我們進行下一步:將ImageMagick的這些畸形文件輸入可執行文件從而使其被執行。而要做到這一點,我們只需要執行與這些文件相關的任意命令就好。這時我們仍然可以對其進行轉換,通過轉換來指導調整這些畸形圖片的大小,從而可以增加得到bug的機會。
這里我把輸出重定向到了一個日志文件上,稍后我們可以進行檢查:
LC_ALL=C;; for f in *-example.*; do timeout 3 convert -resize 2 "$f" /tmp/test.png; echo $f; done &> fuzzing.log
LC_ALL=C;可確保我們輸出的語言是英文。這樣做的目的是可以得到grep的錯誤信息,超時命令可以確保我們在單個文件花費太多時間及時停止。當然這樣可能會導致漏掉那些死循環的bug,在后面的教程中我會講解怎么解決這一問題。同時每個經過調用轉換的文件都需要輸出當前的文件名,因為這使得我們可以在問題出現時知道是哪個文件造成的。
當然這可能需要很長時間,因為很有可能你所使用的輸出文件會變得非常大,所以你還要確保有足夠的空間。
現在,我們可以檢查看下我們發現了什么? 嘗試在日志中尋找下Segmentation faults:
grep -C2 "Segmentation fault" fuzzing.log
這時如果我們發現任何崩潰,我們就會直接看到,并且能夠看到導致崩潰文件的文件名。
直接使用zzuf
上述的方法是通過有用的工具來進行許多文件格式的輸入,但這其實并不是最有效的。Zzuf本身能夠并行的處理任務,并且能夠檢測到正在掛起的測試軟件。因此,其實完全可以讓zzuf來運行你想要進行模糊測試的工具。
因此下面我們來使用另外一個軟件 objdump,這是一款調試可執行文件的工具。它是 binutils的一部分,其輸入應該為可調試文件。而在測試的時候,我們則需要使用 windows EXE 文件,你可以選擇從文件格式存檔中找一個無用的EXE文件。現在,我們在objdump上運行zzuf以及可執行文件。
zzuf -s 0:1000000 -c -C 0 -q -T 3 objdump -x win9x.exe
上圖中的-s表示需要去嘗試1000000種子值,而-c則意味著zzuf僅僅只需要對命令行中給出的文件進行模糊測試。這是很有必要的,因為這可以防止工具通過閱讀配置以及其他的來反饋錯誤信息。而他們也并不會真的模糊化我們的輸入。-C 0則意味著第一次發現崩潰后不用停止, -q 抑制了模糊測試命令的輸出, -T 3則是超時3秒的設定,如果我們陷入到一個無休止的循環中,zzuf是不會被掛起的。
這里你所看到的輸出時這樣的:
zzuf[s=215,r=0.004]: signal 11 (SIGSEGV)
這意味著zzuf發現了一段錯誤的參數 -s 215 and -r 0.004,現在我們重新創建有缺陷的文件:
zzuf -r 0.004 -s 215 < win9x.exe > crash.exe
分析和報告
現在我們已經有了一個由應用程序崩潰生成的模糊文件,我們可以將其發送給應用程序的作者,告訴他該應用程序存在大量問題,應該及時修復。
然后我們還可以借助一款名為 valgrind的工具做更多的分析,只需要在你崩潰的命令前運行valgrind -q命令即可(-q 可以抑制一些不必要的輸出)。
valgrind -q objdump -x crash.exe
它將會顯示如下輸出:
==22449== Process terminating with default action of signal 11 (SIGSEGV) ==22449== Access not within mapped region at address 0x7715FF3 ==22449== at 0x4E7FAC0: bfd_getl16 (libbfd.c:570) ==22449== by 0x4EE356D: pe_print_idata (peigen.c:1328) ==22449== by 0x4EE356D: _bfd_pe_print_private_bfd_data_common (peigen.c:2160) ==22449== by 0x4EDE1F8: pe_print_private_bfd_data (peicode.h:335) ==22449== by 0x408504: dump_bfd_private_header (objdump.c:2643) ==22449== by 0x408504: dump_bfd (objdump.c:3214) ==22449== by 0x408AA7: display_object_bfd (objdump.c:3313) ==22449== by 0x408AA7: display_any_bfd (objdump.c:3387) ==22449== by 0x40AB22: display_file (objdump.c:3408) ==22449== by 0x405249: main (objdump.c:3690)
我個人認為將問題報告給應用程序的開發者是一個非常好的想法,因為如果你所測試的軟件沒有啟用調試符號,你所能夠獲得的輸出中細節將會很少。如果你在模糊測試進行時對軟件進行編譯,那么你完全可以把 -ggdb 列到你的編譯器標志寄存器中,這樣可以確保你可以得到更多的調試信息。另外在編譯時禁用共享庫也是一個好主意,然后你就可以毫無顧忌的使用系統庫對你的程序進行模糊測試了。軟件的配置腳本將會以如下方式進行工作:
CFLAGS="-ggdb" CXXFLAGS="-ggdb" ./configure --disable-shared
以上就是本教程的第一部分,更多詳細的內容可以前往zzuf的官網查看。第二部分中,我將向大家介紹如何通過Address Sanitizer提高發現BUG的能力。
* 原文鏈接: fuzzing-project ,編譯:ch4nge,轉載請注明來自FreeBuf黑客與極客(FreeBuf.COM)