365直播电视版下载-beat365官网在线体育-beat365英国在线体育

Fuzzing101学习笔记

Fuzzing101学习笔记

前言通过对Fuzzing101项目的学习,逐步深入了解模糊测试,掌握工具的安装与使用,以及模糊测试结果的分析和调试。本文是在作者学习fuzz源码之后所写,根据项目中每一篇挑战的Readme.md进行翻译和学习,并参考了网上师傅们的文章。在这里,特别感谢hollk师傅的文章和指导,希望详细学习模糊测试的读者请查看hollk师傅的博客:hollk的博客_CSDN博客-pwn,模糊测试,堆溢出领域博主

项目搭建:

git clone https://github.com/antonio-morales/Fuzzing101

Exercise 1:XpdfCVE-2019-13288:Parser.cc源码中的Parser::getObj()函数可能会产生无限递归导致程序崩溃。

原文链接:CVE-2019-13288 : In Xpdf 4.01.01, the Parser::getObj() function in Parser.cc may cause infinite recursion via a crafted file. A remote at (cvedetails.com)

Fuzz准备搭建Xpdf环境:

cd $HOME

mkdir fuzzing_xpdf && cd fuzzing_xpdf/

# 相关依赖

sudo apt install build-essential

sudo apt update && sudo apt install -y build-essential gcc

# Download Xpdf 3.02

wget https://dl.xpdfreader.com/old/xpdf-3.02.tar.gz

tar -xvzf xpdf-3.02.tar.gz

# Download PDF examples to test Xpdf

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

# Build Xpdf

cd xpdf-3.02

make

测试Xpdf:

$HOME/fuzzing_xpdf/xpdf-3.02/xpdf/pdfinfo -box -meta $HOME/fuzzing_xpdf/pdf_examples/helloworld.pdf

------------------------------------------------------------------

# 结果如下,说明测试成功

Tagged: no

Pages: 1

Encrypted: no

Page size: 200 x 200 pts

MediaBox: 0.00 0.00 200.00 200.00

CropBox: 0.00 0.00 200.00 200.00

BleedBox: 0.00 0.00 200.00 200.00

TrimBox: 0.00 0.00 200.00 200.00

ArtBox: 0.00 0.00 200.00 200.00

File size: 678 bytes

Optimized: no

PDF version: 1.7

搭建Fuzz环境:

# 相关依赖

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

# 搭建 Fuzz

cd $HOME

git clone https://github.com/AFLplusplus/AFLplusplus && cd AFLplusplus

export LLVM_CONFIG="llvm-config-11"

make distrib

sudo make install

使用afl-clang-fast对Xpdf进行插桩:

# 清空已经编译

cd $HOME/fuzzing_xpdf/xpdf-3.02/

make clean

# 使用 afl-clang-fast 编译

export LLVM_CONFIG="llvm-config-11"

export CC=$HOME/AFLplusplus/afl-clang-fast

export CXX=$HOME/AFLplusplus/afl-clang-fast++

make

开始模糊测试,主要参数设置如下:

-i:设置输入实例的文件夹

-o:设置用于存放模糊测试结果的文件夹

-s:设置一个静态随机数作为种子

--:设置测试目标

@@:占位符,指代每一个输入的文件

# 关闭核心转储

sudo su

echo core >/proc/sys/kernel/core_pattern

exit

# 开始 Fuzz

afl-fuzz -i $HOME/fuzzing_xpdf/pdf_examples/ -o $HOME/fuzzing_xpdf/out/ -s 123 -- $HOME/fuzzing_xpdf/xpdf-3.02/xpdf/pdftotext @@ $HOME/fuzzing_xpdf/output

--------------------------------------------------------------------------------------------

# 该结果是作者在程序崩溃了7次后记录

american fuzzy lop ++4.05a {default} (...df/xpdf-3.02/xpdf/pdftotext) [fast]

┌─ process timing ────────────────────────────────────┬─ overall results ────┐

│ run time : 0 days, 0 hrs, 21 min, 8 sec │ cycles done : 0 │

│ last new find : 0 days, 0 hrs, 0 min, 19 sec │ corpus count : 977 │

│last saved crash : 0 days, 0 hrs, 0 min, 59 sec │saved crashes : 7 │

│ last saved hang : 0 days, 0 hrs, 21 min, 1 sec │ saved hangs : 1 │

├─ cycle progress ─────────────────────┬─ map coverage┴──────────────────────┤

│ now processing : 557.4 (57.0%) │ map density : 3.53% / 4.86% │

│ runs timed out : 0 (0.00%) │ count coverage : 3.98 bits/tuple │

├─ stage progress ─────────────────────┼─ findings in depth ─────────────────┤

│ now trying : splice 2 │ favored items : 79 (8.09%) │

│ stage execs : 174/294 (59.18%) │ new edges on : 138 (14.12%) │

│ total execs : 1.13M │ total crashes : 7 (7 saved) │

│ exec speed : 931.5/sec │ total tmouts : 138 (0 saved) │

├─ fuzzing strategy yields ────────────┴─────────────┬─ item geometry ───────┤

│ bit flips : disabled (default, enable with -D) │ levels : 10 │

│ byte flips : disabled (default, enable with -D) │ pending : 825 │

│ arithmetics : disabled (default, enable with -D) │ pend fav : 0 │

│ known ints : disabled (default, enable with -D) │ own finds : 974 │

│ dictionary : n/a │ imported : 0 │

│havoc/splice : 712/549k, 269/356k │ stability : 100.00% │

│py/custom/rq : unused, unused, unused, unused ├───────────────────────┘

│ trim/eff : 2.41%/214k, disabled │ [cpu000:350%]

└────────────────────────────────────────────────────┘

结果分析在fuzzing_xpdf/out/default/crashes文件夹中可以看到导致程序崩溃的输入,作者这里是7个:

pursue@pursue-virtual-machine:~/桌面/Fuzzing101-main/Exercise 1/fuzzing_xpdf/out/default/crashes$ ls

id:000000,sig:11,src:000532,time:98000,execs:105391,op:havoc,rep:8

id:000001,sig:11,src:000532,time:100895,execs:107844,op:havoc,rep:16

id:000002,sig:11,src:000846,time:592160,execs:473175,op:havoc,rep:8

id:000003,sig:11,src:000729,time:666679,execs:535614,op:havoc,rep:8

id:000004,sig:11,src:000557,time:670840,execs:539289,op:havoc,rep:8

id:000005,sig:11,src:000593,time:944864,execs:788622,op:havoc,rep:16

id:000006,sig:11,src:000607+000580,time:1209629,execs:1067185,op:splice,rep:4

README.txt

接下来,我们就需要将这些文件放入gdb中进行调试,看看到底是哪里出错了?

首先重新编译带调试的程序:

cd $HOME/fuzzing_xpdf/xpdf-3.02/

make clean

CFLAGS="-g -O0" CXXFLAGS="-g -O0"

make

开启gdb调试:

gdb --args $HOME/fuzzing_xpdf/xpdf-3.02/xpdf/pdftotext $HOME/fuzzing_xpdf/out/default/crashes/id:000000,sig:11,src:000532,time:98000,execs:105391,op:havoc,rep:8 $HOME/fuzzing_xpdf/output

-----------------------------------------------------------------------------

# gdb

pwndbg> run

# 回溯使用过的函数

pwndbg> bt

#3977 0x000000000049f0c9 in Parser::getObj (this=, obj=0x7fffff85c3c0, fileKey=0x0, encAlgorithm=cryptRC4, keyLength=0, objNum=7, objGen=0) at Parser.cc:94

#3978 0x00000000004d1641 in XRef::fetch (this=0x7965b0, num=7, gen=0, obj=0x7fffff85c3c0) at XRef.cc:823

#3979 0x000000000049f5e5 in Object::dictLookup (this=0x7fffff85c540, key=0x529 , obj=0x7fffff85c3c0) at ./Object.h:253

#3980 Parser::makeStream (this=this@entry=0x2081320, dict=dict@entry=0x7fffff85c540, fileKey=fileKey@entry=0x0, encAlgorithm=encAlgorithm@entry=cryptRC4, keyLength=keyLength@entry=0, objNum=objNum@entry=7, objGen=0) at Parser.cc:156

#3981 0x000000000049f0c9 in Parser::getObj (this=, obj=0x7fffff85c540, fileKey=0x0, encAlgorithm=cryptRC4, keyLength=0, objNum=7, objGen=0) at Parser.cc:94

#3982 0x00000000004d1641 in XRef::fetch (this=0x7965b0, num=7, gen=0, obj=0x7fffff85c540) at XRef.cc:823

#3983 0x000000000049f5e5 in Object::dictLookup (this=0x7fffff85c6c0, key=0x529 , obj=0x7fffff85c540) at ./Object.h:253

#3984 Parser::makeStream (this=this@entry=0x2080e40, dict=dict@entry=0x7fffff85c6c0, fileKey=fileKey@entry=0x0, encAlgorithm=encAlgorithm@entry=cryptRC4, keyLength=keyLength@entry=0, objNum=objNum@entry=7, objGen=0) at Parser.cc:156

#3985 0x000000000049f0c9 in Parser::getObj (this=, obj=0x7fffff85c6c0, fileKey=0x0, encAlgorithm=cryptRC4, keyLength=0, objNum=7, objGen=0) at Parser.cc:94

#3986 0x00000000004d1641 in XRef::fetch (this=0x7965b0, num=7, gen=0, obj=0x7fffff85c6c0) at XRef.cc:823

#3987 0x000000000049f5e5 in Object::dictLookup (this=0x7fffff85c840, key=0x529 , obj=0x7fffff85c6c0) at ./Object.h:253

#3988 Parser::makeStream (this=this@entry=0x2080960, dict=dict@entry=0x7fffff85c840, fileKey=fileKey@entry=0x0, encAlgorithm=encAlgorithm@entry=cryptRC4, keyLength=keyLength@entry=0, objNum=objNum@entry=7, objGen=0) at Parser.cc:156

# 发现一直调用 Parser::getObj 函数

查看源码Parser.cc:94:

// stream objects are not allowed inside content streams or

// object streams

if (allowStreams && buf2.isCmd("stream")) {

if ((str = makeStream(obj, fileKey, encAlgorithm, keyLength,

objNum, objGen))) {

...

发现问题所在,解决方法:只需在分支中加入递归次数的检测,使得超过一定次数程序退出,由于本人的代码能力不是很强,所以没能自己成功修复bug,学习了Xpdf-4.02中的Parser.cc源码:

// 增加了递归的上限

// Max number of nested objects. This is used to catch infinite loops

// in the object structure.

#define recursionLimit 500

// 增加了递归次数的检查

// array

if (!simpleOnly && recursion < recursionLimit && buf1.isCmd("[")) {

...

// dictionary or stream

} else if (!simpleOnly && recursion < recursionLimit && buf1.isCmd("<<")) {

...

// 对比之前版本,发现多了 recursion 这个参数

// stream objects are not allowed inside content streams or

// object streams

if (allowStreams && buf2.isCmd("stream")) {

if ((str = makeStream(obj, fileKey, encAlgorithm, keyLength,

objNum, objGen, recursion + 1))) {

...

Exercise 2:LibexifCVE-2009-3895:基于堆缓冲区溢出漏洞,可以劫持程序流。

原文链接:CVE - CVE-2009-3895 (mitre.org)

CVE-2012-2836:一个越界读取的漏洞,可以从内存中读取潜在的敏感信息。

原文链接:CVE - CVE-2012-2836 (mitre.org)

Fuzz准备首先编译libexif链接库和用于运行这个链接库的程序exif:

cd $HOME

mkdir fuzzing_libexif && cd fuzzing_libexif/

# 编译和安装 libexif 库文件

wget https://sourceforge.net/projects/libexif/files/libexif/0.6.14/libexif-0.6.14.tar.gz

tar -xzvf libexif-0.6.14.tar.gz

cd libexif-0.6.14/

sudo apt-get install autopoint libtool gettext libpopt-dev

autoreconf -fvi # 自动生成 Makefile

./configure --enable-shared=no --prefix="$HOME/fuzzing_libexif/install/" # 使用静态编译

make

make install

# 编译和安装 exif 调用 libexif 库文件

cd $HOME/fuzzing_libexif

wget https://sourceforge.net/projects/libexif/files/exif/0.6.15/exif-0.6.15.tar.gz

tar -xzvf exif-0.6.15.tar.gz

cd exif-exif-0_6_15-release/

autoreconf -fvi

./configure --enable-shared=no --prefix="$HOME/fuzzing_libexif/install/" PKG_CONFIG_PATH=$HOME/fuzzing_libexif/install/lib/pkgconfig

make

make install

测试是否编译成功:

cd $HOME/fuzzing_libexif

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

# 测试

./exif exif-samples-master/jpg/tests/11-tests.jpg

-------------------------------------------------------------------

# 测试结果

EXIF tags in 'exif-samples/11-tests.jpg' ('英特尔' byte order):

--------------------+----------------------------------------------------------

Tag |Value

--------------------+----------------------------------------------------------

Manufacturer |Canon

Model |Canon DIGITAL IXUS 40

Date and Time |2007:09:03 16:03:45

YCbCr Positioning |centered

RelatedImageWidth |2272

RelatedImageLength |1704

Custom Rendered |正常过程

曝光模式 |自动曝光

白平衡 |自动白平衡

数码变焦倍率 |1.00

场景捕获类型 |标准

Exposure Time |1/500 sec.

FNumber |f/2.8

Exif Version |Exif版本2.2

Date and Time (origi|2007:09:03 16:03:45

Date and Time (digit|2007:09:03 16:03:45

ComponentsConfigurat|Y Cb Cr -

Compressed Bits per |3.00

Shutter speed |8.97 EV (APEX: 22, 1/501 sec.)

光圈 |2.97 EV (f/2.8)

曝光偏差 |0.00 EV

MaxApertureValue |2.97 EV (f/2.8)

测距模式 |样式

闪光灯 |Flash did not fire, auto mode.

焦距 |5.8 mm

制作者备忘 |1176 字节未知数据

用户备注 |

FlashPixVersion |FlashPix版本 1.0

色彩空间 |sRGB

PixelXDimension |2272

PixelYDimension |1704

Focal Plane x-Resolu|10142.86

Focal Plane y-Resolu|10142.86

焦平面分辨率�|英寸

传感方式 |单芯片色彩区域传感器

File Source |DSC

--------------------+----------------------------------------------------------

测试成功,接下来用afl-clang-lto重新编译:

# 重新编译 libexif

rm -r $HOME/fuzzing_libexif/install

cd $HOME/fuzzing_libexif/libexif-libexif-0_6_14-release/

make clean

export LLVM_CONFIG="llvm-config-11"

CC=afl-clang-lto ./configure --enable-shared=no --prefix="$HOME/fuzzing_libexif/install/"

make

make install

# 重新编译 exif

cd $HOME/fuzzing_libexif/exif-exif-0_6_15-release

make clean

export LLVM_CONFIG="llvm-config-11"

CC=afl-clang-lto ./configure --enable-shared=no --prefix="$HOME/fuzzing_libexif/install/" PKG_CONFIG_PATH=$HOME/fuzzing_libexif/install/lib/pkgconfig

make

make install

这里说明一下afl-clang-fast和afl-clang-lto区别。原文这样解释到:afl-clang-lto是一种无碰撞检测,它比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)

开始Fuzz:

sudo su

echo core >/proc/sys/kernel/core_pattern

exit

afl-fuzz -i $HOME/fuzzing_libexif/exif-samples-master/jpg/ -o $HOME/fuzzing_libexif/out/ -s 123 -- $HOME/fuzzing_libexif/install/bin/exif @@

结果分析原文是通过Eclipse-CDT来调试的,不过本人更倾向于用pwndbg,主要是省去配置的工作,用一条命令就可以开整;还有就是用习惯了pwndbg,通过pwndbg可以看到更多的内存信息。

首先重新编译带调试信息的libexif和exif,这样就可以源码调试了:

# libexif

rm -r $HOME/fuzzing_libexif/install

cd $HOME/fuzzing_libexif/libexif-libexif-0_6_14-release/

make clean

CFLAGS="-g -O0" CXXFLAGS="-g -O0"

make

# exif

cd $HOME/fuzzing_libexif/exif-exif-0_6_15-release

make clean

CFLAGS="-g -O0" CXXFLAGS="-g -O0" PKG_CONFIG_PATH=$HOME/fuzzing_libexif/install/lib/pkgconfig

make

通过对报错输入的调试,主要有以下两条执行流:

pwndbg> bt

#0 0x000000000022c1bf in exif_get_sshort (buf=0x100451e85 , order=EXIF_BYTE_ORDER_MOTOROLA) at exif-utils.c:92

#1 exif_get_short (buf=0x100451e85 , order=EXIF_BYTE_ORDER_MOTOROLA) at exif-utils.c:104

#2 exif_data_load_data (data=0x452680, d_orig=, ds_orig=) at exif-data.c:819

#3 0x00000000002214d6 in exif_loader_get_data (loader=) at /home/pursue/桌面/Fuzzing101-main/Exercise 2/fuzzing_libexif/libexif-0.6.14/libexif/exif-loader.c:387

#4 main (argc=, argv=) at main.c:438

#5 0x00007ffff7cb7d90 in ?? () from /lib/x86_64-linux-gnu/libc.so.6

#6 0x00007ffff7cb7e40 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6

#7 0x000000000021a925 in _start ()

pwndbg> bt

#0 0x00007ffff7e2eed0 in ?? () from /lib/x86_64-linux-gnu/libc.so.6

#1 0x000000000022efe5 in exif_data_load_data_thumbnail (data=0x452610, d=0x451e16 "MM", ds=2026, offset=702, size=4294967168) at exif-data.c:292

#2 exif_data_load_data_content (data=, ifd=, d=, ds=, offset=674, recursion_depth=) at exif-data.c:381

#3 0x000000000022c322 in exif_data_load_data (data=0x452610, d_orig=, ds_orig=) at exif-data.c:835

#4 0x00000000002214d6 in exif_loader_get_data (loader=) at /home/pursue/桌面/Fuzzing101-main/Exercise 2/fuzzing_libexif/libexif-0.6.14/libexif/exif-loader.c:387

#5 main (argc=, argv=) at main.c:438

#6 0x00007ffff7cb7d90 in ?? () from /lib/x86_64-linux-gnu/libc.so.6

#7 0x00007ffff7cb7e40 in __libc_start_main () from /lib/x86_64-linux-gnu/libc.so.6

#8 0x000000000021a925 in _start ()

对于libexif中的api,该文档做了功能的解释:EXIF library (libexif) API: Globals

第一条执行流:main -> exif_loader_get_data -> exif_data_load_data -> exif_get_short -> exif_get_sshort

可以在回溯中看到buf超越到了不可访问的空间:

0x000000000022c1bf in exif_get_sshort (buf=0x100451e85 , order=EXIF_BYTE_ORDER_MOTOROLA) at exif-utils.c:92 # Cannot access memory at address 0x100451e85

往回找一下,发现在exif-data.c的819行找到了buf的真相:

/* IFD 1 offset */

// ExifLong offset; unsigned int ds;

if (offset + 6 + 2 > ds) { // 检查

return;

}

n = exif_get_short (d + 6 + offset, data->priv->order);

由于这里因为gdb优化代码编译的原因,所以我们不能从回溯中找到参数的信息。这里通过gdb的动调,找到了offset和ds的值。

# pwndbg

──────────────────────────[ REGISTERS / show-flags off / show-compact-regs off ]───────────────────────────

*RBX 0x7c3

*RBP 0xffffffff

───────────────────────────────────[ DISASM / x86-64 / set emulate on ]────────────────────────────────────

► 0x22c117 lea eax, [rbp + 8] <__afl_area_initial>

0x22c11a cmp eax, ebx

0x22c11c jbe exif_data_load_data+1306

可以看到offset的值为0xffffffff,也就是-1,加上8那就是7;而ds的值是0x7c3,显然是可以通过检查的。总结那就是当offset的值在-8 ~ -1之间是能够绕过检查触发程序崩溃的。所以修改如下:

if (offset > 0xfffffff0 | offset + 6 + 2 > ds) {

return;

}

第二条执行流:main -> exif_loader_get_data -> exif_data_load_data -> exif_data_load_data_content -> exif_data_load_data_thumbnail

可以在回溯中清晰的看到memcpy()函数复制的size过大导致崩溃:

# pwndbg

288 data->size = size;

289 data->data = exif_data_alloc (data, data->size);

290 if (!data->data)

291 return;

► 292 memcpy (data->data, d + offset, data->size);

293 }

# bt

0x000000000022efe5 in exif_data_load_data_thumbnail (data=0x452610, d=0x451e16 "MM", ds=2026, offset=702, size=4294967168) at exif-data.c:292 # size=4294967168

以下是exif_data_load_data_thumbnail函数的源码:

static void

exif_data_load_data_thumbnail (ExifData *data, const unsigned char *d,

unsigned int ds, ExifLong offset, ExifLong size)

{

// typedef uint32_t ExifLong; /* 4 bytes */

if (ds < offset + size) {

// 在这里,ds=2026, offset=702, size=0xFFFFFF80=-128,显然是可以通过检查的

exif_log (data->priv->log, EXIF_LOG_CODE_DEBUG, "ExifData",

"Bogus thumbnail offset and size: %i < %i + %i.",

(int) ds, (int) offset, (int) size);

return;

}

if (data->data)

exif_mem_free (data->priv->mem, data->data);

/*

typedef struct _ExifData ExifData;

struct _ExifData

{

ExifContent *ifd[EXIF_IFD_COUNT];

unsigned char *data;

unsigned int size; // 问题就在此处

ExifDataPrivate *priv;

};

*/

data->size = size; // 强制转换的时候出现了问题

// size=0xFFFFFF80=4294967168

data->data = exif_data_alloc (data, data->size);

if (!data->data)

return;

memcpy (data->data, d + offset, data->size);

}

所以只需要更新一下这个检查就行:

if ((unsigned long int) ds < (unsigned long int) offset + (unsigned long int) size){

...

}

总结一下:不难发现,这两个洞都和整数溢出有关。

Exercise 3:TCPdump简单来说,TCPdump就是一款Linux平台下的抓包工具。

CVE-2017-13028:存在一个越界读取的漏洞。

原文链接:https://www.cvedetails.com/cve/CVE-2017-13028/

Fuzz准备搭建环境:

cd $HOME

mkdir fuzzing_tcpdump && cd fuzzing_tcpdump/

wget https://www.tcpdump.org/release/tcpdump-4.9.2.tar.gz

tar -xzvf tcpdump-4.9.2.tar.gz

wget https://www.tcpdump.org/release/libpcap-1.8.0.tar.gz

tar -xzvf libpcap-1.8.0.tar.gz

# 编译 libpcap-1.8.0

cd $HOME/fuzzing_tcpdump/libpcap-1.8.0/

./configure --enable-shared=no

make

# 编译和安装 tcpdump-4.9.2

cd $HOME/fuzzing_tcpdump/tcpdump-4.9.2/

./configure --prefix="$HOME/fuzzing_tcpdump/install/"

make

make install

# 测试

$HOME/fuzzing_tcpdump/install/sbin/tcpdump -h

--------------------------------------------------------------

pursue@pursue-virtual-machine:~/fuzzing_tcpdump/install/sbin$ ./tcpdump -h

tcpdump version 4.9.2

libpcap version 1.8.0

OpenSSL 3.0.2 15 Mar 2022

Usage: tcpdump [-aAbdDefhHIJKlLnNOpqStuUvxX#] [ -B size ] [ -c count ]

[ -C file_size ] [ -E algo:secret ] [ -F file ] [ -G seconds ]

[ -i interface ] [ -j tstamptype ] [ -M secret ] [ --number ]

[ -Q in|out|inout ]

[ -r file ] [ -s snaplen ] [ --time-stamp-precision precision ]

[ --immediate-mode ] [ -T type ] [ --version ] [ -V file ]

[ -w file ] [ -W filecount ] [ -y datalinktype ] [ -z postrotate-command ]

[ -Z user ] [ expression ]

接下来使用ASan对其编译,什么是AddressSanitizer(ASan)?原文给出了这样的解释:AddressSanitizer (ASan)是C和C++的快速内存错误检测器。它由编译器插装模块和运行库组成。该工具能够发现堆栈和全局对象的越界访问,以及释放后使用、双重释放和内存泄漏错误。ASan是开源的,从3.1版开始与LLVM编译器工具链集成。虽然它最初是作为LLVM的项目开发的,但它已被移植到GCC,并包含在GCC版本>= 4.8中。

参考链接:https://clang.llvm.org/docs/AddressSanitizer.html

rm -r $HOME/fuzzing_tcpdump/install

cd $HOME/fuzzing_tcpdump/libpcap-1.8.0/

make clean

cd $HOME/fuzzing_tcpdump/tcpdump-4.9.2/

make clean

cd $HOME/fuzzing_tcpdump/libpcap-1.8.0/

export LLVM_CONFIG="llvm-config-11"

CC=afl-clang-lto ./configure --enable-shared=no --prefix="$HOME/fuzzing_tcpdump/install/"

AFL_USE_ASAN=1 make

cd $HOME/fuzzing_tcpdump/tcpdump-4.9.2/

AFL_USE_ASAN=1 CC=afl-clang-lto ./configure --prefix="$HOME/fuzzing_tcpdump/install/"

AFL_USE_ASAN=1 make

AFL_USE_ASAN=1 make install

但是在编译完成之后,运行程序发现报错:

pursue@pursue-virtual-machine:~/桌面/Fuzzing101-main/Exercise 3/fuzzing_tcpdump/tcpdump-4.9.2$ ./tcpdump -h

==59267==ERROR: AddressSanitizer failed to allocate 0x0 (0) bytes of SetAlternateSignalStack (error code: 22)

==59267==Process memory map follows:

0x000000200000-0x0000003ac000 /home/pursue/桌面/Fuzzing101-main/Exercise 3/fuzzing_tcpdump/tcpdump-4.9.2/tcpdump

0x0000003ac000-0x00000086b000 /home/pursue/桌面/Fuzzing101-main/Exercise 3/fuzzing_tcpdump/tcpdump-4.9.2/tcpdump

0x00000086b000-0x000000870000 /home/pursue/桌面/Fuzzing101-main/Exercise 3/fuzzing_tcpdump/tcpdump-4.9.2/tcpdump

0x000000870000-0x000000998000 /home/pursue/桌面/Fuzzing101-main/Exercise 3/fuzzing_tcpdump/tcpdump-4.9.2/tcpdump

0x000000998000-0x0000015f6000

0x00007fff7000-0x00008fff7000

0x00008fff7000-0x02008fff7000

0x02008fff7000-0x10007fff8000

0x7f7b2d5fe000-0x7f7b2d962000

0x7f7b2d962000-0x7f7b2d98a000 /usr/lib/x86_64-linux-gnu/libc.so.6

0x7f7b2d98a000-0x7f7b2db1f000 /usr/lib/x86_64-linux-gnu/libc.so.6

0x7f7b2db1f000-0x7f7b2db77000 /usr/lib/x86_64-linux-gnu/libc.so.6

0x7f7b2db77000-0x7f7b2db7b000 /usr/lib/x86_64-linux-gnu/libc.so.6

0x7f7b2db7b000-0x7f7b2db7d000 /usr/lib/x86_64-linux-gnu/libc.so.6

0x7f7b2db7d000-0x7f7b2db8a000

0x7f7b2db8a000-0x7f7b2db8d000 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1

0x7f7b2db8d000-0x7f7b2dba4000 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1

0x7f7b2dba4000-0x7f7b2dba8000 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1

0x7f7b2dba8000-0x7f7b2dba9000 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1

0x7f7b2dba9000-0x7f7b2dbaa000 /usr/lib/x86_64-linux-gnu/libgcc_s.so.1

0x7f7b2dbaa000-0x7f7b2dbb8000 /usr/lib/x86_64-linux-gnu/libm.so.6

0x7f7b2dbb8000-0x7f7b2dc34000 /usr/lib/x86_64-linux-gnu/libm.so.6

0x7f7b2dc34000-0x7f7b2dc8f000 /usr/lib/x86_64-linux-gnu/libm.so.6

0x7f7b2dc8f000-0x7f7b2dc90000 /usr/lib/x86_64-linux-gnu/libm.so.6

0x7f7b2dc90000-0x7f7b2dc91000 /usr/lib/x86_64-linux-gnu/libm.so.6

0x7f7b2dc91000-0x7f7b2dd43000 /usr/lib/x86_64-linux-gnu/libcrypto.so.3

0x7f7b2dd43000-0x7f7b2dfa0000 /usr/lib/x86_64-linux-gnu/libcrypto.so.3

0x7f7b2dfa0000-0x7f7b2e072000 /usr/lib/x86_64-linux-gnu/libcrypto.so.3

0x7f7b2e072000-0x7f7b2e0cd000 /usr/lib/x86_64-linux-gnu/libcrypto.so.3

0x7f7b2e0cd000-0x7f7b2e0d0000 /usr/lib/x86_64-linux-gnu/libcrypto.so.3

0x7f7b2e0d0000-0x7f7b2e0d3000

0x7f7b2e0d9000-0x7f7b2e0e5000

0x7f7b2e0e5000-0x7f7b2e0e7000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

0x7f7b2e0e7000-0x7f7b2e111000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

0x7f7b2e111000-0x7f7b2e11c000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

0x7f7b2e11c000-0x7f7b2e11d000

0x7f7b2e11d000-0x7f7b2e11f000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

0x7f7b2e11f000-0x7f7b2e121000 /usr/lib/x86_64-linux-gnu/ld-linux-x86-64.so.2

0x7ffe26590000-0x7ffe265b1000 [stack]

0x7ffe265bf000-0x7ffe265c3000 [vvar]

0x7ffe265c3000-0x7ffe265c5000 [vdso]

0xffffffffff600000-0xffffffffff601000 [vsyscall]

==59267==End of process memory map.

==59267==AddressSanitizer CHECK failed: /build/llvm-toolchain-11-mnvtwk/llvm-toolchain-11-11.1.0/compiler-rt/lib/sanitizer_common/sanitizer_common.cpp:54 "((0 && "unable to mmap")) != (0)" (0x0, 0x0)

原因是用的Ubuntu版本不对,错误是在Ubuntu22.04上出现的,而在Ubuntu20.04上正常。

开始Fuzz:

sudo su

echo core >/proc/sys/kernel/core_pattern

exit

afl-fuzz -m none -i tcpdump-4.9.2/tests/ -o out/ -s 123 -- $HOME/fuzzing_tcpdump/install/sbin/tcpdump -vvvvXX -ee -nn -r @@

结果分析Fuzz的过程有点漫长,近乎跑了半天的程序。

运行其中的一个crash样本

tcpdump-4.9.2/tcpdump -vvvvXX -ee -nn -r out/default/crashes/id:000000,sig:06,src:010739,time:56472860,execs:16241028,op:havoc,rep:8

Exercise 4:LibTIFFlibtiff库是读取和写入tiff文件最主要的一个开源库。

CVE-2016-9297:越界读取漏洞,可通过构建的TIFF_SETGET_C16_ASCII或TIFF_SETGET_C32_ASCII标记值触发。

原文链接:https://cwe.mitre.org/data/definitions/125.html

该挑战我们可以学习到:

如何使用LCOV测量代码覆盖率

如何使用代码覆盖率数据来提高模糊测试的有效性

代码覆盖率是一个软件指标,显示每行代码被触发的次数。通过使用代码覆盖率,我们将了解模糊器到达了代码的哪些部分,并可视化模糊处理过程。

Fuzz准备源码环境搭建:

sudo apt install lcov

cd $HOME

mkdir fuzzing_tiff && cd fuzzing_tiff/

wget https://download.osgeo.org/libtiff/tiff-4.0.4.tar.gz

tar -xzvf tiff-4.0.4.tar.gz

cd tiff-4.0.4/

export LDFLAGS="--coverage"

export CFLAGS="--coverage"

./configure --prefix="$HOME/fuzzing_tiff/install/" --disable-shared

make

make install

测试程序是否编译成功,这里加上各种参数是为了提高代码出现bug的机会:

$HOME/fuzzing_tiff/install/bin/tiffinfo -D -j -c -r -s -w test/images/miniswhite-1c-1b.tiff

cd $HOME/fuzzing_tiff/tiff-4.0.4/

lcov --zerocounters --directory ./ # 重置以前的计数器

lcov --capture --initial --directory ./ --output-file app.info # 返回“基线”覆盖数据文件,其中包含每个检测行的零覆盖率

$HOME/fuzzing_tiff/install/bin/tiffinfo -D -j -c -r -s -w $HOME/fuzzing_tiff/tiff-4.0.4/test/images/palette-1c-1b.tiff

lcov --no-checksum --directory ./ --capture --output-file app2.info # 将当前覆盖状态保存到 app2.info 文件中

genhtml --highlight --legend -output-directory ./html-coverage/ ./app2.info # 通过html页面显示

注意:在该项目里必须要有.gcno文件才能够进行lcov,否则很有可能是编译失败了。

html页面的路径为./html-coverage/index.html:

接下来进行插桩编译:

export LLVM_CONFIG="llvm-config-11"

export CC=afl-clang-lto

./configure --prefix="$HOME/fuzzing_tiff/install/" --disable-shared

AFL_USE_ASAN=1 make

AFL_USE_ASAN=1 make install

开始Fuzz:

sudo su

echo core >/proc/sys/kernel/core_pattern

exit

afl-fuzz -m none -i tiff-4.0.4/test/images/ -o out/ -s 123 -- $HOME/fuzzing_tiff/install/bin/tiffinfo -D -j -c -r -s -w @@

结果分析

运行crash的实例就可以得到ASAN提示:

$HOME/fuzzing_tiff/install/bin/tiffinfo -D -j -c -r -s -w id:000000,sig:06,src:000016,time:52157,execs:64042,op:havoc,rep:2

蓝色部分为读取操作,大概意思就是在线程为T0中,在0x6020000000b1处读取了大小为2的数据,并显示了函数栈的信息。

绿色部分为溢出的情况,其中还显示了堆块分配的函数栈。

由于第一次阅读这样的ASAN报告,不是很熟练,所以对着CVE做了一下源码的分析,CVE告诉我们漏洞是通过TIFF_SETGET_C16_ASCII或TIFF_SETGET_C32_ASCII这两个标志触发的,发现在tif_dirread.c中出现,这里以后者举例:

case TIFF_SETGET_C32_ASCII:

{

uint8* data;

assert(fip->field_readcount==TIFF_VARIABLE2);

assert(fip->field_passcount==1);

err=TIFFReadDirEntryByteArray(tif,dp,&data);

if (err==TIFFReadDirEntryErrOk)

{

int m;

m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);

if (data!=0)

_TIFFfree(data);

if (!m)

return(0);

}

}

这里TIFFSetField()函数的作用在官方文档的解释是根据引用或值获取标记值,对比一下4.2.0版本的源码:

case TIFF_SETGET_C32_ASCII:

{

uint8* data;

assert(fip->field_readcount==TIFF_VARIABLE2);

assert(fip->field_passcount==1);

err=TIFFReadDirEntryByteArray(tif,dp,&data);

if (err==TIFFReadDirEntryErrOk)

{

int m;

if( data != 0 && dp->tdir_count > 0 && data[dp->tdir_count-1] != '\0' )

{

TIFFWarningExt(tif->tif_clientdata,module,"ASCII value for tag \"%s\" does not end in null byte. Forcing it to be null",fip->field_name);

data[dp->tdir_count-1] = '\0';

}

m=TIFFSetField(tif,dp->tdir_tag,(uint32)(dp->tdir_count),data);

if (data!=0)

_TIFFfree(data);

if (!m)

return(0);

}

}

很清楚,这里限制了data这个变量的最后一个字节必须为空字节,用4.2.0版本运行crash的样本,发现没有了ASAN的报告。

Exercise 5:LibXML2LibXML2是C语言的一个库,可以方便对XML文档的各种操作。

CVE-2017-9048:堆栈缓冲区溢出漏洞

在该挑战中我们可以学习到:

使用自定义的字典帮助fuzzer找到新的执行路径

使用多核并行fuzzing提高效率

原文链接:https://nvd.nist.gov/vuln/detail/CVE-2017-9048

Fuzz准备cd $HOME

mkdir Fuzzing_libxml2 && cd Fuzzing_libxml2

wget http://xmlsoft.org/download/libxml2-2.9.4.tar.gz

tar xvf libxml2-2.9.4.tar.gz && cd libxml2-2.9.4/

# build libxml2

sudo apt-get install python-dev

export CC=afl-clang-lto

export CXX=afl-clang-lto++

export CFLAGS="-fsanitize=address"

export CXXFLAGS="-fsanitize=address"

export LDFLAGS="-fsanitize=address"

AFL_USE_ASAN=1 ./configure --prefix="$HOME/Fuzzing_libxml2/libxml2-2.9.4/install" --disable-shared --without-debug --without-ftp --without-http --without-legacy --without-python LIBS='-ldl'

AFL_USE_ASAN=1 make -j$(nproc)

AFL_USE_ASAN=1 make install

似乎编译的时间挺长,检查一下编译后的二进制文件

需要XML实例和字典

mkdir afl_in

cp ./SampleInput.xml afl_in/

mkdir dictionaries && cd dictionaries

wget https://github.com/AFLplusplus/AFLplusplus/blob/stable/dictionaries/xml.dict

cd ..

关于fuzz参数的使用

-x:标记使用的字典

-D:表示启用了确定性突变

-M:表示主模糊器

-S:表示从模糊器

afl-fuzz -m none -i ./afl_in -o afl_out -s 123 -x ./dictionaries/xml.dict -D -M master -- ./libxml2-2.9.4/xmllint --memory --noenc --nocdata --dtdattr --loaddtd --valid --xinclude @@

afl-fuzz -m none -i ./afl_in -o afl_out -s 234 -S slave1 -- ./libxml2-2.9.4/xmllint --memory --noenc --nocdata --dtdattr --loaddtd --valid --xinclude @@

结果分析暂时还未fuzz出结果

相关推荐