2024年6月3日发(作者:)
基于ICMP协议和广播的洪水Ping编程
下面,我们分析一个程序——基于ICMP协议和广播的洪水Ping编程。
我们介绍这样3个问题:
Ping命令以及基于Ping命令的Ping to Death攻击的基本原理
洪水Ping攻击的基本原理
洪水Ping攻击程序的分析
先来看第一个问题。
1、 Ping命令及Ping to Death攻击
1) Ping命令格式:
Ping命令,我们大家都使用过了。例如:
ping 192.168.0.101 –l 1024
这里,Ping的目标地址是:192.168.0.101,ICMP数据包的大小=1024字节
利用这个命令,可以测试从源主机到目标主机网络、TCP/IP 协议栈的工作是否正常。
手工执行的时候,我们需要在Dos命令行输入:ping 192.168.0.101(目标地址)。执行Ping
命令,本质上就是源主机向目标主机发送一个 ICMP的数据包,只不过,这个ICMP数据
报的类型=8(回显请求)。目标主机接收到类型=8的ICMP数据报后,向源主机发送一个类
型=0的回显应答数据包。这是Ping命令执行的基本过程。
2) Ping to Death攻击的原理
从这个过程,我们可以看出:源主机发送一个ICMP请求后,目标主机必须回应。在早
期的操作系统中,例如:Windows95,由于操作系统默认ICMP数据包不会很大,所以,它
们给ICMP数据包预留的缓存不够大,也没有做内存溢出检查。所以,早期的操作系统不能
很好的处理过大的ICMP数据包。当源主机发送一个异常大的ICMP数据包时,目标主机可
能出现内存溢出,死机。这就是Ping to Death攻击的基本原理。
2、洪水Ping攻击的基本原理
随着操作系统的升级,目前Windows系统已经没有了这种BUG,大的Ping包基本没有
了攻击效果。但是,对于一个网站,或者服务器,如果我们在同一时间,向它们发送巨量的
Ping数据包,服务器也必须给予回应,效果上,也会导致服务器变慢,甚至瘫痪。这就是
洪水Ping攻击。
理论上,当大量用户(成千上万)同一时间发送Ping命令到同一台主机,会产生明显
的攻击效果。但是,这不符合黑客攻击的基本原则:用最少的攻击资源换取被攻击者最大的
消耗。
那么,究竟怎样做,才能以最小的代价换取对方最大的牺牲呢?
我们来看,正常情况下,当主机A发送了一个ICMP的报文(类型=8,回显请求)给
主机B,主机B会发送一个ICMP的应答报文(类型=0,回显应答)。由于ICMP是封装在
IP数据报中发送,基于无连接的应用,这就给攻击者了一个机会。(由于发送方可以不建立
连接直接向接收方发送数据,接收方不认证对方身份就必须处理,这就营造了一个可乘之机。
如果是面向连接的,接收方在接收数据前,需要与发送方先建立连接,这样,没有接收方的
允许,连接就无法建立,后续的攻击数据就无法发送)。
好,这是正常情况下ICMP的请求和应答。现在,我们假定:主机A伪装成主机C向
主机B发送了一个ICMP回显请求数据包,结果会怎样呢?主机B会误以为,主机C向自
己发送了一个ICMP的回显请求,它会主动向主机C发送一个ICMP的回显应答。
这里,攻击者发送了一个攻击数据包给主机B,造成了对主机B、C的同时攻击,攻击
1
效果放大了一倍。而且,我们隐藏了攻击主机A的地址,在攻击过程中没有留下我们的痕
迹。
再进一步,如果我们伪装成被攻击的主机,向一个广播地址发送一个ICMP回显请求数
据包,结果又会怎样呢?由于这是个广播数据包,网络内收到广播数据报的主机都会处理,
当大量的主机发现主机C向它们发送了一个ICMP回显请求,它们会同时发送ICMP回显
应答。如果一个局域网内有N台主机,我们在这个局域网内发送一个这样的广播数据包,
被攻击主机就会收到N个回显应答攻击包,相当于一次攻击放大了N倍。
这样,就达到了“以最小的代价换取对方最大的牺牲”的目标。
那么,具体程序是如何做的呢?
3、洪水Ping攻击程序分析
通常情况下,当我们的顶层应用程序需要发送数据时,主机的TCP/IP协议栈会自动将
我们的数据封装在IP数据报中发送出去。这时,我们的IP数据报中源地址就填写了我们自
己的地址。但是,为了伪造主机C,我们需要自己构造IP数据包。自己填写源、目标IP地
址。
为了完成这种底层操作,我们需要使用一个winsock API的函数——setsockopt。
1)setsockopt函数解析
Setsockopt函数用于任意类型(数据报套接口、流式套接口、原始套接口)、任意状态
套接口的选项设置,它的函数原型是:
int setsockopt ( SOCKET s, int level, int optname, const char FAR * optval, int optlen );
这里,s——需要改变选项设置的套接字;
level——指定控制套接字的层次,可以取三个值:1)SOL_SOCKET:通用套接字选项;
2)IPPROTO_IP:IP选项;3)IPPROTO_TCP:TCP选项。
optname——套接字选项的名称。对不同的选项,可以取不同的值,例如:
选项名称 说明 数据类型
========================================================================
SOL_SOCKET
------------------------------------------------------------------------
SO_BROADCAST 允许发送广播数据 BOOL
SO_DEBUG 允许调试 BOOL
SO_DONTROUTE 不查找路由 BOOL
SO_ERROR 获得套接字错误 int
SO_KEEPALIVE 保持连接 BOOL
SO_LINGER 延迟关闭连接 struct linger
SO_OOBINLINE 带外数据放入正常数据流 BOOL
SO_RCVBUF 接收缓冲区大小 int
SO_SNDBUF 发送缓冲区大小 int
SO_RCVLOWAT 接收缓冲区下限 int
SO_SNDLOWAT 发送缓冲区下限 int
SO_RCVTIMEO 接收超时 struct timeval
SO_SNDTIMEO 发送超时 struct timeval
SO_REUSERADDR 允许重用本地地址和端口 BOOL
SO_TYPE 获得套接字类型 int
SO_BSDCOMPAT 与BSD系统兼容 int
2
==========================================================================
IPPROTO_IP
--------------------------------------------------------------------------
IP_HDRINCL 在数据包中包含IP首部 BOOL
IP_OPTINOS IP首部选项 int
IP_TOS 服务类型
IP_TTL 生存时间 int
==========================================================================
IPPRO_TCP
--------------------------------------------------------------------------
TCP_MAXSEG TCP最大数据段的大小 int
TCP_NODELAY 不使用Nagle算法 int
=========================================================================
optval——这是一个指针,我们看选项。选项的值有2类:1)布尔类型,其方式为激活
(设置为TRUE)或禁止(设置为FALSE),比如:选项SO_BROADCAST设置为TRUE,
表示套接字允许发送广播数据;2)整型或结构。
对于布尔类型的选项,如果选项设置为TRUE,optval指向非零整型数,反之,如果选
项设置为FALSE,optval指向一个等于零的整型数。这时,optlen =sizeof(int)。
对于其他选项,optval指向那个存储整型或结构的内存地址,optlen是整型、结构的长
度。
调用setsockopt函数后,如果没有错误发生,返回0,否则,返回一个错误代码。好了,
有关套接字的选项设置,大家可以下来自己看,这里只要知道:构造广播的IP 数据包需要
改变套接口默认的设置就行了。
2)Sleep函数
Sleep函数挂起当前正在执行的线程,等待一段时间后,在向下执行。它的用法
Sleep(800);
表示当前线程等待800(单位是千分之一秒)
3)程序分析
好了下面,我们来看一下程序的实现。这是一个控制台命令程序。它由这么几个部分组
成:
1、 文件头
2、 常量及结构定义
(定义了2个常量,2个结构)
3
注意:IP数据报、ICMP数据报包头的定义与TCP/IP协议是一致的。
3、 定义计算校验和的子函数
4、 最后是主程序
这个程序可以接受3个参数(第一个参数是你打算伪装的主机的IP地址,第二个参数是目
标地址,一般是一个广播地址,第三个参数可选,指定数据包的大小)。在DOS下,输入:
4
FakeSourceIp DestinationIp [PacketSize]
例如:
192.168.15.23 192.168.15.255 6400
表明,我们想伪装的主机IP地址= 192.168.15.23,我们希望向局域网192.168.15.0发送广播
包(广播地址的主机ID全为1,因此,该局域网广播地址=192.168.15.255)
好了,前面,我们讲过:如果我们在命令行输入上述命令,argc=4,argv[1]= FakeSourceIp,
argv[2]= DestinationIp,argv[3]= PacketSize。
另外,程序的开头,还定义了一些变量,我们这里不多讲了。后面用到了再讲。
主程序的第二部分对输入参数进行检查,当参数输入不对时,打印帮助信息。
如果参数正确,将命令行输入的参数保存在相应的变量中。
接下来,调用注册函数,这是winsock编程的第一步。如果注册成功,创建一个原始套接口。
5
套接口创建成功后,调用setsockopt函数2次,改变套接口的选项设置。第一次,告诉套接
口,发送用户数据时,包含IP首部,也就是说,我们要自己构造IP 报的头部。第二次,改
变超时重发的时间(
如果你设了 SO_SNDTIMEO,则在阻塞一定时间后,如果socket buffer还是没有
空闲,TCP/IP会取消阻塞,让你的程序可以继续运行
)。
再接下来,填写好目标地址结构,构造IP数据报的头部,构造ICMP数据包,然后将它们
放入缓冲区SendBuf。注意,在构造IP数据报的头部时,我们在源地址字段填入了伪地址。
在构造ICMP数据报时,它的类型为8,表明这是一个回显请求。
6
最后,计算数据包的校验和,填写数据包总长度,使用一个无限循环,重复发送这个数据包。
好了,程序的主要流程就这样。下来,我给大家一份电子文档,大家下来后,一边看资料,
一边调试。
需要强调的是:
1)这个程序只能运行在Windows2000下,WinXP不允许伪造IP地址发送数据包
2)微软的系统不会回应广播地址的包。因此,如果你想更好的做个测试,最好在Unix
系统下,使用Ping命令测试。你可以在Unix机器上Ping一下你局域网的广播地址,这时,
可以看到很多很多主机发给你的应答数据包。但在Windows下就不行了,Windows的Ping
程序不会对多个应答数据包进行解包。
3)尽管如此,我们仍然可以在Windows2000下测试这个程序,用Sniffer可以观察到伪
造的IP数据包发送情况。这个程序的目的,就是希望大家了解如何使用原始套接口,如何
自己构造和发送一个底层的IP数据包。
7


发布评论