Class Dismissed: 4 Use-After-Free Vulnerabilities in Windows
Today, Microsoft released their latest Patch Tuesday. This Patch includes a fix for CVE-2015-2363, a complementary patch to CVE-2015-2360 from last month. The two CVEs together bundles within themselves IMPORTANT-rated exploitable vulnerabilities which we responsibly disclosed to Microsoft.
These two patches together close four Use-After-Free (UAF) privilege escalation vulnerabilities – any of which enables a threat actor to take complete control of a Windows machine if exploited. In other words, a threat actor that gains access to a Windows machine (say, through a phishing campaign) can exploit any one of these four vulnerabilities to bypass all Windows security measures, defeating mitigation measures such as sandboxing, kernel segregation and memory randomization.
Responsible disclosure: although this blog entry is technical, we won’t reveal any code, or the complete details, to prevent any tech master from being able to reproduce an exploit.
Two months ago FireEye Labs detected a new APT campaign dubbed Operation RussianDoll. The threat actors behind the campaign exploited a vulnerability in the windows kernel GUI library, win32k.sys (CVE-2015-1701) to accomplish a “Sandbox-Escape” after exploiting a Flash vulnerability (CVE-2015-3043).
This campaign was our research trigger. While we analyzed the win32k.sys vulnerability (CVE-2015-1701), we discovered another new vulnerability in close proximity. The issue we found resided within how win32k.sys manages Class objects’ reference counts (more on this later). A deeper research unveiled similar vulnerabilities in three other parts of the Windows’ kernel.
Although the four vulnerabilities are all similar in nature, not all affect the same Windows versions. That said, all of them date back nearly 20 years, since Windows NT 4.0:
- Two of the vulnerabilities affect all Windows versions up to, and including, Windows 7 Service Pack 1.
- One vulnerability affects all Windows versions up to, and including, Windows 8
- One vulnerability affects all Windows versions to date, including Windows 10 Preview.
In this post we decided to focus only on one of the vulnerabilities, which affects Windows version from XP to Windows 7 SP 1.
Window Classes: Basics
For a better understanding of the vulnerability, let’s quickly review kernel window classes.
A kernel window class is a template for creating windows. Each window in the system is a member of a single class whereas each class is associated with a window procedure used by all the windows of a given class. This procedure is responsible for processing window messages and controls the way the window will appear and behave.
Window classes are created by RegisterClass or RegisterClassEx API functions. In order to destroy a window class, the UnregisterClass API is used.
The window class also defines other attributes such as icons, cursors, and more. These attributes are set when the class is registered, but it is also possible to alter the attributes of the class later by calling SetClassLongPtr API function.
You can find more detailed information about classes here – “About Window Classes”.
Internally, window class objects are represented by the tagCLS structure:
Figure 1: The tagCLS structure
The cWndReferenceCount Field
We’d like to point out the cWndReferenceCount field. This field counts how many window instances of a particular class were created. It’s important to note that a class cannot be destroyed before the cWndReferenceCount field reaches 0, meaning before all the class’ windows instances were destroyed.
The kernel assumes that a class cannot be destroyed if one of its window instances is locked. However, as we will show, locking a window is not enough from preventing a class from being destroyed.
Handling class’ icons
We look at class’ icon attribute (the “spicn” field in the tagCLS) since specifically the handling of icons assumes that the class will never be destroyed while the icons are being managed.
To recall, the attributes of a window class can be altered through the SetClassLongPtr API function. The corresponding kernel system call that handles SetClassLongPtr is:
Figure 2: The prototype of NtUserSetClassLong
- hWnd – a handle to a window instance of the relevant class.
- index – the type of the value to be replaced.
- dwNewLong – the new value.
Looking at the NtUserSetClassLong function itself, we see that the first thing it does is validate the window handle and lock the window to prevent the window’s destruction.
Figure 3: Behind the scenes of NtUserSetClassLong
The actual implementation of NtUserSetClassLong is located in xxxSetClassLong. Eventually, the function that sets the icon attribute is xxxSetClassIcon.
If needed, xxxSetClassIcon will call xxxCreateClassSmIcon in order to create a small icon for the new icon:
Figure 4: The code snippet where xxxSetClassIcon calls xxxCreateClassSmIcon
The function xxxCreateClassSmIcon is actually very simple. The main thing it does is call xxxClientCopyImage which, in turn, invokes a user-mode callback in order to get the icon.
Looking at the call chain, this is what received up until now:
Figure 5: The call chain for setting the icon attribute
The important thing to note about the functions in this call chain is that all of them assume that the window class object cannot be freed in the context of the user-mode callback.
At first this seems like a reasonable assumption because, as shown in Figure (3), NtUserSetClassLong initially locked the window thus preventing the class’ destruction.
Not being able to destroy the class suggests that the cWndReferenceCount must be greater than 0.
The Death of a Window
Admittedly, the assumption that the window class object cannot be freed is not entirely incorrect. Indeed a locked window cannot be fully destroyed: when a DestroyWindow is invoked on a locked window it will render the window unusable, most of its resources will be freed, its scrollbars will be destroyed and its handle will practically become unusable.
Nevertheless, the window object itself will remain allocated until the lock count reaches zero.
Let’s see then what happens when we destroy the window.
This is done through the function xxxDestroyWindow which in turn invokes xxxFreeWindow. It is in this function where the code that interests us resides. The reason is that before xxxFreeWindow attempts to free the window, it calls the DereferenceClass function which decreases the window reference count of the class (to recall, the cWndReferenceCount field). It’s important to note that the DereferenceClass function is called even if the window is not later freed:
Figure 6: Dereferencing the class before attempting to free the window
Let’s now piece everything together to see how the Use-After-Free (UAF) is triggered. If the window is destroyed during the user-mode callback – which is invoked by xxxClientCopyImage- then also its corresponding class would be be destroyed. When the callback returns, the code after xxxCreateClassSmIcon will use the freed class object. This effectively triggers the UAF vulnerability.
After xxxClientCopyImage returns from the user-mode call the following code is executed:
Figure 7: Assigning and setting the flags of the icon
The call to HMAssignmentLock with the controlled pointer looks interesting.
Diving into HMAssignmentLock
The purpose of HMAssignmentLock is to assign an object to a structure and lock it:
Figure 8: The code of HMAssignmentLock
We’ll sum this function up quickly by saying that if the object that was previously assigned in the structure is not null, HMUnlockObject will be invoked to unlock it. As figure 8 shows, we can control the object that will be unlocked.
In figure 9 we see that HMUnlockObject will try to decrement the lock count on the controlled object. This means that we can decrement an arbitrary address.
Figure 9: Decrementing the lock count
Due to responsible disclosure considerations we stop here.
This video demonstrates the vulnerability against a 64-bit Windows 7 machine.
What we showed in this post is the ability to decrease any memory address by one.
Eventually, this can lead to executing arbitrary code in the Windows’ kernel memory.
The other three vulnerabilities resulted from our research are based on the same concept. Each, however, is reachable through different code paths.
Complete endpoint security is our mission. Let us show you more.