Threat Research

Deep Analysis of CVE-2016-0010 - Microsoft Office RTF File Handling Heap Overflow Vulnerability

By Kai Lu | January 20, 2016


On the patch Tuesday of this month, Microsoft patched 3 Office vulnerabilities in MS16-004. The vulnerability CVE-2016-0010 was discovered by myself and Fortinet's threat research team at the FortiGuard Labs. It is a heap overflow vulnerability in Microsoft Office because it fails to parse RTF documents correctly. Successful exploitation of this vulnerability could allow malicious users to create remote code execution scenarios. The underlying problem involves a typical heap overflow caused by a user-supplied value which is copied into a buffer allocated based on a user-supplied length. In this blog, I want to analyze the root cause of this vulnerability.


When we use Word to open the crafted RTF file, Word crashes and the crash info is as follows:

Let’s look into the specially crafted RTF file first.  The minimized version of the PoC has one byte difference at offset 0x1733D. The comparison between the normal RTF file and the minimized PoC file shows below.  

Figure 1. The Normal RTF File vs The Minimized PoC File

From above figure 1, we can see the different byte locates in the following structure.

The original structure shows below:

Obviously the vulnerability exists due to an error when handling the “pict” structure in RTF file.

Let’s simply introduce the RTF file format first. The specification can be found at RTF files are usually 7-bit ASCII plain text, consisting of control words, control symbols, and groups. An RTF control word is a specially formatted command used to mark characters for display on a monitor or characters destined for a printer. A control word’s name cannot be longer than 32 letters. A control word is defined by:  \<ASCII Letter Sequence><Delimiter>    (where <Delimiter> marks the end of the control word’s name).

Here we only focus on the control word “\\pict”. An RTF file can include pictures created with other applications. These pictures can be in hexadecimal (the default) or binary format. Pictures are destinations and begin with the control word “\\pict”.  A picture destination has the following syntax:

These control words are described in the following table. 

In the PoC file, the picture uses “\\dibitmap0” and “\\wbmwidthbytes16” control words.

From “\\dibitmapN” definition, we know that the information to be included in RTF from a Windows device-independent bitmap is the concatenation of the BITMAPINFO structure followed by the actual pixel data. Then, the question is how to map the following metadata into the BITMAPINFO structure?

We have known that this picture is a Windows device-independent bitmap.  So we can create a picture in Windows Paint and save it as a BMP file. Then we use 010 Editor BMPTemplate to parse it as shown in the figure 2 below.

Figure 2.  Parsing of the BMP File

Then we map the following metadata in the BITMAPINFO structure. BITMAPINFOHEADER structure data shows below, its length is 0x28.


BITMAPLINE structure data(also known as Pixel Data)shows below, its length is 0x10.


Let’s add the BITMAPFILEHEADER structure and assemble them as a complete BMP file. The following is the assembled BMP file.

Figure 3. Parsing of the Assembled BMP Embedded in RTF File

The Windows BMP File Format Specification can be found at

Let’s continue the analysis.

In order to track the metadata in the BMP file, we set the following breakpoint in WinDbg.

bu mso!Ordinal7809+0x138 " .if(poi(eax+4)==0x0c000004) {.printf \\"test1:\\\\n\\"; db eax;} .else{gc}"

When the breakpoint is hit, we can see the following debug info.

We can see that a heap buffer starts at 0x1c32eff0 and ends at 0x1c32f027, which stores the metadata from “\\pict” control word. Its length is 0x38. 

The following are some snippets of the assembly code and some debug information.

From the above buffer, we can see that biSizeImage is set equal to zero.

Then let’s check the function mso!Ordinal1181.

Then let’s continue to trace into the function mso!Ordinal1181 which code is shown below:

From above analysis, we can see that the sub_3279C4B0 return an invalid PixelData length, in turn, this value is passed to the function MSO_8609 that is used to create heap buffer and it causes to create a heap buffer with smaller size, finally it causes a heap overflow when copying data.

Let’s continue to track into two key functions sub_3279C4B0 and MSO_8609. The function MSO_8609(v5, 4u, 0x28u, Size) is used to create heap buffer and its code shows below. 

As you can see, it takes four parameters as shown below.

  • a1 should be biClrUsed, here its value is zero.
  • a2 is 0x4.
  • a3 is 0x28.
  • a4 is the size of the actual pixel data.  It should be equal to 0x10, but here it is equal to 0. It causes to create a heap buffer with smaller size.

Let's take a look at the heap buffer created by the function MSO_8609.

The function sub_3279C4B0 is used to calculate the size of the pixel data. Following is a snippet of its assembly code.

From the above analysis, the function starting at 0x31d8c4f2 is used to recalculate the size of raster line. Let’s trace into it in Windbg.

The function starting at 0x31d8c4f2 is mapped into sub_3279C4F2 in IDA Pro. Following is its code in IDA Pro.

The original bWidth value is 0x00000004, here we can calculate the size of raster line via the following command in WinDbg.

0:000> ?((20*4+1f)>>3)&1FFFFFFC

Evaluate expression: 16 = 00000010

It's correct.  But when we set bWidth to 0x0c000004, the calculation result becomes zero.

In the function starting at 0x31d8c4f2, these two functions 0x31bf817a and 0x31d8c606 marked as green are used to do the main calculation. Next, let’s see how to calculate.

Following is the code snippet of the function starting at 0x31bf817a.

The function starting at 0x31d8c606 is mapped into sub_3279C606 in IDA Pro. Following is its code in IDA Pro.

The final crash info shows below:

Conclusion & Mitigation

From above analysis, this vulnerability is a typical heap overflow caused by a user-supplied value which is copied into a buffer allocated based on a user-supplied length. Successful exploitation of this vulnerability could allow malicious users to create remote code execution scenarios.

This vulnerability is rated as Critical/Remote Code Execution by Microsoft. It affects all major Microsoft Office versions. All affected Office users should apply the latest Microsoft patch as soon as possible. Fortinet users have been protected against this particular threat with IPS signature MS.Office.RTF.Memory.Corruption since the issue was discovered and reported to Microsoft. 

Additionally,thanks to Peixue Li from Fortinet for reviewing and revising the report and Wayne from Fortinet's Singapore team who gave some comments and good suggestion in the process of writing blog.