AFL++ Fuzz一個libexif例子


CVE-2009-3895

首先在NVD找到漏洞描述如下:

大致意思是說:libexif 0.6.18 中的 libexif/exif-entry.c 中的 exif_entry_fix 函數中基於堆的緩沖區溢出允許遠程攻擊者導致拒絕服務或可能通過無效的 EXIF 圖像執行任意代碼

接下來找到libexif 0.6.18 ,官方在0.6.19版本修復了此漏洞:

CVE-2012-2836

同樣在NVD中找到漏洞描述:

大致意思:0.6.21 之前的 EXIF 標簽解析庫(又名 libexif)中的 exif-data.c 中的 exif_data_load_data 函數允許遠程攻擊者造成拒絕服務(越界讀取)或可能通過精心設計的方式從進程內存中獲取敏感信息圖像中的 EXIF 標簽。簡單來說也就是存在越界訪問漏洞

官方在0.6.21版本修復了此漏洞:

實驗目的

  • 使用外部應用程序Fuzz庫文件
  • 使用afl-clang-lto,這是一種無碰撞檢測,它比afl-clang-fast更快並提供更好的結果

實驗環境

所有測試都在Ubuntu 20.04.2 LTS上測試過。強烈建議您使用相同的操作系統版本以避免不同的Fuzz結果,並在物理機而不是虛擬機上運行 AFL++ ,以獲得最佳性能

Fuzz過程

下載相關文件

首先創建一個文件夾用於存放Fuzz目標:

mkdir libexif && cd libexif

找到libexif文件,下載並解壓:

wget https://sourceforge.net/projects/libexif/files/libexif/0.6.18/libexif-0.6.18.tar.gz
tar -zxvf libexif-0.6.18.tar.gz
cd libexif-0.6.18

因為libexif編譯后是一個庫文件,所以還需要下載使用庫接口的應用程序,這里選擇exif命令行0.6.15

wget https://github.com/libexif/exif/archive/refs/tags/exif-0_6_15-release.tar.gz
tar -xzvf exif-0_6_15-release.tar.gz

構建

首先回到libexif庫文件目錄下進行編譯:

cd ..
sudo apt-get install autopoint libtool gettext libpopt-dev
autoreconf -fvi
./configure --enable-shared=no --prefix="/home/fuzz/libexif/install/"
make
make install

此時庫文件已經編譯好了,再進入exif目錄進行編譯:

cd exif-exif-0_6_15-release/
autoreconf -fvi
./configure --enable-shared=no --prefix="/home/fuzz/libexif/install/" PKG_CONFIG_PATH=$HOME/libexif/install/lib/pkgconfig
make
make install

測試exif能否運行只需要輸入:

$HOME/libexif/install/bin/exif

此時應該看到如下內容:

執行Fuzz

首先要確定程序是做什么的,要輸入什么內容,希望返回什么內容,可以先閱讀程序幫助信息,並測試程序功能。

Exif是一種文件格式,這是在網上搜索到的相關描述:

可交換圖像文件格式(英語:Exchangeable image file format,官方簡稱Exif),是專門為數碼相機的照片設定的,可以記錄數碼照片的屬性信息和拍攝數據。

舉個例子,就像下面這樣:

那么就需要找到這樣的文件樣本,好在萬能的GitHub啥都有,可以直接下載:

git clone https://github.com/ianare/exif-samples.git

下載好后進入目錄,使用exif命令隨便查看一張圖片的信息:

$HOME/libexif/install/bin/exif Nikon_D70.jpg

可以看到如下結果:

現在程序功能已經知道了,需要使用afl編譯器重新編譯程序來執行Fuzz。這次使用afl-clang-lto作為編譯器來構建程序,afl-clang-lto相比於afl-clang-fast是更好的選擇,因為它是一種無碰撞檢測,而且比afl-clang-fast 快。

如果不確定何時使用哪種編譯器,可參考如下內容:

+--------------------------------+
| clang/clang++ 11+ is available | --> use LTO mode (afl-clang-lto/afl-clang-lto++)
+--------------------------------+     see [instrumentation/README.lto.md](instrumentation/README.lto.md)
    |
    | if not, or if the target fails with LTO afl-clang-lto/++
    |
    v
+---------------------------------+
| clang/clang++ 6.0+ is available | --> use LLVM mode (afl-clang-fast/afl-clang-fast++)
+---------------------------------+     see [instrumentation/README.llvm.md](instrumentation/README.llvm.md)
    |
    | if not, or if the target fails with LLVM afl-clang-fast/++
    |
    v
 +--------------------------------+
 | gcc 5+ is available            | -> use GCC_PLUGIN mode (afl-gcc-fast/afl-g++-fast)
 +--------------------------------+    see [instrumentation/README.gcc_plugin.md](instrumentation/README.gcc_plugin.md) and
                                       [instrumentation/README.instrument_list.md](instrumentation/README.instrument_list.md)
    |
    | if not, or if you do not have a gcc with plugin support
    |
    v
   use GCC mode (afl-gcc/afl-g++) (or afl-clang/afl-clang++ for clang)

使用編譯器重新構建程序:

rm -r $HOME/libexif/install
cd $HOME/libexif/libexif-0.6.18
make clean
export LLVM_CONFIG="llvm-config-11"
CC=afl-clang-lto ./configure --enable-shared=no --prefix="$HOME/libexif/install"
make
make install
cd $HOME/libexif/libexif-0.6.18/exif-exif-0_6_15-release
make clean
export LLVM_CONFIG="llvm-config-11"
CC=afl-clang-lto ./configure --enable-shared=no --prefix="$HOME/libexif/install/" PKG_CONFIG_PATH=$HOME/libexif/install/lib/pkgconfig
make
make install

然后可以開始愉快的Fuzz了:

afl-fuzz -i /home/fuzz/libexif/exif_samples/jpg/ -o /home/fuzz/libexif/out -s 123 -- /home/fuzz/libexif/install/bin/exif @@

漏洞復現及修復

漏洞復現

幾分鍾后可獲得多個crash:

使用GDB將crash文件輸入到程序中:

gdb --args /home/fuzz/libexif/install/bin/exif ./crash1.jpg

查看棧回溯:

可看出明顯是malloc_printerr使程序crash,那么再往父函數找,找到exif_content_fix函數,在此處下斷點,重新運行程序,單步跟蹤,看看是什么原因使程序崩潰。跟蹤到__GI___libc_realloc函數時,在_int_realloc報錯,查看參數如下:

_int_realloc函數定義:void* _int_realloc(mstate av, mchunkptr oldp, INTERNAL_SIZE_T oldsize, INTERNAL_SIZE_T nb) ,單步跟進_int_realloc,得到如下結果:

查看堆中內容,觀察到下一chunk的size域已經堆溢出被破壞,無法malloc導致程序crash:

修復

可以在GitHub中查看修復代碼:

Fix a buffer overflow on corrupt EXIF data. · libexif/libexif@8ce72b7

Fix a buffer overflow on corrupted JPEG data · libexif/libexif@00986f6

總結

  • 在進行Fuzz時,信息收集同等重要,如果是復現,需要知曉Fuzz目標的CVE信息。如果是漏洞挖掘過程,則難度會更上一個等級。

  • 熟悉程序的構建過程、程序的功能是必不可少的步驟,如果完全不知道程序是干嘛的,那漏洞挖掘也就無從下手。

  • 在復現漏洞時,應該考慮怎么去證明這個漏洞,以及程序是如何崩潰的,可以在崩潰時的上層函數打上斷點單步跟蹤,觀察參數和函數調用過程

  • 另外:可以使用Eclipse-CDT 代替 GDB 進行調試,這是一個界面化的工具,需要有Java環境,下載鏈接:

    CDT Downloads | The Eclipse Foundation

    具體使用方法就不贅述了,網上有得很。工具都無所謂,看自己喜歡哪種,我就習慣GDB


免責聲明!

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



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