zoukankan      html  css  js  c++  java
  • 基于visual c++之windows核心编程代码分析(36)实践SYN安全隐患监测

    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("\t============gxisone@hotmail.com     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;
    } 


     



     

  • 相关阅读:
    bzoj 2832
    洛谷5月月赛
    P4705 玩游戏
    【bzoj4817】[Sdoi2017]树点涂色&&bzoj3779-重组病毒
    A
    P4715 「英语」Z 语言
    P4714 「数学」约数个数和
    P2860 [USACO06JAN]冗余路径Redundant Paths
    【BZOJ3252】攻略
    BZOJ 1706
  • 原文地址:https://www.cnblogs.com/new0801/p/6177789.html
Copyright © 2011-2022 走看看