Many of today’s advanced persistent threats have been climbing up the ladder - quite literally: Instead of only using user-mode components, APTs more and more frequently include components that are running as part of the operating system kernel.
These kernel components run with the same, or even higher, privileges than most security solutions, and are thus outside the reach of traditional layers of protection. At the same time, running in the context of the kernel also evades scrutiny from security analysts as well as traditional analysis sandboxes, as we described in a previous blog post.
In this post, we want to dive deeper into one specific family containing a kernel component: Turla APT. We summarize some of the tricks the malware authors use to bypass security mechanisms present in the Windows operating system kernel. These tricks have been studied by security experts previously [1, 2], and we show how Lastline’s high-resolution sandbox is able to track this activity fully automatically to detect this threat and protect users.
Microsoft Windows Kernel Hardening
The Windows x64 operating system, such as Windows Vista or later versions, has many security mechanisms for hardening the kernel compared to its x86 predecessors. Two techniques are particularly interesting for the analysis of Turla: Driver-signing and PatchGuard.
Starting with Windows Vista (64-bit), the operating system kernel allows only signed drivers to be loaded by default. This significantly increased the burden for injecting malicious code into the kernel, but does not solve the problem of kernel malware, as we will see later in this post.
Despite driver-signing being enforced by default, Microsoft supports an option to boot its OS in a mode where signature-verification is turned off. This mode is mainly meant for supporting driver testing. Thus, while the driver-signature system increases the burden of an attacker, it still allows malware to load new code into the kernel, if the malware is able to reboot the system without this protective mechanism enabled, or by placing a bootkit in the boot-path running before, and with higher privileges than, the kernel itself. Still, the requirement of rebooting a victim machine incurs a significant burden for the attacker, as reboots inevitably raise unwanted suspicion.
The second significant kernel security improvement, PatchGuard, is a system component mainly aimed at detecting modifications of system-critical data structures such as SSDT, IDT, or the code pages loaded in memory. PatchGuard works by periodically calculating a checksum of these critical regions, and alerting as soon as unexpected changes are detected. Since most rootkits need to modify at least one of the monitored regions to implement their malicious functionality, this checksum approach provides a generic mechanism for detecting the presence of unwanted code.
For example, many traditional rootkits modify the SSDT entries for NtQuerySystemInformation or NtQueryProcessInformation to hide their user-mode processes or driver components, as we described in a previous post. Any attempt to change the SSDT would be detected by a mismatching checksum, allowing PatchGuard to detect the kernel compromise, and halting the compromised system to avoid further damage.
Turla APT Versus the Windows Kernel
The Turla APT is a sophisticated malware and suspected to be state sponsored. What makes this APT family particularly interesting is its design: Most of Turla’s functionality is implemented in a kernel driver that is able to run - completely unnoticed - within Microsoft’s 64-bit Windows operating system kernel, despite various layers of protection designed to block this from happening. Even more, the attackers behind Turla are able to infect a victim kernel without requiring a reboot of the system, making it even more stealthy than many other previously-seen attacks on the kernel.
Various research groups have spent a significant amount of time discovering and analyzing Turla’s functionality [1, 2]. In this post, we want to focus on how Turla manages to completely bypass the security features described above - bypassing PatchGuard as well as the enforcement of driver signature verification, even without requiring a system reboot. Additionally, we show how Lastline’s next-generation sandbox can dissect the functionality of the Turla APT completely automatically and provide a precise threat assessment to analysts.
Bypassing Signature Verification for Drivers
First, let’s see how Turla manages to load untrusted code into the context of the kernel. To execute new code in the kernel, the authors use a nifty trick, using a vulnerable version of a signed VirtualBox driver as a stepping stone: Loading this first driver does not raise suspicion - after all, the code is signed by a trusted entity. However, by loading this driver, a new vulnerability is introduced into the kernel, allowing a user-mode application to write to arbitrary memory locations inside the kernel.
With the ability to modify kernel-memory, the attacker can now tamper with any setting in the kernel. They locate the global variable g_CiEnabled within kernel-memory, which is used to indicate if the kernel is running in a mode where driver-signature verification is enabled or not. More precisely, the location of the variable is computed by loading the ntoskrnl.exe image into the memory of the user-mode component, allowing to calculate the offset of the variable within the image by searching for specific instructions referencing it. This offset is then added to the base-address at which ntoskrnl.exe is loaded in the kernel, which can be calculated by passing SystemModuleInformation as argument to NtQuerySystemInformation.
Virtualbox driver overwriting g_CiEnabled flag (View Full-size)
Patching the value of g_CiEnabled to 0 defeats the first security mechanism, even without requiring a system reboot. This allows the malware to load arbitrary (unsigned) kernel-components from user-mode, simply by writing the payload functionality to a file and calling NtLoadDriver.
Despite the ability to run unsigned code in the operating system kernel, the APT is not yet able to achieve its rootkit behavior, as PatchGuard prevents injecting malicious code into the control-flow of critical system functionality.
This is addressed in the second step of the attack: The attackers start off by hooking functions RtlCaptureContext, KiRetireDpcList, and RtlLookupFunctionEntry in addition to the rootkit-activity related functions, which, as described above, will trigger an alert from PatchGuard the next time the integrity of system memory pages is verified. As soon as this happens, PatchGuard calls KeBugCheckEx, which, in turn, forces a system shutdown by showing the infamous blue-screen-of-death (BSOD).
However, Turla is able to bypass the BSOD using one of two possible techniques: In an earlier version of the APT, the code hooks KeBugCheckEx and forces the function to return without executing the BSOD functionality. After Microsoft updated PatchGuard to use a copy of the KeBugCheckEx function (cloned during the initialization of the system) instead of the global function in the kernel, a newer version of Turla appeared; this new version started hooking RtlCaptureContext instead of KeBugCheckEx. The former function is called internally by KeBugCheckEx (and thus also as part of the copied version), allowing Turla to intercept the execution before raising a BSOD .
Once PatchGuard has been bypassed, the malware has full access to the kernel. With this in place, it performs the classic rootkit behavior: Hooking a number of system calls, mainly to hide/protect its user-mode components. It achieves this by modifying ntoskrnl.exe and ndis.sys in memory, followed by creating a new IDT entry (at index 0xc3) and redirecting all hooked functions to a single interrupt handler (ISR). Each hooked function is associated with a unique identifier, which is used in the ISR to dispatch the function accordingly.
Hook Installation (View Full-size)
Traditional analysis systems typically work by hooking certain functions of interest (such as user-mode API functions or important kernel-code regions). Turla’s behavior defeats most such hooking approaches, as it is able to disable any in-host hooking mechanisms (similarly to how it defeats PatchGuard).
The Lastline analysis sandbox, on the other hand, is based on a full-system emulator. This means that modifications of the Windows kernel, no matter how sophisticated, do not interfere with our ability to capture and analyze the behavior exhibited by malware. A good example that demonstrates this is the following excerpt from an analysis report showing the Turla setup functionality described above (disabling driver-signing and bypassing PatchGuard), as well as more intricate functionality (such as the use of network filter drivers or monitoring process creation).
Behavior overview extracted from Turla APT in Lastline sandbox (View Full-size)
List of API functions hooked in ntoskrnl.exe and ndis.sys (View Full-size)
In addition to the traditional rootkit functionality for hiding user-mode components (by hooking ZwQuerySystemInformation and ZwQueryInformationProcess), Turla also installs a network filter driver at WFP (Windows Filtering Platform) and NDIS (Network Driver Interface Specification) layers. The following snippet shows how the NDIS driver registration takes place which allows the malware to monitor any incoming or outgoing network traffic.
Additionally, Turla monitors newly created processes by registering its callback through PsSetCreateProcessNotifyRoutine which is also included in the analysis report above extracted by the Lastline analysis engine.
Turla is one representative example that shows how two Windows OS hardening techniques - driver signature verification and PatchGuard - can be bypassed completely. The APT is able to tamper with kernel routines without restriction, allowing it to remain hidden on a compromised machine. At the same time, the APT is able to bypass hooking systems that operate within the context of the kernel, rendering traditional sandbox approaches useless.
Lastline’s high-resolution sandbox is able to track malware running in the context of user- and kernel-mode execution, without relying on in-system hooks. This allows for capturing all the malicious functionality of this advanced kernel-based threat, and for the detection of sophisticated targeted attacks.