New issue
Advanced search Search tips
Starred by 3 users

Issue metadata

Status: Fixed
Closed: May 2015

Sign in to add a comment

Issue 259: Microsoft Internet Explorer DirectWrite memory disclosure via uninitialized transient array

Reported by, Feb 6 2015 Project Member

Issue description

The "transient array" specified in the "Type 2 Charstring format" specs [1] but also available in Type1 fonts [2] (originally for the purpose of facilitating Multiple Master fonts) is allocated dynamically only if the DirectWrite CFF interpreter encounters an instruction which requires the presence of the array, such as "get" or "put".

While allocating the array, however, the routine does not automatically clear the contents of the newly created buffer. If a reading PostScript instruction is then used to access an item in the array that has not been previously initialized, it is possible to leak data from the transient array into other structures (such as the operand stack) and further use it e.g. as a parameter of the rendered font shapes. The possibility of such scenario is even mentioned in the [1] specification:

"If *get* is executed prior to *put* for /i/ during execution of the current charstring, the value returned is undefined."

The instructions which make it possible to create an uninitialized allocation are "escape + get" and "escape + put"; however, it is only possible to read uninitialized memory via "escape + get", which loads a 32-bit value from the transient array into the operand stack.

The bug is reproducible only with OTF fonts, because Type1 PostScript fonts are not supported by DirectWrite to our current knowledge (and in particular Internet Explorer which is the most intuitive target doesn't support embedded Type1 PostScript fonts). Therefore, the length of the transient array (and thus the size of the heap allocation) is always 32 elements, or 128 bytes (see the "Appendix B: Type 2 Charstring Implementation Limits" section of [1]).

The latest version of the DirectWrite library at the time of this writing (6.2.9200.16571) is confirmed to be affected, but we expect that all prior versions are prone to the bug, too. The bug can be used remotely to disclose portions of the Microsoft Internet Explorer process memory, which can facilitate defeating ASLR during the exploitation of another vulnerability, or leak other sensitive information.

Attached is a Proof of Concept OTF font, together with a HTML website which embeds the font, uses it to draw glyphs (thus leaking bits) on a HTML5 canvas, reads the pixels back and submits them to a remote server in a loop. In other words, this is a complete POC for disclosing iexplore.exe heap memory.

Glyphs of letters 'a'-'z' are designed to disclose 128 bytes of process memory each by rendering each bit as a black 64x64 units square if the bit is set, or a white one if it is cleared. Therefore, each glyph is a 2048x2048 unit shape, with each of the 32 leaked DWORDs being represented as a separate column. The extraction of respective bits from a 32-bit value is not trivial with Type1/2 CharString instructions, but is possible with the help of multiple arithmetic and conditional operations. The following is a Python function building a CharString payload to extract a specified bit off a specified leaked DWORD, used to create the attached POC font. Full source code of the script will be released at a later time. The CharString for letter 'A' uses the same visual structure to render bytes "aa aa aa aa 55 55 55 55 aa aa aa aa 55 [...]", creating a regular grid used by Javascript to check that all parameters are set correctly.

def leak_bit(dword, bit):
  # Leak a complete dword to the operand stack.
  payload = enc(dword) + cf2_cmdESC_GET

  # Because of signed arithmetic, we must handle the MSB separately.
  if bit == 31:
    payload += enc(0) + enc(1) + enc(0) + enc(3) + cf2_cmdESC_INDEX + cf2_cmdESC_IFELSE + cf2_cmdESC_EXCH + cf2_cmdESC_DROP
    # If the value is negative, flip the MSB for all further calculations.
    payload += enc(0) + enc_dword(2 ** 31) + enc(0) + enc(3) + cf2_cmdESC_INDEX + cf2_cmdESC_IFELSE + cf2_cmdESC_SUB

    # Subtract all bits more significant than the one we're leaking.
    for i in range(30, bit, -1):
      payload += enc(0) + enc_dword(2 ** i) + enc(2) + cf2_cmdESC_INDEX + enc_dword((2 ** i) - 1) + cf2_cmdESC_IFELSE + cf2_cmdESC_SUB

    # Return the specific bit by performing a 32-bit comparison.
    payload += enc(0) + enc(1) + enc(2) + cf2_cmdESC_INDEX + enc_dword((2 ** bit) - 1) + cf2_cmdESC_IFELSE + cf2_cmdESC_EXCH + cf2_cmdESC_DROP

  return payload

This bug is subject to a 90 day disclosure deadline. If 90 days elapse without a broadly available patch, then the bug report will automatically become visible to the public.

[1] "The Type 2 Charstring Format, Technical Note #5177, 16 March 2000",
[2] "The Compact Font Format Specification, Technical Note #5176, Version 1.0, 18 March 1998",
1.5 MB Download

Comment 1 by, Feb 6 2015

Project Member
Labels: Reported-2015-Feb-6

Comment 2 by, Feb 9 2015

Project Member
Labels: MSRC-21473

Comment 3 by, Mar 6 2015

Project Member
We have discovered that another user-mode library which implements Type-2 CharString processing (FNTCACHE.DLL) is also prone to the issue, and reported this to Microsoft.

Comment 4 by, Mar 18 2015

Project Member
Labels: Deadline-Grace
Microsoft has requested a deadline extension under the grace period policy, from the original May 7th deadline to May 12th, which is a Patch Tuesday.

Comment 5 by, Mar 18 2015

Labels: Deadline-Exceeded
For Deadline-Grace, we also add Deadline-Exceeded, because the deadline remains 90 days.

Comment 6 by, May 13 2015

Labels: CVE-2015-1670 Fixed-2015-May-12
Status: Fixed

Comment 7 by, Jun 12 2015

Project Member
Labels: -Restrict-View-Commit

Sign in to add a comment