Summary

Recently, Adobe patched some security
vulnerabilities in Adobe Acrobat and Reader. One of them is a
use-after-free vulnerability (CVE-2016-4119) discovered by Fortinet's
FortiGuard Labs. In this blog, we want to share our analysis of this
vulnerability.

Proof of Concept

This vulnerability can be reproduced by opening the PDF file
“PoC_decrypt.pdf” with Adobe Reader DC. When opened, AcroRd32.exe crashes,
and the crash information shows the following:

Analysis

This vulnerability exists in Adobe Reader DC because it fails to parse
the PDF file correctly. It’s a use-after-free vulnerability based on the
debug information in the previous section. Let’s look into this specially
crafted PDF file first. The comparison between the normal PDF file and the
minimized PoC file is shown below.

Figure 1. The PoC File vs The Original PDF
File

Figure 2. The Parsing of the PoC File with 010
Editor

In Figure 1 and Figure 2, the only difference is a single
byte at offset 0x25B0C between the original PDF file and PoC file, and this
byte is located in obj 29 in the PDF file. The object structure is shown
below.

This object stores an
image with width 405(0x195) and height 134(0x86). The data in it has been
compressed using the deflate algorithm. (For more information on deflate,
please refer to https://tools.ietf.org/html/rfc1951.)
Zlib is a C library which implements the deflate algorithm. We can use a
python script to decompress the data in obj 29. When the script is run, we
can see the following exception.

This means that some error occurs while decompressing the
data. Only part of the data is successfully decompressed. The decompressed
data is shown below and its length is 0x54FC.

Figure 3. Part of Decompressed
Data

By reversing Adobe Reader DC, we can see that it also uses
zlib to decompress the deflate-compressed data. So next, let’s look at the
crash information.

From the above debug
information, we can see that ECX points to an invalid memory address
which is gotten from ESI+C8. ESI (address is 0x1cc81d14) is located in a
heap buffer, with size 0xfe0c. So we need to figure out how the heap buffer
is created, and how the data in it is handled. Following is the code
snippet around the address 0x07881f2d.

The next question,
then, is how to find the heap buffer that causes the access
violation. In Figure 3, we can see some ASCII characters in the
decompressed data. We can search for them in memory and the results are
shown below:

The above memory information
matches the decompressed data in Figure 3. After repeating the
debug, we found the memory address 0x1a1e7619 located in the heap buffer
causes the access violation. The heap buffer starts at address 0x1a1e21f0,
and its size is 0xfe0c. It contains the decompressed data whose size is
0x54fc. Next, we need to trace the heap buffer that starts at address
0x1a1e21f0. We can set the following breakpoint in Windbg:

Following is the ‘if’ branch in function sub_6056dc50.
Because [ebp+var_8C] is equal to 0, it will take the green color branch. In
this branch, the pointer of the heap buffer isn’t set to NULL after the
heap buffer is freed. So this is what causes the use-after-free issue.

Figure 4. ‘If’ Branch in
Function sub_6056dc50

Let’s set the following breakpoint to trace why [ebp-8c] is
equal to zero:

Because [ebp-8c] is
equal to 0, the program takes the green color branch. If it takes the red
color branch, the heap buffer pointed by [this+0x38]+0xC8 will be freed and
set [[this+0x38]+0xC8] to NULL.

Based on the above analysis, we can finally draw a picture to
explain how the heap buffer is created, freed, and then reused.

Figure 8. How the Heap Buffer
is Created, Freed, then Reused

In short, because Adobe Reader DC fails to decompress the
deflate-compressed data, it gets incomplete image data. Then, when it
handles the data, a use-after-free issue is triggered.

Use-after-free vulnerabilities are often very complex and
their causes vary from case to case. The common scenario works like
this:

At some point an object is
created with a vtable,

Later, the object gets called
by a vtable pointer. If the object is freed before it gets called, the
program will crash when it tries to call the object.

To exploit this kind of vulnerability, you normally need to
perform the following steps:

At some point an object is
created with a vtable,

Trigger a free operation on
this object,

Create a fake object which
resembles the freed object as closely as possible,

Later, when the vtable pointer
is called, the fake object will be accessed and gain code
execution.

Mitigation

All users of Adobe Acrobat and Reader are encouraged to
upgrade to the latest version of this software. Additionally, organizations
that have deployed Fortinet IPS solutions are already protected from this
vulnerability with the signature
Adobe.Acrobat.Reader.DC.Memory.Corruption.