UDP 端口扫描
要对端口进行扫描需要先了解一下UDP协议的特征
1
UDP是无连接通信协议,即在数据传输时,数据的发送端和接收端不建立逻辑连接。简单来说,当一台计算机向另外一台计算机发送数据时,
发送端不会确认接收端是否存在,就会发出数据,同样接收端在收到数据时,也不会向发送端反馈是否收到数据。
1
2
由于使用UDP协议消耗资源小,通信效率高,所以通常都会用于音频、视频和普通数据的传输例如视频会议都使用UDP协议,
因为这种情况即使偶尔丢失一两个数据包,也不会对接收结果产生太大影响。
1
2
但是在使用UDP协议传送数据时,由于UDP的面向无连接性,不能保证数据的完整性,
因此在传输重要数据时不建议使用UDP协议。UDP传输数据被限制在64K以内。
1
2
问题记录
在使用scapy构建UDP数据包,调用多线程去发包没收到响应
1
解释器版本为
1
使用构造的UDP数据包去访问未开启UDP服务端口时,会返回ICMP端口不可达
1
靶机50-60端口范围只开放了53domain端口,理论来说在给这个区间的范围内发送UDP端口请求包,应该会收到9个ICMP端口不可达,然而实际只收到了6个响应,导致程序功能没有实现
1
初步怀疑是靶机防火墙可能存在过滤,打开靶机iptables -L 防火墙并没有出入站规则,但死活就是没有收到相应数量的ICMP端口不可达。
1
尝试添加防火墙出站策略,放行所有UDP,ICMP出站数据包,试试是不是防火墙的问题,再打开tcpdumo抓包
1
发现和防火墙一毛钱关系都没有,靶机只响应了6个ICMP端口不可达,剩下三个不知道为啥没响应,搜了一下发现一篇文章指出了问题,大致意思是缺少了某个函数。
1
看了解决问题的程序,奈何自己太垃圾是用其他语言写的,看不懂。开始怀疑自己的是不是对UDP协议理解有问题了,回翻看笔记找到了没收到ICMP不可达的原因,第一和第三都排除了,就剩第二了
1
上网搜了一下ICMP端口不可达响应速率,发现了一篇文章写了华为设备对icmp信息的relay速度有限制,目的就是为了防止被dos占用设备性能,造成正常服务无法工作。然后再翻了一下自己路由器看到了一个熟悉的菊花logo。
1
莫名有了种想砸路由器的冲动。回归正题,找到问题所在了就可以通过修改代码来解决问题了。
1
四层主机端口发现
四层发现指利用OSI中的传输层协议进行主机发现,一般使用TCP、UDP探测。
1
优点:
1、可以探测远程主机;
2、比三层发现更为可靠
1
2
3
缺点:花费时间更长,可能被防火墙过滤
1
探测目标主机是否开放
向目标主机的相应端口发送UDP数据包,如果没有返回回复,则证明这个端口是开放
1
需要注意的是这点是利用了ICMP不可达的原理,如果目标主机不在线那么也没有返回消息,导致误判,所以要求目标主机必须在线
1
数据包构造
1
result = sr1(IP(dst="192.168.3.107")/UDP(dport=53),timeout=1,verbose=0)
1
最常用的udp端口为53DNS服务
1
代码部分
扫描模块
功能
1
接收主函数传过来的IP,端口构造UDP数据包
1
向端口批量发送数据包,并利用是否有返回消息判断端口是否在线
1
def scan(ip, port):
try:
packet = IP(dst=ip)/UDP(dport=port,sport=randint(1,65535))
result = sr1(packet,timeout=5,verbose=0) # timeout=5 为数据包提供五秒等待时间,如果没有回复就放弃,verbose=0,不显示输出
)
if result is None:
print(port)
except:
print("send error")
主函数
功能
接收用户输入的参数
1
判断用户输入的端口是单个还是端口范围
1
如果是端口范围,将起始端口和结束端口for循环进行遍历生成需要扫描的端口
1
def main():
parser = OptionParser("Usage: targetIP start_Port end_port ") # 输出帮助信息
("-i", '--host',type="string", dest="tgtIP",help="specify target host website") # 获取ip地址
("-p", '--port',type="string", dest="hostport",help="specify target host singleport") # 获取单个端口
("-s", '--start',type="string", dest="startport",help="specify target host start_port") # 获取结束端口
("-e", '--end',type="string", dest="endport",help="specify target host end port") # 获取起始端口
options,args= () #实例化用户输入的参数
# 为用户输入的参数建立对象
ip = o
singleport = in)
start = o
end = o
# 如果是单端口要执行的操作
if singleport:
port = singleport
scan(ip,port)
# 如果是端口区间则多线程扫描
if start and end:
start = int(start)
end = int(end)
for p in range(start,end):
port = int(p)
t = Thread(target=scan,args=(ip,port))
t.start()
(1)
完整代码
from random import randint
from time import sleep
from optparse import OptionParser
from import *
def scan(ip, port):
try:
packet = IP(dst=ip)/UDP(dport=port,sport=randint(1,65535)) # 随机src端口,让扫面不易被察觉
result = sr1(packet,timeout=5,verbose=0) # timeout=5 为数据包提供五秒等待时间,如果没有回复就放弃,verbose=0,不显示输出
)
if result is None:
print(ip, port,'is open')
except:
print("send error")
def main():
parser = OptionParser("Usage: targetIP start_Port end_port ") #输出帮助信息
("-i", '--host',type="string", dest="tgtIP",help="specify target host website") # 获取ip地址
("-p", '--port',type="string", dest="hostport",help="specify target host singleport") # 获取单个端口
("-s", '--start',type="string", dest="startport",help="specify target host start_port") # 获取起始端口
("-e", '--end',type="string", dest="endport",help="specify target host end port") #获取结束端口
options,args = () # 实例化用户输入的参数
ip = o
singleport = o
start = o
end = o
# 如果是单端口则执行的操作
if singleport:
port = int(singleport)
scan(ip,port)
# 如果是端口区间则调用多线程去扫描
if start and end:
start = int(start)
end = int(end)
for p in range(start,end):
port = int(p)
t = Thread(target=scan,args=(ip,port))
t.start()
(1)
if __name__ == "__main__":
main()
if __name__ == '__main__':
main()