TrueType font files are made up of a number of tables; each table begins on a 4 byte boundary that comprises an outline font and must be long aligned and padded with zeroes if necessary. Referring to the “TrueType 1.0 Font File Technical Specification”, provided by Microsoft; the TrueType font file begins at byte 0 with the Offset Table. Offset Table is divided into 5 subtable:
sfnt version : 65536(0x0001 0000) for version 1.0
numTables : Number of tables
searchRange : (Maximum power of 2 ≤ numTables) x 16
entrySelector : Log2(Maximum power of 2 ≤ numTables)
rangeShift : numTables x 16 – searchRange
Beginning at byte 12, after the Offset Table, is the Font Table Directory. Entries in the Table Directory must be sorted in ascending order by ‘tag’ name. Overall, the Font Table Directory Header consists of:
tag : 4 byte identifier
checkSum : checksum of the table
offset : Beginning offset of the font table entry
length : Length of the table
The Structure of True Type Font Directory
The required tables in the Font Table Directory:
cmap : character to glyph mapping
glyf : glyph data
head : font header
hhea : horizontal header
hmtx : horizontal metrics
loca : index to location
maxp : maximum profile
name : naming table
post : PostScript information
OS/2 : OS/2 and Windows specific metrics
The optional tables in the Font Table Directory:
cvt : Control Value Table
EBDT : Embedded bitmap data
EBLC : Embedded bitmap location data
EBSC : Embedded bitmap Scaling data
fpgm : font program
gasp : grid-fitting and scan conversion procedure
hdmx : horizontal device metrics
kern : kerning
LTSH : Linear threshold table
prep : CVT Program
VDMX : Vertical Metrics header
vhea : Vertical Metrics
Due to font validation purposes, the dumb fuzzing technique is not recommended for these fields: ‘checkSum’, ‘offset’, ‘length’ and ‘Table’. To reduce the number of irrelevant tests, a checksum validation program is used to determine the checksum of ‘head’ table.
Fix the Checksum value of the “head” Font Table Directory
During the fuzzing process, the table checksum has to re-compute. The checksum calculation implies 4 byte boundaries as shown in Python program below:
<NOTE TO NICO: NO PYTHON PROGRAM IS HERE>
Our font fuzzer is to fuzz the TrueType font file into different sizes which enables the generation of the test cases to determine the size of font in triggering the vulnerability. Each fuzzing process starts with automating the installation of the mutated font in Windows system. It will then display the font; both in open the font file via fontview.exe and displaying the character maps. Lastly, uninstall the font and repeat the process if no vulnerability is found.
The windll.gdi32.AddFontResourceExA function is used to automate the installation of the crafted font into the “C:\Windows\Fonts” folder.
htr = windll.gdi32.AddFontResourceExA(FileFont, FR_PRIVATE, None)
Once the fuzzing environment is ready, a LOGFONT object is created to define the attributes of a font.
Assuming no vulnerability has been found at a font with a specified size that has been called; the windll.gdi32.RemoveFontResourceExW function will be called to remove the fonts in “C:\Windows\Fonts” folder.
windll.gdi32.RemoveFontResourceExW(fileFont, FR_PRIVATE, None)
Another size of font in the range that has been set will be called and the same process will repeat until vulnerability is found or the list of font size elements under a loop function has all been called and no vulnerability is found.
Figure below shows the Blue Screen of Death (BSOD) proof of concept via our font fuzzer. [Editor's note: BOOM! :>]
BSOD of Windows 8 Pro
The details of the fuzzer and findings will be discussed in the talk. Looking forward to see you guys in INFILTRATE 2013.
--- Ling Chuan Lee & Lee Yee Chan from F13 Labs