Wednesday, March 7, 2012

NULL

I have been reading up on linux device drivers recently and decided to write a simple device driver for fun.  To make things more interesting, I included a blatantly obvious null pointer dereference vulnerability in the driver.  And of course, I wrote an exploit for it as well, taking reference from the various exploits that can be found online.  Note that this is purely an exercise and the code will not be very useful in real-world applications.

I will broadly explain how it works below.  But a thorough explanation would probably require multiple pages, so I will leave it to the reader to search and read through the relevant information in books, manuals and online articles.

In C, a pointer is an integer that refers to a location in memory.  When you want to load (or write to) the value that exists at this location via the pointer, you would be dereferencing the pointer.  In C, a NULL pointer is a pointer with the value 0.  This NULL pointer does not correspond to any valid memory by default - trying to dereference it will lead to a segmentation fault.

However, due to how virtual memory is implemented in linux (where the kernel space and user space share the same virtual address space), we can actually map NULL to a valid address.  This can be done via mmap().  If done correctly, dereferencing the NULL pointer would then no longer crash the system.  In fact, if we place our own function pointer at this valid address, the kernel will execute our code in kernel mode.

In a nutshell, this is what I have done in the exploit for my basic device driver.  If you want, you can download dearmo-driver1.zip here.  As there is a chance that the code will screw up your system, you probably should run this in a non-critical virtual machine.  I wrote and ran the code on Fedora 14 with kernel 2.6.35.6-45.fc14.i686, but it should work for all kernel versions 2.6.29 and up.

3 files are included in the download: dearmo-driver1.c, Makefile and rootnull.c.  To set up the system, and to compile and load the device driver, execute the commands below.

#echo 0 > /proc/sys/vm/mmap_min_addr
#echo 0 > /selinux/enforce
$make
#insmod dearmo-driver1.ko

There are still a few more steps to take after this.  Refer to the comments/information in the dearmo-driver1.c file. After that, compile the exploit rootnull.c, then execute it.

$gcc rootnull.c -o rootnull.out
$./rootnull.out


And we have root.