AFL++初探-手把手Fuzz一個PDF解析器


CVE-2019-13288

目前漏洞在正式版本已經被修復,本文章僅供學習Fuzz過程,不存在漏洞利用的內容

這是一個pdf查看器的漏洞,可能通過精心制作的文件導致無限遞歸,由於程序中每個被調用的函數都會在棧上分配一個棧幀,如果一個函數被遞歸調用太多次,就會導致棧內存耗盡和程序崩潰。因此,遠程攻擊者可以利用它進行 DoS 攻擊。

練習目的

  • 使用檢測編譯目標應用程序
  • 運行Fuzzer (afl-fuzz)
  • 使用調試器 (GDB) 對崩潰進行分類

環境構建

環境使用Ubuntu 20.04.2 LTS,盡量在物理機進行Fuzz而不是虛擬機來獲取更多的性能(當然這只是性能方面,對Fuzz最終結果不會產生影響)

VMWare 鏡像下載地址:

UbuntuVMware.zip

此 VM 的用戶名/密碼是fuzz/ fuzz

下載並構建

首先為Fuzz目標創建一個新目錄:

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

結果如下:

安裝AFLplusplus

對於本實驗,使用最新版本的AFL++,GitHub鏈接如下:

GitHub - AFLplusplus/AFLplusplus: The fuzzer afl++ is afl with community patches, qemu 5.1 upgrade, collision-free coverage, enhanced laf-intel & redqueen, AFLfast++ power schedules, MOpt mutators, unicorn_mode, and a lot more!

  • 推薦本地安裝

    安裝依賴:

    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
    

    可能會出現qemu_mode、frida和unicorn安裝失敗的情況,多數原因是因為網絡,這幾個功能是用於二進制文件黑盒Fuzz,可以暫時先不用管,從源碼構建Fuzz不需要這幾個功能

  • 也可以使用docker構建,性能比較低:

    安裝docker:

    sudo apt install docker
    

    拉取鏡像:

    docker pull aflplusplus/aflplusplus
    

    啟動 AFLPlusPlus docker 容器:

    docker run -ti -v $HOME:/home aflplusplus/aflplusplus
    

    然后輸入

    export $HOME="/home"
    

安裝成功后,應該可以使用afl-fuzz了,輸入afl-fuzz命令可以看到如下內容:

使用AFL++開始Fuzz

當源代碼可用時,AFL 可以使用檢測,在每個基本塊(函數、循環等)的開頭插入函數調用。為了為目標應用程序啟用檢測,所以需要使用 AFL 的編譯器編譯代碼。簡單來說就是需要使用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

現在可以使用以下命令運行Fuzz:

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 使用非確定性測試算法,因此兩個Fuzz會話永遠不會相同。這就是為什么設置固定種子 -s 123的原因。用以保證Fuzz結果和示例相同。)
  • @@:是占位符目標的命令行,AFL 將用每個輸入文件名替換它

如果收到「Hmm, your system is configured to send core dump notifications to an external utility...」類似的命令,執行以下操作關閉核心轉儲:

sudo su
echo core >/proc/sys/kernel/core_pattern
exit

幾分鍾后,應該會看到如下內容:

可以看到紅色的uniq crashes值,顯示找到的唯一崩潰的數量。可以在$HOME/fuzzing_xpdf/out/目錄中找到這些崩潰文件。一旦發現第一個崩潰,就可以使用control+c停止 fuzzer。

什么時候可以停止fuzzer?其中一個指標可以參考cycles done 的數字顏色,依次會出現洋蔥紅色,黃色,藍色,綠色,變成綠色時就很難產生新的crash文件了。

復現崩潰和修復漏洞

復現崩潰

$HOME/fuzzing_xpdf/out/目錄中找到崩潰對應的文件。文件名類似於id:000000,sig:11,src:001504+000002,time:924544,op:splice,rep:16

將此文件作為輸入傳遞給 pdftotext 二進制文件(如果提示無法打開文件,將文件名稱改為xxx.pdf再嘗試)

$HOME/fuzzing_xpdf/install/bin/pdftotext '$HOME/fuzzing_xpdf/out/default/crashes/<your_filename>' $HOME/fuzzing_xpdf/output

它會導致分段錯誤並導致程序崩潰:

使用 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:

gdb --args $HOME/fuzzing_xpdf/install/bin/pdftotext $HOME/fuzzing_xpdf/out/default/crashes/<your_filename> $HOME/fuzzing_xpdf/output

然后,在 GDB 中輸入:

run

如果一切順利,應該會看到以下輸出:

然后輸入bt以獲取棧回溯:

滾動調用堆棧,將看到Parser::getObj方法的許多調用,這些調用似乎表示無限遞歸,如上圖的紅框所示。

修復問題

下載4.02版本代碼,對比Parser.cc,可以看到此漏洞被修復:

總結

  • 通過復現一個漏洞,學習AFL++的基本使用方法,並使用GDB查看crash原因
  • 后續還有AFL++Fuzz學習的筆記會同步更新到博客

參考文章


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM