|
[YAPOTTLK]=============================================================[Lawless] Yet another Paper on Trojening the Linux Kernel Typically when one thinks about kernel rootkits on linux, the subject of system call remapping comes up. This technique is tried and true; however, it is also quite easy to detect. Currently available are several utilities, including lomac and my StMichael LKM to handle these attacks. Moving beyond the simple systemcall remapping, there has been information published about actually rewriting some functions during the kernel runtime. Again, this can be detected easily by monitoring the values of the functions via a checksumming mechanism. Again, an example of such attacks on these attacks is available in StMichael_LKM-0.04. So, where to next? One area that has not been explored is the application of kernel threads in the production of a kernel rootkit. Although one would not have the easy access that systemcalls provide, since the kenrel threads are running in kernel space -- one can intercept, replace, or alter system activity in ways that are undetectable. But, for just a moment let me digress. +Kernel Threads+ ---------------- The concept of kernel threads is nothing new. A kernel thread is, for most purposes, no different then a regular user-land process with three exceptions: -- Each Kernel thread executes a single specific kernel function. This is in contrast to regular executable kernel functions accessible via events such as a system-call. -- Kenrel threads run only in kernel-mode, while regular processes run either in user-mode or kernel-mode (via systemcalls) -- Kernel threads are only use linear addresses greater then PAGE_OFFSET (defined in .h), due to the fact they run only in kernel mode. Source: Understanding the Linux Kernel, p94. ISBN: 0-596-00002-2 As mentioned, the kernel threads are simply defined functions within the kernel, that are passed to the kenrel_thread() call and daemonized. Kernel threads acquire their run time via the scheduler, and have a execution priority associated with them. One benefit of the kernel-threads is that since they are already in kernel-space, the latency associated with performing systemcalls is removed. This is, in part, the justification that was used for the implementation of the kernel httpd kernel thread. +Kernel Threads containing Hostile Code+ ---------------------------------------- So, how could a dubious individual utilize this feature of the linux kernel to implement hostile or subversive code on a system? A couple ways come to mind: -- Back-Orafice for Linux (Or some simular linux-based remote-administration *wink* tool. -- Attack-Concealment (Hiding Files, Connections, Processes, etc). To implement these features, we will look at how the kenrel threads could access the network overtly or covertly, modify or intercept filesystem calls. Other items that could be done is to actually modify the memory management to selectively load certain memory pages in depending on some circumstance -- ie, think double books. +Kernel Threads And Overt Network Access+ ----------------------------------------- As a process, the kernel threads have a context. That permits them to easily possess open file descriptors and network sockets. Because of this, writing a specific kernel_therad that would accept connections, or write data to a network socket (via the appropriate system calls) can be done from within kernel space. The only challenge that would have to be handled by the developer of a kernel thread requiring overt network access is working without the comfort of the network libraries. Sure, one could probably statically link the libraries to the module -- but its a waste of space. Moreover, it take the fun out of writing a kernel thread. Ever hear of roughing it? All of the network functions that could be used, with the exception of data manipulation functions (ie, htol), eventually perform a system call. Guess what? The kernel thread executes in kernel context! That means that the kernel thread could simply call the system call directly. For example, to call, say write to a connected socket's file descriptor (say fd 10) the buffer "Hello World", one would use: ret_val = (*sys_call_table[__NR_write])(10,"Hello World",12); +Kernel Threads And Covert Network Access+ ------------------------------------------ Well, that's all fine and dandy. However, if the kernel_tread is truly hostile it probably shouldn't have open network sockets just lying around. Perhaps they could be hidden, but why even bother? Once again, the kernel_thread is executing in kernel context. That means it can see the incoming and outgoing network traffic as it is stored in the individual sk_buff lists, accessible from the skb_head_pool. Reference: linux/net/core/skbuff.c By monitoring established network connections for to read data, or using established network connections to transmit data to connected, the activities of the kernel_thread can be concealed from the system, and specially crafted communications utilities can user innocuous services that legitimately operate on the victim host, such as httpd or sendmail, to manage the network connections by which commands and responses would be transmitted from a controlling remote host and the victim host. +Kernel Threads and File-system Access+ -------------------------------------- In UNIX, everything is represented on the fileystem. System memory, itself, exists as a file, /dev/kmem. Without touching system call tables, how can one control the actual filesystem activity? In Linux, all the filesystems are abstracted under a virtual filesystem layer. Associated with each instance of a filesystem on a device is a operations structure, which maps the real file-system operations to the VFS layer. In the case of ext2fs, the ops table is defined in linux/fs/ext2/super.c and is called ext2_sops. An attacker wishing to manipulate this structure has two options: 1. Rewrite the structure with the tronned operations. 2. Seek out all superblocks, and currently open file descriptors replacing the ops pointer with a address of the tronned operations residing in the kernel_thread. The first option is the easiest to implement, the trojaned structure is simply copied over the original structure. No further changes are necessary. If the structure is being monitored via a checksumming mechanism, it will be identified as changed (as a static structure this is definitely a sign that something is afoot). The risk of this occurring is mitigated by the fact that the ext2_sops structure is not an exported symbol, and is not easily monitored. The second option is be harder to detect, but would requires more work to implement. First, each mounted filesystem would have to have its in-memory copy of its superblock modified to reference the trojaned operations structure. Secondly, all currently open files on those filesystems would have to be modified, as they copy the ops pointer from their superblock upon creation of the file descriptor. +Kernel Thread Concealment+ --------------------------- What good is a kernel thread to do all the nice and naughty things in the world if it stands out like a sore thumb. I mean, part of the reason for looking at this is to hide ones presence. Then why would one be content having a kernel thread appear as: root 9 0.0 0.1 1368 72 ? S Jul14 0:12 [ur0wn3d] OK, maybe that is a little bit over the top, but you get the point. Again, a simple solutions: Remember that filesystem stuff? Yep, proc file system too. One word: proc_sops +Detection and Countermeasures+ ------------------------------- So, faced with this type of mechinism that can conceal attacks and be used as a remote administration tool for linux systems, how do we protect ourselves? 1. Disabling the kenrel_thread call is insufficient. Even if the call is disabled on a system after the necessary kernel threads are started, then one can use their time during init_module to 'roll their own' kernel thread call. 2. Checksumming various common and critical filesystem, memory management, and scheduling data structures would prevent a kernel thread from using its position to subvert the low level memory management, filesystem, and scheduling code. This does not detect or prevent other mallicious effects that could be done by the kernel thread. 3. In StJude, tie kernel threads to the default (no privlage) rule. kernel threads can be identified by abnormalities in their task_struct, so this is possible. It would limit the use of kernel threads as remote administration tools. This is just a brief summery of possible countermeasures. Others may follow. Despite this, the kernel threads provide an elegent and dangerous mechinism for the implementation of hostile code within the linux kernel.