Threat Intelligence

    Mimecast Discovers Use-After-Free Zero-Day Vulnerability in Adobe Reader  

    Adobe Acrobat Reader is a popular target for exploitation attempts; Mimecast Threat Research Labs has discovered a new zero-day vulnerability impacting annotations and comments in the application.

    by Gil Mansharov

    Key Points

    • Mimecast Threat Research Labs discovered a Use-After-Free vulnerability in the latest version of Adobe Acrobat Reader. The vulnerability resides in the implementation and use of annotations in PDF documents.
    • While the vulnerability does not allow for code execution, if exploited by attackers, combined with additional techniques, the vulnerability could further aid in gaining control over affected systems.
    • The vulnerability has not impacted any organizations as of this writing.

    Adobe Acrobat Reader is one of the most popular PDF readers, and as such, it remains a target for potential exploitation attempts. 

    This article details how the Mimecast Threat Research Labs team and I began debugging a zero-day vulnerability encountered during an investigation into reproducing 1-day vulnerabilities in Adobe Acrobat Reader. 

    Anatomy of PDF Annotations in Adobe Reader

    Most modern document readers, including Adobe Acrobat Reader and Microsoft 365, implement features for annotations and comments.

    In Adobe Acrobat Reader, the functionality for annotations is implemented in a DLL file named Annots.api.

    During the course of our ongoing research, we decided to try to interact with the annotation feature using JavaScript for PDF. Luckily, Adobe documents the API for Acrobat’s Javascript engine (based on SpiderMonkey engine), highlighting that the following methods might be relevant:




    Create an annotation in the document


    Create a field in the document


    Set an action for a given trigger for the field


    Destroy the annotation and remove it from the page

    Triggering a Crash

    While testing annotations with an outdated version of Adobe, we tested a script designed to trigger a crash for an existing 1-day vulnerability, and while debugging it, an unexpected crash was introduced. The basic script had the logic below.

    We created an annotation object:

    var annot = this.addAnnot({})

    Then added a text field to the annotation object:

    var f = annot.addField("some_name", {"cFieldType":"text"}, something, something)

    Finally, a trigger was set: the annotation object would be destroyed when the text field blurred.

    f.setAction("OnBlur", "annot.destroy()")

    When the annotation object was accessed programmatically, no unusual behavior was documented.

    However, clicking the text field demonstrated that somehow Adobe Acrobat Reader could access the annotation object, therefore triggering a Use-After-Free bug and crashing the application.

    We were seeing a classic Use-After-Free bug:

    • Free: The annotation object is being freed on an OnBlur event on the text field.

    f.setAction(“OnBlur”, “annot.destroy()”)

    • Use: Clicking the annotation after clicking the text field triggered the OnBlur event and freed the UI object of the annotation, but at the same time, the UI object of the Annotation was being accessed by clicking it.

    Technical Analysis

    To verify the root cause of the crash (Use-After-Free), we debugged Acrobat Reader with WinDBG, and activated GFlags to troubleshoot the bug. To ease the task of debugging, we were forced to disable Protected Mode in Adobe Acrobat Reader.

    When debugging the POC file to trigger the vulnerability, there was an access violation exception, as expected, due to access given to previously freed memory.

    With a simple heap spray in our Javascript code, we also managed to gain control over EIP by corrupting a function pointer in one of Acrobat Reader’s internal objects, as seen in Figure 1:

    Figure 1: Debugging and exception details in WinDBG

    In our Javascript code, we sprayed the heap with 0x0c0d bytes, and it modified the value of the ESI register.

    In addition, the EIP register pointed to the address 0x0, and we could see that the root cause of it was because of a call to a function located at ESI+0x20.

    The value at the address ESI+0x20 was 0x0, which meant that the instruction pointer would be set to this value, and because we had control over ESI, we could also control the function address to be called.

    Gaining control over EIP was not enough for successful exploitation, as in such scenarios the team needed to bypass additional mitigations such as ASLR, DEP, and Acrobat Reader’s sandbox.

    Diving Deeper

    When analyzing and potentially exploiting heap vulnerabilities, it’s important to understand the internals of the heap, and how the objects that we can corrupt are structured.

    Understanding the internal objects of Acrobat Reader isn’t that easy, as the program has no published symbols (unlike Microsoft Office), and it requires additional reverse engineering.

    After initial analysis of the vulnerability and the root cause of the vulnerability, the we decided to dive deeper.

    For this task, we looked at two modules we thought were the most relevant for this vulnerability: Annots.api and AcroRd32.dll.

    To make the analysis easier, we used WinDBG Preview and ran our POC file with Gflags and Time Travel Debugging enabled.

    This way, we could capture a trace file of the execution and replay it backwards and forwards with the debugger.

    We set a breakpoint at the first access we saw to the corrupted object, and when we reached the breakpoint, we wanted to see details on the corrupted heap chunk.

    The screenshot below shows how we could see that the call to the function at 0x710e7b70 changed the contents of the buffer pointed by EDI, and demonstrates how we saw that this was our corrupted buffer.

    Examining the heap chunk that pointed by EDI+0x7A, we could see that the chunk entry was at 0xb7c8010.

    Now we wanted to set a hardware breakpoint on this address, rewind the execution (using Time Travel Debugging), and check all the accesses to this address, including freeing and allocating memory in this address.