While the LNK vulnerability patched by MS10-046 dominated the headlines when the Stuxnet carnival started rolling back in early summer 2010, one of the surprises of further analysis of the Stuxnet binaries/components is that it exploited no less than three other vulnerabilities that were generally unknown at the time. The print spooler attack (MS10-61) is, like the LNK vulnerability, described in our lengthy analysis “Stuxnet under the Microscope”.
However, we also indicated in that paper that there are two Elevation of Privilege (EoP) vulnerabilities that we chose not to describe while patches were pending. One of these has now been patched (MS10-073, re CVE-2010-2743) , so we’re now able to publish some of the information we have on it. (When the other vulnerability has been patched, we plan to update the Stuxnet paper with information on both issues.)
When the Win32/Stuxnet worm doesn't have enough privileges to install itself in the system it exploits a recently patched 0-day vulnerability in the win32k.sys system module to escalate privilege level up to SYSTEM, which enables it to perform any tasks it likes on the local machine. The vulnerable systems are:
- Microsoft Windows 2000;
- Windows XP - all service packs
To perform this trick, it loads a specially crafted keyboard layout file, making it possible to execute arbitrary code with SYSTEM privileges. This elevation of privilege occurs while dispatching input from the keyboard in the Win32k.sys module. While processing input from the keyboard using the NtUserSendInput system service, the following code is executed:
Figure 1: A fragment of the executed code during processing keyboard input
The purpose of this code is to determine how to dispatch the virtual key code of the pressed key. Register ecx specifies in the _aNLSVKProc procedure table the type of the handler, according to the current keyboard layout. to be called. This table consists of three handlers:
Figure 2: _aNLSVKProc procedure table
As we can see from the figure above, the _aNLSVKProc is followed by 3 DWORDs, the last of which (highlighted in red) can be interpreted as a pointer pointing to 0x60636261 in the user-mode address space. Thus, if we set the ecx register in the code in figure 1 with the proper value, namely 5, then we can execute code at 0x6036261 with SYSTEM privileges.
We can manipulate the ecx register in this code by loading a specially crafted keyboard layout file specifying that certain virtual key codes should call the procedure indexed as 5. The keyboard layout file is a dynamic link library of which the .data section is specially structured. Below we present a structure that maps virtual keys to corresponding procedures in the table.
Figure 3: Virtual keymapping
The worm loads a special keyboard layout file by calling NtUserLoadKeyboardLayoutEx and passing it the following hexadecimal constant 0x01AE0160 as an offTable parameter. The low word of this parameter specifies the RVA (Relative Virtual Address) of the KBDTABLES structure from the beginning of the file, while the high word specifies the RVA of KBDNLSTABLES, which is of particular interest. The latter structure determines the address and size of the array of VK_F structures contained in the file.
Figure 4: VK_F structure
In the figure below we present the contents of the .data section where we can see that the structure KBDNLSTABLES located at RVA 0x1AE specifies one structure VK_F located at RVA 0x01C2.
Figure 5: .data section of the crafted keyboard layout file
As we can see, the keyboard layout file contains exactly one VK_F structure that maps a virtual-key with code equal to procedure 0 in _aNLSVKProc with indexed as 5.
One thing we need to do in order to exploit this vulnerability is to allocate a buffer for the code to be executed at address 0x60636261 as in the case with Stuxnet, which allocates 32KB of memory at 0x60630000 and writes shell code at 0x60636261:
Figure 6: Stuxnet allocates 32KB of memory at 0x60630000 for shell code