Skip to main content

LibAFL Fuzzing Holy Bible - Chapter II: Fuzzing Libexif - CVE-2009-3895 & CVE-2012-2836

·1487 words·7 mins
y198
Author
y198
living in fuzzing
tags: libafl
#

Background
#

Antonio Morales đã tạo một cái repo Fuzzing 101 với mục đích là tạo ra các challenge liên quan đến những kiến thức và basic skill của fuzzing dành cho những ai muốn học nó và sử dụng nó để tìm ra các vulnerabilities. Repo này tập trung vào cách sử dụng của AFL++ nhưng trong series mình viết với mục đích là solve những challenge sử dụng LibAFL thay vì là AFL++.

Trong series này thì mình sẽ tìm hiểu các thư viện và viết fuzzers bằng ngôn ngữ Rust, mình sẽ cố gắng solve các challenges gần giống với solution nhất mà mình có thể làm được.

Và trong series này mình sẽ sử dụng ngôn ngữ Rust để viết fuzzers. Nếu như bạn chưa biết Rust và Fuzzers là gì thì mình khuyến khích bạn nên tìm hiểu về nó trước khi đọc những gì tiếp theo.

About LibAFL
#

LibAFL là một sự cải tiến từ AFL++ được viết bằng ngôn ngữ Rust. Nó nhanh hơn, đa dạng nền tảng, no_std compatibles và nó tận dụng tốt nguồn tài nguyên của máy.

Để hiểu rõ hơn về LibAFL bạn có thể coi cái này Fuzzers Like Lego @rC3

Prequesite
#

Rust installation:
#

curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh

AFL++ installation:
#

  • Dependencies:
sudo apt-get update
sudo apt-get install -y python3-pip cmake build-essential git gcc
sudo apt-get install -y build-essential python3-dev automake cmake git flex bison libglib2.0-dev libpixman-1-dev python3-setuptools cargo libgtk-3-dev
# try to install llvm 14 and install the distro default if that fails
sudo apt-get install -y lld-14 llvm-14 llvm-14-dev clang-14 || 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
sudo apt-get install -y ninja-build # for QEMU mode
  • Build AFL++:
git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus
export LLVM_CONFIG="llvm-config-15"
make distrib
sudo make install

Nếu như bạn gặp lỗi với unicornafl thì hãy thử downgrade version của python xuống 3.10.8.

curl https://pyenv.run | bash
pyenv install 3.10.8
pyenv global 3.10.8
  • Test installation:
cd ~
export PATH=$PATH :~/AFLplusplus
afl-fuzz -h

Result:

gh0st@pl4y-Gr0und:~$ afl-fuzz -h
afl-fuzz++4.09a based on afl by Michal Zalewski and a large online community

afl-fuzz [ options ] -- /path/to/fuzzed_app [ ... ]

Required parameters:
  -i dir        - input directory with test cases (or '-' to resume, also see 
                  AFL_AUTORESUME)
  -o dir        - output directory for fuzzer findings

Execution control settings:
  -P strategy   - set fix mutation strategy: explore (focus on new coverage),
                  exploit (focus on triggering crashes). You can also set a
                  number of seconds after without any finds it switches to
                  exploit mode, and back on new coverage (default: 1000)
  -p schedule   - power schedules compute a seed's performance score:
                  fast(default), explore, exploit, seek, rare, mmopt, coe, lin
                  quad -- see docs/FAQ.md for more information
  -f file       - location read by the fuzzed program (default: stdin or @@)
  -t msec       - timeout for each run (auto-scaled, default 1000 ms). Add a '+'
                  to auto-calculate the timeout, the value being the maximum.
  -m megs       - memory limit for child process (0 MB, 0 = no limit [default])
  -O            - use binary-only instrumentation (FRIDA mode)
  -Q            - use binary-only instrumentation (QEMU mode)
  -U            - use unicorn-based instrumentation (Unicorn mode)
  -W            - use qemu-based instrumentation with Wine (Wine mode)
  -X            - use VM fuzzing (NYX mode - standalone mode)
  -Y            - use VM fuzzing (NYX mode - multiple instances mode)

Mutator settings:
  -a            - target input format, "text" or "binary" (default: generic)
  -g minlength  - set min length of generated fuzz input (default: 1)
  -G maxlength  - set max length of generated fuzz input (default: 1048576)
  -D            - enable deterministic fuzzing (once per queue entry)
  -L minutes    - use MOpt(imize) mode and set the time limit for entering the
                  pacemaker mode (minutes of no new finds). 0 = immediately,
                  -1 = immediately and together with normal mutation.
                  Note: this option is usually not very effective
  -c program    - enable CmpLog by specifying a binary compiled for it.
                  if using QEMU/FRIDA or the fuzzing target is compiled
                  for CmpLog then use '-c 0'. To disable Cmplog use '-c -'.
  -l cmplog_opts - CmpLog configuration values (e.g. "2ATR"):
                  1=small files, 2=larger files (default), 3=all files,
                  A=arithmetic solving, T=transformational solving,
                  X=extreme transform solving, R=random colorization bytes.

Fuzzing behavior settings:
  -Z            - sequential queue selection instead of weighted random
  -N            - do not unlink the fuzzing input file (for devices etc.)
  -n            - fuzz without instrumentation (non-instrumented mode)
  -x dict_file  - fuzzer dictionary (see README.md, specify up to 4 times)

Test settings:
  -s seed       - use a fixed seed for the RNG
  -V seconds    - fuzz for a specified time then terminate
  -E execs      - fuzz for an approx. no. of total executions then terminate
                  Note: not precise and can have several more executions.

Other stuff:
  -M/-S id      - distributed mode (-M sets -Z and disables trimming)
                  see docs/fuzzing_in_depth.md#c-using-multiple-cores
                  for effective recommendations for parallel fuzzing.
  -F path       - sync to a foreign fuzzer queue directory (requires -M, can
                  be specified up to 32 times)
  -T text       - text banner to show on the screen
  -I command    - execute this command/script when a new crash is found
  -C            - crash exploration mode (the peruvian rabbit thing)
  -b cpu_id     - bind the fuzzing process to the specified CPU core (0-...)
  -e ext        - file extension for the fuzz test input file (if needed)

To view also the supported environment variables of afl-fuzz please use "-hh".

Compiled with Python 3.11.4 module support, see docs/custom_mutators.md
Compiled without AFL_PERSISTENT_RECORD support.
Compiled with shmat support.
For additional help please consult docs/README.md :)

Objective
#

Ở chapter lần này tương ứng với exercise-2 trong Fuzzing 101. Mục đích của exercise này đó là chúng ta cần phải tìm một cái PoC/crash cho CVE-2009-3895 & CVE-2012-2836.

CVE-2009

Heap-based buffer overflow in the exif_entry_fix function (aka the tag fixup routine) in libexif/exif-entry.c in libexif 0.6.18 allows remote attackers to cause a denial of service or possibly execute arbitrary code via an invalid EXIF image. NOTE: some of these details are obtained from third party information.

CVE-2012-2836

The exif_data_load_data function in exif-data.c in the EXIF Tag Parsing Library (aka libexif) before 0.6.21 allows remote attackers to cause a denial of service (out-of-bounds read) or possibly obtain sensitive information from process memory via crafted EXIF tags in an image.

Before Fuzzing
#

Trước khi bắt đầu fuzzing chúng ta cần phải chuẩn bị một số thứ

Setup our target
#

gh0st@fuzzing-bible:~/fuzzing-101-solutions$ cargo new --lib exercise-2 

Chúng ta update member cho file Cargo.toml gốc

fuzzing-101-solutions/Cargo.toml

[workspace]

members = [
    "exercise-1",
    "exercise-2",
]

Install libexif
#

gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2$ wget https://github.com/libexif/libexif/archive/refs/tags/libexif-0_6_14-release.tar.gz
gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2$ tar -xvf libexif-0_6_14-release.tar.gz
gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2$ rm libexif-0_6_14-release.tar.gz
gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2$ mv libexif-libexif-0_6_14-release libexif

Install requirements

gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2$  sudo apt-get install autopoint libtool gettext libpopt-dev

Build our target
#

Lần này mình tiếp tục sử dụng Makefile.toml vì sự tiện lợi của nó trong việc build những task mình cần cho fuzzing

Nếu bạn chưa biết Makefile.toml là gì thì mình suggest bạn xem blog trước của mình, mình nói khá kỹ về tool này https://hackmd.io/jW6RBTbjTfqjGxRvR-DiLQ#Makefiletoml

[tasks.clean]
dependencies = ["cargo-clean", "libexif-clean", "build-clean"]

[tasks.cargo-clean]
command = "cargo"
args = ["clean"]

[tasks.libexif-clean]
command = "make"
args = ["-C", "libexif", "clean", "-i"]

[tasks.build-clean]
command = "rm"
args = ["-rf", "build/"]

[tasks.build]
dependencies = ["clean", "build-libexif"]
command = "cargo"
args = ["build"]


[tasks.build-libexif]
cwd = "libexif"
script = """
autoreconf -fi
./configure --enable-shared=no --prefix="${CARGO_MAKE_WORKING_DIRECTORY}/../build/"
make -i
make install -i
"""

Run the build

gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2$ cargo make build 

Confirm build thành công

gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2$ ls build/lib/libexif.a
build/lib/libexif.a

Get into fuzzing
#

Setting up fuzzer
#

~/fuzzing-101-solutions/exercise-2/Cargo.toml

[dependencies]
libafl = {version = "0.10.1"}
libafl_cc = {version = "0.10.1"}
libafl_targets = {version = "0.10.1", features = [
    "libfuzzer",
    "sancov_pcguard_hitcounts",
    "sancov_cmplog",
]}
clap = "3.0.0-beta.5"
[lib]
name="exercisetwo"
crate-type=["staticlib]

Get some corpus
#

gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2$ mkdir corpus solutions

Ở trong libexif repo họ để sẵn một số file jpg để làm test data, để thuận tiện thì chúng ta sẽ lấy các file jpg đó về làm test case cho fuzzer.

fuzzing-101-solutions/exercise-2/corpus

git clone --no-checkout --filter=blob:none https://github.com/libexif/libexif.git

fuzzing-101-solutions/exercise-2/corpus

cd libexif
git checkout master -- test/testdata

fuzzing-101-solutions/exercise-2/corpus/libexif

mv test/testdata/*.jpg ../
cd ..
rm -rf libexif

Và đây là những file để làm test case cho fuzzer

gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2/corpus

gh0st@fuzzing-bible:~/fuzzing-101-solutions/exercise-2/corpus$ ls -la
total 72
drwxrwxr-x 2 gh0st gh0st  4096 Thg 12 29 14:55 .
drwxrwxr-x 7 gh0st gh0st  4096 Thg 12 29 14:55 ..
-rw-rw-r-- 1 gh0st gh0st  2026 Thg 12 29 14:54 canon_makernote_variant_1.jpg
-rw-rw-r-- 1 gh0st gh0st  3978 Thg 12 29 14:54 fuji_makernote_variant_1.jpg
-rw-rw-r-- 1 gh0st gh0st  2850 Thg 12 29 14:54 olympus_makernote_variant_2.jpg
-rw-rw-r-- 1 gh0st gh0st  6140 Thg 12 29 14:54 olympus_makernote_variant_3.jpg
-rw-rw-r-- 1 gh0st gh0st 11458 Thg 12 29 14:54 olympus_makernote_variant_4.jpg
-rw-rw-r-- 1 gh0st gh0st  9604 Thg 12 29 14:54 olympus_makernote_variant_5.jpg
-rw-rw-r-- 1 gh0st gh0st  1346 Thg 12 29 14:54 pentax_makernote_variant_2.jpg
-rw-rw-r-- 1 gh0st gh0st  1918 Thg 12 29 14:54 pentax_makernote_variant_3.jpg
-rw-rw-r-- 1 gh0st gh0st  9132 Thg 12 29 14:54 pentax_makernote_variant_4.jpg

Related

LibAFL Fuzzing Holy Bible - Chapter I: Fuzzing Xpdf - CVE-2019-13288
·3850 words·19 mins
Using LibAFL fuzzer to reproduce CVE-2019-13288
WAN bug in RAXE300
·530 words·3 mins
Second bug I found in RAXE300 Netgear device. A WAN bug lead to RCE
My very first bug
·348 words·2 mins
My first bug I found in Real World stuff. A LAN bug in RAXE300 Netgear device