Uninformed: Informative Information for the Uninformed

Vol 8» 2007.Sep



Running Code in Kernel-Mode

There are many who might argue that it's not even necessary to write code that prevents or detects specific types of kernel-mode backdoors. This argument can be made on the grounds of two very specific points. The first point is that in order for one to backdoor the kernel, one must have some way of executing code in kernel-mode. Based on this line of reasoning, one might argue that the focus should instead be given to preventing untrusted code from running in kernel-mode. The second point in this argument is that in order for one to truly compromise the host, some form of data must be persisted. If this is assumed to be the case, then an obvious solution would be to identify ways of preventing or detecting the persistent data. While there may also be additional points, these two represent the common themes observed by the authors. Unfortunately, the fact is that both of these points are, at the time of this writing, flawed.

It is currently not possible with present day operating systems and x86/x64 hardware to guarantee that only specific code will run in the context of an operating system's kernel. Though Microsoft wishes it were possible, which is clearly illustrated by their efforts in Code Integrity and Trusted Boot, there is no real way to guarantee that kernel-mode code cannot be exploited in a manner that might lead to code execution[2]. There have been no shortage of Windows kernel-mode vulnerabilities to illustrate the feasibility of this type of vector[6,10]. This matter is also not helped by the fact that the Windows kernel currently has very few exploit mitigations. This makes the exploitation of kernel vulnerabilities trivial in comparison to some of the mitigations found in user-mode on Windows XP SP2 and, more recently, Windows Vista.

In addition to the exploitation vector, it is also important to consider alternative ways of executing code in kernel-mode that would be largely invisible to the kernel itself. John Heasman has provided some excellent research into the subject of using the BIOS, expansion ROMs, and the Extensible Firmware Interface (EFI) as a means of running arbitrary code in the context of the kernel without necessarily relying on any hooks directly visible to the kernel itself[16,17]. Loïc Duflot described how to use the System Management Mode (SMM) of Intel processors as a method of subverting the operating system to bypass BSD's securelevel restrictions[9]. There has also been a lot discussion around using DMA to directly interact with and modify physical memory without involving the operating system. However, this form of attack is of less concern due to the fact that physical access is required.

The idea of detecting or preventing a rootkit from persisting data is something that is worthy of thoughtful consideration. Indeed, it's true that in order for malware to survive across reboots, it must persist itself in some form or another. By preventing or detecting this persisted data, it would be possible to effectively prevent any form of sustained infection. On the surface, this idea is seemingly both simple and elegant, but the devil is in the details. The fact that this idea is fundamentally flawed can be plainly illustrated using the current state of Anti-Virus technology.

For the sake of argument, assume for the moment that there really is a way to deterministically prevent malware from persisting itself in any form. Now, consider a scenario where a web server at financial institution is compromised and a memory resident rootkit is used. The point here should be obvious: no data associated with the rootkit touches the physical hardware. In this example, one might rightly think that the web server will not be rebooted for an extended period of time. In these circumstances, there is really no difference between a persistent and non-persistent rootkit. Indeed, a memory resident rootkit may not be ideal in certain situations, but it's important to understand the implications.

Based on the current state-of-the-art, it is not possible to deterministically prevent malware from persisting itself. There are far too many methods of persisting data. This is further illustrated by John Heasman in his ACPI and expansion ROM work. To the authors' knowledge, modern tools focus their forensic analysis on the operating system and on file systems. This isn't sufficient, however, as rootkit data can be stored in locations that are largely invisible to the operating system. While this may be true, there has been a significant push in recent years to provide the hardware necessary to implement a trusted system boot. This initiative is being driven by the Trusted Computing Group with involvement from companies such as Microsoft and Intel[42]. One of the major outcomes of this group has been the Trusted Platform Module (TPM) which strives to facilitate a trusted system boot, among other things[43]. At the time of this writing, the effectiveness of TPM is largely unknown, but it is expected that it will be a powerful and useful security feature as it matures.

The fact that there is really no way of preventing untrusted code from running in kernel-mode in combination with the fact that there is really no way to universally prevent untrusted code from persisting itself helps to illustrate the need for thoughtful consideration of ways to both prevent and detect kernel-mode backdoors.