ICMP协议
互联网控制消息协议(英语:Internet Control Message Protocol,缩写:ICMP)是互联网协议族的核心协议之一。它用于网际协议(IP)中发送控制消息,提供可能发生在通信环境中的各种问题反馈。通过这些信息,使管理者可以对所发生的问题作出诊断,然后采取适当的措施解决。
Type
ICMP的类型
- 0 回显请求 Echo Request
- 8 回显应答 Echo Reply
- 3 目标不可达 Destination Unreachable
- 11 超时消息 Time Exceeded
- 5 重定向消息 Redirect
ICMP扫描
利用ICMP协议对来判断存活的主机
原理
对需要扫描的ip发送icmp回显请求Echo Request
,如果收到回显应答Echo Reply
则该ip处于活动状态,简单来说就是ping别人,以是否ping得通来判断是否存活
数据包分析
ping网关
# ping 网关 -c 1
可以看到封装为Ether/IP/ICMP
,ICMP的类型为8
(Echo Request)
答复的数据包ICMP类型为0
(Echo Reply)
>>> ls(ICMP)
type : ByteEnumField = (8) #ICMP类型
code : MultiEnumField (Depends on type) = (0)
chksum : XShortField = (None)
id : XShortField (Cond) = (0)
seq : XShortField (Cond) = (0)
[...]
Python脚本
1.Scapy中ICMP的请求和答复
>>> p = IP(dst='10.35.68.1')/ICMP(type=8)
>>> p.show()
###[ IP ]###
version= 4
ihl= None
tos= 0x0
len= None
id= 1
flags=
frag= 0
ttl= 64
proto= icmp
chksum= None
src= 10.35.71.205
dst= 10.35.68.1
\options\
###[ ICMP ]###
type= echo-request
code= 0
chksum= None
id= 0x0
seq= 0x0
>>> p1 = sr1(p)
Begin emission:
.......Finished sending 1 packets..
..........*
Received 19 packets, got 1 answers, remaining 0 packets
>>> p1 = sr1(p,verbose=False) #关闭消息反馈
>>> p1 #答复的包
<IP version=4 ihl=5 tos=0x0 len=28 id=2899 flags= frag=0 ttl=64 proto=icmp chksum=0xcf7a src=10.35.68.1 dst=10.35.71.205 |<ICMP type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 ' |>>>
>>> p1.getlayer('ICMP') #获取ICMP层
<ICMP type=echo-reply code=0 chksum=0xffff id=0x0 seq=0x0 |<Padding load='\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00 ' |>>
>>> p1.getlayer('ICMP').fields['type'] #获取type的值
0
Python自带的ipaddress
模块
>>> import ipaddress
>>> ip = list(ipaddress.ip_network('192.168.1.0/30'))
>>> ip
[IPv4Address('192.168.1.0'),
IPv4Address('192.168.1.1'),
IPv4Address('192.168.1.2'),
IPv4Address('192.168.1.3')]
>>> for i in ip:
...: print(i)
...:
192.168.1.0
192.168.1.1
192.168.1.2
192.168.1.3
>>> ip = ipaddress.ip_network('192.168.1.1')
>>> for i in ip:
...: print(i)
...:
192.168.1.1
2.demo:先定义两个函数
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from scapy.all import *
#ICMP请求,返回响应包
def icmp_requset(ip_dst,iface=None):
pkt = IP(dst=ip_dst)/ICMP(type=8) #ICMP类型为
req = sr1(pkt,timeout=2,verbose=False) #timeou:超时时间设置 verbose:设置自带消息反馈
return req
#判断是否存活
def icmp_scan(ip_dst):
req = icmp_requset(ip_dst)
#判断是否响应包是否为空
if req:
type = req.getlayer('ICMP').fields['type']
print('[+]',ip_dst,':',type,' Host is up')
else:
pass
if __name__ == '__main__':
icmp_scan('10.35.68.1')
运行结果
[+] 10.35.68.1 : 0 Host is up
3.改进代码,加入扫描子网
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from scapy.all import *
import ipaddress
#ICMP请求,返回响应包
def icmp_requset(ip_dst,iface=None):
pkt = IP(dst=ip_dst)/ICMP(type=8) #ICMP类型为
req = sr1(pkt,timeout=2,verbose=False) #timeou:超时时间设置 verbose:设置自带消息反馈
return req
#判断是否存活
def icmp_scan(ip_dst):
req = icmp_requset(ip_dst)
#判断是否响应包是否为空
if req:
print('[+]',ip_dst,' Host is up')
else:
pass
def main(network):
#Windows**释掉这段
##判断是否为root
# if os.getuid() != 0:
# print('[-]Need root user to run')
# sys.exit(1)
network = list(ipaddress.ip_network(network))
for ip in network:
icmp_scan(ip)
if __name__ == '__main__':
main('10.35.68.0/24')
运行结果
[+] 10.35.68.1 : 0 Host is up
[+] 10.35.68.4 : 0 Host is up
[+] 10.35.68.8 : 0 Host is up
[+] 10.35.68.3 : 0 Host is up
[+] 10.35.68.9 : 0 Host is up
4.代码完善,加上参数选项和子网的识别
argparse
命令行选项模块
threading
多线程模块
#!/usr/bin/env python3
# -*- coding:utf-8 -*-
from scapy.all import IP,ICMP,sr1
import threading
import argparse
import ipaddress
import os
import sys
def icmp_requset(ip_dst,iface=None):
pkt = IP(dst=ip_dst,ttl=64)/ICMP(type=8)
req = sr1(pkt,timeout=3,verbose=False)
return req
def icmp_scan(ip_dst):
req = icmp_requset(ip_dst)
if req:
print('[+]',ip_dst,':',type,' Host is up')
else:
pass
def main():
#Windows中注释掉这段
##判断是否为root
# if os.getuid() != 0:
# print('[-]Need root user to run')
# sys.exit(1)
#命令行选项
parser = argparse.ArgumentParser()
parser.add_argument('network', help='eg:192.168.1.0/24')
args = parser.parse_args()
network = list(ipaddress.ip_network(args.network))
length = len(network)
threads = []
#多线程
for ip in network:
t = threading.Thread(target=icmp_scan,args=(str(ip),))
threads.append(t)
for i in range(length):
threads[i].start()
for i in range(length):
threads[i].join()
if __name__ == '__main__':
main()
运行演示