Sunday, December 4, 2011

Linux rootkit implementation

This is a rootkit i developed some time ago for educational purposes. It has the ability to hide itself from lsmod, hide processes, tcp connections, logged in users and to give uid 0 to any running process. The rootkit does not work on linux kernel >= 3.0.  now works on Linux Kernels >= 3.0 thanks to Dhiru Kholia, who ported it. He also made the proper fixes for the rootkit to compile on CentOS. The rootkit has been successfully tested on kernels >= 2.6.26.

The hiding is performed through file system function hooking. On Linux, every fs driver provides functions to open, read, write and perform operations with files and directories. This functions are stored in a struct file_operations, stored inside every inode. Therefore, every file_operations contains a pointer to the open, read, write(and many other) functions which will be called whenever a user tries to execute those actions on a filesystem object.

So what i did was to retrieve a certain inode and modify the pointer to its read function, replacing it with my own function. In this new function, filtering on the input was performed, in order to remove the entries i wanted to hide.

Let's take for example the connection hiding mechanism. netstat takes tcp connections information from a virtual file named /proc/net/tcp. This file contains one entry per line, each one indicating source and destination port, source and destination address and more information about each open connection. In order to hide a certain connection, i replaced the default read function with my own, in which i read entries on that file and skipped those containing the port i needed to hide.

In order to give orders to the rootkit, i used the same mechanism. I added a write function pointer to the file /proc/buddyinfo, which by default has no write permissions. So after hooking that function, whenever any user writes something to that virtual file, the rootkit will read what was wrote and execute actions based on the input. The commands it supports are the next ones:
  • hide/show. This commands hide/show the rootkit from lsmod(actually from /proc/modules).
  • hsport PORT/ssport PORT. Hides(hsport) connection which have PORT as their source port, or "unhides it"(ssport) if it was previously hidden.
  • hdport PORT/sdport PORT. Same as above but using destination port instead of source.
  • hpid PID/spid PID. Hides or "unhides" a process that has PID as its pid. This is done by hooking the /proc readdir pointer.
  • huser USER/suser USER. This commands hide or "unhide" a logged in user, so that who or other similar commands won't indicate USER is logged in the system. This is done by hooking /var/run/utmp.
  • root PID. This makes the process identified by PID to contain uid 0 and gid 0. This is kind of dirty but works well; the credentials struct from the init process is copied to the process identified by PID.
This is a screenshot showing how the rootkit works, hiding a user, a process, the ssh socket and making the bash process gain root privileges:

You can get the source code In order to compile it, you require your kernel's headers(on debian-based distributions, this can be found on the package linux-headers-2.6.X.X, where X depend on your kernel version). Download both the Makefile and the source file, and then just execute:
insmod rootkit.ko
That's all. Hope you find it useful!


  1. Me tira este error cuando trato de compilarlo en un Ubuntu

    $ make
    make -C /lib/modules/3.0.0-13-generic/build M=/home/ecerutti/rk modules
    make[1]: se ingresa al directorio «/usr/src/linux-headers-3.0.0-13-generic»
    CC [M] /home/ecerutti/rk/rootkit.o
    /home/ecerutti/rk/rootkit.c: En la función ‘hook_proc’:
    /home/ecerutti/rk/rootkit.c:493:5: error: declaración implícita de la función ‘path_lookup’ [-Werror=implicit-function-declaration]
    cc1: algunos avisos se tratan como errores

    make[2]: *** [/home/ecerutti/rk/rootkit.o] Error 1
    make[1]: *** [_module_/home/ecerutti/rk] Error 2
    make[1]: se sale del directorio «/usr/src/linux-headers-3.0.0-13-generic»
    make: *** [all] Error 2

    Estoy usando la última versión de Ubuntu

    $ cat /etc/lsb-release
    DISTRIB_DESCRIPTION="Ubuntu 11.10"

    con un kernel 3.0.0

    $ uname -a
    Linux dulcinea 3.0.0-13-generic #22-Ubuntu SMP Wed Nov 2 13:25:36 UTC 2011 i686 athlon i386 GNU/Linux

    tengo instalado los headers y las build-essentials

    $ dpkg -l | grep linux-header
    ii linux-headers-3.0.0-13 3.0.0-13.22 Header files related to Linux kernel version 3.0.0
    ii linux-headers-3.0.0-13-generic 3.0.0-13.22 Linux kernel headers for version 3.0.0 on x86/x86_64
    ii linux-headers-generic Generic Linux kernel headers

    $ dpkg -l | grep essential
    ii build-essential 11.5ubuntu1 Informational list of build-essential packages

    Estuve googleando un poco en busca de alguna solución pero no vi nada útil.


  2. Thanks for writing and releasing this! It is very helpful to us security tool developers to have samples to examine and test against.

    I've just posted a memory image from a (test) system that I loaded your rootkit on:

  3. FYI, hiding processes this way won't work for recent kernels where proc_dir_entry is opaque structure (no definition inside include files).

  4. I would like to once average coder rootkit is injected on to a machine what process name will be appearing in ps aux list as malicious (average coder) and what is the MD5 hashes. Average coder rootkit