Neurohazard
暮雲煙月,皓首窮經;森羅萬象,如是我聞。

使用 Nmap 对大规模局域网收集 MAC 地址

wpadmin~August 20, 2018 /InfoSec/System Management

使用 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

Your email address will not be published. Required fields are marked *