首页
社区
课程
招聘
Fuzzing101 Exercise 4 - LibTIFF CVE-2016-9297&CVE-2016-9448分析
2023-7-30 18:21 12922

Fuzzing101 Exercise 4 - LibTIFF CVE-2016-9297&CVE-2016-9448分析

2023-7-30 18:21
12922

Fuzzing101 Exercise 4 - LibTIFF CVE-2016-9297&CVE-2016-9448分析

0x00 前言

最近在进行Fuzzing的学习,发现对Crash分析的内容较少,故而写此篇分析记录一下,望与各位同行共同进步。
由于笔者也属于刚入门,若有误望大家指正。

0x01 漏洞信息

1.漏洞简述

• 漏洞名称:Libtiff 越界读取漏洞

• 漏洞编号:CVE-2016-9297

• 漏洞类型:越界读取

• 漏洞影响:拒绝服务

• CVSS评分:(CVSS 3.0 )7.5

• 利用难度:低

• 基础权限:不需要

2.组件概述

LibTIFF是一个开源的用于处理TIFF(Tagged Image File Format)图像文件的C/C++库。TIFF是一种常见的图像文件格式,广泛应用于图像处理和存储。LibTIFF提供了一组功能丰富的API,允许开发者读取、写入、编辑和处理TIFF格式的图像。

3.漏洞利用

使用tiffinfo解析Fuzzing出的样本。

image-20230730163505886

4.漏洞影响

Libtiff <= 4.0.6

5.解决方案

更新至Libtiff4.0.7以上版本

0x02 漏洞复现

1. 环境准备

详细搭建可以参考Fuzzing101

目录创建

1
2
cd $HOME
mkdir fuzzing_tiff && cd fuzzing_tiff/

下载tiff-4.0.4

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

使用ASAN模糊测试。

1
2
3
4
5
6
7
8
rm -r $HOME/fuzzing_tiff/install
cd $HOME/fuzzing_tiff/tiff-4.0.4/
make clean
export LLVM_CONFIG="llvm-config-11"
CC=afl-clang-lto ./configure --prefix="$HOME/fuzzing_tiff/install/" --disable-shared
AFL_USE_ASAN=1 make -j4
AFL_USE_ASAN=1 make install
afl-fuzz -m none -i $HOME/fuzzing_tiff/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 @@
2.FUZZING

image-20230726191551638

0x03 漏洞分析

1. 基本信息

漏洞产生在tif_dirread.c函数中,在Field的TIFFSetGetFieldType属性为TIFF_SETGET_C32_ASCII或TIFF_SETGET_C16_ASCII时,输出Tag Value未在字符串末尾置0,从而可能导致越界读取。

2. 详细分析
2.1基础分析

此次的分析基于Fuzzing101的Exercise4所以选择4.0.4版本进行分析,CVE对该漏洞的描述为:

The TIFFFetchNormalTag function in LibTiff 4.0.6 allows remote attackers to cause a denial of service (out-of-bounds read) via crafted TIFF_SETGET_C16ASCII or TIFF_SETGET_C32_ASCII tag values.

在LibTiff 4.0.6中,TIFFFetchNormalTag函数存在漏洞,该漏洞可以被远程攻击者利用,通过精心构造的TIFF_SETGET_C16ASCII或TIFF_SETGET_C32_ASCII标签值来造成拒绝服务(越界读取)攻击。

2.2静态分析

查看一下crash文件。

image-20230729202713032

00h~01h:0x4949,使用小端序

02h~03h:0x002a,十进制42,为tif文件标识符。

04h~07h:第一个IFD(Image File Dirctory)的偏移。

image-20230729204018058

随后是10h开始的第一个IFD结构。

10h~11h:Directory Entries的数目。此处为11。

后续每12字节代表1个IFD Entry。

最后一个IFD Entry的后四个字节表示下一个IFD结构的偏移,如果没有为0。

IFD Entry结构(一个Entry也可以叫做一个field)。

00h~01h:该field的标识。

02h~03h :该field的数据类型。

04h~07h:数量,Count of the indicated Type,根据数量和类型确定其字节数。

08h~0Bh:值的文件偏移,如果该tag value占用字节数小于四字节,那么value存放于此。

划分一下数据

image-20230729211335813

红框处是下面出现crash寄存器出现的Tag 63253。此处可以注意一下。

tag:0xf715 63253

type:0x0002 ASCII类型

数量:0x00000001 1

Offset or 数据:0x00000003 3

2.3动态分析

AFL+ASAN对Libtiff4.0.4进行Fuzzing,执行Fuzzing出的Crash,得到提示,部分DirectoryEntry(简称DE结构)解析错误,错误为堆溢出。

image-20230729200522596

根据官方提示在__asan::ReportGenericError下断点,这里中断在asan报告错误之前,发生错误之后的地方,bt查看调用栈,产生错误的代码在tif_print.c:127

image-20230729191941723

由于ASAN会对程序进行插桩,阻碍汇编代码的阅读,所以笔者重新编译了一下源程序方便后续的调试。

gdb --args ./install/bin/tiffinfo -D -j -c -r -s -w ./out/default/crashes/crash对程序进行调试,从上述信息得出断点位置b tif_print.c:126,执行的时候上下文信息如图。

image-20230729212409579

这里将raw_data字符串打印了出来,raw_data对应的field为Tag 63253对应的field也就是我们crash文件红框标识的0xf715那一个DE结构。可以猜想一下逻辑,该DE结构被读入内存,输出的时候分配了一段内存空间用来存储其Value,随后根据其DE结构的类型(ASCII)输出Tag和对应的Value。回想一下,当时我们的数据长度为0x1,每一个ASCII类型占8位,所以我们该Tag的Value应该是0x3,但是这里显然,如果将raw_data输出,会输出03 3b e4 e4 f7 ff 7f。这里显然访问了不应该访问的内存。但是这并不会产生crash,因为该内存地址是可读写的。

image-20230729213248332

随后raw_data的内存下一个写入断点,重新执行程序,看看它是什么时候写入的。

第一次,该内存存放了一个_TIFFField结构指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
struct _TIFFField {
    uint32 field_tag;                       /* field's tag */
    short field_readcount;                  /* read count/TIFF_VARIABLE/TIFF_SPP */
    short field_writecount;                 /* write count/TIFF_VARIABLE */
    TIFFDataType field_type;                /* type of associated data */
    uint32 reserved;                        /* reserved for future extension */
    TIFFSetGetFieldType set_field_type;     /* type to be passed to TIFFSetField */
    TIFFSetGetFieldType get_field_type;     /* type to be passed to TIFFGetField */
    unsigned short field_bit;               /* bit in fieldsset bit vector */
    unsigned char field_oktochange;         /* if true, can change while writing */
    unsigned char field_passcount;          /* if true, pass dir count on set */
    char* field_name;                       /* ASCII name */
    TIFFFieldArray* field_subfields;        /* if field points to child ifds, child ifd field definition array */
};

image-20230729214055057

从信息可以看出,该结构是一些的Tag信息,由于Tag 63253是一个在标准的Tag列表中没有,所以会进行一次Merge。

第三次,0x00007ffff7e43be0和最后输出的值很接近了。

image-20230730133820704

image-20230730133717401

image-20230730133705291

bt查看一下调用栈。笔者决定从tif_dirread.c:5351开始跟一遍。

image-20230730133907787

TIFFSetField函数传入了一个DE结构,一个data,这个data存放的值Tag 的Value。

image-20230730134545211

随后进入内部,发现该函数做了如下操作,执行_TIFFVSetField函数找到Tag对应的TIFField malloc一个TIFFValue给它,最后分配了一个空间存储Value,该空间的起始地址也就是后续print的raw_data,尽管只分配了1字节的空间,但是由于是64位的Linux,内存分配的大小最小也是0x20字节,所以如下图,0x20为chunkSize,03为存储的Value。

image-20230730144612147

image-20230730144550430

后续打印会打印0x7ffff7e43b03,属于是越界读取。但是由于该地方的内存只是单纯的一个地址信息,且由内存管理机制决定,所以似乎无法造成信息泄露。尝试修改Tag的Value数目使得读取其他内存,其计算的偏移会和文件的Size进行一个比较,无法利用。

image-20230730161931631

2.4 补丁分析

在输出字符串的结尾提前放置了\x00防止越界读取。

但是显然这里产生了新的漏洞,如果dp->tdir_count=0,那么data就是NULL,这时候对空指针进行了Read操作。

image-20230730165251689

CVE-2016-9448 的描述看起来起来就是这个原因。

image-20230730165539359

image-20230730165506492

按照第一次的补丁修改一下源码,随后修改Tag的Count为0,果然出现了Segmentation fault。

image-20230730165930967

image-20230730165909301

0x04 参考文献

Linux堆内存管理分析:https://murphypei.github.io/blog/2019/01/linux-heap

TIF规范:https://web.archive.org/web/20120703095221/http://partners.adobe.com/public/developer/en/tiff/TIFF6.pdf

ASAN:https://github.com/google/sanitizers/wiki/AddressSanitizerAndDebugger

Fuzzing101:
https://github.com/antonio-morales/Fuzzing101/tree/main/Exercise%204


[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课

上传的附件:
收藏
点赞4
打赏
分享
最新回复 (5)
雪    币: 12712
活跃值: (16332)
能力值: (RANK:730 )
在线值:
发帖
回帖
粉丝
有毒 10 2023-8-3 09:35
2
0
感谢师傅分享,这个角度真的很少有人过多关注
雪    币: 19634
活跃值: (29304)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
秋狝 2023-8-3 09:49
3
1
感谢分享
雪    币: 1511
活跃值: (383)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
KitTraumen 1 2023-8-15 23:00
4
0

感谢师傅分享,我这里是SetByteArray把无关数据写进raw_data所在的地址



读中断

#0  0x0000ffff8b2ed7c4 in tcache_get (tc_idx=<optimized out>) at ./malloc/malloc.c:3197
#1  __GI___libc_malloc (bytes=bytes@entry=1) at ./malloc/malloc.c:3313
#2  0x0000aaaaadf185ec in _TIFFmalloc (s=s@entry=1) at tif_unix.c:283
#3  0x0000aaaaadf0663c in setByteArray (vpp=0xaaaadfa59c68, vp=0xaaaadfa59be0, nmemb=1, elem_size=<optimized out>) at tif_dir.c:51
#4  0x0000aaaaadf0864c in _TIFFVSetField (tif=0xaaaadfa592a0, tag=57347, ap=...) at tif_dir.c:539
#5  0x0000aaaaadf09604 in TIFFVSetField (tif=0xaaaadfa592a0, tag=57347, ap=...) at tif_dir.c:820
#6  0x0000aaaaadf09710 in TIFFSetField (tif=<optimized out>, tag=<optimized out>) at tif_dir.c:764
...



写中断

#0  __memcpy_generic () at ../sysdeps/aarch64/multiarch/../memcpy.S:123
#1  0x0000aaaaadf0864c in _TIFFVSetField (tif=0xaaaadfa592a0, tag=57347, ap=...) at tif_dir.c:539
#2  0x0000aaaaadf09604 in TIFFVSetField (tif=0xaaaadfa592a0, tag=57347, ap=...) at tif_dir.c:820
#3  0x0000aaaaadf09710 in TIFFSetField (tif=<optimized out>, tag=<optimized out>) at tif_dir.c:764
...
最后于 2023-8-15 23:01 被KitTraumen编辑 ,原因:
雪    币: 1036
活跃值: (626)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
hu1y40 1 2023-9-22 10:46
5
0
KitTraumen 感谢师傅分享,我这里是SetByteArray把无关数据写进raw_data所在的地址读中断#0&nbsp;&nbsp;0x0000ffff8b2ed7c4&nbsp;in&a ...
师傅的tag是57347是不同的样本吗?按理说最后print的raw_data就是#3  0x0000aaaaadf0663c in setByteArray (vpp=0xaaaadfa59c68, vp=0xaaaadfa59be0, nmemb=1, elem_size=<optimized out>) at tif_dir.c:51 这里malloc的内存地址。 而setByteArray应该对应此时的tag(57347)的value,师傅能提供样本让我看看吗?
雪    币: 1036
活跃值: (626)
能力值: ( LV4,RANK:50 )
在线值:
发帖
回帖
粉丝
hu1y40 1 2023-9-22 10:49
6
0

最近突然看到一篇对main_arena利用的文章,文中未写入tag对应value之前,内存中存放的是main_arena+96的地址,这样越界读取可能会造成glic的基址泄露。但是我仍未明白为何CVE-2016-9297这个洞会标明拒绝服务。 main_arena相关:https://cloud.tencent.com/developer/article/1740444

最后于 2023-9-22 10:50 被hu1y40编辑 ,原因:
游客
登录 | 注册 方可回帖
返回