Is this thing still on? It’s been a while since we’ve posted to this blog and we think it’s time to start posting deep technical content about Security Research & Defense (SRD) again. For readers who are new or may have forgotten, this blog is the home of the MSRC Vulnerabilities & Mitigations engineering team. We’re the team that is on the receiving end of all vulnerabilities and exploits that affect Microsoft’s offerings. We perform detailed root cause analysis, variant investigation, and we work with many partners across Microsoft to help build mitigations that make Windows, Microsoft Edge, Microsoft Office, and Microsoft Azure more difficult to attack.
To kick things off, we wanted to start with an interesting technical story related to CVE-2016-0040 that illustrates the spirit of our team. This vulnerability was addressed with MS16-014 in February, 2016. Let’s dive in 😊
From Pixels to Proof of Concept (POC)
At MSRC, we typically learn about vulnerabilities when they’re reported to us through firstname.lastname@example.org. However, there are times where we only receive vague hints about the presence of a vulnerability, and it’s up to us to puzzle over what the issue might be. This is one of those stories. It’s the story of how we took a screenshot of a single crashing instruction and ultimately created a proof of concept to trigger the vulnerability in less than 24 hours.
This quickly piqued our interest, but on the surface there really didn’t seem to be much to go on regarding the root cause of the vulnerability aside from the hint about it not being in win32k.sys. Rather than giving up, we decided to dig a bit deeper. Zooming in on the crashing instruction, we could see that the instructions prior to and after the crashing instruction were partially visible:
From this, we inferred that the instruction sequence was likely the following:
This seemed like a pretty unique instruction sequence, so we decided to search around for instances of it within various kernel binaries. Fortunately for us, we have easy access to all of the released binaries that we thought might have been involved in this, so this gave us a nice sample set to search through.
Needle in the haystack
About an hour later, we found a match that seemed like a very intriguing candidate in WMI code located within ntoskrnl.exe:
This match gave us a starting point to begin searching to see if a vulnerability existed. To gain more confidence, we started looking for additional evidence. One of the valuable resources that we use to search for vulnerabilities and exploits is Windows Error Reporting (WER). As John Lambert described in his blog post on MS08-067, WER is the crash reporting mechanism that Microsoft uses to discover and fix bugs at scale. In this case, we found a small number of crash reports in the function WmipRecieveNotifications that matched the exact crashing instruction described in the tweet. This gave us more information about what the issue might be and increased our confidence that there was a vulnerability lurking in this code.
Where there’s smoke…
As with the story of MS08-067, we now had a function where we suspected a vulnerability might be. The next step was to start reading the code to see if we could spot it. After reading through the code in WmipReceiveNotifications, we were able to pinpoint what we thought the issue was: an uninitialized memory use vulnerability leading to a memory write.
In this case, the function has a code path where it conditionally uses a fixed-size local array, highlighted in yellow, to store object event information if the number of handles provided is small enough:
Unfortunately, the blue highlighted code shows that the contents of the object array are only initialized in CHK builds (via DBG=1). This means its contents will be uninitialized if accessed.
Later in the function, the code checks to see if the notification action is associated with a create thread event. If it is, it assumes that the ObjectArray has at least one element and proceeds to access it, as highlighted in red below. This is a problem if the provided HandleCount is set to zero as the contents of the ObjectArray will be uninitialized. To make matters worse, the code proceeds to write to memory using a pointer that is derived from the uninitialized object array. This results in a write to an uninitialized memory address which is a powerful primitive for would-be exploit writers.
From this analysis, we were confident that we had spotted the vulnerability. The only thing left to do was to confirm it.
The next morning, we constructed a proof of concept and used it to confirm that the vulnerability existed by triggering a crash on the exact same instruction that was originally mentioned in the tweet. In less than 24 hours, we had gone from pixels to proof of concept.
On October 25th, 2015, @R00tkitSMM reported the vulnerability they had discovered via email@example.com, but by this time we had already opened an MSRC case roughly a week in advance and had begun working on the fix. Nevertheless, it was @R00tkitSMM who tipped us off about the presence of the issue here and we made sure to recognize their contribution through the acknowledgement for CVE-2016-0040:
That said, this analysis highlights the risks of publishing even seemingly minimal information about vulnerabilities, so we encourage researchers to avoid doing this 😊
In this post, we showed how obscure hints about the presence of a vulnerability can sometimes provide enough information to uncover the underlying issue. While there are many cases where this is not possible, this is another good example of a scenario where we were able to work back and identify the vulnerability using various tools available to us.
Shout outs to Axel Souchet (@0vercl0k), Elia Florio, and Mark Wodrich (@markwo) for their contributions to sleuthing for this vulnerability!
MSRC Vulnerabilities & Mitigations Team