From 4432ab619469f76b277658ad033f529546b06a8a Mon Sep 17 00:00:00 2001 From: Wangolo Joel Date: Sat, 22 Feb 2020 22:03:15 +0300 Subject: [PATCH] Unstablegit add -A Add support for optional arguments are per issue #4 and Merge to return most hosts --- README.md | 20 ++++++-- nmap3/nmap3.py | 121 ++++++++++++++++++++++++++++--------------------- 2 files changed, 85 insertions(+), 56 deletions(-) diff --git a/README.md b/README.md index 48ad561..210f323 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ + # python3-nmap A python 3 library which helps in using nmap port scanner. The way this tools works is by defining each nmap command into a python function making it very easy to use sophisticated nmap commands in other python scripts. For example in nmap if you want to scan for common ports you would to something like this @@ -226,15 +227,24 @@ The following nmaps commands have been added to the following scripts - [Readthedocs](https://nmap.readthedocs.io/) ## TODO -We need to add more nmap options for host discovery - -NmapHostDiscovery +Added Nmap Host discovery techniques - - Only port scan (-Pn) - - Only host discover (-sn) + - Only port scan (-Pn) + - Only host discover (-sn) - Arp discovery on a local network (-PR) - Disable DNS resolution (-n) +NmapHostDiscovery + + - `def nmap_portscan_only(self, host, args=None)` + - `def nmap_no_portscan(self, host, args=None):` + - `def nmap_arp_discovery(self, host, args=None):` + - `def nmap_disable_dns(self, host, args=None):` + +## Upcoming fixes +There are still many things that need to be cleaned and fixed in this +For example when a user scans and entire subnet. Also there is a need to return even the IP of the host that has been scanned. + ## Cross-Selling * [Ethical-tools](https://ethicaltools.gitbook.io/subdomainfinder/) * [Wappalyzer online](https://www.nmmapper.com/st/cms-detection/wappalyzer-online/) diff --git a/nmap3/nmap3.py b/nmap3/nmap3.py index a2cd378..933a83c 100644 --- a/nmap3/nmap3.py +++ b/nmap3/nmap3.py @@ -62,7 +62,7 @@ def default_command(self): """ return self.default_args.format(nmap=self.nmaptool, outarg="-oX") - def scan_top_ports(self, host, default=10): + def scan_top_ports(self, host, default=10, args=None): """ Perform nmap's top ports scan @@ -75,13 +75,18 @@ def scan_top_ports(self, host, default=10): if(default > self.maxport): raise ValueError("Port can not be greater than default 65389") self.host = host - + + if(args): + assert(isinstance(args, str)), "Expected string got {0} instead".format(type(args)) + top_port_args = " {host} --top-ports {default}".format(host=host, default=default) - top_port_command = self.default_command() + top_port_args - top_port_shlex = shlex.split(top_port_command) # prepare it for popen - + scan_command = self.default_command() + top_port_args + if(args): + scan_command += " {0}".format(args) + scan_shlex = shlex.split(scan_command) + # Run the command and get the output - output = self.run_command(top_port_shlex) + output = self.run_command(scan_shlex) if not output: # Probaby and error was raise raise ValueError("Unable to perform requested command") @@ -116,7 +121,7 @@ def nmap_dns_brute_script(self, host, dns_brute="--script dns-brute.nse"): subdomains = parser.filter_subdomains(xml_root) return subdomains - def nmap_version_detection(self, host, arg="-sV"): + def nmap_version_detection(self, host, arg="-sV", args=None): """ Perform nmap scan usign the dns-brute script @@ -127,17 +132,18 @@ def nmap_version_detection(self, host, arg="-sV"): self.host = host command_args = "{host} {default}".format(host=host, default=arg) - command = self.default_command() + command_args - dns_brute_shlex = shlex.split(command) # prepare it for popen - - # Run the command and get the output - output = self.run_command(dns_brute_shlex) + scan_command = self.default_command() + command_args + if(args): + scan_command += " {0}".format(args) + scan_shlex = shlex.split(scan_command) + + output = self.run_command(scan_shlex) xml_root = self.get_xml_et(output) services = self.version_parser(xml_root) return services - def nmap_stealth_scan(self, host, arg="-sA"): + def nmap_stealth_scan(self, host, arg="-sA", args=None): """ nmap -oX - nmmapper.com -sA """ @@ -145,30 +151,31 @@ def nmap_stealth_scan(self, host, arg="-sA"): self.host = host command_args = "{host} {default}".format(host=host, default=arg) - command = self.default_command() + command_args - dns_brute_shlex = shlex.split(command) # prepare it for popen + scan_command = self.default_command() + command_args + if(args): + scan_command += " {0}".format(args) + scan_shlex = shlex.split(scan_command) # Run the command and get the output - output = self.run_command(dns_brute_shlex) + output = self.run_command(scan_shlex) xml_root = self.get_xml_et(output) - def nmap_detect_firewall(self, host, arg="-sA"): # requires root + def nmap_detect_firewall(self, host, arg="-sA", args=None): # requires root """ nmap -oX - nmmapper.com -sA + @ TODO """ self.host = host command_args = "{host} {default}".format(host=host, default=arg) - command = self.default_command() + command_args - dns_brute_shlex = shlex.split(command) # prepare it for popen - + scan_command = self.default_command() + command_args + if(args): + scan_command += " {0}".format(args) + scan_shlex = shlex.split(scan_command) + # TODO - # Run the command and get the output - output = self.run_command(dns_brute_shlex) - xml_root = self.get_xml_et(output) - - def nmap_os_detection(self, host, arg="-O"): # requires root + def nmap_os_detection(self, host, arg="-O", args=None): # requires root """ nmap -oX - nmmapper.com -O NOTE: Requires root @@ -176,16 +183,18 @@ def nmap_os_detection(self, host, arg="-O"): # requires root self.host = host command_args = "{host} {default}".format(host=host, default=arg) - command = self.default_command() + command_args - dns_brute_shlex = shlex.split(command) # prepare it for popen + scan_command = self.default_command() + command_args + if(args): + scan_command += " {0}".format(args) + scan_shlex = shlex.split(scan_command) - output = self.run_command(dns_brute_shlex) + output = self.run_command(scan_shlex) xml_root = self.get_xml_et(output) os_identified = self.os_identifier_parser(xml_root) return os_identified - def nmap_subnet_scan(self, subnet, arg="-p-"): # requires root + def nmap_subnet_scan(self, subnet, arg="-p-", args=None): # requires root """ nmap -oX - nmmapper.com -p- NOTE: Requires root @@ -194,15 +203,18 @@ def nmap_subnet_scan(self, subnet, arg="-p-"): # requires root parser = NmapCommandParser(None) command_args = "{host} {default}".format(host=subnet, default=arg) - command = self.default_command() + command_args - dns_brute_shlex = shlex.split(command) # prepare it for popen - output = self.run_command(dns_brute_shlex) + scan_command = self.default_command() + command_args + if(args): + scan_command += " {0}".format(args) + + scan_shlex = shlex.split(scan_command) + output = self.run_command(scan_shlex) xml_root = self.get_xml_et(output) host_discovered = parser.parse_nmap_subnetscan(xml_root) return host_discovered - def nmap_list_scan(self, subnet, arg="-sL"): # requires root + def nmap_list_scan(self, subnet, arg="-sL", args=None): # requires root """ The list scan is a degenerate form of host discovery that simply lists each host of the network(s) specified, without sending any packets to the target hosts. @@ -213,10 +225,12 @@ def nmap_list_scan(self, subnet, arg="-sL"): # requires root parser = NmapCommandParser(None) command_args = "{host} {default}".format(host=subnet, default=arg) - command = self.default_command() + command_args - dns_brute_shlex = shlex.split(command) # prepare it for popen + scan_command = self.default_command() + command_args + if(args): + scan_command += " {0}".format(args) + scan_shlex = shlex.split(scan_command) - output = self.run_command(dns_brute_shlex) + output = self.run_command(scan_shlex) xml_root = self.get_xml_et(output) host_discovered = parser.parse_nmap_listscan(xml_root) @@ -262,14 +276,12 @@ def filter_top_ports(self, xmlroot): # slowly parse what is required for port in ports: open_ports = {} - - open_ports["protocol"]=port.attrib.get("protocol") - open_ports["port"]=port.attrib.get("portid") - + for key in port.attrib: + open_ports[key]=port.attrib.get(key) + if port.find('state') != None: - open_ports["state"]=port.find("state").attrib.get("state") - open_ports["reason"]=port.find('state').attrib.get("reason") - open_ports["reason_ttl"]=port.find("state").attrib.get("reason_ttl") + for key in port.find('state').attrib: + open_ports[key]=port.find("state").attrib.get(key) if port.find("service") != None: open_ports["service"]=port.find("service").attrib @@ -278,7 +290,6 @@ def filter_top_ports(self, xmlroot): runstats = xmlroot.find("runstats") if(runstats): - if(runstats.find("finished") != None): port_result_dict["runtime"]=runstats.find("finished").attrib @@ -384,7 +395,7 @@ def __init__(self, path=None): self.ping_scan = "-sP" self.idle_scan = "-sL" - def nmap_fin_scan(self, host): + def nmap_fin_scan(self, host, args=None): """ Perform scan using nmap's fin scan @@ -393,7 +404,9 @@ def nmap_fin_scan(self, host): """ fin_scan = " {host} {default}".format(host=host, default=self.fin_scan) fin_scan_command = self.default_command() + fin_scan - fin_scan_shlex = shlex.split(fin_scan_command) # prepare it + if(args): + fin_scan_command += " {0}".format(args) + fin_scan_shlex = shlex.split(fin_scan_command) parser = NmapCommandParser(None) # Use the ping scan parser @@ -402,7 +415,7 @@ def nmap_fin_scan(self, host): fin_results = parser.parse_nmap_idlescan(xml_root) return fin_results - def nmap_syn_scan(self, host): + def nmap_syn_scan(self, host, args=None): """ Perform syn scan on this given host @@ -411,6 +424,8 @@ def nmap_syn_scan(self, host): """ sync_scan = " {host} {default}".format(host=host, default=self.sync_scan) sync_scan_command = self.default_command() + sync_scan + if(args): + sync_scan_command += " {0}".format(args) sync_scan_shlex = shlex.split(sync_scan_command) # prepare it # Use the top_port_parser @@ -440,7 +455,7 @@ def nmap_tcp_scan(self, host, args=None): tcp_results = self.filter_top_ports(xml_root) return tcp_results - def nmap_ping_scan(self, host): + def nmap_ping_scan(self, host, args=None): """ Scan host using nmaps' ping scan @@ -448,6 +463,8 @@ def nmap_ping_scan(self, host): """ ping_scan = " {host} {default}".format(host=host, default=self.ping_scan) ping_scan_command = self.default_command() + ping_scan + if(args): + ping_scan_command += " {0}".format(args) ping_scan_shlex = shlex.split(ping_scan_command) # prepare it parser = NmapCommandParser(None) @@ -456,7 +473,7 @@ def nmap_ping_scan(self, host): ping_results = parser.parse_nmap_pingscan(xml_root) return ping_results - def nmap_idle_scan(self, host): + def nmap_idle_scan(self, host, args=None): """ Using nmap idle_scan @@ -464,6 +481,8 @@ def nmap_idle_scan(self, host): """ idle_scan = " {host} {default}".format(host=host, default=self.idle_scan) idle_scan_command = self.default_command() + idle_scan + if(args): + idle_scan_command += " {0}".format(args) idle_scan_shlex = shlex.split(idle_scan_command) # prepare it parser = NmapCommandParser(None) @@ -585,6 +604,6 @@ def nmap_disable_dns(self, host, args=None): parser.add_argument('-d', '--d', help='Help', required=True) args = parser.parse_args() - nmap = NmapHostDiscovery() - result = nmap.nmap_disable_dns(args.d) + nmap = Nmap() + result = nmap.nmap_version_detection(args.d) print(json.dumps(result, indent=4, sort_keys=True))