Skip to content

Commit

Permalink
Unstablegit add -A Add support for optional arguments are per issue #4
Browse files Browse the repository at this point in the history
…and Merge to return most hosts
  • Loading branch information
Wangolo Joel committed Feb 22, 2020
1 parent b94176a commit 4432ab6
Show file tree
Hide file tree
Showing 2 changed files with 85 additions and 56 deletions.
20 changes: 15 additions & 5 deletions 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
Expand Down Expand Up @@ -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/)
Expand Down
121 changes: 70 additions & 51 deletions nmap3/nmap3.py
Expand Up @@ -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
Expand All @@ -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")
Expand Down Expand Up @@ -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
Expand All @@ -127,65 +132,69 @@ 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
"""
# 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)

# 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
"""
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
Expand All @@ -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.
Expand All @@ -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)
Expand Down Expand Up @@ -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
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down Expand Up @@ -440,14 +455,16 @@ 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
@cmd nmap -sP 192.168.178.1
"""
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)

Expand All @@ -456,14 +473,16 @@ 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
@cmd nmap -sL 192.168.178.1
"""
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)

Expand Down Expand Up @@ -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))

0 comments on commit 4432ab6

Please sign in to comment.