The need to analyze the patch for MS16-030 recently presented itself to us due to some related product research. After the analysis was complete, we realized that the attack surface of the patch was pretty interesting and determined it may be beneficial to share part of the analysis. This post will focus on triggering a patched bug from MS16-030.
An abbreviated list of the changes made to OLEAUT32 are visible below.
In looking at the list of changed functions, we chose to peruse OLEAUT32!_ResToIcon here, but imagine the process may apply to other changes. Lets take a look at the graph overview of the modifications to ResToIcon, which we can assume performs some function related to icons.
There are a ton of changes here, but we need to determine if they are in fact security fixes. Let’s zoom in to some blocks.
Yeah, this looks good for our purposes. There are two calls we can see here: SizeTAdd and ULongLongToULong. Checking the documentation:
SizeTAdd - This is one of a set of inline functions designed to provide arithmetic operations and perform validity checks with minimal impact on performance.
ULongLongToULong - This is one of a set of inline functions designed to provide type conversions and perform validity checks with minimal impact on performance.
Nice, this seems like relevant code. Now how can we exercise this code path? We need to find a path from an entry point in OLEAUT32 to the fixed function OLEAUT32!_ResToIcon.
As we can see above there are several candidates, but after some consideration (and trial and error) we decided to go with OLEAUT32!_OleLoadPicture which is imported by vbscript.dll.
Opening vbscript.dll in IDA, we map paths from OleLoadPicture and they are thankfully very simple.
It seems as though we just need to call vbscript!VbsLoadPicture which is accessible via the vbscript LoadPicture API. Being lazy, we attempted the naive approach and set a breakpoint at the call to OleLoadPicture in vbscript!VbsLoadPicture and opened an icon with the affected API. This did not work.. We bounced off some kind of check.
The problem is that in the logical path to OLEAUT32!OleLoadPicture is blocked off for us by a call to ole32!StgIsStorageFile. What is this API?
"TheStgIsStorageFilefunction indicates whether a particular disk file contains a storage object."
Looking at MSDN, we get the very minimal information above. Further Googling leads us to the fact that we are dealing with a notion of COM Structured Storage, and this nice blurb below (again from MSDN).
'''Structured Storage provides file and data persistence in COM by handling a single file as a structured collection of objects known as storages and streams.'''
So it appears as though we need to create a Structured Storage object and insert an icon in it to reach the desired OLEAUT32!OleLoadPicture call. How can we create this file?
Some further googling leads us to an (awesome) tool to accomplish this called OpenMCDF (http://openmcdf.sourceforge.net). So all we have to do is make a stream off the structured storage root that contains an icon and open the resulting file again with a vbscript call to LoadPicture. So we made one with the Structured Storage eXplorer included in OpenMCDF.
After this, we set our breakpoint at at OleLoadPicture and open this new file. The breakpoint wasn’t hit... What’s going on??
After some analysis, it seems that we are bouncing off another check.
Our current path follows the pink blocks, our desired block is in green. The logic appears to be validating the name of the stream against the string "CONTENTS". Let's rename our stream from “icon” to “CONTENTS” and try again.
This file caused a hit at our breakpoint inOleLoadPicture.
Now, from the same windbg session we then set another breakpoint in OLEAUT32!_ResToIcon to determine if the fixed function was hit by this file.
So, we did indeed hit our breakpoint.
From here we know that our input is reasonably close to the changed code, lets just fire a fuzzer at it and monitor it for faults. Here we are using a dumb fuzzer to generate mutated candidate files, a hacked vbscript harness to open the files, and eEye faultmon to perform automated debugging. Additionally, we were sure to enable gflags page heap. The ugly fuzzer harness can be seen below.
We don’t have to wait very long here as faultmon gives us a crash on the 612thiteration. Let’s open it in windbg...
Nice, we triggered (one of the) patched bugs. We then verified the work by ensuring the crash did not occur after the patch was installed.
Analyzing patches is fun, but really the takeaway here for us was bindiffing sometimes allows us to understand new or less traveled attack surface. This concept of packing up file types into structure storage to hit different parsing code is pretty interesting and may be fruitful in future fuzzing efforts.
Bill Finlayson is the senior data scientist at Endgame. Before Endgame, he was a senior security researcher at Vectra where he researched machine learning models for lateral movement and malware detection. Prior to Vectra, he was a senior researcher at BeyondTrust and a windows reverse engineer at CyberPoint International before that. He received a B.S. in computer science and a M.S. in mathematics from Rutgers University. Bill also holds multiple certifications from data visualization, convolutional neural networks, modeling risk and realities, and more from Coursera.