CVE: CVE-2020-9816

Tested Versions:

  • macOS Catalina 10.15.1 (19B88)

Product URL(s):

Description of the vulnerability

This vulnerability exists in libFontParser.dylib, which is a part of CoreGraphic library is widely used in macOS, iOS, iPadOS to parse Font. Attacker can craft an evil PDF contains malicious font could leads to remote code execution in Apple devices.

The bug exists in TParsingContext::Subroutine method, which parse Subrs field in Type1 Font. TParsingContext::Subroutine try to calculate decrypted buffer size from IV and encrypted buffer size but fail to make sure that decrypted buffer size and encrypted buffer size.

new_len = plen_enc_buf - IV;                // incorrect calculate new_len
    if ( plen_enc_buf <= IV )
    {
      if ( plen_enc_buf == IV )
      {
LABEL_28:
        LOBYTE(IV) = 1;
        return IV;
      }
    }
    else
    {
      pnew_len = new_len;                       // (this + 80) is out_buf header
      if ( (unsigned __int64)(new_len + *((_QWORD *)this + 80)) <= *((_QWORD *)this + 81) )// compare new_size with old_size

As we can see new_len is result of len_enc_buf sub with IV (we can control both IV and new_len) and then new_len is passed to realloc to resize out_buf.

p_enc_buf = enc_buf;                    // reach here
        v11 = (__int64 *)((char *)this + 624);  // in asm result of v9 + *((_QWORD *)this + 80) is passed to this call
        new_size = (*(__int64 (__fastcall **)(char *))(*((_QWORD *)this + 78) + 48LL))((char *)this + 624);
        old_buffer = *((_QWORD *)this + 79);    // old_buffer
        if ( old_buffer )
        {
          v14 = *v11;
          v15 = new_size;
          ppnew_chunk = (*(__int64 (__fastcall **)(char *, __int64, __int64))(v14 + 40))(
                          (char *)this + 624,
                          old_buffer,
                          new_size);            // realloc
        }
...
LenIVDecrypt(
          (unsigned __int8 *)(*((_QWORD *)pthis + 80) + out_buf),
          enc_buf,
          plen_enc_buf,                         // decrypt with p_enc_buf -> heap overflow
          *(signed __int16 *)(*((_QWORD *)pthis + 86) + 56LL));// IV

After that, when LenIVDecrypt is called, TParsingContext::Subroutine use len_enc_buf instead of new_len, which cause heap overflow in TParsingContext::Subroutine.

The attached report comes with evil_font and evil_pdf.pdf as a PoC which can crash Safari PDF Reader and Preview (default PDF Reader in OS X)

To trigger the crash stablely, run the following command:

DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib ./harness evil_font
GuardMalloc[font_harness-73262]: Allocations will be placed on 16 byte boundaries.
GuardMalloc[font_harness-73262]:  - Some buffer overruns may not be noticed.
GuardMalloc[font_harness-73262]:  - Applications using vector instructions (e.g., SSE) should work.
GuardMalloc[font_harness-73262]: version 064511.120.1
[1]    73262 segmentation fault  DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylib ./font_harness type1_crash

To trigger the crash in Preview, because heap in macOS is randomly allocation, you may run this poc several times to get crashed by opening evil_pdf.pdf.

./Preview.app/Contents/MacOS/Preview
CoreGraphics PDF has logged an error. Set environment variable "CG_PDF_VERBOSE" to learn more.
2019-11-05 11:38:44.389 Preview[73561:2751144] WARNING: The SplitView is not layer-backed, but trying to use overlay sidebars.. implicitly layer-backing for now. Please file a radar against this app if you see this.
2019-11-05 11:38:49.977 Preview[73561:2751144] WARNING: The SplitView is not layer-backed, but trying to use overlay sidebars.. implicitly layer-backing for now. Please file a radar against this app if you see this.
Preview(73561,0x700007a58000) malloc: Incorrect checksum for freed object 0x7fec5b6992f8: probably modified after being freed.
Corrupt value: 0x4343434343434343
Preview(73561,0x700007a58000) malloc: *** set a breakpoint in malloc_error_break to debug
[1]    73561 abort      ./Preview.app/Contents/MacOS/Preview

For Safari, because each tabs is a seperate Process, you don’t see Safari crash, but you can track it by Console.app of macOS.

Nov  5 08:34:30 Macbook-Pro com.apple.WebKit.WebContent[66881]: com.apple.WebKit.WebContent(66881,0x70000fe22000) malloc: Incorrect checksum for freed object 0x7f8eb0c441b8: probably modified after being freed.
  Corrupt value: 0x4343434343434343

Timeline

  • 2020-04-07 Vulnerability reported to vendor
  • 2020-05-27 Coordinated public release of advisory