IoCompleteRequest Analysis The exported function IoCompleteRequest in ntoskrnl.exe ends up calling IopCompleteRequest function. We can see on Windows XP that it does a bitwise 40 AND 70 and jumps to the inlined memcpy code which ends up triggering the bugcheck.
On Windows 7 we see the bitwise 40 AND 30 takes a different codepath and never hits our memcpy.
The “test al, 40h” instruction on Windows 7 branches off to another codepath as its doing a bitwise 40 AND 30 instead of bitwise 40 AND 70 as al=30h on Windows 7 which is from the IRP flags value.
IopXxxControlFile Analysis “So what causes the flags value to be 30h instead of 70h?” was my next question. After some investigation I discovered that IopXxxControlFile held the answer. The IopXxxControlFile function had been called earlier in our call stack. This function does a number of checks and validations on the inputs provided such as if addresses are in user space, buffer lengths, etc. and sets up our data in IRP.
In this function near the beginning it calls the ProbeForWrite function which checks if the address falls in the user space range and writable. The first thing the function does though is check the output buffer length, if zero it returns back to the IopXxxControlFile function without even checking the output buffer address. The ProbeForWrite function below is from Windows XP but is also the same for Windows 7.
Returning back to the IopXxxControlFile function and after a number of checks near the end of the code we see our output buffer address being placed in the IRP UserBuffer field and Flags value being updated to 0x70, all it checks on Windows XP if an output buffer address is available.
On Windows 7 we finally discover the root cause as to what has changed in the IopXxxControlFile function. It checks the output buffer length instead of the output buffer address. Since the output buffer length is 0 the flags value does not get set to 0x70 thus mitigating the vulnerability.
What do these flags values mean? So what do these values 10h, 30h, 40h and 70h represent? Searching through wdm.h header file I found these definitions:
Other Windows Versions Since all my tests were on a fully patched Windows XP SP3 32bit and Windows 7 SP1 32bit I thought I’d check some other operating systems. Checking on Windows Server 2003 SP2 Standard Edition 32bit found to have the same issue as Windows XP and during tests exploited successfully. Windows Server 2003 has still got over 5 months before the end-of-life so for those of you still using Windows 2003 better upgrade to a later operating system if you’ve not already done so.
On a clean default installation of Windows Vista 32bit in an unpatched state the output buffer length check had been applied like Windows 7. This means Microsoft did know about this issue and added the check before release.
There are plenty of products designed only to run on Windows Servers, which I have not audited, so maybe it’s a good time for researchers to discover some low-hanging fruit.
Final thoughts One thing is clear from this research and working with vendors: Just because it’s a big company doesn’t mean you’ll get great service. There are plenty of other vendors doing an excellent job so we should not blindly need to go with the likes of McAfee, Symantec or Trend Micro.
Updating machines is a tedious job at times so really we should be focusing on mitigation products like Microsoft EMET and MalwareBytes Anti-Exploit and not be so dependent on constantly updating machines for security. Bottom line is to upgrade to the latest operating systems as it will have a number of mitigations, checks, validations in place that we probably don’t even know about yet keeping us safe.
I’ll start submitting the exploits to Exploit-DB in the next few days and tweet you all once published.
References [PDF]