Tag Archives: linux kernel

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.

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