Exploit-DB #39991
Description: Microsoft Windows Kernel - 'ATMFD.dll' NamedEscape 0x250C Pool Corruption (MS16-074)
Type: dos
Platform: windows
Date: 2016-06-21
Author: Google Security Research

Exploit:
Source: https://bugs.chromium.org/p/project-zero/issues/detail?id=785

The Adobe Type Manager Font Driver (ATMFD.DLL) responsible for handling PostScript and OpenType fonts in the Windows kernel provides a channel of communication with user-mode applications via an undocumented gdi32!NamedEscape API call. The nature of the channel is similar to IOCTLs [1] of type METHOD_BUFFERED [2], in that it also uses a 32-bit escape code (equivalent to control codes in IOCTL), and input and output buffers employed to pass data to the driver and receive information back. We suspect that this little known interface was originally designed to be more universal, but since ATMFD has remained the only third-party font driver in Windows for the past two decades, in reality it can only be used to interact with this single module.

Considering that there hasn't been any public research into the security of ATMFD's NamedEscape handlers, it is likely that it hasn't been thoroughly audited since the creation of the code. The first public vulnerability disclosed in the interface was a 0-day pool corruption (stemming from a 16-bit signedness issue) discovered in Hacking Team's leaked data dump [3], and subsequently fixed by Microsoft in the MS15-077 bulletin [4]. That security issue motivated us to have a deeper look into the security posture of the code area.

The main hurdle in approaching the NamedEscape attack surface is that Microsoft provides no symbols or other debugging information for the ATMFD.DLL library via the Microsoft Symbol Server, which means that all functionality needs to be reverse-engineered from the ground up, with no hints available whatsoever. At least that was what we believed until recently, when we discovered that the user-mode counterpart of ATMFD is ATMLIB.DLL -- a legacy library rarely used by the operating system nowadays, but which comes with debug symbols and implements many of its features by making NamedEscape calls to the kernel-mode driver. This lead to the further discovery of the "Adobe Type Manager Software API for Windows 95 and Windows NT 4" [5] and "Adobe Type Manager Software API: Windows" [6] documents, which greatly helped us understand the semantics of most of the escape codes, some of the underlying structures and other specifics of the code.

All further analysis presented below is relevant to an ATMFD.DLL file found on Windows 7 32-bit, version 5.1.2.247, md5sum e85bed746bbddcd29ad63f6085e1ce78. The driver currently supports 13 different escape codes in the range of 0x2500 - 0x2514. The bug discussed in this report resides in the handler of code 0x250C, which we have named "ATMGetGlyphName", based on the observation of its behavior and how it is used in the ATMLIB!ATMGetGlyphListW function.

Since the execution flow down the call stack is quite complex before we can reach the vulnerable condition, let's briefly summarize the major stages of execution:

  1) The i/o buffer size is enforced to be exactly 48 bytes.
  2) The ATMGetGlyphName handler function (atmfd+0x1F12) locates the font object based on its kernel-mode address provided at offset 4 of the i/o buffer.
  3) The font is mapped into memory (?) by a function at atmfd+0x5AC6.
  4) More logic follows depending on whether the font is a PostScript or OpenType one. We have found the PostScript-specific logic to be uninteresting, so we'll follow the OpenType one.
  5) A function at atmfd+0xDF10 (we call it "FormatOpenTypeGlyphName") is called with a controlled 16-bit glyph index and a pointer to offset 8 of the i/o buffer (to copy the name there).
  6) In order to retrieve the actual glyph name from the .OTF file, another function at atmfd+0x1A2D6 is invoked, we call it "GetOpenTypeGlyphName".

Here, the interesting functionality begins. If the glyph id is between 0 and 390, the name is obtained from a hard-coded list of names. Otherwise, it is extracted from the .OTF file itself, by reading from the Name INDEX [7]. The core of the function is as follows (in pseudo-code):

--- cut ---
  PushMarkerToStack();

  int glyph_name_offset = ReadCFFEntryOffset(glyph_id);
  int next_glyph_name_offset = ReadCFFEntryOffset(glyph_id + 1);

  *pNameLength = next_glyph_name_offset - glyph_name_offset;

  EnsureBytesAreAvailable(next_glyph_name_offset - glyph_name_offset);

  PopMarkerFromStack();
--- cut ---

The function addresses are as follows:

  +-------------------------+---------------+
  |        Function         |    Address    |
  +-------------------------+---------------+
  | PushMarkerToStack       | inlined       |
  | ReadCFFEntryOffset      | atmfd+0x1994D |
  | EnsureBytesAreAvailable | atmfd+0x18D11 |
  | PopMarkerFromStack      | atmfd+0x18B34 |
  +-------------------------+---------------+

The code construct is consistent with the general Name INDEX structure, which is as follows:

  +---------+------------------+------------------------------------------------+
  |  Type   |       Name       |                  Description                   |
  +---------+------------------+------------------------------------------------+
  | Card16  | count            | Number of object stored in INDEX               |
  | OffSize | offSize          | Offset array element size                      |
  | Offset  | offset [count+1] | Offset array (from byte preceding object data) |
  | Card8   | data[<varies>]   | Object data                                    |
  +---------+------------------+------------------------------------------------+

In order to extract any data from an index, it is necessary to read the offset of the interesting entry, and the next one (to calculate the length), which is what the function does. What are the PushMarkerToStack and PopMarkerFromStack functions, though? As it turns out, the font object being operated on has a 16-element stack (each element 32-bit wide). The ATMFD.DLL file contains multiple assertion strings, which show that the