Unmasking Kernel Exploits
A large set of publicly disclosed Advanced Persistent Threat (APT) and nation state attacks use sophisticated malware (e.g Turla, Duqu, Equation Group, Duqu2, etc.) that make use of at least one component running hidden inside the kernel of the Microsoft Windows operating system (OS). There, malware remains hidden from security solutions, and can abuse the highest privileges available on a computer system to achieve the attacker’s evil objectives.
With the ability to run in the OS kernel, malicious code has started to evade automated malware analysis solutions (sandboxes) that have limited visibility into actions executed by malware in the context of the kernel. This new wave of kernel-malware makes the ability to provide in-depth kernel-mode analysis a key requirement for effective advanced malware analysis solutions.
In two recent posts [1, 2] we have looked at how we can analyze and detect these advanced threats, but we have not yet described how attackers manage to inject their code into the Windows kernel. In this post, we highlight some of the difficulties attackers face, and how security researchers and professionals can use full-system emulation to analyze, dissect, and detect zero-day kernel exploitation techniques in an automated way.
Exploiting Microsoft Windows Kernels
All modern versions of Microsoft Windows enable User Account Control (UAC) by default, which grants limited privileges to user mode processes, restricting them in the actions they can perform on a host. For example, by default a program cannot access critical system components, modify the system registry, or load new drivers into the kernel, even if the driver is signed by a trusted entity.
To regain the privileges attackers need to achieve their goals, kernel exploits have become one of the major components in modern attacks. Since we first highlighted malware running in the kernel as a rising threat and announced our own new deep kernel malware analysis capabilities at SXSW Interactive in March, several kernel mode exploits have made headlines including:
- As revealed by Kaspersky Lab this month, Duqu2 uses a kernel mode exploit for CVE-2015-2360 to load its kernel mode component.
- One of the most recent targeted attacks against NATO members and the White House, termed Operation Pawn Storm, attracted massive media attention in April. The malware used in this campaign was equipped with a kernel exploit for CVE-2015-1701.
- Also reported in April, Turla uses two exploits for CVE-2009-1123 and CVE-2010-0232.
And previously in February the well known, possibly government-sponsored, Equation Group APT was reported to have used malware using up to 10 exploits, 3 of them confirmed for CVE-2009-1124, CVE-2011-3402, and CVE-2013-3879.
But well-funded, government-sponsored attacks aren’t the only ones that leverage kernel exploits. Attacking the kernel has become increasingly common, as can be seen by looking at prominent malware families making use of kernel exploits:
- Cidox/Rovnix Bootkit uses exploits for CVE-2013-3660 and CVE-2014-4113.
- Sandworm uses exploits for CVE-2014-4148 and CVE-2014-4113.
- PowerLoader uses exploits for CVE-2013-3660, CVE-2012-1864, and CVE-2012-0217.
… just to name a few.
As one can see, the ability to analyze and identify compromises of the operating system kernel has become crucial in detecting modern threats – not only, but especially with advanced, targeted attacks.
Anatomy of Kernel Exploits
Before we focus on how we detect kernel exploitation, let’s first dive into how a typical kernel exploit works. Usually, exploitation happens in four stages: host preparation, exploit-code setup, kernel vulnerability exploitation, and payload execution.
Host Preparation: In the first phase, the host preparation phase, the attacker tricks the user into executing a piece of user-mode code. This can happen through a conventional exploit, such as a drive-by-download exploit, or by executing the attack as part of user-mode malware already running on a target machine. Increasingly, this user-mode malware is tailor-made to evade traditional sandboxes through a number of techniques we’ve covered before.
Exploit-code Setup: Next, in the exploit-code setup phase, the attacker prepares the shellcode that is later invoked using the kernel exploit. To perform any actions in the context of the kernel, the exploit needs to know information about the kernel internals, such as:
- the location or offsets of critical structures in kernel memory, or
- the addresses of kernel API functions.
Windows kernel modules may vary between different versions of the operating system, between different service pack levels, and even when different system updates have been installed. Thus, an exploit must adapt to these changes. To do this, the user-mode setup code typically opens a kernel image from disk to analyze and find the necessary data.
At the same time, the setup code can find custom OEM drivers available on the system, which can provide additional vulnerabilities to exploit. To this end, the attacker can search for the presence of drivers and probe for devices available on the system.
Vulnerability Exploitation: Once the attacker has gathered all necessary information to make an exploit possible, the kernel vulnerability is exploited. There are two types of exploits that we have to address, depending on the location of the shellcode that is executed: execution of user-space shellcode with kernel privileges (i.e., CPL/Current Privilege Level = 0) versus execution of kernel-space shellcode.
User-space shellcode is easier to implement, because it only requires overwriting a small amount of data in kernel memory. In many cases, this memory is a function or function-pointer causing the next kernel thread executing this function to jump to the user-space memory prepared with the shellcode.
The advantage of this type of shellcode is that there is no limitation on the size of the shellcode (because it doesn’t need to be copied to kernel memory). However, this type of exploit does not work in Windows 8 or later, because of a new security feature known as Supervisor Mode Execution Prevention (SMEP), which prevents execution of code located in user-mode pages with CPL of 0.
Kernel-space shellcode bypasses SMEP but it is more complicated: it requires copying shellcode to kernel memory, but only very few (known) vulnerabilities allow overwriting large amounts of data in the kernel.
Shellcode type overview
Because of this, attackers sometimes use a hybrid approach combining both shellcode types: in a first step, using a small shellcode, the attacker disables SMEP, followed by executing a second, larger shellcode in user memory with CPL of 0.
Payload Execution: Once the shellcode has successfully been executed, the attacker is able to run any payload in the context of the kernel, that is, without any restrictions imposed by the operating system.
In exploits against Microsoft Windows kernels, we typically find two types of payloads: In the first type, the attacker tries to elevate privileges of the user-mode process. The idea is to run an entire process, not just a small piece of shellcode, with elevated privileges, which greatly simplifies writing complex payloads.
To elevate privileges, the payload can copy the access token of the System process and overwrite the current process’ access token. This gives the process the same level of permissions as those granted by the original process’ token. To do this, the payload needs to:
- enumerate EPROCESS structures in kernel memory,
- find the System process, and
- copy the pointer to the token structure inside the EPROCESS structure of the System process to the current process’ EPROCESS structure.
By stealing a pointer to the System process token structure, the process receives all Security Identifiers (SIDs) of that process, including the SID…
Name: Local System
Description: A service account that is used by the operating system.
…which allows performing any actions with system process privileges.
The second type of payload we frequently find is more sophisticated: instead of elevating privileges of the user-mode process, the payload contains code for loading a malicious driver directly into kernel memory without the use of system APIs.
Analysis of Kernel Exploit
An interesting finding that emerged from our research is that some of the attacks are not using their own version of the setup/shellcode/payload functionality. Instead, the attackers use proof-of-concept implementations available on the Internet (sometimes provided for free by researchers, other times sold by specialized exploit groups). Here, the payload invokes a malware process after elevating privileges, providing the attacker with a simple and reliable way to bypass the kernel’s security restrictions.
This allows traditional security solution to claim “kernel exploit detection” capabilities, because the proof-of-concept implementations can be trivially detected using signature-based approaches. Clearly, sophisticated and well-funded attack groups can leverage zero-day exploits – that is, exploits that have not been publicly documented – as part of their attack, and use evasive code to identify or bypass traditional analysis systems before launching the kernel exploit.
As a consequence, the analysis system must not only be able to handle evasive code, but also to inspect code run as part of the operating system kernel. Only then can it correctly identify the malicious behavior and thwart the attack.
Unmasking the Cidox/Rovnix Bootkit
Our system performs in-depth analysis of all stages of kernel exploits, as one can see by looking at the following example (found in the wild) of the Cidox/Rovnix Bootkit
As we can see, every stage of the kernel exploit discussed above is already highlighted in the analysis overview.
But the analysis capabilities of our system go well beyond that! As we already covered in previous blog posts, the Lastline analysis system automatically extracts full-process snapshots containing points of interest for subsequent analysis by a security analyst or researcher.
Our solution tracks the execution of untrusted memory in user- as well as kernel-mode. As a result, the system sees all code fragments associated with the malicious behavior executed as part of the exploit, which can be downloaded as part of the analysis result, and be imported into off-the-shelf tools, such as IDA Pro.
For example, the process-snapshot extracted as part of the Cidox/Rovnix Bootkit exploit analysis shows the malicious payload executed in the context of the kernel:
Here, the code searches for the EPROCESS structure of the System process (using its process-ID 4) as well as for the entry of the malicious process using PsLookupProcessByProcessId. Once found, it duplicates the EPROCESS::Token from System to the malicious process, giving it Local System privileges.
The extracted process-snapshot not only contains all the relevant code-sections (and is stripped from unrelated, benign code cluttering the snapshot), but the system also highlights code areas of interest to guide the analyst in where to look.
Kernel exploits are not only part of advanced and sophisticated attacks, but are now also used in many mainstream malware families. As a result, security solutions and analysis sandboxes must be able to provide deep insights into the execution of kernel code to identify and address these types of threats.
Lastline’s high-resolution sandbox uses a full-system emulation approach that is able to track malicious code running in user- as well as kernel-mode. This provides the analysis system with a complete picture of the malicious behavior exhibited by malware, to catch even the latest zero-day attacks, and provide valuable insights for security professionals and researchers alike.