ICMP协议简介
ICMP 位于TCP/IP 协议族中的网络层,它的目的是用于在 IP 主机、路由器之间传递控制消息。
有了之前 ARP主机发现技术的经验之后,再来了解一下 ICMP 这个协议是如何进行活跃主机发现的,相信对大家来说并不困难。
相比ARP简单明了的工作模式,ICMP虽然要复杂一些,但是用来扫描活跃主机的原理却是一样的。
ICMP 中提供了多种报文,这些报文又可以分成两大类:差错报文和查询报文。 其中,查询报文都是由一个请求和一个应答构成的。
只需要向目标发送一个请求数据包,如果收到了来自目标的回应,就可以判断目标是活跃主机,否则可以判断目标是非活跃主机,这与 ARP 扫描原理是相同的。
这里我只是提一下,而且描述的也相对模糊,所以可以选择性的理解
但是,与ARP扫描不同的地方在于ICMP查询报文有4种,分别是响应请求或应答、 时间戳请求或应答、 地址掩码请求或应答、路由器询问或应答。
ping命令就是响应请求或应答的一种应用,我们经常会使用这个命令来测试本地与目标之间的连通性,例如我们所在的主机 IP 为 192.168.1.1 ,而通信的目标 IP 地址为 192.168.1.2,如果要判断 192.168.1.2 是否为活跃主机就需要向其发送一个ICMP请求,这个请求的格式如下。
IP层内容 源IP地址:192.168.1.1 目的IP地址:192.168.1.2 ICMP层内容 Type:0(表示应答)
以图形的形式描述如下:
- 向目标发送一个ICMP Request
- 如果目标主机处于活跃状态,在正常情况下它就会回应一个ICMP Reply
要注意的是现在很多网络安全设备或者机制都会屏蔽ICMP,在这种情况下即使目标主机处于活跃状态,也收不到任何信息。
- 如果目标主机处于非活跃状态,他不会给出任何回应
那么我们就可以得到结论,只要收到了ICMP回应,就可以判断该主机未活跃状态。
利用ICMP探测主机是否存活
现在编写一个利用ICMP实现的活跃主机扫描程序,这个程序有很多方式可以实现,首先借助Scapy库来完成。其核心思想就是要产生一个ICMP请求。
我们首先查看Scapy库中ICMP类型数据包中需要的参数。
ls(ICMP())
运行结果: 这里面大多数参数都不需要设置,唯一需要注意的是type,这个参数的默认值已经是8,所以无须修改。
另外,ICMP并没有目标地址和源地址,所以需要在IP中进行设置,首先查看一下Scapy库中IP类型数据包中需要的参数。
ls(IP())
运行结果: 这一层和地址有关的参数有两个:dst是目的IP地址,src是源IP地址。
这里面src会自动设置为本机地址。
所以只需要将dst设置为“1目标主机地址”即可将数据发送到目标主机上。
接下来构造一个扫描192.168.43.1的ICMP请求数据包并将其发送出去.
data = IP(dst="192.168.43.1") / ICMP()
ans, unans = sr(data)
ans.summary()
运行结果: 我们再描述仔细一点
data = IP(dst="192.168.43.1") / ICMP()
ans, unans = sr(data)
ans.summary()
for s, r in ans:
print("发出去的包:%s" % s.summary())
print("回应的包:%s" % r.summary())
运行结果: 按照之前的思路,需要对这个请求的回应进行监听,如果得到了回应,那么证明目标在线,并打印输出这个主机的IP地址。
这里很明显是收到包的,所以目标主机是活跃的,那么我们输出这个主机的IP地址。
from scapy.all import *
data = IP(dst="192.168.43.1") / ICMP()
ans, unans = sr(data, timeout=0.1)
ans.summary()
for s, r in ans:
print("发出去的包:%s" % s.summary())
print("回应的包:%s" % r.summary())
for s, r in ans:
print("[*]主机:%s" % r[IP].src)
print("[*]存活!")
运行结果: