CVE-2018-12794类型混淆漏洞详细分析
漏洞概述 通过构造数据可以使程序在处理Template对象时使用Form对象的函数进行处理,从而造成越界数据读取,该漏洞为类型混淆型漏洞。通过构建XML数据包(XDP)模板并对XFA对象执行某些JavaScript操作,攻击者可以强制Reader从Template对象的边界读取数据。成功后,代码将在沙盒渲染器进程中执行。 漏洞细节 POC代码分析 分析漏洞的POC文件,通过PDF流解析工具PdfS
漏洞概述
通过构造数据可以使程序在处理Template对象时使用Form对象的函数进行处理,从而造成越界数据读取,该漏洞为类型混淆型漏洞。通过构建XML数据包(XDP)模板并对XFA对象执行某些JavaScript操作,攻击者可以强制Reader从Template对象的边界读取数据。成功后,代码将在沙盒渲染器进程中执行。
漏洞细节
POC代码分析
分析漏洞的POC文件,通过PDF流解析工具PdfStreamDumper可以看到pdf文件里面的objects流。其中第5个object流为XML Data Package结构。
XML Data Package(XDP)是Adobe Systems创建的XML 文件格式。该格式允许将PDF内容或Adobe XML Forms Architecture(XFA)资源打包在XML 容器中。XDP符合XML 1.0的规范,可以作为独立文档,也可以在PDF文档中携带。XDP提供了一种在XML容器中打包表单组件的机制,XDP还可以打包PDF文件以及XML表单和模板数据。
而在第1个object流对象里面的XFA(XML Forms Architecture)对象会执行JavaScript代码,该代码会操作sub1和sub2,先将sub1添加为xfa.template对象,sub2添加为xfa.from对象,然后将sub2附加到sub1。
XFA为XML Forms Architecture,是一系列专有 XML规范,用于增强Web表单的处理。XFA提供基于模板的语法和处理规则集,允许用户构建交互式表单。基于模板的语法将定义用户在其中提供数据的字段,XFA 的开放特性将提供描述交互式表单的通用 XML 语法。
最后执行JavaScript代码将o2的presence属性设置为inactive ,该属性的含义为隐藏对象并将其从事件处理中排除。在执行该操作的时候将触发crash。

漏洞调试
设置windbg为默认调试器,运行POC文件,windbg将暂停到发生crach的地方。
可以发现程序异常在AcroForm.api模块,ecx的值异常导致程序crash,通过栈回溯可以定位到crash的上一层函数AcroForm!PlugInMain+0x979f1,反汇编该函数并观察ecx的值(ecx的值是直接传入crash函数使用)。
通过反汇编发现ecx的值为[eax+esi*8],而esi只是一个偏移并且为0,所以ecx的值受eax影响。而eax的值是从[edi+1d4]获取。查看[edi+1d4]地址的值可以发现该地址的值其实是pdf主程序路径字符串的一部分,在后面把该字符串的值当成了指针来使用,所以推测是访问越界导致crash。
当重新运行程序,可以发现[edi+1d4]每次的值都差别很大,说明该地址的值是未知区域,每次的值是不可预测的。
在通过heap命令来看该区域堆栈的分配情况可以发现edi所在的空间大小为0x140,edi为该区域的首地址(0x68e5c98+0x8大小的头),推测0x068e5ca0为一个对象指针或者一块申请的内存空间,0x140为该对象或内存空间的大小。而[edi+1d4]所在的堆区域为0x68e5de0所在的堆块,所以在使用[edi+1d4]进行访问的时候会造成越界访问。也可以使用gflags工具开启堆检查来验证。
根据后面的一些指针操作可以发现该堆块保存的都是一些地址,猜测该堆块应该保存的是一个对象。从前面的代码分析中可以知道为XFA对象,再参考《SyScan3602016-_Pwning_Adobe_Reader_with_XFA》报告中给出的关于XFA内部对象的识别办法获取Type-IDs。使用uf poi(poi(对象地址)+8)的命令可以显示出Type-IDs。
使用uf poi(poi(0x068e5ca0)+8)命令,可以看到类型为0x7C00,说明了该堆块保存的是一个XFA对象。
该文件官方没有pdb文件,在调试的时候很多地方很难定位到具体的结构,不过在网上能找到关于XFA结构的研究资料,其中有人做了相关的PDB文件以方便调试,我们找到对应版本的PDB文件加载,在其中搜索B8007C0000就能定位到上图的代码片段。
可以看到0x7C00表示的是XFATemplateModelImpl::Type 的方法,说明该堆块保存的数据为xfa.template对象。通过观察XFATemplateModelImpl相关的有如下函数,其中没有发现有关对象创建和内存申请的函数。
通过交叉引用或直接搜索XFATemplateModelImpl可以找到XFATemplateModelImpl类的构造函数XFATemplateModelImpl::XFATemplateModelImpl。
因为虚表是由构造函数进行初始化,可以通过XFATemplateModelImpl类的构造函数能够定位到XFATemplateModelImpl类的虚表。
通过对该虚表指针进行交叉引用可以得到两处引用,其中一处为XFATemplateModelImpl构造函数的引用,说明还有一处函数也对XFATemplateModelImpl类的虚表指针进行了引用。
通过交叉引用可以找到另一处引用函数sub_208A8FC2。
再对sub_208A8FC2进行交叉引用可以找到在XFATemplateModelFactoryImpl::newModel函数对sub_208A8FC2的调用。
在XFATemplateModelFactoryImpl::newModel函数中可以看到在函数开始就申请了0x140字节的空间,从函数名推测该处是用于new一个大小为0x140的Template对象。
Template对应的类是XFATemplateModelImpl,推测Form对应的类为XFAFormModelImpl,通过查找可以找到与XFATemplateModelImpl类似的XFAFormModelImpl类及函数。
用与查找XFATemplateModelImpl类的办法可以找到XFAFormModelImpl的虚表。在对虚表进行交叉引用找到函数sub_20902394,对sub_20902394进行交叉引用就可定位到相应的初始化Form对象的地址。
可以看到在创建Form对象的时候申请的空间大小为0x270,说明Form对象的大小为0x270。[edi+1d4]的地址实际应该是读取的Form对象中的值,Template对象大小为0x140小于0x1d4从而造成越界数据读取。所以漏洞的根本原因是代码在处理Template对象时使用了Form对象的函数进行处理,造成了类型混淆漏洞。
参考资料
https://github.com/siberas/arpwn
SyScan3602016-_Pwning_Adobe_Reader_with_XFA.pdf
http://blogs.adobe.com/formfeed/2009/03/xfa_30_presenceinactive.html
优秀呀