Tag Archives: calls

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