[CVE44] Microsoft Font Subsetting DLL heap corruption in ReadTableIntoStructure - CVE-2020-0687



CVE Number

CVE-2020-0687

Researcher: linhlhq from Infiniti Team - VinCSS (a member of Vingroup).


Summary

The Microsoft Font Subsetting DLL (fontsub.dll) is a default Windows helper library for subsetting TTF fonts; i.e. converting fonts to their more compact versions based on the specific glyphs used in the document where the fonts are embedded. It is used by Windows GDI and Direct2D.
The DLL exposes two API functions: CreateFontPackage and MergeFontPackage. We have developed a test exploit to invoke a sequence of library APIs. This report describes an issue triggered by a malformed font file in fontsub.dll code through our exploit.

Our initial tested version

Windows 10 x64 version 1909 with fontsub.dll version 10.0.18362.535 (WinBuild.160101.0800).

Affected version (confirmed by Microsoft)

All version of Windows from Windows 7 to Windows 10 latest version (prior to Patch Tuesday this month) and Windows Server 2008 to Windows Server latest version (prior to Patch Tuesday this month). See CVE-2020-0687 link above for more details.

CVSSv3

Score 8.8
CVSS:3.0/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H/E:P/RL:O/RC:C

Details

During fuzzing 2 APIs of fontsub.dll, an invalid font file will cause an error in the MergeFontPackage function.
Function MergeFontPackage is shown below:


unsigned long MergeFontPackage(
  const unsigned char  *puchMergeFontBuffer,
  const unsigned long  ulMergeFontBufferSize,
  const unsigned char  *puchFontPackageBuffer,
  const unsigned long  ulFontPackageBufferSize,
  unsigned char        **ppuchDestBuffer,
  unsigned long        *pulDestBufferSize,
  unsigned long        *pulBytesWritten,
  const unsigned short usMode,
  CFP_ALLOCPROC        lpfnAllocate,
  CFP_REALLOCPROC      lpfnReAllocate,
  CFP_FREEPROC         lpfnFree,
  void                 *lpvReserved
);

The process flow of the function is shown below:
Figure 1: Processing flow of the MergeFontPackage function
After debugging the data stream, we can see that the code of the ReadTableIntoStructure test has the following problem: MergeEblcEbdtTables function after calculating the capacity of struct bitmaptable. It will initialize the arr variable with size_arr:
Figure 2: bitmaptable initialization handler function in MergeEblcEbdtTables

Then run into the while loop to execute the ReadTableIntoStructure function, the condition to exit the loop is when the variable runs j > unk_v3 (value of Table_array).

Inside the ReadTableIntoStructure function, the processing part is shown below:
Figure 3: The processing code that causes an error in the ReadTableIntoStructure function

It also runs a loop to fill in the struct bitmaptable. In this function, we also check to see if the capacity of arr is exceeded, but there is a problem in line 156 where it checks size_1 with the capacity of arr is size_arr, but the placement is not reasonable.

Take the following example:

  • If size_1 = 1 and bitmaptable-> size_arr = 2 => the condition in line 156 will not be satisfied, so the while loop will continue.
  • Go to test i with glyphArray. Assuming i will be less than glyphArray => the condition in line 166 is not satisfied and the program returns to the while loop at this time size_1 is equal to 2 and an error occurs in line 150.
Figure 4: Crash context
This leads to out of bound write memory. It could be potentially used to execute arbitrary code in the context of the FontSub client process. It is easiest to reproduce with PageHeap enabled, but it is also possible to observe a crash in a default system configuration.

Crash information


(6b80.7284): Access violation - code c0000005 (first chance)
First chance exceptions are reported before any exception handling.
This exception may be expected and handled.
FONTSUB!ReadTableIntoStructure+0x22f:
00007ffa`1f0e485b 6689440a10      mov     word ptr [rdx+rcx+10h],ax ds:000001b4`6ad3f010=????
0:000> !analyze -v
*******************************************************************************
*                                                                             *
*                        Exception Analysis                                   *
*                                                                             *
*******************************************************************************

KEY_VALUES_STRING: 1


TIMELINE_ANALYSIS: 1

Timeline: !analyze.Start
    Name: <blank>
    Time: 2020-04-02T12:27:38.906Z
    Diff: 1093 mSec

Timeline: Dump.Current
    Name: <blank>
    Time: 2020-04-02T12:27:40.0Z
    Diff: 0 mSec

Timeline: Process.Start
    Name: <blank>
    Time: 2020-04-02T12:12:45.0Z
    Diff: 895000 mSec

Timeline: OS.Boot
    Name: <blank>
    Time: 2020-03-23T12:28:16.0Z
    Diff: 863964000 mSec


DUMP_CLASS: 2

DUMP_QUALIFIER: 0

FAULTING_IP:
FONTSUB!ReadTableIntoStructure+22f
00007ffa`1eba485b 6689440a10      mov     word ptr [rdx+rcx+10h],ax

EXCEPTION_RECORD:  (.exr -1)
ExceptionAddress: 00007ffa1eba485b (FONTSUB!ReadTableIntoStructure+0x000000000000022f)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 0000000000000001
   Parameter[1]: 000001e16eabf010
Attempt to write to address 000001e16eabf010

FAULTING_THREAD:  0000cde8

PROCESS_NAME:  fuzz_ttf.exe

FOLLOWUP_IP:
FONTSUB!ReadTableIntoStructure+22f
00007ffa`1eba485b 6689440a10      mov     word ptr [rdx+rcx+10h],ax

WRITE_ADDRESS:  000001e16eabf010

ERROR_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

EXCEPTION_CODE: (NTSTATUS) 0xc0000005 - The instruction at 0x%p referenced memory at 0x%p. The memory could not be %s.

EXCEPTION_CODE_STR:  c0000005

EXCEPTION_PARAMETER1:  0000000000000001

EXCEPTION_PARAMETER2:  000001e16eabf010

WATSON_BKT_PROCSTAMP:  5e05a3f2

WATSON_BKT_MODULE:  FONTSUB.dll

WATSON_BKT_MODSTAMP:  22c86eba

WATSON_BKT_MODOFFSET:  1485b

WATSON_BKT_MODVER:  10.0.18362.535

MODULE_VER_PRODUCT:  Microsoft® Windows® Operating System

BUILD_VERSION_STRING:  18362.1.amd64fre.19h1_release.190318-1202

MODLIST_WITH_TSCHKSUM_HASH:  e0701885b4164630ff6784e9b6d075fc447148d6

MODLIST_SHA1_HASH:  e9d8cb4ef4ad38bb2bd153b069d6b052a809b0c9

NTGLOBALFLAG:  2000000

PROCESS_BAM_CURRENT_THROTTLED: 0

PROCESS_BAM_PREVIOUS_THROTTLED: 0

APPLICATION_VERIFIER_FLAGS:  0

PRODUCT_TYPE:  1

SUITE_MASK:  272

DUMP_TYPE:  fe

APPLICATION_VERIFIER_LOADED: 1

ANALYSIS_SESSION_HOST:  DESKTOP-CBBVQA8

ANALYSIS_SESSION_TIME:  04-02-2020 19:27:38.0906

ANALYSIS_VERSION: 10.0.17134.1 amd64fre

THREAD_ATTRIBUTES:
OS_LOCALE:  ENU

PROBLEM_CLASSES:

    ID:     [0n309]
    Type:   [@ACCESS_VIOLATION]
    Class:  Addendum
    Scope:  BUCKET_ID
    Name:   Omit
    Data:   Omit
    PID:    [Unspecified]
    TID:    [0xcde8]
    Frame:  [0] : FONTSUB!ReadTableIntoStructure

    ID:     [0n282]
    Type:   [INVALID_POINTER_WRITE]
    Class:  Primary
    Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
            BUCKET_ID
    Name:   Add
    Data:   Omit
    PID:    [Unspecified]
    TID:    [0xcde8]
    Frame:  [0] : FONTSUB!ReadTableIntoStructure

    ID:     [0n96]
    Type:   [AVRF]
    Class:  Addendum
    Scope:  DEFAULT_BUCKET_ID (Failure Bucket ID prefix)
            BUCKET_ID
    Name:   Add
    Data:   Omit
    PID:    [0x3228]
    TID:    [0xcde8]
    Frame:  [0] : FONTSUB!ReadTableIntoStructure

BUGCHECK_STR:  APPLICATION_FAULT_INVALID_POINTER_WRITE_AVRF

DEFAULT_BUCKET_ID:  INVALID_POINTER_WRITE_AVRF

PRIMARY_PROBLEM_CLASS:  APPLICATION_FAULT

LAST_CONTROL_TRANSFER:  from 00007ffa1eba5e8d to 00007ffa1eba485b

STACK_TEXT: 
0000002a`b50fd620 00007ffa`1eba5e8d : 00000000`00000003 0000001c`00280027 00000038`004e004e 00000000`00000000 : FONTSUB!ReadTableIntoStructure+0x22f
0000002a`b50fd6d0 00007ffa`1eb9b6ed : 000001e1`6ea70f10 0000002a`b50fd9f0 00000000`00000000 00000000`0000000f : FONTSUB!MergeEblcEbdtTables+0xb79
0000002a`b50fd8f0 00007ffa`1eb9c13c : 00000000`00000000 0000002a`b50fdb81 00000000`ffffffff 00000000`0000ffff : FONTSUB!MergeFonts+0x699
0000002a`b50fdaa0 00007ffa`1eb91583 : 00000000`00000c7c 0000002a`b50fdcc8 0000002a`b50fdc18 0000002a`b50fdc20 : FONTSUB!MergeDeltaTTF+0x3dc
0000002a`b50fdbd0 00007ff6`feef1e4e : 000001e1`6cbc89a0 00000000`00003640 00000000`00000000 00000000`00000000 : FONTSUB!MergeFontPackage+0x133
0000002a`b50fdc60 00007ff6`feef21ba : 00000000`00000000 00000000`00000000 00000000`00000000 000001e1`6ca71fcb : fuzz_ttf+0x1e4e
0000002a`b50ffae0 00007ff6`feef332d : 00007ffa`31a0b590 00000000`00000000 00000000`00000000 00000000`00000000 : fuzz_ttf+0x21ba
0000002a`b50ffb40 00007ffa`31be7bd4 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : fuzz_ttf+0x332d
0000002a`b50ffb80 00007ffa`33b2ced1 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : KERNEL32!BaseThreadInitThunk+0x14
0000002a`b50ffbb0 00000000`00000000 : 00000000`00000000 00000000`00000000 00000000`00000000 00000000`00000000 : ntdll!RtlUserThreadStart+0x21


STACK_COMMAND:  ~0s ; .cxr ; kb

THREAD_SHA1_HASH_MOD_FUNC:  9ce9cd8861479d96159761a9691ba4c8c894d465

THREAD_SHA1_HASH_MOD_FUNC_OFFSET:  9d3f8671fbf17c2d1c0c9a4058647f93ece75fc6

THREAD_SHA1_HASH_MOD:  c36dc10ccf4919ee237948f385c765a7701b1bdd

FAULT_INSTR_CODE:  a448966

SYMBOL_STACK_INDEX:  0

SYMBOL_NAME:  FONTSUB!ReadTableIntoStructure+22f

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: FONTSUB

IMAGE_NAME:  FONTSUB.dll

DEBUG_FLR_IMAGE_TIMESTAMP:  22c86eba

FAILURE_BUCKET_ID:  INVALID_POINTER_WRITE_AVRF_c0000005_FONTSUB.dll!ReadTableIntoStructure

BUCKET_ID:  APPLICATION_FAULT_INVALID_POINTER_WRITE_AVRF_FONTSUB!ReadTableIntoStructure+22f

FAILURE_EXCEPTION_CODE:  c0000005

FAILURE_IMAGE_NAME:  FONTSUB.dll

BUCKET_ID_IMAGE_STR:  FONTSUB.dll

FAILURE_MODULE_NAME:  FONTSUB

BUCKET_ID_MODULE_STR:  FONTSUB

FAILURE_FUNCTION_NAME:  ReadTableIntoStructure

BUCKET_ID_FUNCTION_STR:  ReadTableIntoStructure

BUCKET_ID_OFFSET:  22f

BUCKET_ID_MODTIMEDATESTAMP:  22c86eba

BUCKET_ID_MODCHECKSUM:  24c8a

BUCKET_ID_MODVER_STR:  10.0.18362.535

BUCKET_ID_PREFIX_STR:  APPLICATION_FAULT_INVALID_POINTER_WRITE_AVRF_

FAILURE_PROBLEM_CLASS:  APPLICATION_FAULT

FAILURE_SYMBOL_NAME:  FONTSUB.dll!ReadTableIntoStructure

TARGET_TIME:  2020-04-02T12:27:53.000Z

OSBUILD:  18363

OSSERVICEPACK:  329

SERVICEPACK_NUMBER: 0

OS_REVISION: 0

OSPLATFORM_TYPE:  x64

OSNAME:  Windows 10

OSEDITION:  Windows 10 WinNt SingleUserTS

USER_LCID:  0

OSBUILD_TIMESTAMP:  unknown_date

BUILDDATESTAMP_STR:  190318-1202

BUILDLAB_STR:  19h1_release

BUILDOSVER_STR:  10.0.18362.1.amd64fre.19h1_release.190318-1202

ANALYSIS_SESSION_ELAPSED_TIME:  3a49

ANALYSIS_SOURCE:  UM

FAILURE_ID_HASH_STRING:  um:invalid_pointer_write_avrf_c0000005_fontsub.dll!readtableintostructure

FAILURE_ID_HASH:  {edfa825c-ba3b-c2d6-424f-ccecd5a7ca4c}

Followup:     MachineOwner

0:000> lmv a rip
Browse full module list
start             end                 module name
00007ffa`1f0d0000 00007ffa`1f0f2000   FONTSUB    (pdb symbols)          C:\ProgramData\dbg\sym\fontsub.pdb\2A2820FCD9D9D44522A8601FBA7839B71\fontsub.pdb
    Loaded symbol image file: C:\WINDOWS\SYSTEM32\FONTSUB.dll
    Image path: C:\WINDOWS\SYSTEM32\FONTSUB.dll
    Image name: FONTSUB.dll
    Browse all global symbols  functions  data
    Image was built with /Brepro flag.
    Timestamp:        22C86EBA (This is a reproducible build file hash, not a timestamp)
    CheckSum:         00024C8A
    ImageSize:        00022000
    File version:     10.0.18362.535
    Product version:  10.0.18362.535
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        2.0 Dll
    File date:        00000000.00000000
    Translations:     0409.04b0
    Information from resource tables:
        CompanyName:      Microsoft Corporation
        ProductName:      Microsoft® Windows® Operating System
        InternalName:     fontsub
        OriginalFilename: fontsub
        ProductVersion:   10.0.18362.535
        FileVersion:      10.0.18362.535 (WinBuild.160101.0800)
        FileDescription:  Font Subsetting DLL
        LegalCopyright:   © Microsoft Corporation. All rights reserved.

An attacker who successfully exploited this vulnerability could take control of the affected system. An attacker could then install programs; view, change, or delete data; or create new accounts with full user rights. Users whose accounts are configured to have fewer user rights on the system could be less impacted than users who operate with administrative user rights.

There are multiple ways an attacker could exploit this vulnerability:

  • In a web-based attack scenario, an attacker could host a specially crafted website that is designed to exploit this vulnerability and then convince or lure users to browse the website. Normally, an attacker would have no way to force users to browse the attacker-controlled content. Instead, an attacker would have to convince users to take action, typically by getting them to click a link in an email or instant message that takes users to the attacker's website, or by opening an attachment sent through email.
  • In a file-sharing attack scenario, an attacker could provide a specially crafted document file designed to exploit the vulnerability and then convince users to open the document file.
Figure 5: Attack vectors can happen in real life


Timeline 

2020-Jan-03 – Reported vendor
2020-Jan-09 – The vendor confirmed it was a bug
2020-Jan-13 – Updated detailed analysis for vendor
2020-Apr-14 - Public Release 


1 comment: