-
-
[分享]CVE-2013-0640的分析记录
-
发表于: 2018-9-4 23:24 12216
-
1.概述:在Adobe Reader的XFA(XML Forms Architecture)处理模块AcroForm.api 中,存在一个用于得到任意代码执行权限的漏洞,编号为CVE-2013-0640。另一个是 CVE-2013-0641,该漏洞存在于 Adobe sandbox 的 broker 进程中,用于从sandbox 中逃逸,获取高权限,这两个漏洞同时被用在了一个样本中。CVE-2013-0640的POC可在古河的文章下获取(
https://bbs.pediy.com/thread-163035.htm
)。
2.实验环境:版本为11.0.1的Aodbe Reader,XPSP3,Win7,OD,windbg,IDA
3.漏洞触发原因: 漏洞触发的基本过程是这样:AcroForm.api中的内存分配函数Alloc在分配 Adobe Reader的 XML表单中的新节点NewObject后,由一个存在缺陷的函数bugFun来调用这个新节点,一开始分配的时候 NewObject 的大小为40h字节,但是当缺陷函数bugFun再去引用这个节点NewObject的时候,访问的却是[NewObject+44h]的地方,多访问了4个字节,而这个位置也是一个对象的指针,这个漏洞的产生原因就是bugF函数在引用节点NewObject的时候没有对可引用的范围做限制,造成了越界访问。
4.分析记录:这里先是分析了CVE-2013-0640的POC样本,这个POC用来演示CVE-2013-0640的触发和利用,之后再分析了真实样本。
首先将OD设置为实时调试器,接着打开POC,不久OD就会捕获异常,程序停在了“0x88888888”,由于这个函数地址"0x88888888"是伪造的,也是不存在的,于是函数没有正常返回,可以看到是“0x208a54d3”调用了函数,在上面的指令中可以看到取函数地址的过程,如下图所示:
接着用windbg来分析,感觉用windbg下断点更方便。用Windbg附加Aodbe Reader后,直接g命令运行,crash的完整汇编代码如下:
对应的伪代码:
可以对比着看上图OD在crash的现场,在”0x208A54b9“的地址处获得了[NewObject+44h]的虚表指针,在这之前esi的值由”0x208A5488“处的mov esi,[eax]赋予,而eax的值最初由”0x208A5478“处的调用函数生成返回,就是这个函数”0x208A5514“生成了新节点NewObject,具体的分配函数是”0x208A5514“的一个子函数:这里可以看到新节点NewObject的大小为40h,但是上图中”0x208A54b9“处却引用了偏移44h的位置 ,多访问了四个字节:
而这个 [NewObject+44h]的地址存放的也是某个对象的指针,该对象的结构如下:
struct NewObject+44t {
+0 虚表
+4 referencecount //当引用计数为 0 时,对象将被析构
+30 unknown
+48 MemberArray //一个数组结构的指针 }
重新用windbg附加Adobe Reader,一开始有说到漏洞函数存在的模块为AcroForm.api,于是用模块断点”sxe ld AcroForm.api"对漏洞函数所在的模块下断点,成功之后根据上面的分析在”0x208a54b9“处下下断观察[NewObject+44h]的虚表指针被覆盖的过程:
接着通过内存写断点"ba w4 0c0c0c20"来跟踪虚表地址被覆盖的过程,如下图所示:
4.样本构造:(这部分内容参考古河的分析: https://bbs.pediy.com/thread-163035.htm )
通过以上分析可知,只要能控制[NewObject+44h]处该对象指针的值,以及这个值所指向的内存区域的内容,就能控制 EIP,首先将[NewObject+0x44]处的值设为 0x0c0c0c20,于是 0x0c0c0c20 将被当 成一个 Member44_t 对象的指针进行后续操作,同时我们将 0x0c0c0c20 处的内存布局成如下形式:
1. [0x0c0c0c20] = 0x0c0c0c28, 在析构对象调用析构函数时将被使用。
2. [0x0c0c0c24] = 1, 该对象的引用次数,将其设置为 1,于是在 “dec dword ptr [ecx+4]” 的减操作完成后,析构动作立即发生。
3. [0x0c0c0c28] = 0x88888888,这个是虚表中第一个函数,最后 crash 时 EIP 会指向 0x88888888
现在的问题是我们如何精确地控制[NewObject+0x44]处的值,使其变成 0x0c0c0c20? 这个是可以办到的,关键在于 AcroForm.api 中自带的堆内存分配机制。 AcroForm.api 有自己的堆分配管理机制(可选),这个机制和 Windows 自身的很像,它针对大小为 0 ~ 0x100 的内存分配有专门的 0x100 个 freelist,用来 保存已经释放的内存块(当然没有真的调用 free 去释放,同时还有另外的一个 freelist 存放其它大小的 已释放内存块。当一个内存分配请求到来时,先检查 freelist 中有没有合适的内存块,如果找到合适的 则直接返回这个块;如果没有正好合适的大小,则尝试将较大的已释放内存块切成小一点的内存块返 回,实在找不到了才会新分配内存。这里还有一个要点是,对于 freelist 中的内存块,在释放和重新分 配返回时,不会将原有的内容进行清理。 利用这个自定义的内存分配机制,我们现在可以精确地控制[NewObject+0x44]处的内容了。首先分 配一系列较大的内存块,将这些大内存块填充为 0x0c0c0c20。 然后分配一些和 NewObject 大小相同的块,这样做的目的是为了将 freelist 中已有的缓存用完。然后 我们释放所有的大内存块,紧接着触发漏洞。在漏洞触发时,NewObject 被分配,由于大小相同的 freelist 已经被清空,于是它会尝试从我们刚刚释放的某个大内存块中切割出一个 0x40 的小内存块并返 回,换句话说,返回的 NewObject 地址其实是落在我们刚刚释放的某个大内存块中间的。于是在越界 访问 NewObject+0x44 时,得到的值是我们一开始在大内存块中填充的值,即 0x0c0c0c20。
整个过程如下图:
控制eip的示意图:
”NewObject“的生成和越界访问“NewObject+44h”的过程可以参考POC样本中的javascript代码来理解,关键代码如下:
第一步:解析获取节点
xfa.resolveNode("xfa[0].form[0].form1[0].#pageSet[0].page1[0].#subform[0].field" + index.toString() + "[0].#ui[0]");
uiListNodes.push(node);
//解析并获取 XFA 表单中的一个UI节点,这个节点就是在汇编代码中“0x208A5478”处生成的节点对象“NewObject”
var node = xfa.resolveNode("xfa[0].form[0].form1[0].#pageSet[0].page1[0].#subform[0].field" + index.toString() + "[0].#ui[0].#choiceList[0]");
choiceListNodes.push(node);
//解析并获取上面得到的UI节点下面紧邻的choiceList节点,这个节点就是“NewObject+44h”处的那个对象
}
[培训]内核驱动高级班,冲击BAT一流互联网大厂工作,每周日13:00-18:00直播授课
赞赏
- [原创]被村长的真诚感动 3457
- 求一本《0day安全:软件漏洞分析技术》 50502
- [讨论]《疯狂的程序员》的读后感 4215
- [分享]CVE-2013-0640的分析记录 12217
- [讨论]大家有没有遇到这种情况:看视频教程久了之后好像不愿意看书了 5547