向目标主机发送一个,没有开放的端口发送数据,目标主机会返回一个ICMP
目标端口不可达的消息,通过该特征可以对主机进行判断是否在线
注意事项
如果目标主机端口不在线,或者在线且目标端口为开放状态,那么发送出去的UDP数据包不会收到任何回复
判断条件
以返回包中的ip部分proto参数的值作为判断条件,确定目标主机是否返回ICMP消息,
原理是ip包头中的protocol部分用于标记上层协议类型,如果数值为0x01的话表示ICMP
代码部分
数据包构造扫描部分
通过python发包神器scapy构造UDP数据包
端口一定要选择没有开放的,不然会扫描不到主机
def scan(ip):
try: # 端口要求一定是没开放
packet = IP(dst=ip)/UDP(dport=56789)
result = sr1(packet,timeout=0.5,verbose=0)
#result.show()
if int(result[IP].proto) == 0x01: # 0x01 代表的ICMP字段值
time.sleep(0.1)
print(ip + ' ' + "on line")
except:
return
参数获取部分
通过optparse模块接收用户提供的参数,判断是扫描整个网段还是读取ip地址文件
获取到地址后再通过Thread多线程去发送数据包
def main():
# 生成帮助信息,以及接收用户输入的参数,并建立对象
usage = "Usage: arp扫描.py -f -i "
parse = OptionParser(usage=usage)
parse.add_option("-f", "--file", type="string", dest="filename", help="specify the IP address file")
parse.add_option("-i", '--ip', type="string", dest="address", help="specify the IP address")
(option, args) = parse.parse_args()
filename = option.filename
address = option.address
# 判断是不是地址文件
if filename:
if not os.path.exists(filename): #判断文件是否存在
print("The file does not exist. Please enter it again")
sys.exit()
with open(filename, "r") as f: #读取文件
for i in f.readlines():
ip = i.strip()
t = Thread(target=scan, args=(ip,))
t.start()
# 判断是不是整个网段
if address:
prefix = address.split(".")[0] + '.' + address.split(".")[1] + '.' + address.split(".")[2] + "." # 将用户输入的地址以.作为分隔符
for i in range(0, 255):
ip = prefix + str(i) #构造扫描整个网段所需ip
t = Thread(target=scan, args=(ip,))
t.start()
整体代码
import os
import time
from optparse import OptionParser
from scapy.all import *
def scan(ip):
try:
packet = IP(dst=ip)/UDP(dport=56789)
result = sr1(packet,timeout=0.5,verbose=0)
#result.show()
if int(result[IP].proto) == 0x01: # 0x01 代表的ICMP字段值
time.sleep(0.1)
print(ip + ' ' + "on line")
except:
return
def main():
# 生成帮助信息,以及接收用户输入的参数,并建立对象
usage = "Usage: arp扫描.py -f -i "
parse = OptionParser(usage=usage)
parse.add_option("-f", "--file", type="string", dest="filename", help="specify the IP address file")
parse.add_option("-i", '--ip', type="string", dest="address", help="specify the IP address")
(option, args) = parse.parse_args()
filename = option.filename
address = option.address
# 判断是不是地址文件
if filename:
if not os.path.exists(filename): #判断文件是否存在
print("The file does not exist. Please enter it again")
sys.exit()
with open(filename, "r") as f: #读取文件
for i in f.readlines():
ip = i.strip()
t = Thread(target=scan, args=(ip,))
t.start()
# 判断是不是整个网段
if address:
prefix = address.split(".")[0] + '.' + address.split(".")[1] + '.' + address.split(".")[2] + "." # 将用户输入的地址以.作为分隔符
for i in range(0, 255):
ip = prefix + str(i) #构造扫描整个网段所需ip
t = Thread(target=scan, args=(ip,))
t.start()
if __name__ == '__main__':
main()
运行效果