用python写渗透测试脚本 学习记录(四)
用python写渗透测试脚本——信息收集之基于两种协议的主机发现
这是本人第一次写博客,本人作为网络安全初学者,希望通过写博客的形式,记录、巩固、强化自己学习到的东西。同时希望在写博客的过程中能够发现自己的不足,逐渐提高自己。
本人在学习过程中主要参考书籍为《Python安全攻防——渗透测试指南》
渗透测试的过程主要分为:
- 明确目标
- 信息收集
- 漏洞检测
- 漏洞验证
- 信息分析
- 获取所需信息
- 清楚痕迹
- 撰写报告
最近的任务就是使用python完成第二项:信息收集
今天的实验内容是,基于ICMP和TCP协议的主机发现,主要思路为:向目标主机发送报文,若源主机收到响应数据包,则说明该主机处于活跃状态。
首先是使用ICMP协议,进行主机发现。首先向目标主机发送一个ICMP请求消息,若源主机收到目标主机的应答,则表示该主机存在。
# scapy用于发送ping请求和接受应答数据
# random 用于产生随机字段
# optparse用于生成命令行参数形式
from scapy.all import *
from random import randint
from optparse import OptionParser
# 对用户输入的参数进行批量处理,将处理好的IP地址传入scan函数
from scapy.layers.inet import IP, ICMP
def main():
#创建命令行解析器,参数Usage为:当程序运行不正确或具有帮助选项时,要打印的使用情况摘要。
parser = OptionParser("Usage:%prog -i <target host> ")
# add_option()函数,加入选项 type类型、dest存储的变量、help帮助信息
# 获取IP地址参数
parser.add_option('-i', type='string', dest='IP', help='specify target host')
# options,它是一个对象(optpars.Values),保存有命令行参数值。只要知道命令行参数名,就可以访问其对应的值。
# args,它是一个由 positional arguments 组成的列表。
options,args = parser.parse_args()
print("输入要扫描的IP地址为:" + options.IP + "\n")
# 判断输入输入是多台主机还是单台主机
# 若IP中含有'-'则说明扫描的是多态主机
if '-' in options.IP:
# IP地址示例:190.168.45.1-120
# options.IP.split('-')[0].split('.')[3] :将ip地址按照'-'切割成两段(190.168.45.1和120),将前半段(190.168.45.1)按照'.'切割,取切割后的第四段(1)
# options.IP.split('-')[1]: 将ip地址按照'-'切割成两段(190.168.45.1和120),取后半段
for i in range(int(options.IP.split('-')[0].split('.')[3]),int(options.IP.split('-')[1]) + 1):
new_IP = options.IP.split('.')[0] + '.' + options.IP.split('.')[1] + '.' + options.IP.split('.')[2] + '.' + str(i)
scan(new_IP)
# 每次扫描之后线程暂停0.2秒
time.sleep(0.2)
else:
scan(options.IP)
print("扫描结束!")
# 通过调用ICMP,将构造好的请求包发送到目的地址,并并根据目的地址的应答数据判断主机是否存活
def scan(ip):
#65535转化成16进制:FFFF
#定义数据包数据
ip_id = randint(1,65535)
icmp_id = randint(1,65535)
icmp_seq = randint(1,65535)
#构建数据包
packet = IP(dst = ip,ttl = 64,id = ip_id)/ICMP(id = icmp_id,seq = icmp_seq)/b'rootkit'
#发送数据包并接受返回数据
result = sr1(packet, timeout = 1,verbose = False)
#判断返回结果
if result :
for rcv in result:
scan_ip = rcv[IP].src
print(scan_ip + '--->' 'Host is up')
else:
print(ip + '--->' 'host is down')
#使用Nmap进行实现ICMP探测
def NmapScan(ip):
#实例化PortScanner
nm = nmap.PortScanner()
try:
#hosts为目标ip地址,argusments为Nmap扫描参数
#-sn:使用ping进行扫描
#-PE:使用ICMP的echo包
result = nm.scan(hosts = ip,arguments = '-sn -PE')
#对结果进行切片,提取主机状态信息
state = result['scan'][ip]['status']['state']
print("[{}] is [{}]".format(ip,state))
except Exception as e:
pass
if __name__ == '__main__':
try:
main()
except KeyboardInterrupt:
print("被用户中断,终止所有线程")
这是一个简单的发送数据包、接收数据包的工具,没有其他功能,所以我进行测试时,内网的主机都扫描不到,后来我想到这个探测方法和使用ping命令的 原理是相同的,所以我试着使用ping命令测试www.baidu.com,发现可以ping通,于是我使用获得的百度的ip地址进行测试,结果发现使用上述程序可以探测到目标主机(百度)。然后我又想到我可以先使用ping命令测试一下我内网的主机,预期结果是:应该ping不通。结果果然是这样。
对内网主机进行测试
对百度主机进行测试
后来查了好多资料,发现目前的很多网络设备都对ICMP采取了屏蔽策略,在某些时候,即使是源主机和目标主机处于同一局域网下,扫描结果也会不准确。
于是,我继续往下做实验:使用TCP协议进行主机探测。
大致原理为:向目标主机发送ACK数据包时,如果目标主机存活就返回一个RST数据包以终止这个不正常的TCP连接。
def scan_tcp(ip):
try:
#随机生成端口号
dport = random.randint(1,65535)
#构建TCP数据包
packet = IP(dst = ip)/TCP(flags = 'A',dport = dport)
#发送数据包,并接受返回数据
resp = sr1(packet,timeout = 1.0,verbose = 0)
if resp:
#判断flags是否为‘R’(其整型值为4)
if int(resp[TCP].flags) == 4:
time.sleep(0.5)
print(ip + ' ' + "is up")
else:
print(ip + ' ' + "is down")
else:
print(ip + ' ' + "is down")
except:
pass
将上一代码块中的探测方法改为scan_tcp即可使用。
然后我开始测试scan_tcp(),结果也是以失败告终,然后开始思考可能原因:
- 我第一个想到的原因是,端口号,我使用的是随机生成的端口号,所以无法保证目标主机确实开放了此端口。
- 。。。。然后我也没想到其他原因,
解决上述问题的办法我目前能想到的就是端口扫描,找到目标主机的开放端口,将随机生成的端口号改为目标主机的开放端口。
那么问题又来了,我既然都对目标主机开始进行端口扫描了,我为什么还要对他进行主机探测(≖͞_≖̥),,,,