Created
November 11, 2016 16:13
-
-
Save redherringbone/4aeb1a64377f33a846eeab4d8fd8ed40 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import time | |
import subprocess | |
import sys | |
import xml.etree.ElementTree as ET | |
import base64 | |
import os | |
import shutil | |
import csv | |
import logging | |
import logging.handlers | |
import json | |
import pprint | |
from optparse import OptionParser | |
import requests | |
VERSION = "2016-11-11" | |
NMAPFILE = OPT_DIRECTORY = "" | |
OPT_VERBOSE = OPT_JSON = False | |
OUTPUTFILE="allHosts" | |
options = None | |
REPORT_DIR = "/nmap/reports/" | |
DATA_DIR = "/nmap/" | |
def parse_opts(): | |
global NMAPFILE, OPT_VERBOSE, OPT_DIRECTORY, OPT_JSON, options | |
parser = OptionParser(usage="Iterate directory or file, HTTP POST to Elasticsearch. Version=%s") | |
parser.add_option("-f", "--file-name", action="store", dest="file_name", help = "the filename of the nmap scan.") | |
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default = False , help = "Verbose shows all hosts and ports, non-verbose only shows interesting ones") | |
parser.add_option("-d", "--directory", action="store", default=REPORT_DIR, dest="directory_name", help = "Do all xml files in this directory. Default=%s" % (REPORT_DIR)) | |
parser.add_option("-j", "--json", action="store_true", dest="json", default = False, help = "output to JSON and send to Logstash") | |
parser.add_option("-s", "--summary-only", action="store_true", dest="summaryonly", default = False, help = "Show summary only") | |
parser.add_option("-p", "", action="store", dest="portskip", help = "Ports to skip") | |
parser.add_option("-q", "", action="store_true", dest="quiet_actiononly", help = "Quiet mode, only show actionable ports. Suppress errors, do not send to Logstash etc.") | |
(options, args) = parser.parse_args() | |
if options.file_name is None: | |
if options.directory_name is None: | |
print "you MUST enter a file name or directory , see -h" | |
exit(1) | |
NMAPFILE = options.file_name | |
OPT_VERBOSE = options.verbose | |
OPT_DIRECTORY = options.directory_name | |
OPT_JSON = options.json | |
if options.verbose: | |
print "Processing directory %s Processing file %s" % (options.directory_name, options.file_name) | |
return | |
def parseGFile(theFilePath): | |
""" | |
parses | |
""" | |
theFileName = os.path.splitext(os.path.basename(theFilePath))[0] | |
with open(theFilePath, 'r') as theFileH : | |
try: | |
lines = [l.rstrip() for l in theFileH.readlines()] | |
for line in lines: | |
print "%s: %s " %(theFileName, line) | |
except: | |
logOut ("ERROR parseFile (%s)" %(theFilePath)) | |
quit() | |
def doHostJSON(theJSONDict): | |
uri = "http://elasticsearch" | |
headers = {'content-type': 'application/json', 'tag': 'nmap'} | |
if not options.quiet_actiononly: | |
print "Posting to uri %s %s " % (uri, theJSONDict) | |
response = requests.post(uri, data=json.dumps(theJSONDict), headers=headers) | |
print response | |
else: | |
print "(quiet) POST to %s %s " % (uri, theJSONDict) | |
def toInt(theString): | |
try: | |
return(int(theString)) # success, this is an int | |
except: | |
return 0 # crunch the invalid value to 0, use -1 for testing | |
def parseXMLFile(theFilePath): | |
theFileName = os.path.splitext(os.path.basename(theFilePath))[0] | |
if options.verbose: | |
print "processing %s " % (theFilePath) | |
rowout = {'HostAddressAddr': '', 'HostStatusState': '', 'HostStatusReason':'', | |
"Filename": "", "OpenPorts": "" } | |
hostJSON = { "HostStatusState": "", "HostStatusReason": "", "HostStatusTTL": "", | |
"Hostname": "", "PortProtocol": "", "PortID": "", | |
"PortState": "", "PortStateReason": "", "PortStateReasonTTL": "", | |
"HostAddress": "", "Filename": "" | |
} | |
hostJSON["Filename"] = theFileName | |
nCountHosts = 0 | |
nCountPorts = 0 | |
try: | |
theNMAPTree = ET.parse(theFilePath) | |
#ET.dump(theNMAPTree) | |
root = theNMAPTree.getroot() | |
hosts = theNMAPTree.findall(".//host") | |
for host in hosts: | |
portslist = "" | |
for elem in host.iter(): | |
ports = elem.findall("port") | |
if elem.tag == "status": | |
rowout['HostStatusState'] = elem.attrib['state'] | |
rowout['HostStatusReason'] = elem.attrib['reason'] | |
hostJSON['HostStatusState'] = elem.attrib['state'] | |
hostJSON['HostStatusReason'] = elem.attrib['reason'] | |
hostJSON['HostStatusTTL'] = toInt(elem.attrib['reason_ttl']) | |
if elem.tag == "address": | |
rowout['HostAddressAddr'] = elem.attrib['addr'] | |
hostJSON['HostAddress'] = elem.attrib['addr'] | |
if elem.tag == "hostname": | |
hostJSON['Hostname'] = elem.attrib['name'] | |
for port_found in ports: | |
for pelem in port_found: | |
pass | |
states = port_found.findall("state") | |
for selem in states: | |
hostJSON['PortProtocol'] = port_found.attrib["protocol"] | |
hostJSON['PortID'] = toInt(port_found.attrib["portid"]) | |
hostJSON['PortState'] = selem.attrib["state"] | |
hostJSON['PortStateReason'] = selem.attrib["reason"] | |
hostJSON['PortStateReasonTTL'] = toInt(selem.attrib["reason_ttl"]) | |
if options.json: | |
doHostJSON(hostJSON) | |
if selem.attrib["state"] == "open": | |
thisportstate = "" | |
thisportstate += port_found.attrib["protocol"] | |
thisportstate += " " | |
thisportstate += port_found.attrib["portid"] | |
if OPT_VERBOSE: | |
pass | |
else: | |
if port_found.attrib["portid"] == "80" or port_found.attrib["portid"] == "443": | |
thisportstate = "" | |
if options.portskip: | |
if port_found.attrib["portid"] in options.portskip: | |
thisportstate = "" | |
if portslist and thisportstate: | |
portslist += ", " | |
portslist += thisportstate | |
if thisportstate: | |
nCountPorts += 1 | |
NoOpenPorts = False | |
if portslist == "" : | |
portslist = "No open ports" | |
NoOpenPorts = True | |
rowout["OpenPorts"] = portslist | |
rowout["Filename"] = theFileName | |
if options.quiet_actiononly: | |
RowOutputString = "%s: %s: %s " % (theFileName, rowout['HostAddressAddr'], portslist) | |
else: | |
RowOutputString = "%s: %s: %s: %s: %s" % (theFileName, rowout['HostAddressAddr'], | |
rowout['HostStatusState'], rowout['HostStatusReason'], portslist) | |
if not OPT_VERBOSE: | |
if rowout['HostStatusState'] == "down" or NoOpenPorts: | |
RowOutputString = "" | |
if RowOutputString: | |
nCountHosts += 1 | |
if RowOutputString and not options.summaryonly: | |
print RowOutputString | |
if OPT_JSON: | |
pass | |
if nCountHosts > 0 and not options.quiet_actiononly: | |
print "%s\tTotal insecure hosts %s\ttotal insecure ports %s " % (theFileName, nCountHosts, nCountPorts) | |
except Exception, err: | |
logOut ("ERROR %s parseFile (%s)" %(err, theFilePath)) | |
def parseXMLDirectory(theDirectoryPath): | |
if theDirectoryPath[len(theDirectoryPath)-1] != "/": | |
theDirectoryPath += "/" | |
for file in os.listdir(theDirectoryPath): | |
if file.endswith(".xml"): | |
thefile = theDirectoryPath + file | |
parseXMLFile(thefile) | |
parse_opts() | |
if NMAPFILE: | |
parseXMLFile(NMAPFILE) | |
elif OPT_DIRECTORY: | |
parseXMLDirectory(OPT_DIRECTORY) | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment