CVE-2014-4113 Detailed Vulnerability and Patch Analysis
As you might have heard, Microsoft recently patched some vulnerabilities; vulnerabilities related to Sandworm CVE-2014-4114 (Powerpoint exploit) and font parsing (CVE-2014-4148). But in this article, I'm more interested to talk about CVE-2014-4113, which is a local kernel vulnerability that successful exploitation would give you SYSTEM access. So I started analyzing patch (KB3000061) and mid-analysis, I found a PoC for this vulnerability in the wild. Therefore I combined my patch analysis and reverse engineering of PoC binary together to deeply understand this vulnerability and exploitation technique. Here, I'll share it step by step, with all details, so you'll know everything about CVE-2014-4113.
First of all, I downloaded KB3000061 and I noticed that it just does have win32k.sys inside. So I created two folders called Vulnerable and Patched and placed vulnerable and patched versions of win32k.sys inside them. Next, I loaded both of them in IDA and saved both databases. As next step I had to see what've changed in patched version, so I chose TurboDiff for this job. TurboDiff simply gives you a plain-text table of changed functions. For this particular patch, it gave me 25 changed function. I started checking each changed function and one of them caught my attention. In the internal function of xxxHandleMenuMessages, I noticed that patched version does have an additional check for returned value from xxxMNFindWindowFromPoint (internal function). That check was a call to IsMFMWFPWindow function and parameter to IsMFMWFPWindow was exactly return value of xxxMNFindWindowFromPoint. So I figured out that here something was wrong and Microsoft added a code to check return value of xxxMNFindWindowFromPoint. You can see change here:
Take a look at both functions with zoom out, vulnerable part:
Knowing this, I started to think about exploitation method of this vulnerability, how to trigger this vulnerability and make xxxHandleMenuMessages API to call xxxSendMessage with an invalid HANDLE. As soon as I saw that the vulnerability is related to window system and possible NULL value during xxxHandleMenuMessage process, I just remembered this. For exploiting that, you had to map zero/null page, create a fake object at zero page and trigger the vulnerability. So this was the general idea, now I had to find a way to trigger this vulnerability by causing xxxHandleMenuMessage call xxxSendMessage with a NULL handle. Luckily I suddenly saw that there is a PoC published online for this vulnerability, so as a lazy person, instead of trying to solve it on my own as a practice/challenge, I just downloaded the sample and started to analyze it. Lots of things was as I thought, the only missing part in chain of exploitation was how to make that NULL in xxxHandleMenuMessage. It was done by hooking and altering parameters in user mode, you can read more about these tricks here and here.
So basically the PoC deletes the menu and returns -5, so xxxSendMessage will use a tagWND object starting from -5 (0xFFFFFFFB) to positive values which is in user-mode. The PoC allocated zero-page using ZwAllocateVirtualMemory with 0x01 as base address and writes a fake tagWND object here. Windows allows zero page allocation for 16-bit application compatibility/support. So the tagWND object have two important parts, one is WS_EXECUTE_IN_KERNEL flag which is at offset ((BYTE*)&pWnd->state)+0x02 and the other one is callback function which is at offset 0x60. So by setting 0x16 to 0x04, you are telling kernel that the callback function at 0x60 needs to be executed in kernel. So the PoC modifies return value (returns -5) by hooking, but before that, it writes 0x04 to 0x16 - 0x05 (0x11) offset (WS_EXECUTE_IN_KERNEL flag) and address of shellcode at 0x60 - 0x05 (0x5B) -which will be executed in kernel-. See:
The shellcode does nothing other than replacing current process token with SYSTEM process (pid = 4) token. Therefore, any process created by current process will have SYSTEM token too. Here is the shellcode:
and here is what zero page looks like:
Cyan color holds address of shellcode and yellow background holds WS_EXECUTE_IN_KERNEL flag.
For triggering the vulnerability, simply it creates two layer popup menu (one main popup menu and one sub menu inside it), then it calls TrackPopupMenu to trigger the hook. In hook function, it replaces window handler using SetWindowLongA API, see:
and new handler function, simply deletes popup menu and returns 0xFFFFFFFB (-5):
That was it. Using this simple hooking and altering popup menu, kernel will call and execute callback function at null page, in kernel space. I think I've said enough about this bug. So please update your OS, specially servers, as soon as possible, because lowest access (for example ASP.NET shell with ASP.NET user account) can get SYSTEM access using this vulnerability.