From 220c9dd4dd37137736d594d5067a93b134f9a322 Mon Sep 17 00:00:00 2001 From: Jake Miller Date: Mon, 4 Feb 2019 14:23:22 -0500 Subject: [PATCH] Added -u to display open|filtered ports --- nmap_xml_parser.py | 113 +++++++++++++++++++++++++-------------------- 1 file changed, 64 insertions(+), 49 deletions(-) diff --git a/nmap_xml_parser.py b/nmap_xml_parser.py index 3740794..e2814b8 100644 --- a/nmap_xml_parser.py +++ b/nmap_xml_parser.py @@ -1,5 +1,4 @@ -#!/usr/bin/env python3 - +#!/usr/bin/env python __author__ = 'Jake Miller (@LaconicWolf)' __date__ = '20171220' @@ -8,10 +7,9 @@ __description__ = """Parses the XML output from an nmap scan. The user can specify whether the data should be printed, displayed as a list of IP addresses, or output to a csv file. Will append to a csv if the filename - already exists + already exists. """ - import xml.etree.ElementTree as etree import os import csv @@ -19,17 +17,6 @@ import argparse from collections import Counter from time import sleep - -def get_xml_root(xml): - """Parses an xml file and returns the tree.""" - try: - tree = etree.parse(xml) - except Exception as error: - print("[-] A an error occurred. The XML may not be well formed. Please review the error and try again: {}".format(error)) - exit() - return tree.getroot() - - def get_host_data(root): """Traverses the xml tree and build lists of scan information and returns a list of lists. @@ -71,9 +58,14 @@ def get_host_data(root): for port in ports: port_data = [] - # Ignore ports that are not 'open' - if not port.findall('state')[0].attrib['state'] == 'open': - continue + if args.udp_open: + # Display both open ports and open}filtered ports + if not 'open' in port.findall('state')[0].attrib['state']: + continue + else: + # Ignore ports that are not 'open' + if not port.findall('state')[0].attrib['state'] == 'open': + continue proto = port.attrib['protocol'] port_id = port.attrib['portid'] @@ -96,7 +88,9 @@ def get_host_data(root): script_output = '' # Create a list of the port data - port_data.extend((ip_address, host_name, os_name, proto, port_id, service, product, servicefp, script_id, script_output)) + port_data.extend((ip_address, host_name, os_name, + proto, port_id, service, product, + servicefp, script_id, script_output)) # Add the port data to the host data host_data.append(port_data) @@ -107,26 +101,40 @@ def get_host_data(root): host_data.append(addr_info) return host_data - def parse_xml(filename): - """Calls functions to read the xml and extract elements and values.""" - root = get_xml_root(filename) - return get_host_data(root) - + """Given an XML filename, reads and parses the XML file and passes the + the root node of type xml.etree.ElementTree.Element to the get_host_data + function, which will futher parse the data and return a list of lists + containing the scan data for a host or hosts.""" + try: + tree = etree.parse(filename) + except Exception as error: + print("[-] A an error occurred. The XML may not be well formed. " + "Please review the error and try again: {}".format(error)) + exit() + root = tree.getroot() + scan_data = get_host_data(root) + return scan_data def parse_to_csv(data): - """Accepts a list and adds the items to (or creates) a CSV file.""" + """Given a list of data, adds the items to (or creates) a CSV file.""" if not os.path.isfile(csv_name): csv_file = open(csv_name, 'w', newline='') csv_writer = csv.writer(csv_file) - top_row = ['IP', 'Host', 'OS', 'Proto', 'Port', 'Service', 'Product', 'Service FP', 'NSE Script ID', 'NSE Script Output', 'Notes'] + top_row = [ + 'IP', 'Host', 'OS', 'Proto', 'Port', + 'Service', 'Product', 'Service FP', + 'NSE Script ID', 'NSE Script Output', 'Notes' + ] csv_writer.writerow(top_row) - print('\n[+] The file {} does not exist. New file created!\n'.format(csv_name)) + print('\n[+] The file {} does not exist. New file created!\n'.format( + csv_name)) else: try: csv_file = open(csv_name, 'a', newline='') except PermissionError as e: - print("\n[-] Permission denied to open the file {}. Check if the file is open and try again.\n".format(csv_name)) + print("\n[-] Permission denied to open the file {}. " + "Check if the file is open and try again.\n".format(csv_name)) print("Print data to the terminal:\n") if args.debug: print(e) @@ -139,15 +147,13 @@ def parse_to_csv(data): csv_writer.writerow(item) csv_file.close() - def list_ip_addresses(data): - """Parses the input data to display only the IP address information""" + """Parses the input data to return only the IP address information""" ip_list = [item[0] for item in data] sorted_set = sorted(set(ip_list)) addr_list = [ip for ip in sorted_set] return addr_list - def print_web_ports(data): """Examines the port information and prints out the IP and port info in URL format (https://ipaddr:port/). @@ -173,7 +179,6 @@ def print_web_ports(data): else: continue - def least_common_ports(data, n): """Examines the port index from data and prints the least common ports.""" c = Counter() @@ -189,7 +194,6 @@ def least_common_ports(data, n): for p in c.most_common()[:-n-1:-1]: print("{0:5} {1:8}".format(p[0], p[1])) - def most_common_ports(data, n): """Examines the port index from data and prints the most common ports.""" c = Counter() @@ -205,7 +209,6 @@ def most_common_ports(data, n): for p in c.most_common(n): print("{0:5} {1:8}".format(p[0], p[1])) - def print_filtered_port(data, filtered_port): """Examines the port index from data and see if it matches the filtered_port. If it matches, print the IP address. @@ -220,13 +223,11 @@ def print_filtered_port(data, filtered_port): if port == filtered_port: print(item[0]) - def print_data(data): """Prints the data to the terminal.""" for item in data: print(' '.join(item)) - def main(): """Main function of the script.""" for filename in args.filename: @@ -234,7 +235,8 @@ def main(): # Checks the file path if not os.path.exists(filename): parser.print_help() - print("\n[-] The file {} cannot be found or you do not have permission to open the file.".format(filename)) + print("\n[-] The file {} cannot be found or you do not have " + "permission to open the file.".format(filename)) continue if not args.skip_entity_check: @@ -242,12 +244,16 @@ def main(): with open(filename) as fh: contents = fh.read() if ' to specify the file\n") + print("\n[-] Please specify an input file to parse. " + "Use -f to specify the file\n") exit() - if not args.ip_addresses and not args.csv and not args.print_all and not args.print_web_ports \ - and not args.least_common_ports and not args.most_common_ports and not args.filter_by_port: + if not args.ip_addresses and not args.csv and not args.print_all \ + and not args.print_web_ports and not args.least_common_ports \ + and not args.most_common_ports and not args.filter_by_port: parser.print_help() print("\n[-] Please choose an output option. Use -csv, -ip, or -p\n") exit() csv_name = args.csv - main() + main() \ No newline at end of file