Analysis of CVE-2015-2360 – Duqu 2.0 Zero Day Vulnerability
The recent Duqu 2.0 targeted attack used several zero-day vulnerabilities as part of its attack. One of the vulnerabilities used was CVE-2015-2360, which was fixed by MS15-061 as part of the June Patch Tuesday release. Like CVE-2015-1701, this is also in the Win32k.sys file, which is commonly targeted by attackers to bypass existing vulnerability mitigation techniques.
The vulnerability lies in how windows are handled by the operating system. Some background information about this is necessary:
- If an application wants to show a window, it needs to perform two steps:
- Registering a window class. This will lead the OS kernel to create a window class object, which exists in kernel space and an application program cannot access it directly from user mode. The structure is named tagCLS. The window class object specifies the window ‘s style and behavior.
- Creating a window with the window class object which was registering in the previous step. The progress will lead the OS kernel to create a window object, which exists in kernel space and application program cannot access it directly from user mode. This structure is named tagWND.
- Every window has a window procedure to handle window messages. The window procedure can be run in user mode or kernel mode. It depends on the window class object’s file named CSF_flags. If the CSF_flags field has the flag “Server Side Proc”, the window object’s window procedure can be run in kernel mode. If it does not have the flag, the window object’s window procedure can be run in user mode. If one application program provides its own window procedure which is not the default window procedure, the window procedure only runs in user mode: the window class object’s CSF_flags field doesn’t include “Server Side Proc” flag.
Figure 1. tagCLS structure
From Figure 1, we can see the tagCLS structure’s CSF_flags field is a 32-bit number. Every bit represents one Characteristic. The first bit is the flag for the “Server Side Proc” characteristic.
- win32.sys has a characteristic that it will switch to user mode to run some user mode callback functions to do some work which is fit for user mode. This is frequently exploited by attackers.
Let’s take a look the vulnerability. The vulnerability can be summarized in the following figure:
Figure 2. Vulnerable message handling process
When a window message is received (for example, from WM_SetIcon), the kernel will handle the message. The process is lengthy. In the above illustration, I only included the parts which are related to the vulnerability. The vulnerability exists in the step 4: it doesn’t check that the tagCLS object is valid after it switches back from user mode and continuously does some operation on the tagCLS object. This poses a serious security risk
Here is how the above vulnerability can be exploited.
- Register a window class, and get the tagCLS object’s address in kernel space by an information leak method. We call the window class object as tagCLS A.
- Create a buffer whose size is the same as the tagCLS object size, and place the tagCLS A’s address into the buffer at a carefully calculated offset.
- Hook the related usermode ClientCopyImage callback function with a fake callback function. When the kernel processes a window message (for example, WM_SetIcon), it will switch to user mode to call some user mode callback. The user mode callback address is acquired from the process environment block (PEB). The PEB can be accessed from a user mode program. The attacker can replace it with his own code, which we called via the fake callback function.
- Register a window class again and call the window class object as tagCLS B; create a window object with tagCLS B.
- Send window message WM_Seticon to the window object created at the previous step. The OS kernel handles the message and will switch to user mode to run the fake call function. In the fake call back function, the attacker does the following:
- Unregister tagCLS B, which lead the OS kernel to free tagCLS B from the kernel pool.
- Call an (unspecified) API with the buffer prepared at step 2. It will cause the kernel to reuse the space just freed and copy the buffer’s contents to the space. In other words, tagCLS B becomes a “fake” tagCLS B.
- Switching back to kernel mode, because of the vulnerability, the OS kernel doesn’t check whether tagCLS B is fake. It will perform operations on the fake tagCLS B continuously. One operation is to get one field‘s value within the fake tagCLS B, and use the value as an object pointer. Then, subtract one from the object’s one field which is pointed at by the object pointer. The attacker has already replaced tagCLS A’s address at this position. The kernel will subtract one from tagCLS A’s CSF_flags field. The original value is 0xC2 (the Sever Side Proc bit is 0). After subtraction, the CSF_flags field value become 0xC2 (the Sever Side Proc bit is 1).
- Create a window with window class tagCLS A. Because the tagCLS A’s CSF_flags already includes the Sever Side Proc bit, the window procedure of the newly create window can be run in kernel mode. This means that the attacker can now run their code with elevated kernel mode privileges, effectively allowing for a complete compromise of the affected system.
The figure below summarizes the rather lengthy exploit process:
Figure 3. Exploit process
The most effective solution for this vulnerability is to roll out the appropriate official patch. It is also worth noting that this vulnerability is only an escalation-of-privilege vulnerability. Other attack techniques are necessary to get code running on the targeted system in the first place; solutions that focus on preventing and detecting these may also be useful to administrators.