序言
Fuzzing101系列包含針對10 個真實目標的10個練習,在練習中一步一步學習Fuzzing技術的知識。
模糊測試(Fuzzing/Fuzz)是一種自動化軟件測試技術,它基於爲程序提供隨機或變異的輸入值並監視它的異常和崩潰。
AFL、libFuzzer 和 HonggFuzz 是現實世界應用中最多的三個模糊器,這三個都是覆蓋引導的進化模糊器(Coverage-guided evolutionary fuzzer)。其中
-
進化(evolutionary)是一種受進化算法啓發的元啓發式方法,它基本上包括通過使用選擇標準(例如覆蓋率)隨時間推移初始子集(種子)的進化和變異。
-
覆蓋引導(Coverage-guided)是指爲了增加發現新崩潰的機會,覆蓋引導的模糊器收集和比較不同輸入之間的代碼覆蓋率數據,並選擇那些導致新執行路徑的輸入。
在這個練習中,我們將fuzz Xpdf PDF 查看器。目的是在 XPDF 3.02 中找到 CVE-2019-13288 的崩潰/PoC。
CVE-2019-13288 是一個漏洞,它可能會通過精心製作的文件導致無限遞歸。由於程序中每個被調用的函數都會在棧上分配一個棧幀,如果一個函數被遞歸調用這麼多次,就會導致棧內存耗盡和程序崩潰。因此,遠程攻擊者可以利用它進行 DoS 攻擊。可以在以下鏈接中找到有關不受控制的遞歸漏洞的更多信息:https://cwe.mitre.org/data/definitions/674.html
你會學到什麼
完成本練習後,你將瞭解使用 AFL 進行 fuzz 的基礎,例如:
-
使用檢測編譯目標應用程序
-
運行模糊器(afl-fuzz)
-
使用調試器 (GDB) 對崩潰進行分類
環境
所有練習都在 Ubuntu 20.04.2 LTS 上進行了測試。 我強烈建議您使用相同的操作系統版本以避免不同的模糊測試結果,並在裸機硬件而不是虛擬機上運行 AFL,以獲得最佳性能。
否則,您可以在此處找到 Ubuntu 20.04.2 LTS 鏡像。用戶名爲 fuzz
/ fuzz
。
AFL 使用非確定性測試算法,因此兩個模糊測試會話永遠不會相同。我強烈建議設置一個固定的種子(-s 123
),這樣你的模糊測試結果將與本文的結果相似。
下載並構建目標
首先爲要進行模糊測試的項目創建一個新目錄:
cd $HOME
mkdir fuzzing_xpdf && cd fuzzing_xpdf/
爲了完全準備好環境,需要安裝一些額外的工具(make 和 gcc)
sudo apt install build-essential
下載 Xpdf 3.02:
wget https://dl.xpdfreader.com/old/xpdf-3.02.tar.gz
tar -xvzf xpdf-3.02.tar.gz
構建 Xpdf:
cd xpdf-3.02
sudo apt update && sudo apt install -y build-essential gcc
./configure --prefix="$HOME/fuzzing_xpdf/install/"
make
make install
下面對 Xpdf 進行測試,首先下載一些 PDF 示例:
cd $HOME/fuzzing_xpdf
mkdir pdf_examples && cd pdf_examples
wget https://github.com/mozilla/pdf.js-sample-files/raw/master/helloworld.pdf
wget http://www.africau.edu/images/default/sample.pdf
wget https://www.melbpc.org.au/wp-content/uploads/2017/10/small-example-pdf-file.pdf
使用以下命令測試 pdfinfo 二進制文件:
$HOME/fuzzing_xpdf/install/bin/pdfinfo -box -meta $HOME/fuzzing_xpdf/pdf_examples/helloworld.pdf
安裝 AFL++
我們將使用最新版本的 AFL++ fuzzer(https://github.com/AFLplusplus/AFLplusplus)
安裝依賴項
sudo apt-get update
sudo apt-get install -y build-essential python3-dev automake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools
sudo apt-get install -y lld-11 llvm-11 llvm-11-dev clang-11 || sudo apt-get install -y lld llvm llvm-dev clang
sudo apt-get install -y gcc-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-plugin-dev libstdc++-$(gcc --version|head -n1|sed 's/.* //'|sed 's/\..*//')-dev
構建 AFL++
cd $HOME
git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus
export LLVM_CONFIG="llvm-config-11"
make distrib
sudo make install
執行afl-fuzz
,查看是否安裝成功
認識 AFL++
AFL 是一個覆蓋引導的模糊器(coverage-guided fuzzer),這意味着它收集每個變異輸入的覆蓋信息,來發現新的執行路徑和潛在的錯誤。當源代碼可用時,AFL 可以使用插樁(instrumentation),在每個基本塊(函數、循環等)的開頭插入函數調用。
要爲我們的目標程序啓用檢測,我們需要使用 AFL 的編譯器編譯源代碼。
首先,我們要清理所有之前編譯的目標文件和可執行文件:
rm -r $HOME/fuzzing_xpdf/install
cd $HOME/fuzzing_xpdf/xpdf-3.02/
make clean
現在我們將使用 afl-clang-fast
編譯器構建 xpdf:
export LLVM_CONFIG="llvm-config-11"
CC=$HOME/AFLplusplus/afl-clang-fast CXX=$HOME/AFLplusplus/afl-clang-fast++ ./configure --prefix="$HOME/fuzzing_xpdf/install/"
make
make install
現在可以使用以下命令運行 fuzzer:
afl-fuzz -i $HOME/fuzzing_xpdf/pdf_examples/ -o $HOME/fuzzing_xpdf/out/ -s 123 -- $HOME/fuzzing_xpdf/install/bin/pdftotext @@ $HOME/fuzzing_xpdf/output
每個選項的簡要說明
-
-i
表示輸入示例的目錄 -
-o
表示 AFL + + 將存儲的變異文件的目錄 -
-s
表示要使用的靜態隨機種子 -
@@
是佔位符目標的命令行,AFL 將用每個輸入文件名替換
fuzzer將會對每個不同的輸入文件運行 $HOME/fuzzing_xpdf/install/bin/pdftotext <input-file-name> $HOME/fuzzing_xpdf/output
命令
出現錯誤,根據提示,執行以下操作:
sudo su
echo core >/proc/sys/kernel/core_pattern
exit
成功運行,等待一段時間後,發現已經有了一個crash
可以在$HOME/fuzzing_xpdf/out/
目錄中找到這些崩潰文件。一旦發現第一次崩潰,就可以停止fuzzer,上圖中已經出現了一個獨特的崩潰。根據您的機器性能,最多可能需要一到兩個小時才能發生崩潰。
爲了完成這個練習,下面嘗試使用指定的文件重現崩潰,調試崩潰發現問題,並且修復問題。
重現崩潰
在$HOME/fuzzing_xpdf/out/
目錄下找到 crash 對應的文件。文件名類似於id:000000,sig:11,src:000390,time:103613,execs:71732,op:havoc,rep:16
將此文件作爲輸入傳遞給 pdftotext
$HOME/fuzzing_xpdf/install/bin/pdftotext '/home/fuzz/fuzzing_xpdf/out/default/crashes/<your_filename>' $HOME/fuzzing_xpdf/output
它將導致段錯誤segmentation fault並導致程序崩潰。
調試
使用 gdb 找出程序因該輸入而崩潰的原因。
首先使用調試信息重建 Xpdf 來獲得符號堆棧跟蹤:
rm -r $HOME/fuzzing_xpdf/install
cd $HOME/fuzzing_xpdf/xpdf-3.02/
make clean
CFLAGS="-g -O0" CXXFLAGS="-g -O0" ./configure --prefix="$HOME/fuzzing_xpdf/install/"
make
make install
然後使用GDB,輸入run
gdb --args $HOME/fuzzing_xpdf/install/bin/pdftotext $HOME/fuzzing_xpdf/out/default/crashes/<your_filename> $HOME/fuzzing_xpdf/output
然後輸入bt
回溯查看棧幀
發現有許多次Parser::getObj
的調用,它們似乎表示一個無限遞歸。如果你去 https://www.cvedetails.com/cve/cve-2019-13288/ ,你可以看到描述符合我們從 GDB 得到的回溯。
實驗推薦
實驗:Fuzz之AFL(合天網安實驗室) 點擊進入實操>>
更多靶場實驗練習、網安學習資料,請點擊這裏>>