Fuzz-Lab4:LibTIFF
这次我们将模糊 LibTIFF 图像库(读取和写入 tiff 文件最主要的一个开源库),目标是在 libtiff 4.0.4 中为 [CVE-2016-9297] 找到 crash/PoC,并 测量 crash/PoC 的代码覆盖率数据
- CVE-2016-9297 是一个越界读取漏洞,可以通过特制的 TIFF_SETGET_C16_ASCII 或 TIFF_SETGET_C32_ASCII 标记值触发
- 越界读取是当程序读取超出预期缓冲区末尾或开头之前的数据时发生的漏洞
- 结果,它允许远程攻击者导致拒绝服务或可能从进程内存中获取潜在的敏感信息
完成本练习后,您将了解:
- 如何使用 LCOV 测量代码覆盖率
- 如何使用代码覆盖率数据来提高模糊测试的有效性
Do it yourself!
为了完成这个练习,你需要:
- Fuzz LibTiff(启用 ASan)直到出现一些独特的崩溃
- 对崩溃进行分类以找到漏洞的 PoC
- 测量这个 PoC 的代码覆盖率
- 修复问题
Download and build your target
1 | cd $HOME |
作为目标二进制文件,我们可以对位于 /bin
文件夹中的 tiffinfo
二进制文件进行模糊测试,作为种子输入语料库,我们将使用 /test/images/
文件夹中的示例图像
要测试一切是否正常,只需键入:
1 | HOME/fuzzing_tiff/install2/bin/tiffinfo -D -j -c -r -s -w $HOME/tiff-4.0.4/test/images/palette-1c-1b.tiff |
- 在最后一个命令行中,您可以看到我启用了所有这些标志:“-j -c -r -s -w”,这是为了提高 代码覆盖率 并增加发现错误的机会
结果:
1 | TIFF Directory at offset 0xbd4 (3028) |
- 标签图像文件格式(Tag Image File Format,TIFF)是一种灵活的位图格式,主要用来存储包括照片和艺术图在内的图像
- 而 LibTIFF 就是打开 TIFF 文件的一种工具
Code coverage
代码覆盖率是一种软件指标,显示每行代码被触发的次数,通过使用代码覆盖率,我们将了解模糊器已到达代码的哪些部分并 可视化 模糊测试过程
首先,我们需要安装 lcov ,我们可以使用以下命令来完成:
1 | sudo apt install lcov |
- lcov 是 gcc 测试覆盖率的前端图形展示工具
现在我们需要使用 —coverage 标志(编译器和链接器)重建 libTIFF:
1 | cd $HOME/tiff-4.0.4/ |
然后我们依次输入以下内容来收集代码覆盖率数据:
1 | cd $HOME/tiff-4.0.4/ |
最后,我们必须生成 HTML 输出:
1 | genhtml --highlight --legend -output-directory ./html-coverage/ ./app2.info |
- 如果一切顺利,代码覆盖率报告将在 html-coverage 文件夹中创建,只需打开
./html-coverage/index.html
文件,您应该会看到如下内容:
- 其实我并不知道这个东西有什么用
Fuzz LibTIFF
现在我们将在启用 ASAN 的情况下编译 libtiff
首先,我们要清理所有以前编译的目标文件和可执行文件:
1 | rm -r $HOME/fuzzing_tiff/install |
现在,我们在调用 make 之前设置 AFL_USE_ASAN=1:
1 | export LLVM_CONFIG="llvm-config-11" |
现在,您可以使用以下命令运行模糊器:
1 | afl-fuzz -m none -i $HOME/tiff-4.0.4/test/images/ -o $HOME/fuzzing_tiff/out/ -s 123 -- $HOME/fuzzing_tiff/install/bin/tiffinfo -D -j -c -r -s -w @@ |
结果:
Triage
接下来我们要使用 ASan 对崩溃进行分类
调试使用 ASan 构建的程序比前面的练习要容易得多,我们需要做的就是向程序提供崩溃文件:
1 | HOME/fuzzing_tiff/install/bin/tiffinfo -D -j -c -r -s -w ./id:000000,sig:11,src:000009,time:67581,execs:76549,op:havoc,rep:4 |
结果如下:
1 | TIFFReadDirectory: Warning, Bogus "StripByteCounts" field, ignoring and calculating from imagelength. |
- 输出的上半截就是报错信息,下半截是执行跟踪
- 程序 crash 的原因是无效的地址
0x000000000000
除了这种 crash 以外,还有其他原因:
1 | HOME/fuzzing_tiff/install/bin/tiffinfo -D -j -c -r -s -w ./id:000002,sig:06,src:000009,time:81829,execs:92343,op:havoc,rep:8 |
1 | TIFFReadDirectoryCheckOrder: Warning, Invalid TIFF directory; tags are not sorted in ascending order. |
- 这种 crash 的原因就是堆溢出
- 目前只发现这两种类型的 crash
经过对比发现:[CVE-2016-9297] 的 PoC 为 id:000002
(通过精心编制的 TIFF_SETGET_C16ASCII 或 TIFF_SETGET_C32_ASCII 标记值来造成越界读取)
PoC Code coverage
1 | cd $HOME/tiff-4.0.4/ |
然后我们依次输入以下内容来收集代码覆盖率数据:
1 | cd $HOME/tiff-4.0.4/ |
最后,我们必须生成 HTML 输出:
1 | genhtml --highlight --legend -output-directory ./html-coverage/ ./app2.info |
- 如果一切顺利,代码覆盖率报告将在 html-coverage 文件夹中创建,只需打开
./html-coverage/index.html
文件,您应该会看到如下内容:
Reproduce the crash
先使用没有 ASan 的 tiffinfo
来运行 crash 文件:
1 | ➜ bin ./tiffinfo test |
- 发现程序的输出异常,我们先利用 ASan 进行调试,ASan 提供的报错信息如下:
1 | ==3333==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x6070000000d1 at pc 0x0000002aadf2 bp 0x7fffffffda30 sp 0x7fffffffd1f0 |
- 根据 ASan 提供的信息,在
0x2aadf2
打上断点,对比溢出点执行前后 heap 的变化:
1 | *RAX 0x2aadf2 (fputs+386) ◂— lea rdx, [rbp - 0x840] |
1 | RAX 0x2aadf2 (fputs+386) ◂— lea rdx, [rbp - 0x840] |
1 | pwndbg> telescope 0x7fffffffda30-0x840 |
- 其实这里还不容易看出内存泄露
- 所以我们用 GDB 在没有 ASan 的
tiffinfo->tif_print.c:127
处打断点,进行调试:
1 | ► 0x289711 <TIFFPrintDirectory+11761> call fputs@plt <fputs@plt> |
1 | pwndbg> telescope 0x49edc0 |
- 目标
fputs
执行结果:
1 | pwndbg> c |
- 注意
0x49ee00
处:[0x2e]->[.]
[0x23]->[#]
[0x29]->[)]
- 这是
0x29232e (tiffFields+2030)
的后3字节,而fputs
把它打印出来了(内存泄露)
因为 fputs
遇到 \x00
才会停止,这就导致了内存泄露