Using the Nmap Port Scanner with Python
In this tutorial, we will learn how to integrate the Nmap security scanner with our Post scanner program.
What is Nmap?
Nmap(Network Mapper) is a security scanner, originally written by Gordon Lyon(also known by his pseudonym Fyodor Vaskovich), and used to discover hosts and services on a computer network, thereby building a map of the network. To accomplish its goal, Nmap sends specially crafted packets to the target host(s) and then analyzes their responses.
Some of the useful Nmap features include:
- Host Discovery: This enables to identify hosts on any network. For example, listing the hosts that respond to TCP and/or ICMP requests or have a particular port open.
- Port Scanning: Enumerating(counting and listing one by one) all the open ports on the target hosts.
- Version Detection: Interrogating network services on remote devices to determine application name and version number.
- OS Detection: Determining the operating system and hardware characteristics of the network devices.
- Scriptable Interaction with the target: Using Nmap Scripting Engine(NSE) and Lua programming language, we can easily write sripts to perform operations on the network devices.
Although Nmap is a command line interface, you can download and install the GUI interface for Nmap known as zenmap.
Above is the screenshot of the command line, when you run nmap
command, all the options available for Target specifications and Host discovery, Scan Techniques etc are listed for your assistance. In case you want to install nmap in your machine, then:
- Run,
sudo apt-get install nmap
for Linux.
- For Windows and Mac OS X, download and install Nmap: https://nmap.org/download.html
The Port scanner program that we wrote in the last tutorial provides a quick script for performing a TCP connect scan. This is very limited as we might require the ability to perform additional scan types such as ACK
, RST
, FIN
, or SYN-ACK
scans provided by the Nmap toolkit. Nmap, delivers a rather extensive amount of functionality. This begs the question, why not just use Nmap? Why bother about writing a script for Port scanner?
Nmap is written in C and LUA programming languages, and can be easily integrated into Python. Nmap produces XML based output which provides us with the ability to utilize the full functionality of Nmap from within a Python script. So our Port Scanner script is just the outer shell, inside it we will be using Nmap now.
So, before we start using Nmap, let's first install nmap module:
- Use the command,
pip install python-nmap
- Or install by downloading the package from here.
Using Nmap in Python script
Below are the commands which can be used to successfully scan all the ports and return the results in a JSON format.
>>> import nmap
>>> nmScan = nmap.PortScanner()
>>>
>>> nmScan.scan('127.0.0.1', '21-443')
We all know, what import nmap
is for, it is to import the nmap
module to our python script. Then we initialise the Nmap PortScanner to scan the ports on our local network.
The third line i.e. nmScan.scan('127.0.0.1', '21-443')
returns a dictionary of the scan, executed on the local Home(127.0.0.1) network, for port numbers between 21 to 443. You can also provide the IP address of any remote server as well, to scan the available ports.
If you want to run the Nmap command using the command line, you can easily get the command line equivalent of the nmScan.scan('127.0.0.1', '22-443')
line of code, by using the command_line()
method, which reads the scan
method call and generate an equivalent command for running on command line.
>>> import nmap
>>> nmScan = nmap.PortScanner()
>>>
>>> nmScan.scan('127.0.0.1', '21-443')
>>> nmScan.command_line()
'nmap -oX - -p 21-443 -sV 127.0.0.1'
More Nmap methods
Now, let's see some more commands:
>>> nmScan.scaninfo()
{'tcp': {'services': '22-443', 'method': 'connect'}}
>>> nmScan.all_hosts()
['127.0.0.1']
>>> nmScan['127.0.0.1'].hostname()
'localhost'
>>> nmScan['127.0.0.1'].state()
'up'
>>> nmScan['127.0.0.1'].all_protocols()
['tcp']
>>> nmScan['127.0.0.1']['tcp'].keys()
[80, 25, 443, 22, 111]
>>> nmScan['127.0.0.1'].has_tcp(22)
True
>>> nmScan['127.0.0.1'].has_tcp(23)
False
>>> nmScan['127.0.0.1']['tcp'][22]
{'state': 'open', 'reason': 'syn-ack', 'name': 'ssh'}
>>> nmScan['127.0.0.1'].tcp(22)
{'state': 'open', 'reason': 'syn-ack', 'name': 'ssh'}
Let's talk about a few of the methods used above. The method all_protocols()
returns the protocol for the current network being scanned. The method keys()
returns all the active ports available within the specified range.
When we used the keys()
method on our local computer, only the port 80
was returned, because no other port in the specified range is active.
Note:In last command an error is raised. This is because in command nmScan['127.0.0.1']['tcp'].keys()
, only key value obtained is [80], whereas in last line we are specifing [22].
Below we have a simple program, to scan and list the ports for a given host:
import nmap
# initialize the port scanner
nmScan = nmap.PortScanner()
# scan localhost for ports in range 21-443
nmScan.scan('127.0.0.1', '21-443')
# run a loop to print all the found result about the ports
for host in nmScan.all_hosts():
print('Host : %s (%s)' % (host, nmScan[host].hostname()))
print('State : %s' % nmScan[host].state())
for proto in nmScan[host].all_protocols():
print('----------')
print('Protocol : %s' % proto)
lport = nmScan[host][proto].keys()
lport.sort()
for port in lport:
print ('port : %s\tstate : %s' % (port, nmScan[host][proto][port]['state'])
Host : 127.0.0.1 (localhost)
State : up
----------
Protocol : tcp
port : 22 state : open
port : 25 state : open
port : 80 state : open
port : 111 state : open
port : 443 state : open