Fuzzing101系列 Exercise 1 - Xpdf

序言

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

Fuzzing101系列 Exercise 1 - Xpdf_第1张图片

安装 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,查看是否安装成功

Fuzzing101系列 Exercise 1 - Xpdf_第2张图片

认识 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 $HOME/fuzzing_xpdf/output 命令

Fuzzing101系列 Exercise 1 - Xpdf_第3张图片

出现错误,根据提示,执行以下操作:

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

成功运行,等待一段时间后,发现已经有了一个crash

Fuzzing101系列 Exercise 1 - Xpdf_第4张图片

可以在$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/' $HOME/fuzzing_xpdf/output

它将导致段错误segmentation fault并导致程序崩溃。

Fuzzing101系列 Exercise 1 - Xpdf_第5张图片

调试

使用 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/ $HOME/fuzzing_xpdf/output

Fuzzing101系列 Exercise 1 - Xpdf_第6张图片

然后输入bt回溯查看栈帧

Fuzzing101系列 Exercise 1 - Xpdf_第7张图片

发现有许多次Parser::getObj的调用,它们似乎表示一个无限递归。如果你去 https://www.cvedetails.com/cve/cve-2019-13288/ ,你可以看到描述符合我们从 GDB 得到的回溯。

实验推荐:Fuzz之AFL
链接:https://www.hetianlab.com/expc.do?ec=ECID5ec5-3232-4f16-8c14-c98b75f8915d&pk_campaign=weixin-wemedia#stu

你可能感兴趣的:(python,开发语言,安全)