]>
Linux Kernel Rootkits 2002 Rainer Wichmann Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the GNU Free Documentation License from the Free Software Foundation by visiting their Web site or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. This is version 1.0 of the Linux Kernel Rootkits paper. Introduction After a succesful intrusion into a system, usually the intruder will install a so-called "rootkit" to secure further access. Such rootkits are readily available on the net and are designed to be used even by less experienced users. Rootkits usually comprise tools to erase traces of the intrusion from audit logs, "backdoors" that allow easy access, once installed, and means to hide the rootkit itself from administrators (such as, e.g., a modified executables of 'ps' and 'ls' that will hide processes and files of the rootkit. Advanced rootkits will install such modified executables with the same sizes and timestamps as the original ones (which is quite easy - any executable can be padded to a larger size by simply adding random junk at the end), and also with the same CRC checksum (which also can be adjusted). To detect such rootkits, it is necessary to have a database of cryptographic checksums of critical files, and compare these against the actual files. Useful cryptographic checksums include MD5, SHA-1, TIGER (but not CRC, which can be faked). Any application program is controlled by the kernel, and any system access (such as writing to/reading from the disk) is performed by the kernel. The application will call a kernel syscall, and the kernel will do the work and deliver the result back to the application. From a users viewpoint, these syscalls are the lowest level of system functions, and provide access to filesystems, network connections, and other goodies. By modifying kernel syscalls, kernel rootkits can hide files, directories, processes, or network connections without modifying any system binaries. Obviously, checksums to confirm the integrity of a system are useless in this situation. About This Document This document was written in DocBook(SGML). The SGML source is available online. You can use the source to create other formats including PostScript, and PDF. Permission is granted to copy, distribute and/or modify this document under the terms of the GNU Free Documentation License, Version 1.1 or any later version published by the Free Software Foundation with no Invariant Sections, no Front-Cover Texts, and no Back-Cover Texts. You may obtain a copy of the GNU Free Documentation License from the Free Software Foundation by visiting their Web site or by writing to: Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. You can reach the author at rwichmann {at} la-samhna.de. The basics Subverting the kernel There are basically two ways how a rootkit can subvert the kernel to perform actions on behalf of an intruder: Loading a kernel module The Linux kernel (and many other operating systems) can load kernel modules (e.g. device drivers) at runtime. This allows an intruder to insert a module that overrides kernel syscalls in order to return incorrect values (e.g. does not list certain files), or provides new functions useful for an intruder (e.g. give root privileges to certain processes). It is possible to compile a kernel where the interface for loadable kernel modules is disabled. Writing to /dev/kmem The special device /dev/kmem is basically a device that gives access to the memory region occupied by the running kernel. By writing to /dev/kmem it is possible to overwrite the kernel at runtime, and thus perform any arbitrary modification. The only problem may be to find the correct location in /dev/kmem, if one wants to overwrite some particular part of the kernel. However, this is usually a solveable problem. Access to /dev/kmem can only be denied by patching the kernel. A patch to make /dev/kmem non-writeable has been published in Phrack issue 58, article 0x07 ("Linux on-the-fly kernel patching without LKM", by sd & devik). As noted in a bugtraq post by Guillaume Pellat, this patch still allows to write to /dev/kmem by using mmap() rather than direct file I/O. Suitable places in the flow of execution When a system call (e.g. open() to open a file) is made by an application, the flow of control looks like this: An interrupt is triggered, and execution continues at the interrupt handler defined for that interrupt. On Linux, interrupt 80 is used. A rootkit could replace the kernels interrupt handler by an own function. This requires a modification of the Interrupt Descriptor Table (IDT). A discussion of this method, as well as proof-of-cocept code, is published in Phrack issue 59, article 0x04 ("Handling the Interrupt Descriptor Table", by kad). This article also provides source code for a utility CheckIDT that can be used to list the IDT and save the current state to check its integrity later on. The interrupt handler (named system_call() on Linux) looks up the address of the requested syscall in the syscall table, and executes a jump to the respective address. A rootkit may (a) modify the interrupt handler to use a (rootkit-supplied) different syscall table, or (b) modify the entries in the syscall table to point to the rootkits replacement functions. Method (a) is currently used by one rootkit only, the SucKIT rootkit presented in Phrack issue 58, article 0x07 ("Linux on-the-fly kernel patching without LKM", by sd & devik). This is a fully working rootkit that is loaded through /dev/kmem (i.e. it does not need a kernel with support for loadable kernel modules. It provides a password protected remote access connect-back shell initiated by a spoofed packet (bypassing most of firewall configurations), and can hide processes, files and connections. Method (b) is used by a large number of rootkits, because it is very easy to code. For a list of these rootkits, see . The syscall function is executed, and control returns to the application. A rootkit may overwrite the syscall function to place a jump to its own replacement function at the start of the syscall function. No currently known rootkit uses this method. List of Kernel Rootkits Rootkits loaded via /dev/kmem SucKIT is a rootkit presented in Phrack issue 58, article 0x07 ("Linux on-the-fly kernel patching without LKM", by sd & devik). This is a fully working rootkit that is loaded through /dev/kmem (i.e. it does not need a kernel with support for loadable kernel modules. It provides a password protected remote access connect-back shell initiated by a spoofed packet (bypassing most of firewall configurations), and can hide processes, files and connections. Loadable Kernel Modules Except for the SucKIT rootkit, all published rootkits are LKM rootkits and use the method of syscall table modification (see ). The following list provides an overview of these rootkits. Rial by techno[k] (technok at pkcrew dot org) hides files, file parts, and connections. No backdoor is provided. Hiding of file parts is buggy, less will hang. RIAL does not hide itself (use lsmod or cat /proc/modules to detect). heroin by Runar Jensen (zarq at opaque dot org) hides files and processes. No backdoor is provided. Cannot be removed with rmmod, and tries to hide itself, but can be found by bash$ cat /proc/ksyms | grep heroin afhrm by Michal Zalewski (lcamtuf at boss dot staszic dot waw dot pl) redirects (and hides) files. No backdoor is provided. Runs on 2.2 with some work, but file hiding seems to have bugs. Can hide itself, but method appears to be inappropriate for 2.2 kernels (results are rather suspicious). Synapsis (v. 0.4) by Berserker (berserker dot ncl at infinito dot it) Hides files, processes, and users. Gives root privileges to a user with a pre-defined UID (default 666). Hides ports. Can be controlled via cat password command. Hides itself from lsmod, but can be found by cat /proc/modules. File hiding and control interface have bugs. adore by Stealth hides files, processes, services, and can execute a process (e.g. /bin/sh) with root privileges. Controlled with a helper program ava. Adore hides itself, and cannot be removed by rmmod. knark by Creed (creed at sekure dot net) hides files, processes, services, redirect commands, and can give root privileges. Creed is controlled with a set of helper programs, and can execute commands sent from a remote host. It hides itself and cannot be removed by rmmod. itf by plaguez (dube0866 at eurobretagne dot fr) has been published in Phrack issue 52. It hides files and processes, redirect commands, hides the PROMISC flag (i.e. sniffers), and can give root privileges. It installs a backdoor, hides itself and cannot be removed by rmmod. kis by optyx (optyx at uberhax0r dot net) is a client/server system to remotely control a machine, with a kernel rootkit as the server on the remotely controlled machine. It can hide processes, files, connections, redirect execution, and execute commands. It hides itself and can remove security modules already loaded. Detecting Kernel Rootkits To get a list of kernel modules, two standard methods can be used: bash$ lsmod bash$ cat /proc/modules In addition, one can look at the list of symbols exported by modules (/proc/ksyms), where the name of the corresponding module will be listed in square brackets, like the following symbol exported from the snd (sound) module: c85029f4 snd_task_name [snd] Unfortunately, being a kernel module, an LKM rootkit can easily defeat such efforts by a variety of methods. Fortunately, there is a better way to detect an LKM rootkit: In order to replace kernel syscalls with their own code, LKM rootkits modify the table which holds the addresses of these syscalls, to point to the module's replacement function instead of the original kernel function. Now, whenever a kernel is compiled, a map of kernel symbols and their respective addresses in the kernel is generated. This map is called System.map (sometimes with the kernel version appended), and usually install in the same location as the kernel (e.g. /boot). Thus, a straightforward way to detect hijacked kernel syscalls is to compare this map against the actual addresses of all syscalls, which will show all syscalls whose address is different from the original address listed in the map. Programs This is a non-exhaustive list of programs that are useful for the detection of kernel modifications in a running system. kern_check.c kern_check.c is a small command-line utility (for Linux 2.2.x, 2.4.x) that will compare your System.map against your kernels syscall table and warn about any inconsistencies (PGP signature kern_check.c.asc). bash$ gpg --verify kern_check.c.asc kern_check.c bash$ gcc -O2 -Wall -o kern_check kern_check.c bash$ su bash$ kern_check /path/to/System.map NOTE This will only detect rootkits that modify the syscall table directly. In particular, it will not detect the SucKIT rootkit (see ). CheckIDT CheckIDT, published in Phrack issue 59, article 0x04 ("Handling the Interrupt Descriptor Table", by kad) is a utility that can be used to list the Interrupt Descriptor Table (IDT) (see ) and save the current state to check its integrity later on. Currently there is no published real rootkit that uses the IDT, only proof-of-concept code. samhain samhain is a file integrity checker that can also check for kernel integrity. samhain performs checks for all of the points discussed in .