libnmap.process

Purpose of libnmap.process

The purpose of this module is to enable the lib users to launch and control nmap scans. This module will consequently fire the nmap command following the specified parameters provided in the constructor.

It is to note that this module will not perform a full inline parsing of the data. Only specific events are parsed and exploitable via either a callback function defined by the user and provided in the constructor; either by running the process in the background and accessing the NmapProcess attributes will the scan is running.

To run an nmap scan, you need to:

  • instanciate NmapProcess
  • call the run*() methods

Raw results of the scans will be available in the following properties:

  • NmapProcess.stdout: string, XML output
  • NmapProcess.stderr: string, text error message from nmap process

To instanciate a NmapProcess instance, call the constructor with appropriate parameters

Processing of events

While Nmap is running, some events are process and parsed. This would enable you to:

  • evaluate estimated time to completion and progress in percentage
  • find out which task is running and how many nmap task have been executed
  • know the start time and nmap version

As you may know, depending on the nmap options you specified, nmap will execute several tasks like “DNS Resolve”, “Ping Scan”, “Connect Scan”, “NSE scripts”,… This is of course independent from libnmap but the lib is able to parse these tasks and will instanciate a NmapTask object for any task executed. The list of executed task is available via the following properties:

  • NmapProcess.tasks: list of NmapTask object (executed nmap tasks)
  • NmapProcess.current_task: returns the currently running NmapTask

You will find below the list of attributes you can use when dealing with NmapTask:

  • name: task name (check nmap documentation for the complete list)
  • etc: unix timestamp of estimated time to completion
  • progress: estimated percentage of task completion
  • percent: estimated percentage of task completion (same as progress)
  • remaining: estimated number of seconds to completion
  • status: status of the task (‘started’ or ‘ended’)
  • starttime: unix timestamp of when the task started
  • endtime: unix timestamp of when the task ended, 0 if not completed yet
  • extrainfo: extra information stored for specific tasks
  • updated: unix timestamp of last data update for this task

Using libnmap.process

This modules enables you to launch nmap scans with simples python commands:

from libnmap.process import NmapProcess

nm = NmapProcess("scanme.nmap.org", options="-sV")
rc = nm.run()

if nm.rc == 0:
    print nm.stdout
else:
    print nm.stderr

This module is also able to trigger a callback function provided by the user. This callback will be triggered each time nmap returns data to the lib. It is to note that the lib forces nmap to return its status (progress and etc) every two seconds. The event callback could then play around with those values while running.

To go a bit further, you can always use the threading capabilities of the NmapProcess class and run the class in the background

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from libnmap.process import NmapProcess
from time import sleep


nmap_proc = NmapProcess(targets="scanme.nmap.org", options="-sT")
nmap_proc.run_background()
while nmap_proc.is_running():
    print("Nmap Scan running: ETC: {0} DONE: {1}%".format(nmap_proc.etc,
                                                          nmap_proc.progress))
    sleep(2)

print("rc: {0} output: {1}".format(nmap_proc.rc, nmap_proc.summary))

The above code will print out the following on standard output:

(pydev)[dev@bouteille python-nmap-lib]$ python examples/proc_async.py
Nmap Scan running: ETC: 0 DONE: 0%
Nmap Scan running: ETC: 1369433951 DONE: 2.45%
Nmap Scan running: ETC: 1369433932 DONE: 13.55%
Nmap Scan running: ETC: 1369433930 DONE: 25.35%
Nmap Scan running: ETC: 1369433931 DONE: 33.40%
Nmap Scan running: ETC: 1369433932 DONE: 41.50%
Nmap Scan running: ETC: 1369433931 DONE: 52.90%
Nmap Scan running: ETC: 1369433931 DONE: 62.55%
Nmap Scan running: ETC: 1369433930 DONE: 75.55%
Nmap Scan running: ETC: 1369433931 DONE: 81.35%
Nmap Scan running: ETC: 1369433931 DONE: 99.99%
rc: 0 output: Nmap done at Sat May 25 00:18:51 2013; 1 IP address (1 host up) scanned in 22.02 seconds
(pydev)[dev@bouteille python-nmap-lib]$

Another and last example of a simple use of the NmapProcess class. The code below prints out the scan results a la nmap

#!/usr/bin/env python
# -*- coding: utf-8 -*-

from libnmap.process import NmapProcess
from libnmap.parser import NmapParser, NmapParserException


# start a new nmap scan on localhost with some specific options
def do_scan(targets, options):
    parsed = None
    nmproc = NmapProcess(targets, options)
    rc = nmproc.run()
    if rc != 0:
        print("nmap scan failed: {0}".format(nmproc.stderr))
    print(type(nmproc.stdout))

    try:
        parsed = NmapParser.parse(nmproc.stdout)
    except NmapParserException as e:
        print("Exception raised while parsing scan: {0}".format(e.msg))

    return parsed


# print scan results from a nmap report
def print_scan(nmap_report):
    print("Starting Nmap {0} ( http://nmap.org ) at {1}".format(
        nmap_report.version,
        nmap_report.started))

    for host in nmap_report.hosts:
        if len(host.hostnames):
            tmp_host = host.hostnames.pop()
        else:
            tmp_host = host.address

        print("Nmap scan report for {0} ({1})".format(
            tmp_host,
            host.address))
        print("Host is {0}.".format(host.status))
        print("  PORT     STATE         SERVICE")

        for serv in host.services:
            pserv = "{0:>5s}/{1:3s}  {2:12s}  {3}".format(
                    str(serv.port),
                    serv.protocol,
                    serv.state,
                    serv.service)
            if len(serv.banner):
                pserv += " ({0})".format(serv.banner)
            print(pserv)
    print(nmap_report.summary)


if __name__ == "__main__":
    report = do_scan("127.0.0.1", "-sV")
    if report:
        print_scan(report)
    else:
        print("No results returned")

The above code will print out the following on standard output:

(pydev)[dev@bouteille python-nmap-lib]$ python examples/proc_nmap_like.py
Starting Nmap 5.51 ( http://nmap.org ) at Sat May 25 00:14:54 2013
Nmap scan report for localhost (127.0.0.1)
Host is up.
  PORT     STATE         SERVICE
   22/tcp  open          ssh (product: OpenSSH extrainfo: protocol 2.0 version: 5.3)
   25/tcp  open          smtp (product: Postfix smtpd hostname:  bouteille.localdomain)
   80/tcp  open          http (product: nginx version: 1.0.15)
  111/tcp  open          rpcbind (version: 2-4 extrainfo: rpc #100000)
  631/tcp  open          ipp (product: CUPS version: 1.4)
Nmap done at Sat May 25 00:15:00 2013; 1 IP address (1 host up) scanned in 6.25 seconds
(pydev)[dev@bouteille python-nmap-lib]$

The full source code is available on GitHub. Please, do not hesitate to fork it and issue pull requests.

NmapProcess methods

class libnmap.process.NmapProcess(targets='127.0.0.1', options='-sT', event_callback=None, safe_mode=True, fqp=None)[source]

NmapProcess is a class which wraps around the nmap executable.

Consequently, in order to run an NmapProcess, nmap should be installed on the host running the script. By default NmapProcess will produce the output of the nmap scan in the nmap XML format. This could be then parsed out via the NmapParser class from libnmap.parser module.

__init__(targets='127.0.0.1', options='-sT', event_callback=None, safe_mode=True, fqp=None)[source]

Constructor of NmapProcess class.

Parameters:
  • targets (string or list) – hosts to be scanned. Could be a string of hosts separated with a coma or a python list of hosts/ip.
  • options – list of nmap options to be applied to scan. These options are all documented in nmap’s man pages.
  • event_callback

    callable function which will be ran each time nmap process outputs data. This function will receive two parameters:

    1. the nmap process object
    2. the data produced by nmap process. See readme for examples.
  • safe_mode – parameter to protect unsafe options like -oN, -oG, -iL, -oA,…
  • fqp – full qualified path, if None, nmap will be searched in the PATH
Returns:

NmapProcess object

command

return the constructed nmap command or empty string if not constructed yet.

Returns:string
current_task

Accessor for the current NmapTask beeing run

Returns:NmapTask or None if no task started yet
elapsed

Accessor returning for how long the scan ran (in seconds)

Returns:string
endtime

Accessor for time when scan ended

Returns:string. Unix timestamp
etc

Accessor for estimated time to completion

Returns:estimated time to completion
get_command_line()[source]

Public method returning the reconstructed command line ran via the lib

Returns:the full nmap command line to run
Return type:string
has_failed()[source]

Checks if nmap has failed.

Returns:True if nmap process errored.
has_terminated()[source]

Checks if nmap has terminated. Could have failed or succeeded

Returns:True if nmap process is not running anymore.
is_running()[source]

Checks if nmap is still running.

Returns:True if nmap is still running
is_successful()[source]

Checks if nmap terminated successfully.

Returns:True if nmap terminated successfully.
options

Provides the list of options for that scan

Returns:list of string (nmap options)
progress

Accessor for progress status in percentage

Returns:percentage of job processed.
rc

Accessor for nmap execution’s return code

Returns:nmap execution’s return code
run()[source]

Public method which is usually called right after the constructor of NmapProcess. This method starts the nmap executable’s subprocess. It will also bind a Process that will read from subprocess’ stdout and stderr and push the lines read in a python queue for futher processing. This processing is waken-up each time data is pushed from the nmap binary into the stdout reading routine. Processing could be performed by a user-provided callback. The whole NmapProcess object could be accessible asynchroneously.

return: return code from nmap execution

run_background()[source]

run nmap scan in background as a thread. For privileged scans, consider NmapProcess.sudo_run_background()

starttime

Accessor for time when scan started

Returns:string. Unix timestamp
state

Accessor for nmap execution state. Possible states are:

  • self.READY
  • self.RUNNING
  • self.FAILED
  • self.CANCELLED
  • self.DONE
Returns:integer (from above documented enum)
stderr

Accessor for nmap standart error

Returns:output from nmap when errors occured.
Return type:string
stdout

Accessor for nmap standart output

Returns:output from nmap scan in XML
Return type:string
stop()[source]

Send KILL -15 to the nmap subprocess and gently ask the threads to stop.

sudo_run(run_as='root')[source]

Public method enabling the library’s user to run the scan with priviledges via sudo. The sudo configuration should be set manually on the local system otherwise sudo will prompt for a password. This method alters the command line by prefixing the sudo command to nmap and will then call self.run()

Parameters:run_as – user name to which the lib needs to sudo to run the scan
Returns:return code from nmap execution
sudo_run_background(run_as='root')[source]

Public method enabling the library’s user to run in background a nmap scan with priviledges via sudo. The sudo configuration should be set manually on the local system otherwise sudo will prompt for a password. This method alters the command line by prefixing the sudo command to nmap and will then call self.run()

Parameters:run_as – user name to which the lib needs to sudo to run the scan
Returns:return code from nmap execution
summary

Accessor returning a short summary of the scan’s results

Returns:string
targets

Provides the list of targets to scan

Returns:list of string
tasks

Accessor returning for the list of tasks ran during nmap scan

Returns:dict of NmapTask object
version

Accessor for nmap binary version number

Returns:version number of nmap binary
Return type:string

NmapTask methods

class libnmap.process.NmapTask(name, starttime=0, extrainfo='')[source]

NmapTask is a internal class used by process. Each time nmap starts a new task during the scan, a new class will be instanciated. Classes examples are: “Ping Scan”, “NSE script”, “DNS Resolve”,.. To each class an estimated time to complete is assigned and updated at least every second within the NmapProcess. A property NmapProcess.current_task points to the running task at time T and a dictionnary NmapProcess.tasks with “task name” as key is built during scan execution