CVE-2016-7259: An empty file into the blue

A binary analysis of CVE-2016-7259: A win32k kernel bug.

Forewords

The vulnerability was found by one of our fuzzers in 2015 (made by Richard) and analyzed later by me (Sebastien).

The vulnerability deals with *.pfm and *.pfb files (strangely enough, not their format per se):

  • Printer Font Metric (PFM) is a binary version of AFM (Adobe Font Metrics). It contains font metric information.
  • Printer Font Binary (PFB) is a binary PostScript font format created by Adobe Systems. It contains a font's glyph data.

Vulnerability Description

A crash in the Windows windowing kernel graphic component (win32k.sys) happens when a specially crafted PostScript Type 1 font (*.pfm) font file is loaded.

The crash is due to Windows OS not properly checking that the size of the related *.pfb file size is 0.

Simply put: having an empty *.pfb file crashes the system.

Stack Trace

(See version_information section for software version information)

Information and stack trace at time of crash with public Microsoft symbols:

*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

Use !analyze -v to get detailed debugging information.

BugCheck 1E, {c0000005, 8e3c7280, 0, 18}

*** WARNING: Unable to verify checksum for Test.exe
*** ERROR: Module load completed but symbols could not be loaded for Test.exe
Probably caused by : win32k.sys ( win32k!PUBLIC_PFTOBJ::bLoadFonts+ffffffffffffff33 )

Followup:     MachineOwner
---------

nt!RtlpBreakWithStatusInstruction:
8216a9f4 cc              int     3
1: kd> !analyze -v
*******************************************************************************
*                                                                             *
*                        Bugcheck Analysis                                    *
*                                                                             *
*******************************************************************************

KMODE_EXCEPTION_NOT_HANDLED (1e)
This is a very common bugcheck.  Usually the exception address pinpoints
the driver/function that caused the problem.  Always note this address
as well as the link date of the driver/image that contains this address.
Arguments:
Arg1: c0000005, The exception code that was not handled
Arg2: 8e3c7280, The address that the exception occurred at
Arg3: 00000000, Parameter 0 of the exception
Arg4: 00000018, Parameter 1 of the exception

Debugging Details:
------------------


BUGCHECK_P1: ffffffffc0000005

BUGCHECK_P2: ffffffff8e3c7280

BUGCHECK_P3: 0

BUGCHECK_P4: 18

READ_ADDRESS:  00000018

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

FAULTING_IP:
win32k!PUBLIC_PFTOBJ::bLoadFonts+ffffffffffffff33
8e3c7280 f6411808        test    byte ptr [ecx+18h],8

EXCEPTION_PARAMETER2:  00000018

BUGCHECK_STR:  0x1E_c0000005_R

CPU_COUNT: 4

CPU_MHZ: db6

CPU_VENDOR:  GenuineIntel

CPU_FAMILY: 6

CPU_MODEL: 3a

CPU_STEPPING: 9

DEFAULT_BUCKET_ID:  WIN8_DRIVER_FAULT

PROCESS_NAME:  ConsoleApplica

CURRENT_IRQL:  0

ANALYSIS_VERSION: 10.0.10240.9 x86fre

EXCEPTION_RECORD:  a8815898 -- (.exr 0xffffffffa8815898)
ExceptionAddress: 8e3c7280 (win32k!PUBLIC_PFTOBJ::bLoadFonts+0xffffff33)
   ExceptionCode: c0000005 (Access violation)
  ExceptionFlags: 00000000
NumberParameters: 2
   Parameter[0]: 00000000
   Parameter[1]: 00000018
Attempt to read from address 00000018

TRAP_FRAME:  a8815974 -- (.trap 0xffffffffa8815974)
ErrCode = 00000000
eax=00000000 ebx=00000000 ecx=00000000 edx=00c295b0 esi=9ee20398 edi=00000002
eip=8e3c7280 esp=a88159e8 ebp=a8815a4c iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
win32k!PUBLIC_PFTOBJ::bLoadFonts+0xffffffff`ffffff33:
8e3c7280 f6411808        test    byte ptr [ecx+18h],8       ds:0023:00000018=??
Resetting default scope

LAST_CONTROL_TRANSFER:  from 821e6aeb to 8216a9f4

STACK_TEXT:
a8814ee4 821e6aeb 00000003 6296f150 00000065 nt!RtlpBreakWithStatusInstruction
a8814f38 821e6605 8303f340 a8815338 a881536c nt!KiBugCheckDebugBreak+0x1f
a881530c 821695c6 0000001e c0000005 8e3c7280 nt!KeBugCheck2+0x676
a8815330 821694fd 0000001e c0000005 8e3c7280 nt!KiBugCheck2+0xc6
a8815350 821e479b 0000001e c0000005 8e3c7280 nt!KeBugCheckEx+0x19
a881536c 8217f672 a8815898 8226f180 a8815460 nt!KiFatalExceptionHandler+0x1a
a8815390 8217f644 a8815898 8226f180 a8815460 nt!ExecuteHandler2+0x26
a8815450 820fa3bd a8815898 a8815460 00010037 nt!ExecuteHandler+0x24
a881587c 8217b156 a8815898 00000000 a8815974 nt!KiDispatchException+0x101
a88158e8 8217d99b 00000000 00000000 00000000 nt!KiDispatchTrapException+0x4e
a88158e8 8e3c7280 00000000 00000000 00000000 nt!KiTrap0E+0x1a7
a8815a4c 8e3c0bb8 8da41000 000000d8 00000002 win32k!PUBLIC_PFTOBJ::bLoadFonts+0xffffff33
a8815aac 8e3c0aee 00000002 00000011 00000000 win32k!GreAddFontResourceWInternal+0xa3
a8815bf4 8217a417 00a65558 000000d8 00000002 win32k!NtGdiAddFontResourceW+0xbc
a8815bf4 77bcca70 00a65558 000000d8 00000002 nt!KiSystemServicePostCall
002ee75c 75e1b67c 75e1adfb 00a65558 000000d8 ntdll!KiFastSystemCallRet
002ee760 75e1adfb 00a65558 000000d8 00000002 GDI32!NtGdiAddFontResourceW+0xa
002ee7a0 75e4993b 002ee7d4 00000011 00000000 GDI32!GdiAddFontResourceW+0x5b
002ee9f8 01024b8b 00415b70 00000010 00000000 GDI32!AddFontResourceExA+0xeb
WARNING: Stack unwind information not available. Following frames may be wrong.
002ef4d0 01029314 002b02d4 0000003f 00322540 Test+0x84b8b
002ef7d0 0107763a 00000003 00322518 00322820 Test+0x89314
002ef81c 0107781d 002ef838 76074198 7fd66000 Test+0xd763a
002ef824 76074198 7fd66000 76074170 fa31b76d Test+0xd781d
002ef838 77bb2cb1 7fd66000 fa4bb319 00000000 KERNEL32!BaseThreadInitThunk+0x24
002ef880 77bb2c7f ffffffff 77bde751 00000000 ntdll!__RtlUserThreadStart+0x2b
002ef890 00000000 0100b103 7fd66000 00000000 ntdll!_RtlUserThreadStart+0x1b


STACK_COMMAND:  kb

FOLLOWUP_IP:
win32k!PUBLIC_PFTOBJ::bLoadFonts+ffffffffffffff33
8e3c7280 f6411808        test    byte ptr [ecx+18h],8

SYMBOL_STACK_INDEX:  b

SYMBOL_NAME:  win32k!PUBLIC_PFTOBJ::bLoadFonts+ffffffffffffff33

FOLLOWUP_NAME:  MachineOwner

MODULE_NAME: win32k

IMAGE_NAME:  win32k.sys

DEBUG_FLR_IMAGE_TIMESTAMP:  577fb612

IMAGE_VERSION:  6.3.9600.18405

BUCKET_ID_FUNC_OFFSET:  ffffffffffffff33

FAILURE_BUCKET_ID:  0x1E_c0000005_R_win32k!PUBLIC_PFTOBJ::bLoadFonts

BUCKET_ID:  0x1E_c0000005_R_win32k!PUBLIC_PFTOBJ::bLoadFonts

PRIMARY_PROBLEM_CLASS:  0x1E_c0000005_R_win32k!PUBLIC_PFTOBJ::bLoadFonts

ANALYSIS_SOURCE:  KM

FAILURE_ID_HASH_STRING:  km:0x1e_c0000005_r_win32k!public_pftobj::bloadfonts

FAILURE_ID_HASH:  {de897383-506f-34a6-612f-9272467400a7}

Followup:     MachineOwner
---------

Analysis

The faulty syscall is win32k!NtGdiAddFontResourceW. According to Reactos source code the function prototype is:

__kernel_entry
INT
W32KAPI
APIENTRY
NtGdiAddFontResourceW(
    _In_reads_(cwc) WCHAR *pwszFiles,
    _In_ ULONG cwc,
    _In_ ULONG cFiles,
    _In_ FLONG f,
    _In_ DWORD dwPidTid,
    _In_opt_ DESIGNVECTOR *pdv);

The crash happens on a NULL pointer dereference in the win32k!PUBLIC_PFTOBJ::bLoadFonts function:

1: kd> .trap 0xffffffffa8815974
ErrCode = 00000000
eax=00000000 ebx=00000000 ecx=00000000 edx=00c295b0 esi=9ee20398 edi=00000002
eip=8e3c7280 esp=a88159e8 ebp=a8815a4c iopl=0         nv up ei pl nz na po nc
cs=0008  ss=0010  ds=0023  es=0023  fs=0030  gs=0000             efl=00010202
win32k!PUBLIC_PFTOBJ::bLoadFonts+0xffffffff`ffffff33:
8e3c7280 f6411808        test    byte ptr [ecx+18h],8       ds:0023:00000018=??

The previous line is:

; in win32k!PUBLIC_PFTOBJ::bLoadFonts
.text:001A827D mov     ecx, [esi+eax*4] ; ecx = nullptr

Register configuration is as follows:

  • ESI register points to a kernel pool memory block.

  • EAX register is the number file passed to the syscall (win32k!NtGdiAddFontResourceW) in the 1st argument.
    • Note: multiple file names can be passed to the syscall with the | separator character.
  • EDI is the number of files passed in the 1st argument of the syscall.

The kernel pool memory block (where the null pointer lies) is allocated and has a size of 0x90 bytes:

1: kd> !pool @esi
Pool page 9ee20398 region is Paged session pool
 9ee20000 size:  338 previous size:    0  (Allocated)  Gfnt
 9ee20338 size:   10 previous size:  338  (Free)       Free
 9ee20348 size:   48 previous size:   10  (Allocated)  Ussm
*9ee20390 size:   90 previous size:   48  (Allocated) *Gffv
        Pooltag Gffv : Gdi FONTFILEVIEW
 9ee20420 size:   68 previous size:   90  (Allocated)  Usqm
 9ee20488 size:  288 previous size:   68  (Allocated)  Gla5
 9ee20710 size:  8f0 previous size:  288  (Allocated)  Gla1

The kernel pool memory block is allocated in the same function (win32k!PUBLIC_PFTOBJ::bLoadFonts):

; in win32k!PUBLIC_PFTOBJ::bLoadFonts
.text:001A8449  mov     ecx, edi ; ecx = edi = number of files = 2
; [...]
.text:001A844F  mov     edx, 'vffG'      ; block tag
.text:001A8454  lea     eax, ds:7[edi*4] ; lea eax,[edi*4+7] ; edi = 2 ; eax = 0x0f
.text:001A845B  shl     ecx, 6           ; before: ecx = 2; after: ecx = 0x80
.text:001A845E  and     eax, 0FFFFFFF8h  ; eax = 8
.text:001A8461  push    1
.text:001A8463  add     ecx, eax         ; NumberOfBytes: 0x80 + 8 = 0x88
.text:001A8465  mov     [esp+64h+var_28], eax
.text:001A8469  call    PALLOCMEM2(x,x,x)
.text:001A846E  mov     [esp+60h+pFontFileView], eax ; kernel pool block pointer

Then the win32k!vLoadFontFileView function is called:

; in win32k!PUBLIC_PFTOBJ::bLoadFonts
.text:001A8539  push    [esp+80h+pFontFileView] ; unsigned __int16 *
.text:001A853D  call    vLoadFontFileView

Inside win32k!vLoadFontFileView, both of the font files (*.pfm and *.pfb) are loaded and then mapped. The mapping occurs in the win32k!MapFontFiles function.

; in win32k!vLoadFontFileView
.text:0018D5BD  push    [ebp+arg_C]     ; 1: kd> dp 9efb2a90
.text:0018D5BD                          ; 9efb2a90  00000000 00000000 00000000 00000000
.text:0018D5C0  mov     edx, [ebp+arg_0] ; 1: kd> dd 8d9f1108
.text:0018D5C0                           ; 8d9f1108  8d9f1110 8d9f1150 00000000 00000000
.text:0018D5C3  mov     ecx, ebx        ; ebx = ecx = 2 (number of files)
.text:0018D5C5  push    [ebp+arg_8]     ; points on P
.text:0018D5C8  call    MapFontFiles(ulong,_FONTFILEVIEW * *,void * *,ulong *)

The call stack on win32k!MapFontFiles function entry looks like this:

3: kd> k
# ChildEBP RetAddr
00 8a4e7988 8e1805cd win32k!MapFontFiles
01 8a4e79bc 8e19b542 win32k!vLoadFontFileView+0x18a
02 8a4e7a4c 8e194bb8 win32k!PUBLIC_PFTOBJ::bLoadFonts+0x1f5
03 8a4e7aac 8e194aee win32k!GreAddFontResourceWInternal+0xa3
04 8a4e7bf4 81574417 win32k!NtGdiAddFontResourceW+0xbc

Inside win32k!MapFontFiles we have a loop that maps both of the font files using the win32k!EngMapFontFileFDInternal function:

; in win32k!MapFontFiles
.text:001A1CAA  add     eax, ecx        ; 2nd -> eax = 9efb2a9c
.text:001A1CAC  mov     edx, ecx
.text:001A1CAE  push    0
.text:001A1CB0  push    eax
.text:001A1CB1  mov     eax, [ebp+var_4]
.text:001A1CB4  mov     ecx, [ecx+eax]
.text:001A1CB7  call    EngMapFontFileFDInternal(x,x,x,x)
.text:001A1CBC  test    eax, eax        ;  eax = 0 on 2nd pass
.text:001A1CBE  jz      @@ErrorMapFontFile
.text:001A1CC4  mov     ecx, [ebp+arg_0] ; 1: kd> dp 9efb2a90
.text:001A1CC4                          ; 9efb2a90  00b70000 00000000 000002f3 00000000
.text:001A1CC4                          ; 9efb2aa0  46140003 38616c47 010807fe 00000001
.text:001A1CC4                          ; 9efb2ab0  80000000 00000000 00008208 00000000
.text:001A1CC7  inc     edi
.text:001A1CC8  mov     eax, [ebp+var_C] ; 8
.text:001A1CCB  add     ecx, 4
.text:001A1CCE  mov     [ebp+arg_0], ecx
.text:001A1CD1  cmp     edi, [ebp+number_of_files] ; 2
.text:001A1CD4  jb      short loc_1A1CAA ; 2nd -> eax = 9efb2a9c

The first loop pass is used to open and map the *.pfm font file, the second one being used for the *.pfb file.

In w32k!EngMapFontFileFDInternal we have a call to win32k!bCreateSection:

; in w32k!EngMapFontFileFDInternal
.text:00142AB9  mov     ecx, [ebx+28h]  ; du poi(@ebx + 28)
.text:00142AB9                          ; 8da41000  "\??\C:\WORK\FONTS\TEST\FONTS\LIB"
.text:00142AB9                          ; 8da41040  "TEST63.PFB"
.text:00142AB9                          ;
.text:00142ABC  shr     eax, 3
.text:00142ABF  and     al, 1
.text:00142AC1  movzx   eax, al
.text:00142AC4  push    eax             ; int (0)
.text:00142AC5  lea     eax, [esp+74h+var_5C]
.text:00142AC9  push    eax             ; struct _FILEVIEW *
.text:00142ACA  push    esi             ; unsigned __int16 * (0)
.text:00142ACB  call    bCreateSection(ushort *,_FILEVIEW *,int,int *,uchar)

Inside win32k!bCreateSection, the code uses nt!IoCreateFile. Here (after the call to open the file), the resulting handle refers to the *.pfb file:

!handle 80000bf8


PROCESS 9dcd2040  SessionId: 1  Cid: 0af0    Peb: 7f58c000  ParentCid: 0e58
    DirBase: 00e08540  ObjectTable: af8583c0  HandleCount: <Data Not Accessible>
    Image: FontLoader.exe


Kernel handle Error reading handle count.


80000bf8: Object: ab226d70  GrantedAccess: 001200a9 Entry: a47827f0

Object: ab226d70  Type: (8023c868) File
    ObjectHeader: ab226d58 (new version)

        HandleCount: 1  PointerCount: 1

        Directory Object: 00000000  Name: \Work\fonts\test\fonts\Test-Italic63.pfb {HarddiskVolume2}

The code then uses nt!ZwQueryInformationFile to query file information. Note that the code doesn't check if the file size is 0.

;  in win32!bCreateSection
.text:000DC47B  lea     eax, [ebp+FileInformation]
.text:000DC47E  push    5               ; FileInformationClass
.text:000DC480  push    18h             ; Length
.text:000DC482  push    eax             ; FileInformation
.text:000DC483  lea     eax, [ebp+IoStatusBlock]
.text:000DC486  push    eax             ; IoStatusBlock
.text:000DC487  push    [ebp+FileHandle] ; FileHandle
.text:000DC48A  call    edi ; ZwQueryInformationFile(x,x,x,x,x)

The code then calls win32k!ZwWin32CreateSection which is merely a wrapper around nt!ZwCreateSection:

;  in win32k!bCreateSection
.text:000DC548  mov     [ebp+ObjectAttributes.Length], 18h
.text:000DC552  mov     [ebp+ObjectAttributes.RootDirectory], ebx
.text:000DC558  mov     [ebp+ObjectAttributes.Attributes], 200h
.text:000DC562  mov     [ebp+ObjectAttributes.ObjectName], ebx
.text:000DC568  mov     [ebp+ObjectAttributes.SecurityDescriptor], ebx
.text:000DC56E  mov     [ebp+ObjectAttributes.SecurityQualityOfService], ebx
.text:000DC574  test    cl, 2
.text:000DC577  jnz     loc_21098C
.text:000DC57D  push    ecx             ; int
.text:000DC57E  push    ecx             ; int
.text:000DC57F  push    [ebp+FileHandle] ; FileHandle
.text:000DC582  neg     esi
.text:000DC584  lea     eax, [ebp+MaximumSize]
.text:000DC587  push    ecx             ; int
.text:000DC588  sbb     esi, esi
.text:000DC58A  lea     ecx, [ebp+var_60] ; int
.text:000DC58D  and     esi, 0FFFFFFE4h
.text:000DC590  add     esi, 20h
.text:000DC593  push    esi             ; SectionPageProtection
.text:000DC594  push    eax             ; MaximumSize
.text:000DC595  lea     eax, [ebp+ObjectAttributes]
.text:000DC59B  push    eax             ; ObjectAttributes
.text:000DC59C  call    ZwWin32CreateSection(x,x,x,x,x,x,x,x,x) ; fail inside!!!
.text:000DC5A1  test    eax, eax        ; HRESULT indicates error
.text:000DC5A3  js      loc_21091E      ; take jcc

The code can't create a section of an empty file, which results in an error code.

The file handle is then closed and an error is signaled by zeroing the eax register:

;  in win32k!bCreateSection
.text:0021091E  push    [ebp+FileHandle] ; Handle
.text:00210921  call    ds:ZwClose(x)
.text:00210927
.text:00210927 loc_210927:
.text:00210927  xor     eax, eax  ; function returns 0
.text:00210929  jmp     loc_DC613 ; go to function epilogue

The 0 return value is still seen as an error by the caller (win32k!EngMapFontFileFDInternal) which also exits:

; in win32k!EngMapFontFileFDInternal
.text:00142ACB  call    bCreateSection(ushort *,_FILEVIEW *,int,int *,uchar)
.text:00142AD0  mov     [esp+70h+ret_val], eax
; [...]
.text:00142AE4  mov     eax, [esp+70h+ret_val]
.text:00142AE8
.text:00142AE8 loc_142AE8:
.text:00142AE8  test    eax, eax
.text:00142AEA  jz      loc_142B77  ; to function epilogue

Back to win32k!MapFontFiles on the call site to win32k!EngMapFontFileFDInternal. We can see that a 0 return value is also taken as an error.

The file is then unmapped and the first pointer sized value in the font file view (pointer by the esi register) is also zeroed. This value corresponds to the file mapping.

; in win32k!MapFontFiles
.text:001A1CB7  call    EngMapFontFileFDInternal(x,x,x,x)
.text:001A1CBC  test    eax, eax        ;  eax = 0 on 2nd pass
.text:001A1CBE  jz      @@ErrorMapFontFile
; [...]
.text:00230C89 @@ErrorMapFontFile:
.text:00230C89  test    edi, edi
.text:00230C8B  jz      short loc_230CAC
.text:00230C8D  sub     ebx, esi
.text:00230C8F  sub     [ebp+arg_4], esi
.text:00230C92
.text:00230C92 loc_230C92:
.text:00230C92  push    dword ptr [esi]
.text:00230C94  call    EngUnmapFontFileFD(x)  ; unmap file
.text:00230C99  mov     eax, [ebp+arg_4]
.text:00230C9C  xor     ecx, ecx
.text:00230C9E  mov     [esi], ecx      ; esi=pFontFileView ; ecx = 0
.text:00230CAC loc_230CAC:
.text:00230CAC  xor     al, al  ; exits with 0

The function then exits (with a zero value, indicating an error) and we are back to win32k!vLoadFontFileView.

Inside this function the return code is checked and the win32k!vLoadFontFileView function also exits but the error code is not backported to the caller (PUBLIC_PFTOBJ::bLoadFonts).

; in  win32k!PUBLIC_PFTOBJ::bLoadFonts
.text:001A853D  call    vLoadFontFileView
.text:001A8542  mov     eax, [esp+60h+p_minus_pfontfileview] ; eax = [a5861a34]=00000000
.text:001A8542      ; --------------------------
.text:001A8542      ; fonte file view first DWORD has been zeroed!
.text:001A8542      ; 3: kd> dp 9e417dd8 L1
.text:001A8542      ; 9e417dd8  00000000
; [...]
.text:001A8570
.text:001A8570 loc_1A8570:
.text:001A8570  cmp     [esp+60h+var_ghsemPublicPFT], 0 ; [a5861a18]=00000000
.text:001A8575  jz      loc_1A86FF  ; clean up

The file is unmapped once again but the pointer is 0:

; in  win32k!PUBLIC_PFTOBJ::bLoadFonts
.text:001A8710  push    dword ptr [ebx+esi*4] ; 0 !!!
.text:001A8713  call    EngUnmapFontFileFD(x)

And then the font file view is used again, but as the pointer is 0 the code tries to dereference the NULL address:

; in  win32k!PUBLIC_PFTOBJ::bLoadFonts
.text:001A8279  mov     esi, [esp+60h+pFontFileView]
.text:001A8279          ; note: first dword is 0
.text:001A8279          ; 1: kd> dp 9e417dd8 L4
.text:001A8279          ; 9e417dd8  00000000 9e417e20 1471fe00 01d13591
.text:001A827D
.text:001A827D loc_1A827D:
.text:001A827D  mov     ecx, [esi+eax*4] ; ecx is a NULL pointer
.text:001A8280  test    byte ptr [ecx+18h], 8 ; crash here!!!

Version Information

Windows version - Windows 8.1 Update 1 x86 [up to date on 2016-08-25]:

3: kd> vertarget
Windows 8.1 Kernel Version 9600 MP (4 procs) Free x86 compatible
Product: WinNt, suite: TerminalServer SingleUserTS
Built by: 9600.18379.x86fre.winblue_ltsb.160614-0600
Machine Name:
Kernel base = 0x8160b000 PsLoadedModuleList = 0x81805618
Debug session time: Thu Aug 25 16:03:28.779 2016 (UTC + 2:00)
System Uptime: 0 days 0:12:29.534

Win32k.sys module information:

3: kd> lm vm win32k
Browse full module list
start    end        module name
8e234000 8e59b000   win32k     (pdb symbols)          g:\symbols\win32k.pdb\ACF8092B8851410DBBB1D0C026BFCCAE2\win32k.pdb
    Loaded symbol image file: win32k.sys
    Image path: \SystemRoot\System32\win32k.sys
    Image name: win32k.sys
    Browse all global symbols  functions  data
    Timestamp:        Fri Jul 08 16:17:54 2016 (577FB612)
    CheckSum:         003599F0
    ImageSize:        00367000
    File version:     6.3.9600.18405
    Product version:  6.3.9600.18405
    File flags:       0 (Mask 3F)
    File OS:          40004 NT Win32
    File type:        3.7 Driver
    File date:        00000000.00000000
    Translations:     0409.04b0
    CompanyName:      Microsoft Corporation
    ProductName:      Microsoft Windows Operating System
    InternalName:     win32k.sys
    OriginalFilename: win32k.sys
    ProductVersion:   6.3.9600.18405
    FileVersion:      6.3.9600.18405 (winblue_ltsb.160708-0600)
    FileDescription:  Multi-User Win32 Driver
    LegalCopyright:   Microsoft Corporation. All rights reserved.

Detection

The file format of the font itself is not in cause.

You should check for any PostScript Type 1 font (*.pfm extension) font file and its associated *.pfb file.

If the *.pfb file is empty (file size is 0 byte), then the crash can occur.

Mitigation

NULL pointer dereference protection on newer Windows systems will mitigate this problem as it is not possible to allocate the page at 0.

Time Line

  • 2015-12-xx: [QB] Vulnerability found; Pushed for later thorough analysis
  • 2016-08-25: [QB] Vulnerability unstacked and analyzed
  • 2016-08-26: [QB] Report vulnerability to Microsoft
  • 2016-08-26: [MS] Microsoft acknowledge reception
  • 2016-09-15: [MS] Microsoft has a successful repro
  • 2016-11-02: [QB] Ask if they deemed the bug as being important or not
  • 2016-11-10: [MS] Acknowledge fix will be released in Dec. patch Tuesday
  • 2016-12-13: [MS] Fix for CVE-2016-7259 is released
  • 2016-12-14: [QB] Quick look at the patch and blog release

Comments