使用 Nmap 对大规模局域网收集 MAC 地址
参考资料
https://github.com/materaj/nmap-parser-xml-to-csv
https://github.com/RASSec/NMAP_INTERFACE
正文
对大规模局域网收集 MAC 地址
Nmap 6 Network Exploration and Security Auditing
nmap -vvv -n -sn -PR -oX arp_info.xml 192.168.1.254/24
nmap -vvv -n -O --osscan-guess -oX os_info.xml 192.168.1.254/24
解析脚本
Python Parse 脚本
nmap-parser-xml-to-csv.py
# -*- coding:utf-8 -*-
# !/usr/bin/env python
# Slightly modified by BLKStone
# @Time : 2018/8/23 14:31
# Original Info
__description__ = 'nmap xml script output parser'
__author__ = 'Didier Stevens, modify by Sumedt Jitpukdebodin'
__version__ = '0.2'
__date__ = '2014/04/30'
import optparse
import xml.dom.minidom
import glob
import collections
QUOTE = '"'
def ToString(value):
if type(value) == type(''):
return value
else:
return str(value)
def Quote(value, separator, quote):
value = ToString(value)
if separator in value:
return quote + value + quote
else:
return value
def MakeCSVLine(row, separator, quote):
return separator.join([Quote(value, separator, quote) for value in row])
class cOutput():
def __init__(self, filename=None):
self.filename = filename
if self.filename and self.filename != '':
self.f = open(self.filename, 'w')
else:
self.f = None
def Line(self, line):
if self.f:
self.f.write(line + '\n')
else:
print(line)
def Close(self):
if self.f:
self.f.close()
self.f = None
class cOutputCSV():
def __init__(self, options):
if options.output:
self.oOutput = cOutput(options.output)
else:
self.oOutput = cOutput()
self.options = options
def Row(self, row):
self.oOutput.Line(MakeCSVLine(row, self.options.separator, QUOTE))
def Close(self):
self.oOutput.Close()
def NmapXmlParser(filenames, options):
oOuput = cOutputCSV(options)
# oOuput.Row(['Start Time', 'End time', 'address', 'vendor', 'hostname', 'port',
# 'state', 'service', 'script', 'output'])
oOuput.Row(['Start Time','End time','address','mac_address','vendor','hostname', 'port',
'state', 'service', 'script', 'output'])
for filename in filenames:
domNmap = xml.dom.minidom.parse(open(filename, 'r'))
# Add start date
nmap_header = domNmap.getElementsByTagName('nmaprun')
date = [nmap_header[0].getAttribute('startstr')]
# Add end date
nmap_footer = domNmap.getElementsByTagName('runstats')
enddate = [enddate.getAttribute('timestr') for enddate in nmap_footer[0].getElementsByTagName('finished')]
# for hosttag in domNmap.getElementsByTagName('host'):
# row = [str(date)]
# addresses = [address.getAttribute('addr') for address in hosttag.getElementsByTagName('address') if
# address.getAttribute('addrtype') == 'ipv4']
for hosttag in domNmap.getElementsByTagName('host'):
for port in hosttag.getElementsByTagName('port'):
scriptFound = False
# 获取信息
addresses = [address.getAttribute('addr') for address in hosttag.getElementsByTagName('address') if
address.getAttribute('addrtype') == 'ipv4']
mac_addresses = [address.getAttribute('addr') for address in hosttag.getElementsByTagName('address') if
address.getAttribute('addrtype') == 'mac']
vendors = [address.getAttribute('vendor') for address in hosttag.getElementsByTagName('address') if
address.getAttribute('addrtype') == 'mac']
### Remove all hostname(user,ptr) to be just user type only.
# hostnames = [hostname.getAttribute('name') for hostname in hosttag.getElementsByTagName('hostname')]
hostnames = [hostname.getAttribute('name') for hostname in
hosttag.getElementsByTagName('hostname')] # if hostname.getAttribute('type') == 'user']
row = ['|'.join(date)]
row.append('|'.join(enddate))
row.append('|'.join(addresses))
row.append('|'.join(mac_addresses))
row.append('|'.join(vendors))
row.append('|'.join(hostnames))
row.append(port.getAttribute('portid'))
for state in port.getElementsByTagName('state'):
row.append(state.getAttribute('state'))
for service in port.getElementsByTagName('service'):
row.append(service.getAttribute('name'))
if hosttag.getElementsByTagName('script'):
scriptFound = True
for script in hosttag.getElementsByTagName('script'):
row.append(script.getAttribute('id'))
row.append(repr(script.getAttribute('output').encode('ascii').replace('\n ', '')))
# print(row)
oOuput.Row(row)
oOuput.Close()
def File2Strings(filename):
try:
f = open(filename, 'r')
except:
return None
try:
return map(lambda line: line.rstrip('\n'), f.readlines())
except:
return None
finally:
f.close()
def ProcessAt(argument):
if argument.startswith('@'):
strings = File2Strings(argument[1:])
if strings == None:
raise Exception('Error reading %s' % argument)
else:
return strings
else:
return [argument]
def ExpandFilenameArguments(filenames):
return list(collections.OrderedDict.fromkeys(sum(map(glob.glob, sum(map(ProcessAt, filenames), [])), [])))
def Main():
moredesc = '''
Arguments:
@file: process each file listed in the text file specified
wildcards are supported'''
oParser = optparse.OptionParser(usage='usage: %prog [options] [@]file ...\n' + __description__ + moredesc,
version='%prog ' + __version__)
oParser.add_option('-o', '--output', type=str, default='', help='Output to file')
oParser.add_option('-s', '--separator', default=';', help='Separator character (default ;)')
(options, args) = oParser.parse_args()
if len(args) == 0:
oParser.print_help()
else:
NmapXmlParser(ExpandFilenameArguments(args), options)
if __name__ == '__main__':
# python nmap-parser-xml-to-csv.py -s "," -o test.csv os_info.xml
Main()
针对 smb 协议优化的脚本
nmap –script “smb-vuln-ms17-010.nse,smb-os-discovery.nse” -p445 –open -oX d:\demo.xml 192.168.1.1/16
#!/usr/bin/env python
# coding: utf-8
from argparse import ArgumentParser, FileType
from lxml import etree
import sys
def parse(f):
ret = []
tree = etree.parse(f)
for host in tree.iter('host'):
host_info, smb_vuln = {}, None
try:
hostscript = host.iter('hostscript').next()
except:
continue
if hostscript is None:
continue
for script in hostscript.iter('script'):
if script.get('id') == 'smb-os-discovery':
for elem in script.iter('elem'):
key = elem.get('key')
if key in ('lanmanager', 'server'):
host_info[key] = elem.text
if host_info[key] is not None:
host_info[key] = host_info[key].strip('\\x00')
elif script.get('id') == 'smb-vuln-ms17-010':
smb_vuln = script
# 仅保存存在 17-010 问题的记录
if smb_vuln is None:
continue
address = host.iter('address').next()
host_info['host'] = address.get('addr')
ret.append(host_info)
return ret
def main():
parser = ArgumentParser()
parser.add_argument('input', type=FileType('rb'), help=u'xml path')
parser.add_argument('-o', help=u'csv file to output', type=FileType('w'), default=sys.stdout)
args = parser.parse_args()
data = parse(args.input)
headers = ['host', 'lanmanager', 'server']
args.o.write(','.join(headers) + '\n')
for item in data:
cols = []
for h in headers:
cols.append(item.get(h, 'NULL'))
args.o.write(','.join(cols) + '\n')
if __name__ == '__main__':
main()
Leave a Reply