python-libnmap Documentation

repository·master·Indexed 19 days ago

https://github.com/savon-noir/python-libnmap

A Python library for automating, manipulating, and reporting on Nmap scan data. It provides tools for launching scans via NmapProcess, parsing XML results with NmapParser, and comparing scans using the libnmap.diff module. The library features a hierarchical object model (NmapReport, NmapHost, NmapService) and supports datastore integration through plugins for MongoDB, SQLAlchemy, and AWS S3.

Tokens
3.8K
Snippets
9
Records
18
Agent score
66%

What's inside python-libnmap

  1. Overview of libnmap modules

    master

    libnmap is a Python toolkit designed for manipulating Nmap data. It is organized into several functional modules:

    • process: Used to launch Nmap scans.
    • parse: Used to parse Nmap reports or scan results (currently XML only) from files or strings.
    • report: Used to manipulate parsed scan results and to de/serialize scan results in JSON format.
    • diff: Used to compare changes between two different scans.
    • objects: Provides core Nmap data models such as NmapHost, NmapService, NmapReport, NmapOSFingerprint, and CPE. Most objects support a .diff() method to compare themselves with similar objects.
    • plugins: Extends the NmapReport object to support direct datastore integration. Supported/planned plugins include:
      • mongodb (basic/POC)
      • sqlalchemy (supports SQLite, MySQL, etc.)
      • rabbitMQ (planned)
      • couchdb (planned)
      • elastic search (planned)
      • csv (planned)
  2. Diff two Nmap objects using libnmap.diff

    master

    The libnmap.diff module allows you to compare two Nmap objects of the same type (specifically NmapService, NmapHost, or NmapReport).

    When you call the .diff() method on one object passing another as an argument, it returns an NmapDiff object. You can then use the following methods on the NmapDiff object to retrieve a Python set() of keys that have changed:

    • added(): Keys present in the second object but not the first.
    • removed(): Keys present in the first object but not the second.
    • changed(): Keys present in both objects but with different values.
    • unchanged(): Keys present in both objects with identical values.

    Note: The keys returned correspond to the attributes found in the object's get_dict() method.

    from libnmap.parser import NmapParser
    
    # Load two different Nmap reports
    rep1 = NmapParser.parse_fromfile('report1.xml')
    rep2 = NmapParser.parse_fromfile('report2.xml')
    
    # Get the set of attributes that changed between the reports
    diff_obj = rep1.diff(rep2)
    changed_keys = diff_obj.changed()
    
    for key in changed_keys:
        print(f"Attribute {key} changed")
  3. Understand the libnmap.objects data hierarchy

    master

    The libnmap.objects module provides a structured way to manipulate Nmap scan data through a hierarchical object model. The data is organized into three primary layers:

    1. NmapReport: The top-level container. It includes scan "header" data (start time, command, version), a list of NmapHost objects, and scan "footer" data (end time, summary).
    2. NmapHost: Represents a scanned host. It includes host "header" data (state, hostnames, IP), a list of NmapService objects, and host "footer" data (OS version, fingerprint, uptime).
    3. NmapService: Represents a specific service found on a host. It includes service state, service name, and optional data like service banners or NSE (Nmap Scripting Engine) script results.

    For advanced analysis, you can also access NmapOSFingerprint (which contains NmapOSMatch, NmapOSClass, and OSFPPortUsed) and CPE (Common Platform Enumeration) objects found within NmapService or NmapOSClass.

  4. Configure datastore plugins for NmapReport

    master

    The plugins module allows you to support various datastores directly within the NmapReport object. Depending on your needs, you may need to install additional dependencies.

    Supported Plugins

    • mongodb: Supports insert, get, getAll, and delete.
    • sqlalchemy: Supports insert, get, getAll, and delete.
    • aws s3: Supports insert, get, getAll, and delete (Note: not supported for Python 3 due to boto limitations).
    • csv: (Planned/Todo)
    • elastic search: (Planned/Todo)

    Optional Dependencies

    To use these plugins, install the corresponding packages:

    • For MongoDB: pymongo
    • For SQLAlchemy: sqlalchemy (plus your database driver, e.g., MySQL-python)
    • For AWS S3: boto
  5. Monitor nmap scan progress and tasks

    master

    While an NmapProcess is running, the library parses specific events to provide real-time feedback on the scan status. Nmap executes various tasks (e.g., "DNS Resolve", "Ping Scan", "Connect Scan", "NSE scripts"), and libnmap instantiates an NmapTask object for each.

    To track progress, you can access:

    • NmapProcess.tasks: A list of all NmapTask objects executed so far.
    • NmapProcess.current_task: The NmapTask currently being executed.
  6. Parse Nmap XML outputs with NmapParser

    master

    The libnmap.parser module is used to parse Nmap XML scan reports. The NmapParser class acts as a factory and should never be instantiated directly. Instead, use its class methods to parse data from strings or files.

    Supported input types:

    • A complete Nmap XML scan report.
    • An incomplete or interrupted Nmap XML scan report.
    • Partial XML tags: <host>, <ports>, or <port>.

    Input can be provided as either a raw string or a file path.

    from libnmap.parser import NmapParser
    
    nmap_report = NmapParser.parse_fromfile('path/to/scan.xml')
    print(f"Nmap scan summary: {nmap_report.summary}")
  7. Perform a deep recursive diff of Nmap reports

    master

    Because Nmap objects are often nested (e.g., a NmapReport contains NmapHost objects, which contain NmapService objects), a simple diff only compares the top-level attributes. To find specific changes deep within the hierarchy, you must manually traverse the objects using their IDs.

    To find a changed service within a changed host:

    1. Diff the reports to find changed host IDs.
    2. Use get_host_byid(host_id) to retrieve the specific host objects from both reports.
    3. Diff those host objects to find changed service IDs.
    4. Use get_service_byid(service_id) to retrieve the specific service objects.
    5. Diff the service objects to see the exact attribute changes.
    from libnmap.parser import NmapParser
    
    rep1 = NmapParser.parse_fromfile('libnmap/test/files/1_hosts.xml')
    rep2 = NmapParser.parse_fromfile('libnmap/test/files/1_hosts_diff.xml')
    
    # 1. Find changed hosts
    rep1_items_changed = rep1.diff(rep2).changed()
    changed_host_id = rep1_items_changed.pop().split('::')[1]
    
    changed_host1 = rep1.get_host_byid(changed_host_id)
    changed_host2 = rep2.get_host_byid(changed_host_id)
    
    # 2. Find changed services within that host
    host1_items_changed = changed_host1.diff(changed_host2).changed()
    changed_service_id = host1_items_changed.pop().split('::')[1]
    
    changed_service1 = changed_host1.get_service_byid(changed_service_id)
    changed_service2 = changed_host2.get_service_byid(changed_service_id)
    
    # 3. Find specific service attribute changes
    service1_items_changed = changed_service1.diff(changed_service2).changed()
    
    for diff_attr in service1_items_changed:
        print("diff({0}, {1}) [{2}:{3}] [{4}:{5}]".format(
            changed_service1.id, 
            changed_service2.id, 
            diff_attr, 
            getattr(changed_service1, diff_attr), 
            diff_attr, 
            getattr(changed_service2, diff_attr)
        ))
  8. Launch and control nmap scans with NmapProcess

    master

    The libnmap.process module allows you to launch and control nmap scans by instantiating an NmapProcess object and calling its run*() methods.

    Note that this module does not perform full inline parsing of all data; it only parses specific events that can be accessed via callbacks or by inspecting attributes while the scan is running.

    Raw scan results are available via:

    • NmapProcess.stdout: The XML output from nmap.
    • NmapProcess.stderr: Text error messages from the nmap process.
    • NmapProcess.rc: The return code of the process.
    from libnmap.process import NmapProcess
    
    # Instantiate with target and options
    nm = NmapProcess("scanme.nmap.org", options="-sV")
    
    # Run the scan
    rc = nm.run()
    
    if nm.rc == 0:
        print(nm.stdout)
    else:
        print(nm.stderr)
  9. Secure XML parsing with defusedxml

    master

    If you are parsing untrusted XML scan outputs, you should install the defusedxml library to protect against XML External Entity (XXE) attacks, which can lead to Denial of Service, file inclusion, or remote code execution.

    If defusedxml is installed in your environment, python-libnmap will automatically prefer it over the standard ElementTree or cElementTree parsers.

    pip install defusedxml
  10. Install python-libnmap

    master

    You can install python-libnmap using pip from PyPI, or by cloning the repository and installing it locally.

    Via pip

    pip install python-libnmap

    Via git and pip

    git clone https://github.com/savon-noir/python-libnmap.git
    cd python-libnmap
    pip install .
    pip install python-libnmap
  11. Integrate NmapParser with NmapProcess

    master

    You can combine libnmap.process.NmapProcess with libnmap.parser.NmapParser to run a scan and immediately parse the results from the standard output.

    from libnmap.process import NmapProcess
    from libnmap.parser import NmapParser
    
    # Run the scan
    nm = NmapProcess("127.0.0.1, scanme.nmap.org")
    nm.run()
    
    # Parse the stdout from the process
    nmap_report = NmapParser.parse(nm.stdout)
    
    for scanned_host in nmap_report.hosts:
        print(scanned_host)