360 Security Guard · 2015/05/13 18:26

0 x00 preface


Author: [email protected] Team

On May 12, 2015, Beijing time, Microsoft pushed the May Patch day patch, including SECURITY updates for IE, Windows kernel, Windows kernel drivers, Office and many other components. Two 0day bugs fixed this month

Cve-2015-1674 (technet.microsoft.com/en-us/libra…) Windows Kernel Security Bypass Vulnerability fixed in MS15-052

Cve-2015-1701 (technet.microsoft.com/en-us/libra…) Windows Kernel mode driver permission Promotion vulnerability fixed in MS15-051 It also caught our attention.

It has been confirmed that CVE-2015-1674 is a kernel KASLR bypass vulnerability discovered by the author in mid-2014, and CVE-2015-1701 was discovered in Fireeye’s report on Operation RussianDoll released on April 18 this year. The kernel 0day vulnerability, used in a highly targeted attack by the Russian hacking group APT28, Hfiref0x, a hacker from the Russian security community Kernelmode.info, also posted the full attack code for the CVE-2015-1701 vulnerability on his Github (github.com/hfiref0x/CV…) . The author of this Blog on these three repair 0day vulnerabilities this month, talk about their principles, details and repair methods and some peripheral information.

0x01 CVE-2015-1674/MS15-052


Vulnerability information

Ms15-052 is a security update for CNG.sys issued by Microsoft to fix the CVE-2015-1674 vulnerability. This vulnerability is actually identical to a post I made on Weibo (weibo.com/1648808737/…) last October when Microsoft released the first preview version of Windows 10 (9860). Introduced a loophole in the CVE – 2015-0010 / MS05-010 (technet.microsoft.com/library/sec…). It is the same problem, which belongs to the security vulnerability that Microsoft did not fully fix when repairing CVE-2015-0010.

After the release of Windows 10, I tested two vulnerabilities that KASLR bypassed, One is j00ru on NoSuchCon 2013 released a using kernel KiTrap01 debug exception handling problems detecting kernel address around KASLR (j00ru.vexillium.org/blog/21_05_…). The other is an unpublicized KASLR bypass vulnerability in a CNG.sys that I discovered in reverse Windows 8.1 kernel in 2014. Neither of these vulnerabilities was fixed in the Windows 9860 preview released at that time.

Since the CNG.sys Device (\Device\CNG) is one of the few devices in the system that has ALL APPLICATION PACKAGES DACL set up to allow arbitrary access even to highly isolated AppContainers, Also, this problem affects both x86 and X64 systems (J00RU’s KASLR bypass can only be used on x86 systems), making the latter more practical. This is one of the kernel bugs that 360Vulcan Team reserves for pwn2OWn-type matches, and Microsoft has been very vague about KASLR bypass vulnerabilities (j00RU’s KASLR bypass has not been fixed until the latest version of Windows 10 10074). Therefore, I did not report this vulnerability to Microsoft, and CVE-2015-1674 is the vulnerability I mentioned here in this patch day.

Microsoft decided to fix the vulnerability in a new version of Windows 10, possibly because it affected THE EPM in IE and Spartan (enhanced protection mode, mainly using AppContainer). Microsoft has quietly fully fixed the bug, and during patch Day in February, Microsoft pushed MS05-010 for Windows 8/8.1/Server 2012/Server 2012 R2, which was also affected, in an attempt to fix the problem.

However, it is interesting that in MS05-010, although Microsoft gave the vulnerability CVE-2015-0010 number, it did not fully fix the problem, resulting in the vulnerability was finally used by Lokihardt from Korea in Pwn2Own 2015, to break the Windows kernel. As a result of the use of Pwn2Own 2015, Microsoft issued another security update ms15-052 with a new vulnerability number: CVE-2015-1674. In fact, this “new” vulnerability is almost the same problem as CVE-2015-0010. It is a legacy problem of CVE-2015-0010 that has not been fully fixed. It is difficult to understand that in Windows 10 9926, The problems with BOTH CVE-2015-0010 and CVE-2015-1674 were fixed at once, and it appears that there was some confusion and oversight within Microsoft during the development of Windows 10 that caused the current problems.

In ZDI has the loophole website has released some of the details: www.zerodayinitiative.com/advisories/… Since there are not many attack surfaces in CNg. sys, experienced security researchers can easily find the details of this vulnerability based on this information. Therefore, I will directly introduce the specific information of this vulnerability.

Vulnerability details

This vulnerability exists in the device control processing code of CNG.sys. Cng. SYS is Microsoft’s next generation kernel cryptography driver. It provides many cryptographic-related interfaces through DeviceControl (DeviceControl) and function output. Like many Windows kernel drivers, its DeviceControl processing is mixed with control functions that are open to other kernel drivers and user-mode programs. This is often the source of many kernel security vulnerabilities. I mentioned in ISC 2014 on 360 XP Shield 3.0 kernel protection that KASLR bypass in a control interface that affected Windows systems and still affects many important third party drivers has a similar problem.

CNG. Sys particularity lies in the fact that he created equipment (after \ Device \ CNG), can use ObSetSecurityObjectByPointer for equipment set up a special Security Descriptor, This security descriptor allows users of ALL APPLICATION PACKAGES permissions to have full control over the device. For those of you who are familiar with Microsoft’s AppContainer/EPM mechanism, you will know that a device with this permission can be directly accessed by rendering processes in isolation mode of IE or Spartan. CNG also wants all processes to have access to its interfaces. So the driver’s IRP_MJ_CREATE processing allows arbitrary access without checking, that is, the related interface in cng. SYS, even if the process is protected by IE/Spartan or enhanced protection mode, can be accessed at will.

In CNG. SYS equipment control code, there are multiple control code is specially provide for the use of external drive, such as 0 x39024, 0 x39040, 0 x39044, 0 x39048, 0 x39064 etc, these devices to control code will be returned to the caller including FIPSSHA, FIPS3Des, HMAC MD5, FIPS GenRandom,SSL encryption and decryption and Key management, BCrypto series interface and a series of functions implemented in CNG internal interface address, through this, external drivers can directly call the interface of these functions, related cryptographic operations, without their own implementation of these interfaces.

The problem here is that there is no check to see if the source of the IRP is kernel mode for the interfaces set up for these special external kernel-mode drivers, so user-mode programs can call these device control codes directly through the DeviceIoControl function to obtain the interfaces for these functions. Of course, user-mode programs cannot use these interfaces directly, but with the mirrored layout of CNG.SYS, user-mode programs can obtain the base address of CNG.SYS and the location of relevant key data, completely bypassing the Microsoft kernel’s KASLR kernel-mode address randomization technique.

In Microsoft MS05-010, in view of 0 x39024 this interface for processing and repair (CVE – 2015-0010), and on the repair of the code below a line, just lay there is a problem of 0 x39040/0 x39044/0 x39048/0 x39064 interface, Directly ignored in the February patch. Lokihardt players who used the bug in Pwn2Own in March must have had a good laugh when they saw the patch 🙂

It wasn’t until this month that Microsoft officially fixed the 0x39040 to 0x39064 series of interfaces and renamed the failed bug CVE-2015-1674.

Here’s some background: Before Windows 8.1, Microsoft did not pay attention to local KASLR issues, although from Windows NT onwards, Microsoft’s kernel modules were randomly addressed (especially in X64 + Windows 8 + high entropy random number), but only to make remote kernel vulnerabilities more difficult. This is mainly because before Windows 8.1, any process with any permission can obtain the kernel and kernel driver and module base address through NtQuerySystemInformation and SystemModuleInformation, and can ignore KASLR directly.

That changed with Windows 8.1, when Microsoft introduced KASLR mitigation for native programs to further combat sandboxed attacks using kernel vulnerabilities in IE protected mode, enhanced protected mode. Alex Ionescu analyzed the mechanism on his BLOG: (www.alex-ionescu.com/?p=82), in Windows 8.1, if a process is running below a low integrity level (protected or enhanced protected mode), Methods related to obtaining the kernel module base address, such as SystemModuleInformation, are blocked, so that even if an attacker triggers a kernel vulnerability in protected or enhanced protected mode, it is difficult to exploit it further because the kernel base address is not available.

The security vulnerability of CNG opens the door for attackers to bypass KASLR with such mitigation, because it happens to be a vulnerability that can be used in both protected and enhanced protected modes, and can be called stably on both X64 and x86 systems. After obtaining CNG related key data addresses, If an attacker has a vulnerability to write to any address in the kernel, it can override the list of functions stored in the cng. SYS data segment and gain the right to execute kernel code when called by other kernel-mode drivers.

Vulnerability repair method


In the IRP_MJ_DEVICE_CONTROL processing code, for 0x39024,0x39040 and other control codes, check Irp->RequestMode, you can distinguish the kernel mode driver and user mode call, to avoid the occurrence of vulnerability. Such a simple bug, almost parallel code, was ignored by the Patch repair department of Microsoft, it took two times, six months to completely fix, have to say it is a tragedy.

0x02 CVE-2015-1701 / MS15-051


Vulnerability information

Cve-2015-1701 is Fireeye’s April 18 report “Operation RussianDoll: Adobe & Windows Zero-day Exploits by Russia’s APT28 in Highly Targeted Attack “is used in conjunction with Adobe Flash The exploit uses the Windows kernel privilege promotion vulnerability, which has not been fixed since April, so information about the vulnerability is also vague on Fireeye’s website.

At Patch Day this month, Microsoft fixed the privilege promotion vulnerability with patch MS15-051, and almost immediately after the patch was released, Hfiref0x, a hacker on the Russian forum kernelmode.info, posted the full attack code exploiting the vulnerability on its Github (github.com/hfiref0x/CV…) “Seemed to hint at the vulnerability’s close ties to Russia.

This vulnerability is similar to the CVE-2014-4113 vulnerability exposed in October last year. It is a time sequence problem caused by the Windows kernel driver Win32K. sys in the process of creating Windows, which causes the kernel window object mark disorder, resulting in arbitrary code execution of the kernel. Microsoft fixed the problem starting with Windows 8, but somehow the bug persists in Windows XP/2003/Vista/Windows 7/ Server 2008/ Server 2008 R2.

Another mistake Microsoft seems to have made was in the patch announcement for MS15-051 (technet.microsoft.com/en-us/libra…). The vulnerability affects None on Windows7 /Windows 2008 R2, but in reality it affects Both Windows7 and Server 2008 R2, which is the target of the attack code on Github.

Vulnerability details

By analyzing the attack code, we can see that the vulnerability occurred in the kernel-mode driver win32K.sys window creation function: xxxCreateWindowEx, which is a complex function in the GDI kernel to create kernel window objects through user32! CreateWindow(Ex)->NtUserCreateWindowEx can finally be called to the kernel function.

After analyzing a set of parameters, xxxCreateWindows allocates a Win32 object of window type using HMAllocateObject and populates it with parameters such as the window’s Class object. Using hex-Rays Decompiler, we see that on operating systems that did not fix the bug before Windows 8 +, there is a logical process like this:

#! c++ if ( pcls->spicn && ! pcls->spicnSm ) { xxxCreateClassSmIcon(pcls); } pwnd->hModule = hMoudle; pwnd->lpfnWndProc = MapClientNeuterToClientPfn(pcls, 0, bansi);Copy the code

Here xxxCreateClassSmIcon icon for the window class is the purpose of creating a small icon in the cache, next, the system will be through MapClientNeuterToClientPfn according to window class set WindowProc for window.

There seems to be no problem here, but if we look at the implementation of xxxCreateClassSmIcon, we can see that the xxxCreateClassSmIcon is implemented through xxxClientCopyImage->KeUserModeCallback, That is, the call is ultimately implemented in conjunction with the user-mode callback.

For those familiar with Window management, KeUserModeCallback actually ends up calling the corresponding function placed in PEB->KernelCallbackTable, which is ultimately implemented in user mode. Here, for example, user32! Will finally be called. The __xxxClientCopyImage function.

Kernel Mode Callback is a set of user mode-kernel Mode interactive Callback mechanism dedicated to Win32K. It is also a function designed to improve performance in windowed Kernel system. Due to the existence of this mechanism, User-mode programs may control and interrupt the logical process of kernel execution by hooking the kernel callback function of the system, thus causing many security vulnerabilities, including the HISTORICAL CVE-2013-3167 vulnerability, which is caused by this mechanism.

Tarjei Mandt, a former head of the Norman Threat Research team (now Azimuth Security), I also published a topic called “Kernel Attacks Through User-mode Callbacks” on Blackhat 2011, which specifically analyzed the security vulnerabilities caused by this call back mechanism. Interested readers can take a closer look.

Continuing with this vulnerability, we know from our analysis that by hooking user32! The __xxxClientCopyImage function will interrupt the xxxCreateWindowEx process and perform the desired action at the xxxCreateClassSmIcon position of the code above, that is, before the system populates PWN ->lpfnWndProc. So how do you take advantage of that? In the hfiref0x post, we can see that after hook the function, the code only does one line:

#! c++ SetWindowLongPtr(GetFirstThreadHWND(), GWLP_WNDPROC, (LONG_PTR)&DefWindowProc);Copy the code

SetWindowLongPtr is a function that sets the data and attributes of a window. GWLP_WNDPROC is a function that subclasses a window and unsubclasses a window. Replace the window’s calling procedure with its own function to take over some of the window’s processing, or subclass it by setting it to DefWindowProc.

Where GetFirestThreadHWND is a trick to get a handle to the window that is currently being created, because now xxxCreateWindowEx is being interrupted during the kernel process, just with the user mode code and xxxCreateClassSmIcon information, There is no way to know which window object/handle is being created.

But we know that in the Win32k kernel, all kernel window information is all mapped to a memory address in user mode, through user32! GSharedInfo we can get its address (which is a read-only mapping of the kernel-mode window information list), and we just said that the kernel window object was created via HMAllocateObject when we interrupted, so it is actually already retrievable in gSharedInfo. This technique is not new and has been used in some past vulnerability attack code, such as the CVE-2013-1300 Exploit used by MWR Labs in Pwn2Own2013.

We see here that the code replaces the WindowProc of the window being created by the current thread with DefWindowProc using SetWindowLongPtr, and then seems to have the ability to execute kernel code. Why? The answer can be found by looking in depth at the implementation of SetWindowLongPtr->NtUserSetWindowLongPtr. When index (GWLP_WNDPROC(-4)) <0, it will call xxxSetWindowData to complete the final setting. When xxxSetWindowData determines that index is GWLP_WNDPROC, it executes the following logic:

#! c++ ptr = MapClientToServerPfn(dwData); if ( ptr ) { ClrWF(pwn, WFANSIPROC); SetWF(pwn, WFSERVERSIDEPROC); pwn->lpfnWndProc =ptr;Copy the code

The logic here is to check whether GWLP_WNDPROC is an unsubclass operation, and if it is, it needs to be set to the kernel to take over the window process, setting the window to the Server Side Proc flag. This flag means that the window procedure function will be called in kernel mode.

The MapClientToServerPfn check is to check whether the WindowProc (dwData of SetWindowLongPtr) set for the current window is a preset function in apfnClientA/W in GPSI (PCSERVERINFO) Number, namely, the handlers prepared in User32 for various Windows, such as ScrollBarWndProcW, MenuWndProcW, ButtonWndProcW, and so on, as well as DefWindowProcW here.

If validation is one of these default window procedures, then set the window flag to run the window procedure functions in kernel mode and change the window procedure functions to the corresponding kernel handlers included in GPSI ->aStoCidPfn, such as xxxSBWndProc, xxxDefWindowProc, XxxMenuWindowProc, and so on.

There seems to be no problem here, because WindowProc(Win32K! XxxDefWindowProc).

However, if we look at the logical sequence of xxxCreateWindowEx, we can see that this can cause serious problems:

1. XxxCreateWindowEx call HMAllocateObject to create window object 2. 3. XxxClientCopyImage is interrupted, The user mode function call SetWindowLongPtr sets WindowProc to the window currently being created. DefWindowProc, considered by xxxSetWindowData to be de-subclassing, sets the window procedure to be executed in kernel mode and sets WindowProc to the kernel function win32K! XxxDefWindowProc 5. Returning from xxxCreateClassSmIcon, continue to call MapClientNeuterToClientPfn transformation of the current window class function default WindowProc function (i.e., user mode control), Then set the WindowProc of the window object to the user's own window objectCopy the code

As we can see, because this break happens just before xxxCreateWindowProc sets the WindowProc for the window, it is invalid for xxxSetWindowData to change the WindowProc of the window to xxxDefWindowProc, The WindowProc of the window is changed to the WindowProc of the user mode application. At this point, the flag of the window is set to execute WindowProc in kernel mode. Then when xxxSendMessage or other functions send messages to the window, It jumps directly in kernel mode and calls functions that are actually in user mode for processing, causing kernel-mode code to execute directly.

By breaking the xxxCreateWindowEx process just before setting the window to WindowProc and using SetWindowLongPtr to trick the system into thinking it was de-subclassing and setting the window to kernel mode, When returning xxxCreateWindowEx, setting the window procedure function overwrites the subclassed function, but does not remove the kernel-mode execution flag of the window function, resulting in arbitrary kernel-mode code execution.

The Exploit code eventually acquires the token of the system process and overwrites its own token for permission promotion, which is nothing to be said.

Vulnerability repair method

On Windows 8 and later, Microsoft has fixed this timing logic by modifying the window’s WindowProc and then calling xxxCreateClassSmIcon, so that xxxCreateClassSmIcon is interrupted and the subclassing window is removed. The final window handler will also be Win32K! XxxDefWindowProc, instead of being modified to user-mode functions, does not exist this vulnerability.

This month’s patch also fixes this vulnerability for Windows 2003/Vista/7/Server 2008/Server 2008 R2.

On Windows 8 and up, if the CPU supports SMEP (above IvyBridge), this kernel-mode call to user-mode functions will be intercepted, but attackers can also hide payload in the kernel address space to bypass this interception. For Microsoft XP operating system without official patches, 360 XP shield provides Win32K kernel function takeover processing from V2.0, for CVE-2015-1701 this type of vulnerability without upgrading, you can be directly immune.