工作過程中經常遇到客戶讓對大量資產開放的端口以及服務進行統計,於是乎就寫了個nmap 導出xml批量處理腳本。
腳本基本功能:
- 提取IP,端口 以及端口對應的服務
- 將結果導出至Excel( xlsx)
- 支持批量xml處理
包依賴
-
xlsxwriter
-
安裝
pip install xlsxwriter
Python代碼
好久沒用過XML解析了,有點生疏
# -*- coding: utf-8 -*-
"""
@author:隨時靜聽
@file: parserXML.py
@time: 2018/08/23
@email:wang_di@topsec.com.cn
"""
# http://blog.51cto.com/maoyao/1772102
# https://xlsxwriter.readthedocs.io/format.html
import re
try:
import xml.etree.cElementTree as ET
except:
import xml.etree.ElementTree as ET
import glob
import os
import time
# import xlwt
import xlsxwriter
import argparse
from multiprocessing import Process,Pool,Lock
XMLPATH='report'
DEFAULT_STYLE={
'font_size': 12, # 字體大小
'bold': False, # 是否粗體
# 'bg_color': '#101010', # 表格背景顏色
'font_color': 'black', # 字體顏色
'align': 'left', # 居中對齊
'valign':'vcenter',
'font_name':'Courier New',
'top': 2, # 上邊框
# 后面參數是線條寬度
'left': 2, # 左邊框
'right': 2, # 右邊框
'bottom': 2 # 底邊框
}
TITLE=[
(u'序號',8),
('IP',22),
(u'端口',10),
(u'服務',18),
(u'開放狀態',15),
]
#獲取寫入格式
def get_style(default=DEFAULT_STYLE,**kw):
return default.update(**kw)
def parseNmap(filename):
try:
tree=ET.parse(filename)
root=tree.getroot()
except Exception as e:
print e
return {}
data_lst=[]
for host in root.iter('host'):
if host.find('status').get('state') == 'down':
continue
address=host.find('address').get('addr',None)
# print address
if not address:
continue
ports=[]
for port in host.iter('port'):
state=port.find('state').get('state','')
port_num= port.get('portid',None)
serv=port.find('service')
serv= serv.get('name','') if serv is not None else ""
# print serv
ports.append([port_num,serv,state])
data_lst.append({address:ports})
# return {address:ports}
return data_lst
def reportEXCEL(filename,datalst,title=TITLE,style=DEFAULT_STYLE,**kwargs):
if not datalst:
return ''
if os.path.exists(filename):
print u"%s 文件已經存在" % filename
path,name=os.path.split(filename)
filename=os.path.splitext(name)[0]
filename=filename+str(time.strftime("%Y%m%d%H%M%S",time.localtime()))+'.xlsx'
filename=os.path.join(path,filename)
print 'data will save as new file named :%s ' % filename
book=xlsxwriter.Workbook(filename)
title_style= style if not kwargs.get('title',None) else kwargs.get('title')
row_hight=[20,16] if not kwargs.get('row_set',None) else kwargs.get('row_set') #標題題和常規的高度
# col_width=[8,22] if not kwargs.get('col_set',None) else kwargs.get('col_set') #序號,其他寬度
sheet_name= 'sheet' if not kwargs.get('sheet_name',None) else kwargs.get('sheet_name')
sheet=book.add_worksheet(sheet_name)
row_hight=row_hight+(2000-len(row_hight))*[row_hight[-1]]
for row , h in enumerate(row_hight):
sheet.set_row(row,h)
col_width=map(lambda x:x[1],title)
for col , w in enumerate(col_width):
sheet.set_column(col,col,w)
title_style = book.add_format(title_style)
for index,t in enumerate(title):
sheet.write(0,index,t[0],title_style)
row=1
col=0
style=book.add_format(style)
index2=0
for index,item in enumerate(datalst):
# print item
for ip,ports in item.items():
port_num=len(ports)
if not ports:
continue
index2=index2+1
for i,data in enumerate(ports):
sheet.write(row,2,data[0],style)
sheet.write(row,3,data[1],style)
sheet.write(row,4,data[2],style)
row = row + 1
if row-port_num+1 != row:
sheet.merge_range('B'+str(row-port_num+1)+':B'+str(row),ip,style)
sheet.merge_range('A'+str(row-port_num+1)+':A'+str(row),index2,style)
else:
# print index2
sheet.write(row-1,0,index2,style)
sheet.write(row-1,1,ip,style)
print 'Reprot result of xml parser to file: %s' % filename
book.close()
def main(XMLPATH,REPORTFILENAME):
data_lst=[]
for xml in get_xml(XMLPATH):
data=parseNmap(xml)
if data:
data_lst.extend(data)
# print data
reportEXCEL(REPORTFILENAME,data_lst)
if __name__ == '__main__':
import sys
if len(sys.argv)<3:
print '[!] Usage: parserXML.py XMLPATH [reportfilename]'
print '[!] Demo: parserXML.py xmldir result.xlsx'
else:
XMLPATH=sys.argv[1]
REPORTFILENAME = sys.argv[2]
print '[-] set parser XML file dir: %s' % XMLPATH
print '[-] set report Excel file name: %s' % REPORTFILENAME
if not os.path.exists(XMLPATH):
print "[!] '%s' path does not exists!" % XMLPATH
exit(1)
main(XMLPATH,REPORTFILENAME)
pass
只放代碼不教使用就是在耍流氓,接下來,如何在命令行使用
新建getResult.bat
@echo off
python "%~dp0\parser_nmap_xml_2_excel.py" %1 %2 %3 %4 %5 %6 %7 %8 %9
注意:我這里腳本名稱是arser_nmap_xml_2_excel.py,你換成你的名稱,就是你復制上面python代碼放的那個文件的名字
將腳本和getResult.bat放在一個固定額路徑下,並將這個路徑加入環境變量中:
//在控制台就可以直接使用了
getResult 存放xml的文件夾 導出xlsx文件名
效果圖
