SYN (synchronize)
SYN是TCP/IP建立连接时使用的握手信号。在客户机和服务器之间建立正常的TCP网络连接时,客户机首先发出一个SYN消息,服务器使用SYN-ACK应答表示接收到了这个消息,最后客户机再以ACK消息响应。这样在客户机和服务器之间才能建立起可靠的TCP连接,数据才可以在客户机和服务器之间传递。 TCP连接的第一个包,非常小的一种数据包。SYN 攻击包括大量此类的包,由于这些包看上去来自实际不存在的站点,因此无法有效进行处理。每个机器的欺骗包都要花几秒钟进行尝试方可放弃提供正常响应。
SYN攻击属于DoS攻击的一种,它利用TCP协议缺陷,通过发送大量的半连接请求,耗费CPU和内存资源。SYN攻击除了能影响主机外,还可以危害路由器、防火墙等网络系统,事实上SYN攻击并不管目标是什么系统,只要这些系统打开TCP服务就可以实施。服务器接收到连接请求(syn= j),将此信息加入未连接队列,并发送请求包给客户(syn=k,ack=j+1),此时进入SYN_RECV状态。当服务器未收到客户端的确认包时,重发请求包,一直到超时,才将此条目从未连接队列删除。配合IP欺骗,SYN攻击能达到很好的效果,通常,客户端在短时间内伪造大量不存在的IP地址,向服务器不断地发送syn包,服务器回复确认包,并等待客户的确认,由于源地址是不存在的,服务器需要不断的重发直至超时,这些伪造的SYN包将长时间占用未连接队列,正常的SYN请求被丢弃,目标系统运行缓慢,严重者引起网络堵塞甚至系统瘫痪。
下面我们来亲自体验SYN编程,实现安全隐患监测
先实现检测主机信息
#include <winsock2.h> #include <stdio.h> #pragma comment(lib,"ws2_32.lib") int main() { //////////////// // 初始化 Windows sockets API. // WORD wVersionRequested = MAKEWORD(2, 2); WSADATA wsaData; if (WSAStartup(wVersionRequested, &wsaData)) { printf("WSAStartup failed %s\n", WSAGetLastError()); return 0; } ////////////////// // 获得主机名. // char hostname[256]; int res = gethostname(hostname, sizeof(hostname)); if (res != 0) { printf("Error: %u\n", WSAGetLastError()); return 0; } printf("hostname=%s\n", hostname); //////////////// // 根据主机名获取主机信息. // hostent* pHostent = gethostbyname(hostname); if (pHostent==NULL) { printf("Error: %u\n", WSAGetLastError()); return 0; } ////////////////// // 解析返回的hostent信息. // hostent& he = *pHostent; printf("name=%s\naliases=%s\naddrtype=%d\nlength=%d\n", he.h_name, he.h_aliases, he.h_addrtype, he.h_length); sockaddr_in sa; //根据 he.h_addr_list[nAdapter]是否为空来获取所有IP地址 for (int nAdapter=0; he.h_addr_list[nAdapter]; nAdapter++) { memcpy ( &sa.sin_addr.s_addr, he.h_addr_list[nAdapter],he.h_length); // 输出机器的IP地址. printf("Address [%d%]: %s\n",nAdapter, inet_ntoa(sa.sin_addr)); // 显示地址串 } ////////////////// // 终止 Windows sockets API // WSACleanup(); return 0; }
下面开始SYN 扫描
#include <winsock2.h> #include <ws2tcpip.h> #include <stdio.h> #include <time.h> #include "mstcpip.h" #pragma comment(lib,"ws2_32.lib") #define SEQ 0x28376839 SOCKET sockRaw = INVALID_SOCKET, sockListen = INVALID_SOCKET; struct sockaddr_in dest; BOOL ScanOK=FALSE; char *DEST_HOST; int DEST_PORT; int DEST_PORTEND; int play=0; clock_t start,end;//程序运行的起始和结束时间 float costtime;//程序耗时 typedef struct _iphdr { unsigned char h_lenver; //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 //定义TCP首部 { USHORT th_sport; //16位源端口 USHORT th_dport; //16位目的端口 unsigned int th_seq; //32位序列号 unsigned int th_ack; //32位确认号 unsigned char th_lenres; //4位首部长度/6位保留字 unsigned char th_flag; //6位标志位 USHORT th_win; //16位窗口大小 USHORT th_sum; //16位校验和 USHORT th_urp; //16位紧急数据偏移量 }TCP_HEADER; struct //定义TCP伪首部 { unsigned long saddr; //源地址 unsigned long daddr; //目的地址 char mbz; char ptcl; //协议类型 unsigned short tcpl; //TCP长度 }psd_header; //SOCK错误处理程序 void CheckSockError(int iErrorCode, char *pErrorMsg) { if(iErrorCode==SOCKET_ERROR) { printf("%s Error:%d\n", pErrorMsg, GetLastError()); closesocket(sockRaw); ExitProcess(-1); } } //计算检验和 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); } //IP解包程序 bool DecodeIPHeader(char *buf, int bytes) { IP_HEADER *iphdr; TCP_HEADER *tcphdr; unsigned short iphdrlen; iphdr = (IP_HEADER *)buf; iphdrlen = sizeof(unsigned long) * (iphdr->h_lenver & 0xf); tcphdr = (TCP_HEADER*)(buf + iphdrlen); //是否来自目标IP if(iphdr->sourceIP != dest.sin_addr.s_addr) return false; //序列号是否正确 if((ntohl(tcphdr->th_ack) != (SEQ+1)) && (ntohl(tcphdr->th_ack) != SEQ)) return false; //if(tcphdr->th_flag == 20)return true; //SYN/ACK - 扫描到一个端口 if(tcphdr ->th_flag == 18) { printf("\t%d\t open \n",ntohs(tcphdr->th_sport)); return true; } return true; } void usage(void) { printf("\t===================SYN portscaner======================\n"); printf("\[email protected] 2004/7/6===========\n"); printf("\tusage: synscan DomainName[IP] StartPort-EndPort\n"); printf("\tExample: synscan www.163.com 1-139\n"); printf("\tExample: synscan 192.168.1.1 8000-9000\n"); } DWORD WINAPI RecvThread(LPVOID para)//接收数据线程函数 { int iErrorCode; struct hostent *hp; char RecvBuf[65535]={0}; sockListen = socket(AF_INET , SOCK_RAW , IPPROTO_IP); CheckSockError(sockListen, "socket"); //设置IP头操作选项 BOOL bOpt = true; iErrorCode = setsockopt(sockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&bOpt,sizeof(bOpt)); CheckSockError(iErrorCode, "setsockopt()"); //获得本地IP SOCKADDR_IN sa; unsigned char LocalName[256]; iErrorCode = gethostname((char*)LocalName,sizeof(LocalName)-1); CheckSockError(iErrorCode, "gethostname()"); if((hp = gethostbyname((char*)LocalName)) == NULL) { CheckSockError(SOCKET_ERROR, "gethostbyname()"); } memcpy(&sa.sin_addr.S_un.S_addr,hp->h_addr_list[1],hp->h_length); sa.sin_family = AF_INET; sa.sin_port = htons(7000); iErrorCode = bind(sockListen, (PSOCKADDR)&sa, sizeof(sa)); CheckSockError(iErrorCode, "bind"); //设置SOCK_RAW为SIO_RCVALL,以便接收所有的IP包 DWORD dwBufferLen[10] ; DWORD dwBufferInLen = 1 ; DWORD dwBytesReturned = 0 ; iErrorCode=WSAIoctl(sockListen, SIO_RCVALL,&dwBufferInLen, sizeof(dwBufferInLen),&dwBufferLen, sizeof(dwBufferLen),&dwBytesReturned , NULL , NULL ); CheckSockError(iErrorCode, "Ioctl"); memset(RecvBuf, 0, sizeof(RecvBuf)); //接收数据 for(;;) { iErrorCode = recv(sockListen, RecvBuf, sizeof(RecvBuf), 0); //CheckSockError(iErrorCode, "recv"); DecodeIPHeader(RecvBuf,iErrorCode) ; } if(ScanOK) { closesocket(sockListen); return 0; } } void playx(void) // 定义状态提示函数 { // 进度条 char *plays[12]= { " | ", " / ", " - ", " \\ ", " | ", " / ", " - ", " \\ ", " | ", " / ", " - ", " \\ ", }; printf(" =%s=\r", plays[play]); play=(play==11)?0:play+1; Sleep(2); } //主函数 int main(int argc,char **argv) { char *p; if(argc!=3) { usage(); return 0; } p=argv[2];//处理端口参数 if(strstr(argv[2],"-")) { DEST_PORT=atoi(argv[2]); for(;*p;) if(*(p++)=='-')break; DEST_PORTEND=atoi(p); if(DEST_PORT<1 || DEST_PORTEND>65535) { printf("Port Error!\n"); return 0; } } DEST_HOST=argv[1]; usage(); int iErrorCode; int datasize; struct hostent *hp; IP_HEADER ip_header; TCP_HEADER tcp_header; char SendBuf[128]={0}; //初始化SOCKET WSADATA wsaData; iErrorCode = WSAStartup(MAKEWORD(2,2),&wsaData); CheckSockError(iErrorCode, "WSAStartup()"); sockRaw = socket(AF_INET , SOCK_RAW , IPPROTO_IP); CheckSockError(sockRaw, "socket()"); sockListen = socket(AF_INET , SOCK_RAW , IPPROTO_IP); CheckSockError(sockListen, "socket"); //设置IP头操作选项 BOOL bOpt = true; iErrorCode = setsockopt(sockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&bOpt,sizeof(bOpt)); CheckSockError(iErrorCode, "setsockopt()"); //获得本地IP SOCKADDR_IN sa; unsigned char LocalName[256]; iErrorCode = gethostname((char*)LocalName,sizeof(LocalName)-1); CheckSockError(iErrorCode, "gethostname()"); if((hp = gethostbyname((char*)LocalName)) == NULL) { CheckSockError(SOCKET_ERROR, "gethostbyname()"); } memcpy(&sa.sin_addr.S_un.S_addr,hp->h_addr_list[1],hp->h_length); sa.sin_family = AF_INET; sa.sin_port = htons(7000); iErrorCode = bind(sockListen, (PSOCKADDR)&sa, sizeof(sa)); CheckSockError(iErrorCode, "bind"); //获得目标主机IP memset(&dest,0,sizeof(dest)); dest.sin_family = AF_INET; dest.sin_port = htons(DEST_PORT); if((dest.sin_addr.s_addr = inet_addr(DEST_HOST)) == INADDR_NONE) { if((hp = gethostbyname(DEST_HOST)) != NULL) { memcpy(&(dest.sin_addr),hp->h_addr_list[1],hp->h_length); dest.sin_family = hp->h_addrtype; printf("dest.sin_addr = %s\n",inet_ntoa(dest.sin_addr)); } else { CheckSockError(SOCKET_ERROR, "gethostbyname()"); } } //开启监听线程 HANDLE Thread=CreateThread(NULL,0,RecvThread,0,0,0); //填充IP首部 ip_header.h_lenver=(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=sa.sin_addr.s_addr; //32位源IP地址 ip_header.destIP=dest.sin_addr.s_addr; //32位目的IP地址 //填充TCP首部 tcp_header.th_sport=htons(7000); //源端口号 tcp_header.th_lenres=(sizeof(TCP_HEADER)/4<<4|0); //TCP长度和保留位 tcp_header.th_win=htons(16384); //填充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)); Sleep(500); printf("\n"); printf("Scaning %s\n",DEST_HOST); start=clock();//开始计时 for(;DEST_PORT<DEST_PORTEND;DEST_PORT++) { playx(); tcp_header.th_dport=htons(DEST_PORT); //目的端口号 tcp_header.th_ack=0; //ACK序列号置为0 tcp_header.th_flag=2; //SYN 标志 tcp_header.th_seq=htonl(SEQ); //SYN序列号 tcp_header.th_urp=0; //偏移 tcp_header.th_sum=0; //校验和 //计算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报文 iErrorCode=sendto(sockRaw,SendBuf,datasize,0,(struct sockaddr*) &dest, sizeof(dest)); CheckSockError(iErrorCode, "sendto()"); } end=clock();//计时结束 ScanOK=TRUE; printf("Closeing Thread.....\n"); WaitForSingleObject(Thread,5000); CloseHandle(Thread); costtime= (float)(end - start) / CLOCKS_PER_SEC; //转换时间格式 printf("Cost time:%f Sec",costtime);//显示耗时 //退出前清理 if(sockRaw != INVALID_SOCKET) closesocket(sockRaw); WSACleanup(); return 0; }