New issue
Advanced search Search tips
Starred by 3 users

Issue metadata

Status: Fixed
Closed: May 2015

Sign in to add a comment

Issue 277: Microsoft Windows Presentation Foundation memory disclosure via uninitialized transient array

Reported by, Mar 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 WPF CFF interpreter (implemented in the PresentationCFFRasterizerNative_v0300.dll file) 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 WPF. 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 PresentationCFFRasterizerNative_v0300.dll library at the time of this writing is confirmed to be affected, but we expect that all prior versions are prone to the bug, too. Attached is a Proof of Concept OTF font, together with a .NET "Font Dialog Sample" application, which renders text entered by the user using a chosen font. In order to reproduce the issue, the poc.otf font should be installed in the system and later selected in the aforementioned example .NET program.

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.

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
27.8 KB Download

Comment 1 by, Mar 12 2015

Labels: -Reported-2015-March-6 Reported-2015-Mar-6

Comment 2 by, May 21 2015

Project Member
Labels: Fixed-2015-May-12 CVE-2015-1670 MSRC-21712
Status: Fixed

Comment 3 by, Jun 12 2015

Project Member
Labels: -Restrict-View-Commit

Sign in to add a comment