This past Patch Tuesday Microsoft released MS15-010: Vulnerabilities in Windows Kernel-Mode Driver Could Allow Remote Code Execution. This patch addressed multiple privately reported vulnerabilities in win32k.sys and one publicly disclosed vulnerability in cng.sys.

Win32k.sys Diff

The first notable thing we noticed was that several handlers for TrueType instructions, @irtp_*, were touched. While we did analyze these changes, they will not be the topic of this post.

1

Changed functions in win32k.sys

The next interesting thing we noticed was that there is a relationship between _FindSystemTimer and _xxxDispatchMessage in that the latter calls the former. We are going to take a closer look at these two functions.

_xxxDispatchMessageA

The diff for _xxxDispatchMessageA only showed one changed basic-block, so we can visualize it easily with in a combined display.

2

Diff of WIN32K!_xxxDispatchMessage

Based on the altered signature of _FindSystemTimer, it appears as if we are calling it with an extra parameter post-patch. To get more understanding, let's look at _FindSystemTimer .

_FindSystemTimer

The changes to _FindSystemTimer are minimal. Before the patch, we have a small function that traverses a global linked list (starting at gtmrListHead) to search for the system timer pTmr associated with the passed message pMsg. Upon successful validation of the pTmr->flags and the pMsg->lParam, the current pTmr is returned to the caller. Otherwise null is returned. The IDA Pro disassembly of the pre-patched version of _FindSystemTimer is shown below:

3WIN32K!FindSystemTimer pre-patch

The patched FindSystemTimer now takes two parameters, a pMsg and a pWnd. This function is similar to the unpatched version, except that it now performs further validation of the wParam member of pMsg against the nID member of pTmr. Additionally the passed in pWnd is validated against the pTimer spWnd member.

[caption id="attachment_21021" align="alignnone" width="357"] WIN32K!FindSystemTimer post-patch[/caption]

Clearly there had been a problem with one of the parameters that is now validated, which is going to be our starting point for fuzzing.

Stepping Back

Given that xxxDispatchMessage resides in the kernel, how can we exercise it from userspace?

5

USER32!DispatchMessageA

We begin with USER32!DispatchMessageA, which is an exported function that is basically a wrapper for USER32!DispatchMessageWorker.

6USER32!DispatchMessageWorker

Inside DispatchMessageWorker is logic that decides how to handle the incoming message. The above IDA snippet illustrates the handling of WM_SYSTIMER in DispatchMessageWorker. The associated C code might appear as shown below:

7b WM_SYSTIMER handling code

So, if our message is WM_SYSTIMER it is then passed to the Windows kernel via WIN32K!NtUserDispatchMessage, the disassembly for which is given below:

8WIN32K!NtUserDispatchMessage

win32k!NtUserDispatchMessage is a simple function that performs a sanity check on the message parameter and passes it to _xxxDispatchMessage.

9WIN32K!_xxxDispatchMessage path to patched function call (displayed pre-patch)

Here is where we finally get to a patched function. In this case win32k!_xxxDispatchMessage contains some logic for processing WM_SYSTIMER messages. The logical flow to the patched code is governed by EAX being a WM_SYSTIMER.

WM_SYSTIMER

Using IDA, we learn that WM_SYSTIMER is defined as 0x118, which is a good start. Then if we search for WM_SYSTIMER in Google, we get better information from http://www.baiyujia.com/vfpadvanced/f_vfpa_wm_systimer.asp.

10LMGTFY

From IDA and the Google search result, it looks like WM_SYSTIMER is an undocumented message with value 0x118. Further, we see that the lParam and wParam for this message are also undocumented. The above explanation seems to indicate that WM_SYSTIMER is related to the caret blink rate.

Fuzzing

Our starting point for fuzzing is a classic Win32 API program that creates and displays a caret. The code below has been adapted from http://www.winprog.org/tutorial/simple_window.html:

11CreateCaret code

We expect to see WM_SYSTIMER messages emitted when this code is run.

12

Spy++ Output

Looking at the output of Spy++, we do indeed see our 0x118 messages. At this point we optimistically then retooled our example code to fuzz the wParam, hwnd, and lParam of our Msg and waited. And waited. But we never got the expected kernel exception. Rather then give up at this point, we thought of drilling back into the code that creates a caret (xxxCreateCaret) to see where it sets its timer.

13

WIN32K!xxxCreateCaret

A combination of luck and intuition indicated that the second parameter to the SetSystemTimer call (0xffff) might specify the type of the timer (see the wParam in the Spy++ output above). So we used IDA to determine all of the callers of the SetSystemTimer function.

14

XREFS to SetSystemTimer

It looks like we have a few options here. Beginning with some C++ forms code, we exercised SetTooltipTimer and MouseHover and managed to trigger the timer with a new wParam (0xfffa).

15

More Spy++ output

Fuzzing attempts at SetTooltipTimer and MouseHover also failed to trigger a crash. Fuzzing additional callers (including 20 minutes with mouse sonar APIs) failed until we arrived at xxxFlashWindow, which we had noticed in earlier research but for some reason overlooked until later in the fuzzing exercise.

16

LMGTFY 2

Fortunately xxxFlashWindow is easy to fuzz since it's called directly from the userspace FlashWindow function. Therefore we can simply add a line of code to our previous template to start generating our timer messages.

17

FlashWindow Frankenstein code

As a verification check, we look at what we believe to be the timer type parameter of the call to SetSystemTimer inside the xxxFlashWindow function.

18

WIN32K!xxxFlashWindow call to SetSystemTimer

Based on the above disassembly fragment, we hope to see a wParam of 0xfff8.

19

Even more Spy++ output

Firing up Spy++ (again) and interacting with our toy application, we see that indeed we are receiving the expected wParam.

Crash

We modify our cobbled together example codes to make a dumb fuzzer, the source code for which is given below:

[caption id="attachment_21016" align="alignnone" width="385"]20

Fuzzing code[/caption]

Using the above code, we finally got our crash:

21

Crash Details

We are crashing in _GetProp, with what appears to be a null pointer dereference.

23

WIN32K!_GetProp

GetProp is a function which searches a list of window properties extracted from the passed PWND for a property which has a string member matching the passed string. The undocumented PWND struct can be seen in the ReactOS source code:

[caption id="attachment_21018" align="alignnone" width="385"]22

ReactOS _WND struct[/caption]

Now it is clear that we are dereferencing a null pointer when trying to access the pWnd->ppropList in _GetProp.

While a discussion of exploitation is outside the scope of this post, it should be noted that mitigation against kernel null pointer dereferences is available for Windows 7 and is in place by default in Windows 8+.