0x01应用背景
安全服务的工作,日常扫扫扫、日常的工作一次性让人扫描多个网段,经验充足的老师傅会使用xml转excel,但是新入门的安服小伙伴们,是否也经历过一段手工一个个整理的时期呢,我是的。后来,随着需求的复杂化,输出的形式也各种各样,不得不使整个过程自动化,不然真的会做到我是谁我在哪我在做什么,所以本文我用以下三种场景,由最初简单的需求到最终复杂化的,step by step教大家如何将python和安服结合在一起,为自己节省更多的时间和体力,并投入时间到学习中,有效地增值自己。
需求1为扫描地址211.191.233.175的21,22,23,25,443,80,8080是否开放,按ip地址-端口-状态-服务整理成excel。
需求2为扫描地址A部门211.191.233.0-211.191.235.0和B部门21.1.1.0-21.1.3.0两个地址段(实际有100多个部门,平均每个部门有十来个地址段)的21,22,23,25,443,80,8080是否开放,按每个部门整理成一个excel(也就是要整理100多个excel,手工做真的夭寿了)格式是ip地址-端口-状态-服务。
需求3为excel里面已经给出了各单位部门和起始的IP和终止的IP,需要扫描excel所有地址段,(实际有100多个部门,平均每个部门有十来个地址段)的21,22,23,25,443,80,8080是否开放,按每个部门整理成一个excel,大概要整理100多次,一次7个端口
0x02 文章结构简介
扫描需求与nmap参数
前言
需求1介绍与应用脚本编写
需求2介绍与应用脚本编写
需求3介绍与应用脚本编写
延伸—扫描效率优化
0x03扫描需求与nmap参数
前言:
本文相关的ip地址已经替换过个别数字进行脱敏处理,所以本文中出现过的ip不合理或者扫不到也是正常的。
在很久以前我还是一个渗透实习生,那时候还需要兼做挺多一些安全服务的工作,做下扫描、整理下报告。第一次的时候任务是这样的,需要我一次性扫描十几个ip地址段然后整理成 ip地址-端口-状态-服务 格式一一对应地用excel整理出来。这个第一次做的时候我真的手工一个一个去整理出来,手工做了整整一天。
附版式图(已替换个别数字脱敏)
后来学会了python,一秒出结果了。
现成的工具网上有一个xml转xls,但是在长期的扫描过程这种方式不算很方便。
如果我扫描命令是nmap -n -Pn -v 8.8.8.8 >result.txt 输出将会重定向到一个txt文件,扫描到一半的时候还可以打开txt来看扫描的进度等等。本文就是基于输出重定向的结果进行结果处理。
前期准备
1.地址段需要准确,比如要扫192.168.1.0到192.168.2.255;需要整理成192.168.1-2.0-255这种格式,(excel直接复制下来可能会出现"和空格个别有些未换行,需要检查整理替换一下)
2.nmap.exe添加到环境变量
3.python2.74.python安装模块xlwt(pip install xlwt)
5.运行时命令:python pl-nmscan.py + 地址段txt的所在文件夹路径
需求1:
需求为扫描地址211.191.233.175的21,22,23,25,443,80,8080是否开放,按ip地址-端口-状态-服务整理成excel。
由需求得知,需要知道指定端口是否开放即可了。所以对应扫描参数如下:
nmap-n -Pn -p 21,22,23,25,443,80,8080 211.191.233.175 >result.txt
-n是不做地址解析
-Pn是绕过防火墙探测端口(结果更准确一点)
-p是指定端口
>result.txt是指定输出的文件和路径
扫描的结果大致如下
使用(下章节我会附上代码)工具后,会在当前目录下输出一个excel。
命令是:pythonF:\cybersec\poc\Selftools\myPythontools\nmapScan.pyC:\Users\lenovo\Desktop\result.txt
输出结果是这样的:(ip已替换数字脱敏处理)
所以可以发现上面txt中端口是开放的地址,都被输出到这个excel里面。
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# made by 3s_NwGeekimport xlwt,re,sys,osclass FILE:def __init__(self, FILEPATH):self.filepath=FILEPATH #文件完整路径self.filename = (FILEPATH.split("\\")[-1]) # 有后缀文件名self.dirpath = FILEPATH.replace(self.filename,"") # 文件所在文件夹路径self.filename_noformat = self.filename.split(".")[0] # 无后缀文件名self.fileformat = "." + self.filename.split(".")[-1] # 文件名后缀def rename(self,NEWNAME):
newname = self.dirpath + NEWNAME + self.fileformat #文件重命名新路经os.rename(self.filepath,newname)def copy(self,targpath):
os.system("copy %s %s" % (self.filepath, targpath))if __name__ == '__main__':print "usage:nmapScan.pyC:\\Users\\PortResult.txt"f=FILE(sys.argv[1])
items=open(sys.argv[1],"r+").read().splitlines() #读取txt
line=0file = xlwt.Workbook(encoding = 'utf-8')
table = file.add_sheet('NmapResult')
table.col(0).width=220*20vaule=['ip地址','端口','状态','协议'] #写入excel首行for columnin range(0,len(vaule)):
table.write(0,column, vaule[column])for item in items: #每行往下读取扫描结果if "Nmap" in item :
ip=item.replace("Nmap scan report for ","")#获取ipif "open" in item : #获取ip对应的端口if "Discovered" not in item:
result=ip+" "+item
line=line+1vaule= re.sub(r"\s{2,}","",result).split(" ")#nmap扫描结果bug有时候会有多个空格,使用正则多个空格替换成一个for column in range(0,4): #写入结果
table.write(line,column,vaule[column])
p=f.dirpath+'NmapReport.xls'file.save(p)
使用方法如下
usage:nmapScan.py C:\\Users\\PortResult.txt
需求2:
需求为扫描地址A部门211.191.233.0-211.191.235.0和B部门21.1.1.0-21.1.3.0两个地址段(实际有50多个部门,每个部门有十来个地址段)的21,22,23,25,443,80,8080是否开放,按每个部门整理成一个excel(也就是要整理50多个excel,手工做真的夭寿了)格式是ip地址-端口-状态-服务。
由需求得知,需要知道指定地址段中的ip端口是否开放即可了。所以对应扫描参数如下:
每个部门的扫描参数命令是:
nmap -n -Pn -iL A单位.txt -p 21,22,23,25,443,80,8080 >A单位result.txt
-iL是按每行读取字典作为扫描目标
因为涉及多个地址段,所以需要把资产地址段保存为txt文件进行读取,而且有规定的格式。所以ip地址段的格式比如说是这样的211.191.233.0-211.191.235.0这样nmap不能识别,所以正确写法要改成这样的211.191.233-235.0-255
然后使用python用个for循环调用nmap每个单位扫一次就可以了,再使用需求1的脚本循环输出即可。
扫描前的准备txt
脚本运行如下图:
Python nmap_scan_pl.py 所有txt文件所在的文件夹路径
输出结果有多个excel,一个部门一个excel,每个都是这样的(ip已脱敏)
使用python编写脚本如下
#!/usr/bin/python
# -*- coding: UTF-8 -*-
# made by 3s_NwGeekimport xlwt,re,glob,os,sysclass FILE:def __init__(self, FILEPATH):self.filepath=FILEPATH #文件完整路径self.filename = (FILEPATH.split("\\")[-1]) # 有后缀文件名self.dirpath = FILEPATH.replace(self.filename, "") # 文件所在文件夹路径def main(paths):
f=FILE(paths)
items=open(paths,"r+").read().splitlines()# items=open("C:\Users\lenovo\Desktop\\1.txt","r+").read().splitlines()line=0file = xlwt.Workbook(encoding = 'utf-8') # 注意这里的Workbook首字母是大写table = file.add_sheet('NmapResult') #新建一个sheettable.col(0).width=220*20vaule=['ip地址','端口','状态','协议号']for column in range(0, 4):
table.write(line, column, vaule[column])for item in items:if "Nmap" in item :if "Discovered" not in item:
ip=item.replace("Nmap scan report for ","")if "open" in item :if "Discovered" not in item:
result=ip+" "+item
line=line+1vaule= re.sub(r"\s{2,}"," ",result).split(" ")for column in range(0,6):try:
table.write(line,column,vaule[column])except:passsavepath = path + '\\scan_result'try:
os.mkdir(savepath)except:passfile.save(r'%s.xls'%(savepath+'\\'+f.filename_noformat))print "done"def cmdgen (paths):#命令生成cmd=[]
savepath=path+'\\nmap_result'try:
os.mkdir(savepath)except:pass
for filepath in glob.glob(paths):#读取所有资产准备生成命令.txtf=FILE(filepath)
cmd.append('nmap -v -n -Pn -p 80,8080,443 -iL %s > %s'%(f.filepath,savepath+'\\'+f.filename))#生成命令数组return cmddef excute(cmd): #调用nmap函数for c in cmd:print 'scaning :%s\nwait..'%c
res = str(os.popen(c).read()) #读取回显print resdef resoutput():
nmap_resultpath=path+'\\nmap_result\*.txt'for filepath in glob.glob(nmap_resultpath):#读取所有扫描结果main(filepath)#输出if __name__ == '__main__':if len(sys.argv) <2:
usage = "\n####################################\nusage: python nmap_Scans_output.py C:\\\\Desktop\\dir\\\n文件夹是扫描的地址段\n####################################"print usage
sys.exit()
path=sys.argv[1]
tpath=path+'\*.txt' #拼接扫描路径cmd=cmdgen(tpath)#生成扫描命令参数
excute(cmd) #调用nmap扫描
resoutput() #输出nmap结果
需求3:
需求为excel里面已经给出了单位部门和起始的IP和终止的IP,需要扫描excel所有地址段,(这次实际有100多个部门,每个部门有十来个地址段)的21,22,23,25,443,80,8080是否开放,按每个部门整理成一个excel,也是一个很要命的需求了如果手工做的话。(IP已做替换数字脱敏处理,所以出现了255以上的数字)
我是这样处理的,先把每行excel读取下来,处理成一数组,然后数组的第二第三位是起始和终止ip,整理为nmap扫描的格式,然后每个部门分类生成一个扫描的txt,使用python用for循环调用nmap去扫描生成txt的结果,然后使用需求1的脚本去生成扫描结果excel。最终实现从运行脚本到扫描最后输出结果,一键完成。
结果生成100多个端口扫描结果的excel。
是在2基础上增加个读取excel整理成多个txt。读取excel并整理成nmap扫描格式代码如下,新增了一个函数,其余的跟需求2一样,就不冗余粘贴了,贴出了新增函数的代码。
不过值得注意的是:
按之前给出来的nmap格式扫描会出现问题,比如说要扫192.1.1.20到192.1.2.21的地址。如果拼接成192.1.1-2.20-21,那么nmap扫描的就只有4个地址:
分别是192.1.1.20、192.1.1.21、192.1.2.20、192.1.2.21
所以以下代码已经做好了调整,自动生成为
192.1.1.20-255
192.1.2.0-21
所以使用本函数是可以正常进行扫描的
defip_xls(filename):
data = xlrd.open_workbook(filename)
table = data.sheets()[0]
nrows = table.nrows # 获取该sheet中的有效行数ncols = table.ncols # 获取列表的有效列数for num in range(1, nrows): #循环次数row = table.row_values(num)# print rowstart_ip=row[2].encode("unicode_escape").replace(' ','').split('.')
stop_ip = row[3].encode("unicode_escape").replace(' ','').split('.')
c_start_ip=start_ip[2]
d_start_ip=start_ip[3]
c_stop_ip=stop_ip[2]
d_stop_ip=stop_ip[3].replace('\n','')
department=row[1]+row[5].replace('\n','')
f = codecs.open('%s.txt' % (path+'\\'+department), 'a','utf-8')if start_ip[0] == stop_ip[0] and start_ip[1] ==stop_ip[1] and c_start_ip == c_stop_ip: #192.168.1.0-99if int(d_start_ip) <= int(d_stop_ip) :
nmapip = (start_ip[0]+'.'+start_ip[1]+'.'+c_start_ip+'.'+d_start_ip+'-'+d_stop_ip).replace('\\n','')
output= nmapip.replace('\n','')
f.write(output+'\n')elif start_ip[0] == stop_ip[0] and start_ip[1] ==stop_ip[1] and int(c_start_ip) <int(c_stop_ip): ##192.168.1-3.0-99if int(c_stop_ip)-int(c_start_ip)>1:
nmapip = start_ip[0]+'.'+start_ip[1]+'.'+c_start_ip+'.'+d_start_ip+'-'+'254' ##192.168.1.9-255output= nmapip.replace('\n','')
f.write(output+'\n')
nmapip = (start_ip[0] + '.' + start_ip[1] +'.' + str(int(c_start_ip) + 1) + '-' +str(int(c_stop_ip) - 1) +'.' + '1' + '-' + '254').replace('--','-') ##192.168.2.0-255output= nmapip.replace('\n','')
f.write(output+'\n')
nmapip = start_ip[0]+'.'+start_ip[1]+'.'+c_stop_ip+'.'+'0'+'-'+d_stop_ip ##192.168.3.0-99output= nmapip.replace('\n','')
f.write(output+'\n')else:print '\n\nerror for start_ip:%s - stop_ip:%s'%(row[2],row[3])print '\n\n IP format success!!\n\nbegin scanning:'
输出多个结果:
每个部门输出格式:
0x04延伸—扫描效率优化
经过长期扫描经验总结,个人觉得有多个可以提高扫描效率的地方。所以写了个扫描器进行端口扫描。
我一般进行nmap扫描的参数是这样的:
nmap -v -Pn -n -p21,22,23,3389,161,443,445,3306,1521,5901,1143,5900,80,7001,8000-8080,2181,111,11211--max-retries 2 --initial-rtt-timeout 5 --min-hostgroup50 --min-parallelism 50 -iL target.txt >PortResult.txt
但是我觉得nmap已经满足不了我的效率要求了,就算加了以上几个参数。
因为长期比较多需求是做全端口的扫描,会发现nmap的全端口扫描实在是太慢了,有一次任务扫800多个ip的全端口,整整扫了一个月才扫完,因为nmap多了比较多的判断,不只是在单纯地判断端口是否开放。所以,python可以帮到你,使用socket快速判断端口是否开放。
个人觉得可以从多方面进行优化
使用有线网络的时候超时时间可以缩短到5秒,无线的话需要10秒才能比较准确。
多线程与多协程
逻辑上的优化,比较少的服务器是单单开放20000端口到30000端口以上的。所以我们可以从端口1扫到20000端口然后判断是否有开放的端口,没有开放的端口就不继续扫下去,有开放的端口继续扫下去,那么可以算出来,使用了这个逻辑判断就可以提高了35535/65535也就是提升大概二分之一的效率了,如果觉得20000个端口不够保险,那可以改成30000或者到40000,再继续扫,那也提高了很可观的效率。
最后:重磅消息,我们字节脉搏为了上线与众位大佬交流,积极准备了上千份礼物,将于两周内开始举办活动,具体时间呢还未定,因为某一些奖品还没到,请大家敬请期待,同时扫一下关注我们吧!第一时间参加活动