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

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

hu1y40 看雪学苑 2023-08-19 18:20

最近在进行Fuzzing的学习,发现对Crash分析的内容较少,故而写此篇分析记录一下,望与各位同行共同进步。

由于笔者也属于刚入门,若有误望大家指正。

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出的样本。

4.漏洞影响

Libtiff <= 4.0.6

5.解决方案

更新至Libtiff4.0.7以上版本

1. 环境准备

详细搭建可以参考Fuzzing101

目录创建

“`




下载tiff-4.0.4  
> ```

使用ASAN模糊测试。

“`



#####   
##### 2.FUZZING  


![](https://mmbiz.qpic.cn/sz_mmbiz_png/1UG7KPNHN8FdUSfeIs50LDKC7jk6QDYk99Y9A08hOpCU8dsRPHdmEL5Obffc3kURy0qn2icXT5icBeqGsFDztaeA/640?wx_fmt=png "")  
####   
####   
#####   
##### 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文件。  


![](https://mmbiz.qpic.cn/sz_mmbiz_png/1UG7KPNHN8FdUSfeIs50LDKC7jk6QDYkMaTP8knpQziaxQNF9rqSTOtl3admBZZdhDkXMAJXibZ7wIcb73MhRcrw/640?wx_fmt=png "")  


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

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

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

![](https://mmbiz.qpic.cn/sz_mmbiz_png/1UG7KPNHN8FdUSfeIs50LDKC7jk6QDYkF11icLDpEPKuicHa0HHkic2FY8I1ngDWC86wwKNRmJDLC5vnkfdHicffPw/640?wx_fmt=png "")  

随后是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存放于此。  


划分一下数据  


![](https://mmbiz.qpic.cn/sz_mmbiz_png/1UG7KPNHN8FdUSfeIs50LDKC7jk6QDYkVHgAVuecs9Uvqgd2tiaIwpJdpBSUbia8UYIAAHTKhQXfCxh1yibcasgzw/640?wx_fmt=png "")  


红框处是下面出现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结构)解析错误,错误为堆溢出。  


![](https://mmbiz.qpic.cn/sz_mmbiz_png/1UG7KPNHN8FdUSfeIs50LDKC7jk6QDYkJ2wEVvRWSA9R7wX3X6l7Xutaf4EBlNw7FJUEdx5J9LnREdPpjPY2icg/640?wx_fmt=png "")  


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


![](https://mmbiz.qpic.cn/sz_mmbiz_png/1UG7KPNHN8FdUSfeIs50LDKC7jk6QDYkdG14e2NzCaefoVSz3FHJzLLFialFJcX6gJiab9rcX9O6PJ4h2d3FZXqw/640?wx_fmt=png "")  


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


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


![](https://mmbiz.qpic.cn/sz_mmbiz_png/1UG7KPNHN8FdUSfeIs50LDKC7jk6QDYkKxxCjLXIQkP3hiaEOOdQzzSFNhdXNRvk4Uj8WDtr9zk3bcLKKibvicicTA/640?wx_fmt=png "")  


这里将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,因为该内存地址是可读写的。  


![](https://mmbiz.qpic.cn/sz_mmbiz_png/1UG7KPNHN8FdUSfeIs50LDKC7jk6QDYk4YRhTibj3iaPIXY5H9KsVrmC34hgugYYEM8MVlKrSkbuVhqvxUq5eeWw/640?wx_fmt=png "")  


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


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

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

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

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

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

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

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

2.4 补丁分析

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

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

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

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

参考文献

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

看雪ID:hu1y40

https://bbs.kanxue.com/user-home-937383.htm

*本文为看雪论坛精华文章,由 hu1y40 原创,转载请注明来自看雪社区

#往期推荐

1、在 Windows下搭建LLVM 使用环境

2、深入学习smali语法

3、安卓加固脱壳分享

4、Flutter 逆向初探

5、一个简单实践理解栈空间转移

6、记一次某盾手游加固的脱壳与修复

球分享

球点赞

球在看