Adobe Reader漏洞分析、调试报告
一.漏洞描述
Adobe Reader在阅读PDF文件时使用一些公共格式载入字体说明,比如TrueTypeFont (TTF).
TTF中有几个片段负责格式化存储字体字形的描述,其中一个片段是字节码语言,它由TTF渲染器中的一个解释器执行。这个解释器是一个基于堆栈的虚拟机,因此它使用的大部分指令都以某种方式修改指令。MINDEX指令可以从栈中弹出一个值,并利用这个值作为一个索引进入栈区。该索引上的值被移到栈顶,栈中原有的值依次向下移动以填补移动索引值产生的空间。
MINDEX 指令的伪码:
index = stack.pop()
new_top = stack[index]
for (i = 1; i<= index; i++)
stack[i] = stack[i - 1]
stack[0] = new_top
由于所有的栈操作都以4byte为单位,故而该索引值为了找到用于移动的位偏移值,会在Adobe Reader的解释器里进行乘以4的运算。但却没有对这个乘法运算进行整数溢出的检测。这个“索引”的原始值作为一个数字元素复制到一个循环中,如果这个“索引”足够大的(在进行乘4运算时能溢出一个小数值的)数值时,会导致缓冲区溢出。
1.补充
在解析文件时,首先查看“PDF key /FontFile2”可能会获得TTF数据。
找到TTF数据段后,需要对其进行解析,并检查“glyf”表,每个字形条目都可以包含0个或多个TTF字节码格式的指令,需要对他们进行解码和模拟,一次来发现MINDEX指令。
找到MINDEX指令后,需要检查位于栈顶的值(将被用做索引),如果这个值位于下列范围:0x40000001<= index <= 0x7fffffff ,那么这个PDF文件应标记为恶意的PDF文件。
二、 调试环境与工具
环境:Windows XP3 + AdobeReader9.4.0.195
工具:OllbDBG + IDA Pro + 010 Editer
三、 调试记录
载入POC后程序出现内存访问异常:
080079CE MOV DWORD PTR DS:[ECX],EBX ;ECX=0823F000,EBX=0
ALT+M查看内存窗口,发现程序尝试是向CoolType.dll的.rscr段写入数据,而.rscr段内存一般都只读的,在执行MOV DWORD PTR DS:[ECX],EBX发生了内存访问异常。
按MAPP的描述,发生异常的位置在MINDEX 指令处,载入IDA看看这段代码:
回头再看看图1中的EDX,EDX是一个很大的值,而字节码解释器的堆栈位于CoolType.dll的.dada内存中。MINDEX 指令处在取栈最上面的索引值后,跟据索引值计算出偏移量去取值后,堆中的元素向下移动去填补取出值的位置(堆的增长方向是向高地址与windows程序中的堆栈不同),即高地址的4个字节复制到相邻的低地址的4个字节,如果这个栈中的索引没有验证大小,MINDEX 指令在移动数据直到索引值为0才停下,如果在移动过程中覆盖到重要的数据,此漏洞可变为可利用的漏洞。
.text:0800798B MINDEX proc near ; CODE XREF: sub_800690E+49p
.text:0800798B ; sub_806C605+48p
.text:0800798B ; DATA XREF: .data:0821BF68o
.text:0800798B
.text:0800798B arg_0 = dwordptr 4
.text:0800798B
.text:0800798B moveax, StackTop
.text:08007990 movecx, Var
.text:08007996 push ebx
.text:08007997 push esi
.text:08007998 movesi, [ecx] ; stack.base
.text:0800799A lea edx, [eax-4]
.text:0800799D cmpedx, esi ; 弹出一个值后的堆栈地址是否大于或栈基
.text:0800799F push edi
.text:080079A0 jb short FailRet
.text:080079A0
.text:080079A2 movedi, [ecx+154h] ; Stack.Limit?
.text:080079A8 cmpedx, edi ; 栈顶是否大于stack.limit
.text:080079AA jnb short FailRet
.text:080079AA
.text:080079AC add eax, 0FFFFFFFCh ; -4
.text:080079AF movedx, [eax] ; 取索引
.text:080079B1 movebx, edx
.text:080079B3 shlebx, 2 ; 计算出偏移量,偏移量=索引*4
.text:080079B6 movecx, eax
.text:080079B8 sub ecx, ebx ;ebx=偏移量
.text:080079BA cmpecx, esi
.text:080079BC jb short FailRet
.text:080079BC
.text:080079BE cmpecx, edi
.text:080079C0 jnb short FailRet
.text:080079C0
.text:080079C2 test edx, edx
.text:080079C4 movedi, [ecx] ; 保存取出的值。
.text:080079C6 jle short loc_80079D7
.text:080079C6
.text:080079C8
.text:080079C8 Moving: ; CODE XREF: MINDEX+47j
.text:080079C8 decedx
.text:080079C9 lea esi, [ecx+4]
.text:080079CC movebx, [esi]
.text:080079CE mov [ecx], ebx
.text:080079D0 movecx, esi
.text:080079D2 jnz short Moving
.text:080079D2
.text:080079D4 sub eax, 4
.text:080079D4
.text:080079D7
.text:080079D7 loc_80079D7: ; CODE XREF: MINDEX+3Bj
.text:080079D7 mov [eax], edi
.text:080079D9 add eax, 4
.text:080079DC movStackTop, eax
.text:080079E1 moveax, [esp+0Ch+arg_0]
.text:080079E5 jmp short loc_80079F6
.text:080079E5
.text:080079E7 ; ---------------------------------------------------------------------------
.text:080079E7
.text:080079E7 FailRet: ; CODE XREF: MINDEX+15j
.text:080079E7 ; MINDEX+1Fj MINDEX+31j
.text:080079E7 ; MINDEX+35j
.text:080079E7 moveax, dwEIP
.text:080079EC mov dword_8232434, 1110h
.text:080079EC
.text:080079F6
.text:080079F6 loc_80079F6: ; CODE XREF: MINDEX+5Aj
.text:080079F6 pop edi
.text:080079F7 pop esi
.text:080079F8 pop ebx
.text:080079F9 retn
.text:080079F9
.text:080079F9 MINDEX endp
四、字节码相关分析
通过日志断点打印字节码信息,发现此索引是跟据glyf中的字节码数据计算出来的。
1. 打PCode长度信息:
2.设置打印PCode地址信息日志断点:
3.打印虚拟机”指令”信息:
4.虚拟机指令执行前的当前堆栈数据:
5.指令结束后的当前虚拟机堆栈的数据:
6.指令分隔符号信息,便于查看信息:
OllyDBG重新载入AdobeReade.exe,在MINDEX 指令的首地址下普通断点后,打开poc文件后开始打印日志,程序停下来之后查看最后的记录:
08006927 条件: PCode = 02DD6B33
08006928 条件: Instruction = 0026
08006956 条件: 执行前堆栈[vm_esp] = 40000001
0800798B 断点位于
从打印的信息来看MINDEX 指令是0x26,当前堆栈为[vm_esp] = 0x40000001.
0x40000001正好当前栈的索引值。Eax值指向当前PCode的地址。
从分析日志来看:
索引的值是7fff + 7fff + 3FFF0003
08006927 条件: PCode = 02DD6B2A
08006928 条件: Instruction = 0078//跳转指令
08006956 条件: 执行前堆栈[vm_esp] = 00000000
0800695E 条件: 执行后[vm_esp] = 3FFF0003
08006962 条件: **********************************************************************
08006927 条件: PCode = 02DD6B2B
08006928 条件: Instruction = 0041Push_Imm16,将7fff,7fff压入堆栈再相加
08006956 条件: 执行前堆栈[vm_esp] = 3FFF0003
0800695E 条件: 执行后[vm_esp] = 00007FFF
08006962 条件: **********************************************************************
08006927 条件: PCode = 02DD6B31
08006928 条件: Instruction = 0060 ADD [ESP-4],[ESP]
08006956 条件: 执行前堆栈[vm_esp] = 00007FFF
0800695E 条件: 执行后[vm_esp] = 0000FFFE7fff + 7fff = fffe
08006962 条件: **********************************************************************
08006927 条件: PCode = 02DD6B32
08006928 条件: Instruction = 0060ADD [ESP-4],[ESP]
08006956 条件: 执行前堆栈[vm_esp] = 0000FFFE
0800695E 条件: 执行后[vm_esp] = 40000001 3FFF0003 + fffe = 40000001
08006962 条件: **********************************************************************
08006927 条件: PCode = 02DD6B33
08006928 条件: Instruction = 0026 MINDEX 指令
08006956 条件: 执行前堆栈[vm_esp] = 40000001
0800798B 断点位于
再往上查看日志3FFF0003是从哪来的:
分析日志得知:00FFFC00 + 3EFF0403 = 3FFF0003
08006962 条件: **********************************************************************
08006927 条件: PCode = 02DED7D2
08006928 条件: Instruction = 0041
08006955 条件: 执行前VM_ESP地址= 08236230
08006956 条件: 执行前堆栈[vm_esp] = 3EFF0403
0800695E 条件: 执行后[vm_esp] = 00007FFF
0800695F 条件: 执行后VM_ESP地址= 08236238
08006962 条件: **********************************************************************
08006927 条件: PCode = 02DED7D8
08006928 条件: Instruction = 0063
08006955 条件: 执行前VM_ESP地址= 08236238
08006956 条件: 执行前堆栈[vm_esp] = 00007FFF
0800695E 条件: 执行后[vm_esp] = 00FFFC00
0800695F 条件: 执行后VM_ESP地址= 08236234
08006962 条件: **********************************************************************
08006927 条件: PCode = 02DED7D9
08006928 条件: Instruction = 0060ADD [ESP-4],[ESP]
08006955 条件: 执行前VM_ESP地址= 0823623408236234的值是7FFF而08236234-4的值是3EFF0403
08006956 条件: 执行前堆栈[vm_esp] = 00FFFC00
0800695E 条件: 执行后[vm_esp] = 3FFF0003 00FFFC00 + 3EFF0403 = 3FFF0003
0800695F 条件: 执行后VM_ESP地址= 08236230
08006962 条件: **********************************************************************
日志最开始的地方显示PCode的长度为0x79:
08006917 条件: Pcode长度= 00000079
一直通过追述到源头到发现此值是在一个循环中逐步增加计算索引的一个过程。
复制内存中的PCode在010 Editer中查看:
最后此漏洞分析到此完成了,还有很多东西不相关的分析没有贴上来,对于文件格式不明白,所以还有很多东西搞不清楚
密码忘了不用怕 按照下面的步骤可以轻松破解win2000的密码
第一步,网站下载NTFSDOS Professional软件,下载后进行安装,安装后执行NTFSDOS Professional Boot Disk Wizard程序,根据向导,会提示依次插入两张软盘,其实能用到的就是第一张。第二步,用Win98软盘或光
详情2018-01-30 11:05:05责编:llp 来源:驱动管家如何降低ie mime sniffing功能带来的风险?
IE有一个特性,那就是在将一个文件展示给用户之前会首先检查文件的类型,这乍看起来并没什么问题,但实际上这是相当危险的,因为这会允许IE执行图片中的代码,即嵌入在一个图像中的JavaScript代码。引入MIME sni
详情2018-02-28 18:12:04责编:llp 来源:驱动管家保护你的隐私,grub密码怎么被md5加密?
GRUB——全称”Grand unified bootloader“的缩写,是GNU项目的一个启动加载包。在linux系统启动过程中,GRUB在MBR(主引导加载程序或主引导记录master boot record)之后启动,故又将GRUB称为次引导加载程序
详情2018-01-30 16:39:48责编:llp 来源:驱动管家dsa是什么?dsa算法应用哪些参数?
DSA是基于整数有限域离散对数难题的,其安全性与RSA相比差不多。DSA的一个重要特点是两个素数公开,这样,当使用别人的p和q时,即使不知道私钥,你也能确认它们是否是随机产生的,还是作了手脚。RSA算法却作不到
详情2018-01-17 17:08:02责编:llp 来源:驱动管家互联网有哪些恶意软件?互联网十大恶意软件
想要从所有的安全厂商那里得到所有的数据并分析恶意软件感染的难度无异于“上青天”。不过总会有安全企业会通过自己的数据来分析当前网络威胁的数量和类型,以及恶意软件传播的高峰期或谷底期。安全厂商Check Po
详情2018-01-14 10:34:55责编:llp 来源:驱动管家directaccess可以提高企业安全性 具体如何操作?
Direct Access 称为直接访问,是Windows 7(企业版或者更高级版本)和Windows Server 2008 R2中的一项新功能,外界的网络可以不用建立VPN连接,克服了VPN的很多局限性,直接访问公司防火墙之后的资源,既高速又
详情2018-02-06 16:55:33责编:llp 来源:驱动管家暴力修改程序代码有哪些流程?软件的保护方式有哪些?
暴破顾名思义就是暴力修改程序的代码来达到破解的目的。当然根据共享软件的注册方式我们可以对症下药 比如说没有注册的软件有功能限制、使用次数限制、使用日期限制等,我们就可以分别对待了!我们只需要解除这
详情2018-02-16 16:45:46责编:llp 来源:驱动管家病毒清除软件:1kb文件夹快捷方式病毒清除专用附件
1KB文件夹快捷方式病毒清除专用附件包含三部分。1、清理工具2、数据流清除工具3、wscript文件权限恢复在系统盘为FAT32的系统内,只需要使用“清理工具”清理即可。在系统盘为ntfs的系统内,首先使用“清理工具”
详情2018-01-20 16:47:00责编:llp 来源:驱动管家mcafee防病毒软件怎么保护网站服务器?安全的web目录怎么设置?
本文主要拿ASP文件做演示,大家可以修改E: wwwroot** asp为我们所希望限制的文件格式
详情2018-01-18 19:33:52责编:llp 来源:驱动管家csrf worm技术分析 百度有哪些漏洞会导致web蠕虫出现?
漏洞起因:百度是国内最大的中文搜索引擎。同时百度也提供了百度空间、百度贴吧等BLOG社区服务,拥有海量的用户群,号称全球最大中文社区。80sec发现过百度产品一系列的安全漏洞,其中一些问题得到了有效的修补,
详情2018-02-25 14:59:26责编:llp 来源:驱动管家
- phpcms v9 blind哪里存在漏洞?参数过滤存在SQL注入漏洞
- linux下安装Nvidia显卡驱动的详细步骤
- 在笔记本电脑的Ubuntu系统上安装Nvidia显卡驱动的方法
- Win10升级助手绿色版1.0.218下载 绿色免安装 解压后即可使用
- 在wps工具上怎么样设计出多样化的文字样式
- 电脑想要开启内存双通道模式应该怎么操作
- 映泰X370GT5怎么样 映泰X370GT5评测
- 蔚来为购买ES8提供每台1.112万元的补贴
- 虽然谷歌Chrome浏览器小幅下滑 但仍占PC浏览器主导地位
- 电脑连接蓝牙鼠标的时候提示输入码无效怎么解决
- 在win10电脑上怎么快速打开html文件
- 小鲜4评测结果 小鲜4用起来怎么样?
- 360手机q5可以装双卡吗?360手机q5配置如何?
- 电脑提示无法访问光驱怎么办?两个简单步骤轻松搞定
- 虚拟内存太低怎么办 虚拟内存如何设置最好
- 怎么利用搜狐网站的url跳转漏洞盗取密码?
- 软件防火墙如何入侵?先要找到注入点
- 苹果电脑安装win7如何管理驱动程序 蓝牙驱动出问题的解决方法
- parallels desktop安装驱动方法
- qsv格式转换mp4格式怎么转换?