我们看到大多 PDF 文档的漏洞被提交给了 ZDI ,其中大部分都是涉及到了 Adobe Reader 这款软件。然而在众多的提交报告中,只有特别的漏洞才能吸引我们的眼球。在七月份中的 Reader 的更新报告中涉及到了一个 CVE-2018-12794 / ZDI-18-682 的补丁。 Sebastian Apelt 写了一份高质量的 write-up 向我们介绍了这个漏洞。
The underlying cause of the vulnerability is a Type Confusion condition. By constructing an XML Data Package (XDP) template and performing certain JavaScript actions on XML Forms Architecture (XFA) objects, an attacker can force Reader to reference data out of the bounds of a Template object. When successful, code execution occurs within the sandboxed renderer process.
漏洞的类型是一个类型混淆。通过构建一个 XML 数据包(XML Data Packge)模版并对 XML Forms Architecture(XFA)对象执行某些 JavaScript 操作,攻击者可以强制 Reader 从 模版对象的边界数据。成功后,代码将在沙箱的进程中执行。
The XDP template required to trigger this vulnerability is surprisingly simple:
触发漏洞的 PoC 是很简洁的(XDP template):
该漏洞由两条 JavaScript 指令触发。通过将一个子表单附加到另一个子表单,我们可以触发底层模板对象的Out-Of-Bounds(OOB)Read。在这种情况下,附加一个引用的子表单时会发生漏洞
xfa.template and one by xfa.form and then calling <object>.presence = “inactive”;.
After enabling PageHeap, the resulting crash happens on a CMP instruction when reading OOB of the Template object. While the object only seems to be of size 0x140
bytes, we dereference data beyond the buffer boundaries at offset 0x1d0
:
当我们启动 PageHeap后,在读取越界的 Temlate 对象的时候,会在 CMP 指令上发生 crash 。虽然对象大概只有0x140大小,我们可以对数据解引用到0x1d0位置,超过了本来的范围
Based on the crash, we know the unique object’s type is 0x7c00
. By looking at the symbolized version of acroform.api
from Solaris 9.4.1, we can see that this specific type id belongs to the XFATemplateModelImpl
object, which is simply the “template” object from the underlying XDP:
基于崩溃,我们知道 unique objects 的类型是 0x7c00。通过查看 Solaris 9.4.1中 acroform.api 的符号化版本,我们可以看到这个特定的类型id属于XFATemplateModelImpl对象,它只是来自底层XDP的“模板”对象:
Going back to the non-symbolized Windows version of acroform.api
confirms that the Template object is of size 0x140
bytes, which is the size of the object referenced OOB from above. The size can be found in a few easy steps:
回到没有符号的 windows 版本的 acroform.api
确认Template 对象的大小为0x140字节,这是从上面引用OOB的对象的大小。这个大小我们只需几个简单的步骤就能找到:
Find the static variable 0x7c00
in Acroform.api
and look for the XFATemplateModelImpl::Type
method:
从 Acroform.api
中找到静态变量 0x7c00
并查找 `XFATemplateModelImpl::Type
的方法
Xref gives you XFATemplateModelImpl
vtable:
通过交叉引用得到XFATemplateModelImpl
的虚表
Xref to vtable start gives you constructor
通过交叉引用 虚表的开始地址 得到 构造函数。
Xref to constructor and scrolling a few lines up will show you the object’s size, which is 0x140
bytes:
通过交叉引用构造函数之后向上滚动几行,我们就能看到安个对象的大小。大小为 0x140 字节
Since we cause an OOB read of the Template Object, we can surmise the code expected a different, larger object instead of the Template object, which also indicate this is a type confusion bug. Most likely, the type confusion occurs between the xfa.template
and xfa.form
objects. While xfa.template
is of size 0x140
bytes, the xfa.form
object has size 0x270
bytes.
因为我们在读Template对象的时候造成了OOB读,我们可以确信这段代码本来是想要一个不一样的,更大的对象而不是Template对象,也就是说这是一个类型混淆漏洞。更可能是是,在xfa.template和xfa.form对象之间有一个类型混淆,而xfa.template是0x140大小,xfa.form对象是0x270大小
We can’t execute JavaScript code before the Template Object is instantiated, so controlling the crash isn’t trivial. To accomplish this, an exploit would need to resort to controllable allocations and frees during the PDF parsing process or any other controlled data handling before XDP parsing happens. An alternative method to control the crash would be to construct a PDF that contains an attached PDF that triggers the vulnerability. Heap feng shui would have to happen in the “outer” PDF triggering the vuln in the “inner” (attached) PDF. Then again, opening the attached PDF in a way that makes it execute JavaScript code requires elevated privileges, so it might not be effective against most users.
我们无法在实例化模板对象之前执行JavaScript代码,因此控制崩溃并非易事。为了实现这一点,在XDP解析发生之前,在PDF解析过程或任何其他受控数据处理期间,漏洞的利用需要求助于可控制的分配和释放。控制崩溃的另一种方法是构建一个PDF,然后PDF里再嵌套一个可以触发漏洞的PDF。堆风水按理说可以在外层PDF里来做,从而触发内层(attach上去的)PDF。那么又回来了,打开attach的PDF来让他执行js代码需要逃逸之后的权限,所以对于大多数用户来说可能没有太好的效果
The fact that this crash can be controlled can be observed by executing poc.pdf without PageHeap. The resulting crash will eventually occur due to parts of a Unicode string being read and used as a pointer. The following is a crash output without PageHeap:
事实上,我们可以通过在没有PageHeap的情况下执行poc.pdf来观察是否可以控制此崩溃。造成崩溃的原因是,读取了Unicode字符串的一部分并被当作指针使用,最终造成了崩溃。以下是没有PageHeap的崩溃输出:
If you want to test this out for yourself, the PoC is here. It should work on Adobe Reader versions prior to 2018.011.20040.
如果你想要测试这个漏洞,PoC的地址在这。只在 Adobe Reader 2018.011.20040 的版本有效。
Looking at the advisories we’ve published this year, you’ll find a heap of PDF-related cases. Adobe Reader may be the most popular, but plenty of bugs exist in Foxit Reader as well. Throw in built-in PDF renderers in operating systems, and it’s understandable why so many researchers investigate this attack surface.
看看我们今年发布的报告,您会发现一堆与PDF相关的案例。 其中 Adobe Reader 可能是最受欢迎的,但福昕阅读器中也同样存在大量漏洞。因为操作系统一般都内置了 PDF renderers,所以有那么多的研究者研究这个攻击面也不为过。