Vous êtes sur la page 1sur 47

Hacking with Linux Kernel Modules

by Nitesh Dhanjani
nitesh(at)dhanjani.com Hack In The Box Conference, December 2003 Kuala Lumpur, Malaysia.

Why Learn About LKMs?


Helps better understand the Linux OS. Kernel programming can be time consuming but not necessarily more difficult. Fun! Moderate C programming skills required.
(c) Nitesh Dhanjani 2

Introduction to LKMs
Linux == Monolithic kernel. Read http://www.dina.dk/~abraham/Linus _vs_Tanenbaum.html for lots of fun and entertainment on this topic. LKMs can add and/or change kernel functionality on-the-fly. However, code must be statically linked in some cases.

(c) Nitesh Dhanjani

Advantages
No need to recompile kernel. Easier to debug and develop. Modules can be loaded and unloaded on demand. Why bloat the kernel?

(c) Nitesh Dhanjani

Manually Loading and Unloading LKMs


LKMs can be manually loaded using insmod. Similarly, they can be removed using rmmod.
Usage Counter must be 0 in order to unload.

Loaded modules can be listed using lsmod.


(c) Nitesh Dhanjani 5

Loading On-Demand
Kernel thread (kmod) executes modprobe to load modules on demand. This program handles module dependencies. The modprobe program uses the modules.dep file to calculate dependencies. The modules.dep file is created by depmod which is usually executed during startup.
(c) Nitesh Dhanjani 6

What are System Calls?


Programs spend most of their time in user mode. They switch to kernel mode when an OS service is required. These services are offered via System Calls which serve as gates into the kernel. System Calls cause software interrupts.
(c) Nitesh Dhanjani 7

What are System Calls?


The kernel maintains a System Call Table which contains pointers to functions implementing the system calls. See /usr/include/bits/syscall.h for a list of supported System Calls. Also see /usr/src/linux/arch/i386/kernel/entry.S
(c) Nitesh Dhanjani 8

What are System Calls?


$ more /usr/include/bits/syscall.h #define SYS_stime __NR_stime #define SYS_getresuid __NR_getresuid #define SYS_rt_sigqueueinfo __NR_rt_sigqueueinfo #define SYS_mmap2 __NR_mmap2 #define SYS_fsync __NR_fsync
(c) Nitesh Dhanjani 9

What are System Calls?


$ more /usr/src/linux/arch/i386/kernel/entry.S ENTRY(sys_call_table) .long SYMBOL_NAME(sys_exit) .long SYMBOL_NAME(sys_fork) .long SYMBOL_NAME(sys_read) .long SYMBOL_NAME(sys_write) .long SYMBOL_NAME(sys_open) /* 5 */ .long SYMBOL_NAME(sys_close)
(c) Nitesh Dhanjani 10

Library Functions
Library functions are linked to programs and are more portable. They wrap around system calls to perform certain operations. Example: fopen() in-turn calls sys_open() to actually open a file. Use the strace program to look at the system calls being invoked by an executable.
(c) Nitesh Dhanjani 11

Library Functions
Simple C program to display /etc/passwd:
#include <stdio.h> int main(void) { if(!(myfile=fopen("/etc/passwd","r"))) { exit(1); } while(!feof(myfile)) { /*code to read and write from myfile here*/ } exit(0); }
(c) Nitesh Dhanjani 12

Library functions
Run strace on the executable:
[bash]$ strace -o strace_output ./a.out

Search for passwd in the output file:


[bash]$ grep passwd strace_output open("/etc/passwd", O_RDONLY) = 3

Sure enough, fopen does call sys_open!


(c) Nitesh Dhanjani 13

Intercepting System Calls


Hook the System Call by altering the System Call Table (sys_call_table). Cause your own function to be called instead of the real System Call. Call the real System Call when done (in most cases).
(c) Nitesh Dhanjani 14

Example - Intercepting sys_exit()


Programs usually call sys_exit() to return a 0 when the program exits successfully. Else a non-zero value is returned. In our example, we will intercept sys_exit(). We will then print the value passed to it onto the console. Eventually, we will call the real sys_exit().
(c) Nitesh Dhanjani 15

Example - Intercepting sys_exit()


NOTE: This example will serve as a skeleton for future examples in this presentation. Store the location of the real sys_exit() System Call. Modify the System Call Table to point to our fake exit call. Within our fake exit call, print the value passed to it, and then invoke the real sys_exit().
(c) Nitesh Dhanjani 16

Example - Intercepting sys_exit()


Headers: #include <linux/module.h> #include <linux/kernel.h> #include <sys/syscall.h> Need exported System Call Table: extern void *sys_call_table[];
(c) Nitesh Dhanjani 17

Example - Intercepting sys_exit()


Get insmod to shut-up about licensing issues: MODULE_LICENSE(GPL); Prototype pointer for storing the original sys_exit call:
asmlinkage int (*original_sys_exit)(int);
(c) Nitesh Dhanjani 18

Example - Intercepting sys_exit()


Our fake exit call:
asmlinkage int our_fake_exit_function(int error_code) { /*Print message on console every time we are called*/ printk("HEY! sys_exit called with error_code = %d\n",error_code); /*Call original sys_exit and return its value*/ return original_sys_exit(error_code); }
(c) Nitesh Dhanjani 19

Example - Intercepting sys_exit()


Initialization & System Call Table Manipulation:
/*This function is called when the module is loaded*/ int init_module(void) { /*Store reference to the original sys_exit call*/ original_sys_exit = sys_call_table[__NR_exit];

Continued..
(c) Nitesh Dhanjani 20

Example - Intercepting sys_exit()


/*Manipulate sys_call_table to call our fake exit function instead*/ sys_call_table[__NR_exit]=our_fake_exit _function; printk("\nhello\n"); return 0; }
(c) Nitesh Dhanjani 21

Example - Intercepting sys_exit()


Compile and load:
[bash]$ gcc -D__KERNEL__ -DMODULE I/usr/src/linux/include/ -c exit.c [bash]# insmod ./exit.o

Run ls so it returns a non-zero value:


[bash]$ ls some-file-that-does-not-exist

Output from our module:


HEY! sys_exit called with error_code=1
(c) Nitesh Dhanjani 22

Redhat 9 Kernel
Redhat 9s kernel does not export sys_call_table. To export it: Edit /usr/src/linux/kernel/ksysms.c and add the line: EXPORT_SYMBOL(sys_call_table) Then, recompile and re-install your kernel Reboot. Or, compile your own v2.4 stock kernel.
(c) Nitesh Dhanjani 23

Preventing File Access Intercepting sys_open()


Create list of files that need to be protected against access (even by root). Intercept sys_open and check the filenames inode against inode of file to be protected. If the the inodes match, return -EACCESS. Else, call and return the value from the original sys_open.
(c) Nitesh Dhanjani 24

Preventing File Access Intercepting sys_open()


asmlinkage int our_fake_open_function(const char *filename, int flags,int mode) { int error; struct nameidata nd; struct inode *inode; error=user_path_walk(filename,&nd);

Continued
(c) Nitesh Dhanjani 25

Preventing File Access Intercepting sys_open()


if(!error) {inode=nd.dentry->d_inode; /*Have to do this before calling user_path_walk() from kernel space:*/ fs=get_fs(); set_fs(get_ds()); error=user_path_walk(/tmp/protected,& nd_t); set_fs(fs); Continued..
(c) Nitesh Dhanjani 26

Preventing File Access Intercepting sys_open()


if(!error) { inode_t=nd_t.dentry->d_inode; if(inode==inode_t) return -EACCES; } } return original_sys_open(filename,flags,mode) }
(c) Nitesh Dhanjani 27

Preventing File Access Intercepting sys_open()

DEMO

(c) Nitesh Dhanjani

28

Annoying Backdoor
Remote backdoor to listen on a TCP port. When a connection is made to a certain port, access to a particular file is prohibited by using our previous example. When another connection in made to the port, access to the file is allowed again. Not a particularly lethal backdoor, but a first-step implementation towards a very annoying one :-)
(c) Nitesh Dhanjani 29

Annoying Backdoor
init_module(void) { flag =1; original_sys_open = sys_call_table[__NR_open]; socket_create(..); bind(..); listen(..); kernel_thread(do_server,); }
(c) Nitesh Dhanjani 30

Annoying Backdoor
int do_server(..) { while(1) { accept(..); if(flag==1) { /*intercept sys_open and hide our file*. Set flag to 0*/} else{ /*Restore sys_open. Set flag to 1*/} }

}
(c) Nitesh Dhanjani 31

Annoying Backdoor
For more information on socket programming within kernel threads, read The Design of kHTTPd by Allesandro Rubini [http://www.linux.it/kerneldocs/khttpd/khttpd.htm] Also, see kHTTpd source-code for more tricks.
(c) Nitesh Dhanjani 32

Annoying Backdoor

DEMO

(c) Nitesh Dhanjani

33

/proc/ksyms
Contains the Kernel Symbol Table. For example:
cat /proc/ksysms | grep open

will display information about our fake sys_open call. Use EXPORT_NO_SYMBOLS macro in order to not export symbols. Or, do partial file hiding (intercept sys_open).
(c) Nitesh Dhanjani 34

/proc/modules
Contains list of currently loaded modules. For example, try:
cat /proc/modules | more

Do partial file hiding by intercepting sys_open. Much more stealthy: alter kernel module structure on-the-fly. See Plaguezs paper in Phrack 52, article 18.

(c) Nitesh Dhanjani

35

THCs tutorial
(nearly) Complete Linux Loadable Kernel modules by pragmatic (THC) [http://packetstormsecurity.nl/docs/hack/LKM_H ACKING.html] Hiding Processes: Manipulate access to /proc. /dev/kmem Hiding Modules. Pitfalls: User and Kernel Space memory management. And lots of other advanced techniques.
(c) Nitesh Dhanjani 36

modexecvehash
Developed by me during an independent study course at Purdue University with Professor Gustavo Rodriguez-Rivera. LKM that protects important executables against rootkits by verifying hashes on-the-fly. Proof-of-concept only. At this stage of development, this module may be by-passed by using advanced techniques such as raw memory and disk access.
(c) Nitesh Dhanjani 37

modexecvehash
Intercept sys_execve() and compute inode of file being executed. Compare this inode with that present in a database. If a match is found proceed further, otherwise return by calling the original sys_execve(). Compute hash of program being executed and compare it against the hash in the database. If they dont match, return an error. Else, return by calling the original sys_execve(). Other features.
(c) Nitesh Dhanjani 38

modexecvehash
Obtain source from http://dhanjani.com/presentations/hwlkm/ Untar modexecvehash.tar.gz in /root (important). Read README. Run make. Run ./makehashdb.sh > /root/hashdb Run insmod ./execvehash.o Test: Create backup of /usr/bin/passwd, replace it with /bin/ls, and then attempt to execute /usr/bin/passwd. It will not be allowed to execute. Dont forget to restore /usr/bin/passwd when done.
(c) Nitesh Dhanjani 39

Kernels 2.5 and Above


In the recent 2.5 and 2.6 kernels, sys_call_table is not being exported due to the following reasons: Intercepting System Calls is not considered clean. Licensing issues. Alternative: Linux Security Module (LSM) project. See http://lsm.immunix.org/
(c) Nitesh Dhanjani 40

Source Code
Source code for examples in this presentation can be obtained from: http://dhanjani.com/presentations/hwlkm/

(c) Nitesh Dhanjani

41

Question & Answers

???

(c) Nitesh Dhanjani

42

Resources
(nearly) Complete Linux Loadable Kernel Modules by pragmatic (THC) [http://packetstormsecurity.nl/docs/hack/LKM_HACKING .html] Loadable Kernel Module Programming and System Call Interception by Nitesh Dhanjani & Gustavo RodriguezRivera [http://www.linuxjournal.com/article.php?sid=4378] The Design of kHTTPd by Alessandro Rubini [http://www.linux.it/kerneldocs/khttpd/khttpd.html]
(c) Nitesh Dhanjani 43

Resources
Kernel System Calls by Alessandro Rubini [http://www.linux.it/kerneldocs/ksys/ksys.html] Linux Device Drivers by Alessandro Rubini [http://www.xml.com/ldd/chapter/book/] The Linux Kernel Module Programming Guide by Peter Jay Salzman [http://www.faqs.org/docs/kernel/] Weakening the Linux Kernel by plaguez [http://www.phrack.org/phrack/52/P52-18]
(c) Nitesh Dhanjani 44

Special Thanks

Gustavo Rodriguez-Rivera Purdue University West Lafayette, IN USA.

(c) Nitesh Dhanjani

45

Also Recommended

Advanced Kernel Keylogger by Red Dragon (RD) of THC. HITB, December 2003.

(c) Nitesh Dhanjani

46

Thank-You

;-)

(c) Nitesh Dhanjani

47

Vous aimerez peut-être aussi