背景:
客户爸爸最近突然要求我对公司所有IP进行一次操作系统识别的扫描。听起来这个要求并无过分,然而却有以下难点:
1、客户爸爸不能提供具体要扫描的IP地址,只能提供整个IP规划。甚至连一个EXCEL表格的子网都无法提供,仅仅丢了一个用于分配子网的某应用系统给我。(客户爸爸连自己的网内终端的操作系统都搞不清楚,资产识别这方面的管理可见一斑,更别指望提供别的了。)
2、客户爸爸提供的子网规划异常混乱,里面既有32位掩码、30位掩码的设备用IP,也有16位、15位、13位掩码的海量IP池。体现不出明显的包含关系,需要自己去梳理判断。
3、客户爸爸的体量超乎想象,全国各地都有它的组织,19到24位掩码之间的子网都有400多个。折合IP能有几十万。
4、客户爸爸不接受一个报告,必须每一个组织一个报告,方便他们阅读并发放给对应组织。
分析:
1、子网梳理:经过分析发现,客户爸爸的子网掩码在19到24位间是分配给具体的组织的(分子公司、项目组、商业体等)。那么我需要先去掉表格(自己导出的)中的类似16位、15位掩码的大区子网,去掉类似30位、32位的特殊设备(如路由器、VPN)等使用的子网。最终保留一个子网对应组织的关系。原始表如下图(乱)。
2、操作系统识别方法:用天镜、Nessus等扫描器都可以,然而他们输出的报告都太臃肿无法满足客户的需要,杀鸡焉用牛刀?况且要在扫描器上创建400多个任务,然后再导出400多份报告也太痛苦了(当然可以使用爬虫自动化,但也无比麻烦)。那么最好的选择无疑是Python的Nmap模块了。
3、输出报告设计:
1)每个子网一个报告,报告以子网所在的组织命名
2)报告只显示3列,IP、开放端口、操作系统
代码实现:
代码部分分两个文件,一个用于处理子网,另一个用于nmap识别操作系统并输出报告。
子网处理代码把ip.xls的文件经过处理后输出到new_ip.xls,如下:
import xlrd #读excel模块
import xlwt #写excel模块
def read_excel(excel_name,sheetname):
# 打开Excel文件
wb = xlrd.open_workbook(excel_name)
sheet = wb.sheet_by_name(sheetname)
dic = {}
# 把第2列作为字典的键,一行数据保存为列表,作为字典的值。列表中也包含第一列的值哦
for i in range(sheet.nrows-1):
lis = []
for j in range(sheet.ncols):
lis.append(sheet.cell(i+1,j).value)
dic[sheet.cell(i+1,1).value] = lis
find_and_delete(dic)
def find_and_delete(dic):
for k in list(dic.keys()): #这里一定要遍历列表,如果遍历字典就会报错,原因是字典在遍历过程中不能pop
if '/30' in str(k) or '/32' in str(k) or '/15' in str(k) or '/16' in str(k) or '/17' in str(k):
dic.pop(k)
write_excel(dic)
def write_excel(dic):
book = xlwt.Workbook(encoding='utf-8', style_compression=0) #创建对象
sheet = book.add_sheet('Subnets', cell_overwrite_ok=True)
x = -1 #单元格x坐标
for i in dic.keys():
x += 1
y = 0 #单元格y坐标
for j in dic[i]: #列表中的元素就是单元格的值
sheet.write(x, y, j)
y += 1
book.save('new_ip.xls')
if __name__=='__main__':
read_excel('ip.xls','Subnets')
Namp识别操作系统并输出报告代码如下:
import nmap
import xlrd #读excel模块
import xlwt #写excel模块
#import threading
# 逐行读取表里的内容,提取子网和对应的分公司名,子网用于扫描,分公司名作为扫描报告的文件名
def get_subnets(excel_name,sheetname):
wb = xlrd.open_workbook(excel_name) # 打开excel文件创建对象
sheet = wb.sheet_by_name(sheetname) # 获取表内容
for i in range(sheet.nrows): # 遍历所有的行
lis = [] #创建空列表用于保存子网和公司名
# threading_list=[]
for j in range(1, 3): # 每行只遍历第2列和第3列的内容,也就是子网和分公司名
lis.append(sheet.cell(i + 1, j).value) # 将每行2列、3列的内容作为元素添加到列表(+1是为了去掉首行)
network = lis[0]
company = lis[1]
print(network, company)
# for x in range(0, 11):
# th = threading.Thread(target=nmap_scan, args=(network,company,))
# threading_list.append(th)
# for t in threading_list:
# t.start()
# for t in threading_list:
# t.join()
nmap_scan(network,company)
# namp扫描并将结果输出到excel表中作为报告
def nmap_scan(network,company):
excel_name=company.replace('/','_')+'.xls' # 将‘/’替换成‘_’,否则不能作为文件名
#创建excel对象以及先将首行写好
book = xlwt.Workbook(encoding='utf-8', style_compression=0) # 创建对象
sheet = book.add_sheet('os', cell_overwrite_ok=True)
style = xlwt.XFStyle() # 初始化样式
font = xlwt.Font() # 为样式创建字体
font.name = 'Times New Roman'
font.bold = True # 黑体
style.font = font # 设定样式
sheet.write(0, 0, 'IP', style) # 首行第一列
sheet.write(0, 1, '开放端口', style) # 首行第二列
sheet.write(0, 2, '操作系统', style) # 首行第三列
x = 0 # 行数计数器
#nmap扫描并获取ip、端口、操作系统
nm=nmap.PortScanner() #实例化
os_scan=nm.scan(hosts=network,arguments='-sS -O --open') # nmap使用的关键参数
os_scan_d1=os_scan['scan'] # 取结果的scan键的值(对我这个任务来说有用的信息在这里)
for v in os_scan_d1.values():
x+=1 #行数计数器,用于后面写入excel
ip = v['addresses']['ipv4'] # 取IP
try:
os = v['osmatch'][0]['name'] # 取操作系统类型,因为有些识别不到操作系统,所以用了try避免报错程序结束
except:
pass
portlist = [] #取端口的空列表
for p in v['tcp'].keys():
portlist.append(str(p)) #将每个端口都加到列表中
ports = ','.join(portlist) #将列表中的所有元素以‘,’号连接成一个字符串,用于写入excel(因为单元格不能写列表)
#print(ip, ports, os)
#以下将nmap的结果ip, ports, os写入excel表
sheet.write(x, 0, ip)
sheet.write(x, 1, ports)
sheet.write(x, 2, os)
sheet.col(0).width = 4000 #第1列宽度
sheet.col(1).width = 8000
sheet.col(2).width = 10000
book.save(excel_name) #保存为以分公司名命名的excel文件
if __name__=="__main__":
get_subnets('new_ip.xls','Subnets') #传入的是excel名和表名
最终结果: