././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158390.5052698 python-libnmap-0.7.2/0000755000175100001640000000000000000000000014023 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158390.5052698 python-libnmap-0.7.2/PKG-INFO0000644000175100001640000001554700000000000015134 0ustar00runnerdockerMetadata-Version: 1.1 Name: python-libnmap Version: 0.7.2 Summary: Python NMAP library enabling you to start async nmap tasks, parse and compare/diff scan results Home-page: http://pypi.python.org/pypi/python-libnmap/ Author: Ronald Bister Author-email: mini.pelle@gmail.com License: Apache 2.0 Description: python-libnmap ============== Code status ----------- |preflight-check| |Coverage Status| |License| Use cases --------- libnmap is a python library enabling python developers to manipulate nmap process and data. libnmap is what you were looking for if you need to implement the following: - automate or schedule nmap scans on a regular basis - manipulate nmap scans results to do reporting - compare and diff nmap scans to generate graphs - batch process scan reports - … The above uses cases will be easy to implement with the help of the libnmap modules. libnmap modules --------------- The lib currently offers the following modules: - **process**: enables you to launch nmap scans - **parse**: enables you to parse nmap reports or scan results (only XML so far) from a file, a string,… - **report**: enables you to manipulate a parsed scan result and de/serialize scan results in a json format - **diff**: enables you to see what changed between two scans - **common**: contains basic nmap objects like NmapHost and NmapService. It is to note that each object can be “diff()ed” with another similar object. - **plugins**: enables you to support datastores for your scan results directly in the “NmapReport” object. from report module: - mongodb: insert/get/getAll/delete - sqlalchemy: insert/get/getAll/delete - aws s3: insert/get/getAll/delete (not supported for python3 since boto is not supporting py3) - csv: todo (easy to implement) - elastic search: todo Documentation ------------- All the documentation is available on `read the docs `__. This documentation contains small code samples that you directly reuse. Dependencies ------------ libnmap has by default no dependencies, except defusedxml if you need to import untrusted XML scans data. The only additional python modules you’ll have to install depends if you wish to use libnmap to store reports on an exotic data store via libnmap’s independents plugins. Below the list of optional dependencies: - `sqlalchemy `__ (+the driver ie:MySQL-python) - `pymongo `__ - `boto `__ Security -------- If you are importing/parsing untrusted XML scan outputs with python-libnmap, install defusedxml library: .. code:: bash ronald@brouette:~/dev$ pip install defusedxml This will prevent you from being vulnerable to `XML External Entities attacks `__. For more information, read the `official libnmap documentation `__ This note relates to a cascaded CVE vulnerability from the python core library XML ElementTree. Nevertheless, python-libnmap has been assigned an `official CVE `__ to track this issue. This CVE is addressed from v0.7.2. Python Support -------------- The libnmap code is tested against the following python interpreters: - Python 2.7 - Python 3.6 - Python 3.7 - Python 3.8 Install ------- You can install libnmap via pip: .. code:: bash ronald@brouette:~$ pip install python-libnmap or via git and dist utils (à l’ancienne): .. code:: bash ronald@brouette:~$ git clone https://github.com/savon-noir/python-libnmap.git ronald@brouette:~$ cd python-libnmap ronald@brouette:~$ python setup.py install or via git and pip: .. code:: bash ronald@brouette:~$ git clone https://github.com/savon-noir/python-libnmap.git ronald@brouette:~$ cd python-libnmap ronald@brouette:~$ pip install . Examples -------- Some codes samples are available in the examples directory or in the `documentation `__. Among other example, you notice an sample code pushing nmap scan reports in an ElasticSearch instance and allowing you to create fancy dashboards in Kibana like the screenshot below: .. figure:: https://github.com/savon-noir/python-libnmap/blob/es/examples/kibanalibnmap.png :alt: Kibanane Contributors ------------ Mike @bmx0r Boutillier for S3 and SQL-Alechemy plugins and for the constructive critics. Thanks! .. |preflight-check| image:: https://github.com/savon-noir/python-libnmap/workflows/Preflight%20Check/badge.svg .. |Coverage Status| image:: https://coveralls.io/repos/github/savon-noir/python-libnmap/badge.svg?branch=master :target: https://coveralls.io/github/savon-noir/python-libnmap?branch=master .. |License| image:: https://img.shields.io/badge/License-Apache%202.0-blue.svg :target: https://opensource.org/licenses/Apache-2.0 Platform: UNKNOWN Classifier: License :: OSI Approved :: Apache Software License Classifier: Development Status :: 5 - Production/Stable Classifier: Environment :: Console Classifier: Programming Language :: Python :: 2 Classifier: Programming Language :: Python :: 2.7 Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3.3 Classifier: Programming Language :: Python :: 3.4 Classifier: Programming Language :: Python :: 3.5 Classifier: Programming Language :: Python :: 3.6 Classifier: Programming Language :: Python :: 3.7 Classifier: Programming Language :: Python :: 3.8 Classifier: Topic :: System :: Networking ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/README.rst0000644000175100001640000001126600000000000015520 0ustar00runnerdockerpython-libnmap ============== Code status ----------- |preflight-check| |Coverage Status| |License| Use cases --------- libnmap is a python library enabling python developers to manipulate nmap process and data. libnmap is what you were looking for if you need to implement the following: - automate or schedule nmap scans on a regular basis - manipulate nmap scans results to do reporting - compare and diff nmap scans to generate graphs - batch process scan reports - … The above uses cases will be easy to implement with the help of the libnmap modules. libnmap modules --------------- The lib currently offers the following modules: - **process**: enables you to launch nmap scans - **parse**: enables you to parse nmap reports or scan results (only XML so far) from a file, a string,… - **report**: enables you to manipulate a parsed scan result and de/serialize scan results in a json format - **diff**: enables you to see what changed between two scans - **common**: contains basic nmap objects like NmapHost and NmapService. It is to note that each object can be “diff()ed” with another similar object. - **plugins**: enables you to support datastores for your scan results directly in the “NmapReport” object. from report module: - mongodb: insert/get/getAll/delete - sqlalchemy: insert/get/getAll/delete - aws s3: insert/get/getAll/delete (not supported for python3 since boto is not supporting py3) - csv: todo (easy to implement) - elastic search: todo Documentation ------------- All the documentation is available on `read the docs `__. This documentation contains small code samples that you directly reuse. Dependencies ------------ libnmap has by default no dependencies, except defusedxml if you need to import untrusted XML scans data. The only additional python modules you’ll have to install depends if you wish to use libnmap to store reports on an exotic data store via libnmap’s independents plugins. Below the list of optional dependencies: - `sqlalchemy `__ (+the driver ie:MySQL-python) - `pymongo `__ - `boto `__ Security -------- If you are importing/parsing untrusted XML scan outputs with python-libnmap, install defusedxml library: .. code:: bash ronald@brouette:~/dev$ pip install defusedxml This will prevent you from being vulnerable to `XML External Entities attacks `__. For more information, read the `official libnmap documentation `__ This note relates to a cascaded CVE vulnerability from the python core library XML ElementTree. Nevertheless, python-libnmap has been assigned an `official CVE `__ to track this issue. This CVE is addressed from v0.7.2. Python Support -------------- The libnmap code is tested against the following python interpreters: - Python 2.7 - Python 3.6 - Python 3.7 - Python 3.8 Install ------- You can install libnmap via pip: .. code:: bash ronald@brouette:~$ pip install python-libnmap or via git and dist utils (à l’ancienne): .. code:: bash ronald@brouette:~$ git clone https://github.com/savon-noir/python-libnmap.git ronald@brouette:~$ cd python-libnmap ronald@brouette:~$ python setup.py install or via git and pip: .. code:: bash ronald@brouette:~$ git clone https://github.com/savon-noir/python-libnmap.git ronald@brouette:~$ cd python-libnmap ronald@brouette:~$ pip install . Examples -------- Some codes samples are available in the examples directory or in the `documentation `__. Among other example, you notice an sample code pushing nmap scan reports in an ElasticSearch instance and allowing you to create fancy dashboards in Kibana like the screenshot below: .. figure:: https://github.com/savon-noir/python-libnmap/blob/es/examples/kibanalibnmap.png :alt: Kibanane Contributors ------------ Mike @bmx0r Boutillier for S3 and SQL-Alechemy plugins and for the constructive critics. Thanks! .. |preflight-check| image:: https://github.com/savon-noir/python-libnmap/workflows/Preflight%20Check/badge.svg .. |Coverage Status| image:: https://coveralls.io/repos/github/savon-noir/python-libnmap/badge.svg?branch=master :target: https://coveralls.io/github/savon-noir/python-libnmap?branch=master .. |License| image:: https://img.shields.io/badge/License-Apache%202.0-blue.svg :target: https://opensource.org/licenses/Apache-2.0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/TODO0000644000175100001640000000255200000000000014517 0ustar00runnerdocker0.7.2: clean-up blacked code and pylint it 0.7.2: add unittest for defusedxml to fix billionlaugh and external entities security issues 0.7.2: Change License from CC-BY to Apache 2.0 0.7.2: Enabled defusedxml support as preferred option for parsing () 0.7.2: add extra_requires for plugins deps and defusedxml 0.7.2: Remove code duplication in sudo_run and sudo_run_background from process.py 0.7.2: Fix empty nmap outputs due to subprocess race condition (Merge PR79 from @Shouren) 0.7.2: Added banner_dict support + unittest (Merge edited PR from @cfoulds) release: - changelog date not respecting KACL specs - check https://github.com/anton-yurchenko/git-release - https://github.com/sean0x42/markdown-extract Contribution file: - specify where version needs to be set before adding tag to commit - libnmap/__init__.py - docs/conf.py - setup.py - CHANGELOG.md (set correct date) 0.7.3: add CSV backend support 0.7.3: improve API for NSE scripts 0.7.3: add support for post,pre and host scripts 0.7.3: add a Contribution guideline page 0.7.3: add development environment config and setup 0.7.3: add pre-commit hooks to enforce black and isort 0.7.3: automate in github actions the git workflow + doc update + pypi update 0.7.4: Add support and tests for traceroute in nmap 0.7.5: create complete python testing environment based on docker-compose and some examples ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158390.5052698 python-libnmap-0.7.2/docs/0000755000175100001640000000000000000000000014753 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/diff.rst0000644000175100001640000000700100000000000016413 0ustar00runnerdockerlibnmap.diff ============== Using libnmap.diff module ------------------------- This modules enables the user to diff two NmapObjects: NmapService, NmapHost, NmapReport. The constructor returns a NmapDiff object which he can then use to call its inherited methods: - added() - removed() - changed() - unchanged() Those methods return a python set() of keys which have been changed/added/removed/unchanged from one object to another. The keys of each objects could be found in the implementation of the get_dict() methods of the compared objects. The example below is a heavy version of going through all nested objects to see waht has changed after a diff:: #!/usr/bin/env python 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') 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) 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) 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)) This outputs the following line:: (pydev)$ python /tmp/z.py diff(tcp.3306, tcp.3306) [state:open] [state:filtered] (pydev)$ Of course, the above code is quite ugly and heavy but the idea behind diff was to be as generic as possible in order to let the user of the lib defines its own algorithms to extract the data. A less manual and more clever approach would be to recursively retrieve the changed attributes and values of nested objects. Below, you will find a small code example doing it .. literalinclude:: ../examples/diff_sample2.py This code will output the following:: ~ NmapReport: started at 1361737906 hosts up 2/2 hosts_total: 1 => 2 ~ NmapReport: started at 1361737906 hosts up 2/2 commandline: nmap -sT -vv -oX 1_hosts.xml localhost => nmap -sS -vv -oX 2_hosts.xml localhost scanme.nmap.org ~ NmapReport: started at 1361737906 hosts up 2/2 hosts_up: 1 => 2 ~ NmapService: [closed 25/tcp smtp ()] state: open => closed + NmapService: [open 23/tcp telnet ()] - NmapService: [open 111/tcp rpcbind ()] ~ NmapReport: started at 1361737906 hosts up 2/2 scan_type: connect => syn ~ NmapReport: started at 1361737906 hosts up 2/2 elapsed: 0.14 => 134.36 + NmapHost: [74.207.244.221 (scanme.nmap.org scanme.nmap.org) - up] Note that, in the above example, lines prefixed with: 1. '~' means values changed 2. '+ means values were added 3. '-' means values were removed NmapDiff methods ---------------- .. automodule:: libnmap.diff .. autoclass:: NmapDiff :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/index.rst0000644000175100001640000000335700000000000016624 0ustar00runnerdockerWelcome to libnmap's documentation! =================================== About libnmap ------------- libnmap is a python toolkit for manipulating nmap. It currently offers the following modules: - process: enables you to launch nmap scans - parse: enables you to parse nmap reports or scan results (only XML so far) from a file, a string,... - report: enables you to manipulate a parsed scan result and de/serialize scan results in a json format - diff: enables you to see what changed between two scans - objects: contains basic nmap objects like NmapHost and NmapService. It is to note that each object can be "diff()ed" with another similar object. - report: contains NmapReport class definition - host: contains NmapHost class definition - service: contains NmapService class definition - os: contains NmapOSFingerprint class definition and some other classes like NmapOSMatch, NmapOSClass,... - cpe: contains CPE class defdinition - plugins: enables you to support datastores for your scan results directly in the "NmapReport" object from report module - mongodb: only plugin implemented so far, ultra basic, for POC purpose only - sqlalchemy: Allow to store/retreive NmapReport to sqlite/mysql/... all engine supported by sqlalchemy - rabbitMQ : todo - couchdb: todo - elastic search: todo - csv: todo libnmap's modules ----------------- The full `source code `_ is available on GitHub. Please, do not hesitate to fork it and issue pull requests. The different modules are documented below: .. toctree:: :maxdepth: 2 :glob: process parser objects objects/* diff plugins_s3 Indices and tables ================== * :ref:`genindex` * :ref:`modindex` * :ref:`search` ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158390.5052698 python-libnmap-0.7.2/docs/objects/0000755000175100001640000000000000000000000016404 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/objects/cpe.rst0000644000175100001640000000032000000000000017700 0ustar00runnerdockerlibnmap.objects.cpe =================== Using libnmap.objects.cpe module -------------------------------- TODO CPE methods ----------- .. automodule:: libnmap.objects.cpe .. autoclass:: CPE :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/objects/nmaphost.rst0000644000175100001640000000033700000000000020772 0ustar00runnerdockerlibnmap.objects.host ==================== Using libnmap.objects.host module --------------------------------- TODO NmapHost methods ---------------- .. automodule:: libnmap.objects .. autoclass:: NmapHost :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/objects/nmapreport.rst0000644000175100001640000000035500000000000021330 0ustar00runnerdockerlibnmap.objects.report ====================== Using libnmap.objects.report module ----------------------------------- TODO NmapReport methods ------------------ .. automodule:: libnmap.objects .. autoclass:: NmapReport :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/objects/nmapservice.rst0000644000175100001640000000036400000000000021455 0ustar00runnerdockerlibnmap.objects.service ======================= Using libnmap.objects.service module ------------------------------------ TODO NmapService methods ------------------- .. automodule:: libnmap.objects .. autoclass:: NmapService :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/objects/os.rst0000644000175100001640000000076100000000000017563 0ustar00runnerdockerlibnmap.objects.os ================== Using libnmap.objects.os module ------------------------------- TODO NmapOSFingerprint methods ------------------------- .. automodule:: libnmap.objects.os .. autoclass:: NmapOSFingerprint :members: NmapOSMatch methods ------------------- .. autoclass:: NmapOSMatch :members: NmapOSClass methods ------------------- .. autoclass:: NmapOSClass :members: OSFPPortUsed methods -------------------- .. autoclass:: OSFPPortUsed :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/objects.rst0000644000175100001640000000312300000000000017135 0ustar00runnerdockerlibnmap.objects =============== Using libnmap.objects module ---------------------------- This module contains the definition and API of all "NmapObjects" which enables user to manipulate nmap data: 1. NmapReport 2. NmapHost 3. NmapService The three objects above are the most common one that one would manipulate. For more advanced usage, the following objects might be useful 1. NmapOSFingerprint (contains: NmapOSMatch, NmapOSClass, OSFPPortUsed) 2. CPE (Common platform enumeration contained in NmapService or NmapOSClass) The following structure applies by default: NmapReport contains: - Scan "header" data (start time, nmap command, nmap version, ...) - List of NmapHosts (0 to X scanned hosts could be nested in a nmap report) - Scan "footer" data (end time, summary, ...) NmapHost contains: - Host "header" data (state, hostnames, ip, ...) - List of NmapService (0 to X scanned services could be nested in a scanned host) - Host "footer" data (os version, fingerprint, uptime, ...) NmapService contains: - scan results for this service: - service state, service name - optional: service banner - optional: NSE scripts data Each of the above-mentioned objects have a diff() method which enables the user of the lib the compare two different objects of the same type. If you read the code you'll see the dirty trick with id() which ensures that proper objects are being compared. The logic of diff will certainly change overtime but the API (i/o) will be kept as is. For more info on diff, please check the module's `documentation _`. ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/parser.rst0000644000175100001640000001005400000000000017001 0ustar00runnerdockerlibnmap.parser ============== Security note for libnmap.parser -------------------------------- **TLDR:** if you are importing/parsing untrusted XML scan outputs with python-libnmap, install defusedxml library: .. code-block:: bash ronald@brouette:~/dev$ pip install defusedxml By default, python-libnmap's parser module does not enforces an extra XML parser module than the one provided in the python core distribution. In versions previous to 0.7.2, by default, the `ElementTree XML API was used `_. This XML library is vulnerable to several `XML External Entities attacks `_ which may lead to: - Denial of Service attacks - Remote and local files inclusions - Remote code execution This implies, de facto, that parsing any untrusted XML file could result in any of the above. Fortunately, one of the python core developer is maintaining an alternative Python XML parsing library: `defusedxml `_ which addresses all the above vulnerabilities. Since the above vulnerabilities will only affect you if you are parsing untrusted XML scan outputs, by default, the defusedxml library is not enforced. But if the defusedxml library is installed, it will be the preferred XML parser picked by python-libnmap. Consider the following lines from libnmap.parser module: .. literalinclude:: ../libnmap/parser.py :linenos: :lines: 3-10 - Line 4 first tries to import defusedxml - if it fails, it then tries to load cElementTree (known to be more performant) - if it fails, it then defaults to XML ElementTree. Purpose of libnmap.parser ------------------------- This modules enables you to parse nmap scans' output. For now on, only XML parsing is supported. NmapParser is a factory which will return a NmapReport, NmapHost or NmapService object. All these objects' API are documented. The module is capable of parsing: - a complete nmap XML scan report - an incomplete/interrupted nmap XML scan report - partial nmap xml tags: , and Input the above capabilities could be either a string or a file path. Based on the provided data, NmapParse.parse() could return the following: - NmapReport object: in case a full nmap xml/dict report was prodivded - NmapHost object: in case a nmap xml section was provided - NmapService object: in case a nmap xml section was provided - Python dict with following keys: ports and extraports; python lists. Using libnmap.parser module --------------------------- NmapParser parse the whole data and returns nmap objects usable via their documented API. The NmapParser should never be instanciated and only the following methods should be called: - NmapParser.parse(string) - NmapParser.parse_fromfile(file_path) - NmapParser.parse_fromstring(string) All of the above methods can receive as input: - a full XML nmap scan result and returns a NmapReport object - a scanned host in XML (... tag) and will return a NmapHost object - a list of scanned services in XML (... tag) and will return a python array of NmapService objects - a scanned service in XML (... tag) and will return a NmapService object Small example: .. code-block:: python from libnmap.parser import NmapParser nmap_report = NmapParser.parse_fromfile('libnmap/test/files/1_os_banner_scripts.xml') print "Nmap scan summary: {0}".format(nmap_report.summary) Basic usage from a processed scan: .. code-block:: python from libnmap.process import NmapProcess from libnmap.parser import NmapParser nm = NmapProcess("127.0.0.1, scanme.nmap.org") nm.run() nmap_report = NmapParser.parse(nm.stdout) for scanned_hosts in nmap_report.hosts: print scanned_hosts For more details on using the results from NmapParser, refer to the API of class: NmapReport, NmapHost, NmapService. NmapParser methods ------------------ .. automodule:: libnmap.parser .. autoclass:: NmapParser :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/plugins_s3.rst0000644000175100001640000000051100000000000017570 0ustar00runnerdockerlibnmap.plugins.s3.NmapS3Plugin =============================== Using libnmap.plugins.s3 ------------------------ This modules enables the user to directly use S3 buckets to store and retrieve NmapReports. NmapS3Plugin methods -------------------- .. automodule:: libnmap.plugins.s3 .. autoclass:: NmapS3Plugin :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3012645 python-libnmap-0.7.2/docs/process.rst0000644000175100001640000001266100000000000017171 0ustar00runnerdockerlibnmap.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 or by running the process in the background and accessing the NmapProcess attributes while the scan is running. To run an nmap scan, you need to: - instantiate 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 instantiate an NmapProcess instance, call the constructor with the appropriate parameters Processing of events -------------------- While Nmap is running, some events are processed 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 tasks 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 instantiate 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 .. literalinclude:: ../examples/proc_async.py 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 .. literalinclude:: ../examples/proc_nmap_like.py 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 ------------------- .. automodule:: libnmap.process .. autoclass:: NmapProcess :members: .. automethod:: __init__ NmapTask methods ------------------- .. autoclass:: NmapTask :members: ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158390.5052698 python-libnmap-0.7.2/libnmap/0000755000175100001640000000000000000000000015445 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3052647 python-libnmap-0.7.2/libnmap/__init__.py0000644000175100001640000000035700000000000017563 0ustar00runnerdocker# -*- coding: utf-8 -*- __author__ = "Ronald Bister, Mike Boutillier" __credits__ = ["Ronald Bister", "Mike Boutillier"] __maintainer__ = "Ronald Bister" __email__ = "mini.pelle@gmail.com" __license__ = "Apache 2.0" __version__ = "0.7.2" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3052647 python-libnmap-0.7.2/libnmap/diff.py0000644000175100001640000000527400000000000016737 0ustar00runnerdocker# -*- coding: utf-8 -*- class DictDiffer(object): """ Calculate the difference between two dictionaries as: (1) items added (2) items removed (3) keys same in both but changed values (4) keys same in both and unchanged values """ def __init__(self, current_dict, past_dict): self.current_dict = current_dict self.past_dict = past_dict self.set_current = set(current_dict.keys()) self.set_past = set(past_dict.keys()) self.intersect = self.set_current.intersection(self.set_past) def added(self): return self.set_current - self.intersect def removed(self): return self.set_past - self.intersect def changed(self): return set( o for o in self.intersect if self.past_dict[o] != self.current_dict[o] ) def unchanged(self): return set( o for o in self.intersect if self.past_dict[o] == self.current_dict[o] ) class NmapDiff(DictDiffer): """ NmapDiff compares two objects of same type to enable the user to check: - what has changed - what has been added - what has been removed - what was kept unchanged NmapDiff inherit from DictDiffer which makes the actual comparison. The different methods from DictDiffer used by NmapDiff are the following: - NmapDiff.changed() - NmapDiff.added() - NmapDiff.removed() - NmapDiff.unchanged() Each of the returns a python set() of key which have changed in the compared objects. To check the different keys that could be returned, refer to the get_dict() method of the objects you which to compare (i.e: libnmap.objects.NmapHost, NmapService,...). """ def __init__(self, nmap_obj1, nmap_obj2): """ Constructor of NmapDiff: - Checks if the two objects are of the same class - Checks if the objects are "comparable" via a call to id() (dirty) - Inherits from DictDiffer and """ if ( nmap_obj1.__class__ != nmap_obj2.__class__ or nmap_obj1.id != nmap_obj2.id ): raise NmapDiffException("Comparing objects with non-matching id") self.object1 = nmap_obj1.get_dict() self.object2 = nmap_obj2.get_dict() DictDiffer.__init__(self, self.object1, self.object2) def __repr__(self): return ( "added: [{0}] -- changed: [{1}] -- " "unchanged: [{2}] -- removed [{3}]".format( self.added(), self.changed(), self.unchanged(), self.removed() ) ) class NmapDiffException(Exception): def __init__(self, msg): self.msg = msg ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158390.5052698 python-libnmap-0.7.2/libnmap/objects/0000755000175100001640000000000000000000000017076 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3052647 python-libnmap-0.7.2/libnmap/objects/__init__.py0000644000175100001640000000032600000000000021210 0ustar00runnerdocker# -*- coding: utf-8 -*- from libnmap.objects.host import NmapHost from libnmap.objects.report import NmapReport from libnmap.objects.service import NmapService __all__ = ["NmapReport", "NmapHost", "NmapService"] ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3052647 python-libnmap-0.7.2/libnmap/objects/cpe.py0000644000175100001640000000441000000000000020216 0ustar00runnerdocker# -*- coding: utf-8 -*- class CPE(object): """ CPE class offers an API for basic CPE objects. These objects could be found in NmapService or in tag within NmapHost. :todo: interpret CPE string and provide appropriate API """ def __init__(self, cpestring): self._cpestring = cpestring zk = [ "cpe", "part", "vendor", "product", "version", "update", "edition", "language", ] self._cpedict = dict((k, "") for k in zk) splitup = cpestring.split(":") self._cpedict.update(dict(zip(zk, splitup))) @property def cpestring(self): """ Accessor for the full CPE string. """ return self._cpestring @property def cpedict(self): """ Accessor for _cpedict """ return self._cpedict def __repr__(self): return self._cpestring def get_part(self): """ Returns the cpe part (/o, /h, /a) """ return self._cpedict["part"] def get_vendor(self): """ Returns the vendor name """ return self._cpedict["vendor"] def get_product(self): """ Returns the product name """ return self._cpedict["product"] def get_version(self): """ Returns the version of the cpe """ return self._cpedict["version"] def get_update(self): """ Returns the update version """ return self._cpedict["update"] def get_edition(self): """ Returns the cpe edition """ return self._cpedict["edition"] def get_language(self): """ Returns the cpe language """ return self._cpedict["language"] def is_application(self): """ Returns True if cpe describes an application """ return self.get_part() == "/a" def is_hardware(self): """ Returns True if cpe describes a hardware """ return self.get_part() == "/h" def is_operating_system(self): """ Returns True if cpe describes an operating system """ return self.get_part() == "/o" ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1608158378.3052647 python-libnmap-0.7.2/libnmap/objects/host.py0000644000175100001640000003320700000000000020432 0ustar00runnerdocker# -*- coding: utf-8 -*- from libnmap.diff import NmapDiff from libnmap.objects.os import NmapOSFingerprint class NmapHost(object): """ NmapHost is a class representing a host object of NmapReport """ def __init__( self, starttime="", endtime="", address=None, status=None, hostnames=None, services=None, extras=None, ): """ NmapHost constructor :param starttime: unix timestamp of when the scan against that host started :type starttime: string :param endtime: unix timestamp of when the scan against that host ended :type endtime: string :param address: dict ie :{'addr': '127.0.0.1', 'addrtype': 'ipv4'} :param status: dict ie:{'reason': 'localhost-response', 'state': 'up'} :return: NmapHost: """ self._starttime = starttime self._endtime = endtime self._hostnames = hostnames if hostnames is not None else [] self._status = status if status is not None else {} self._services = services if services is not None else [] self._extras = extras if extras is not None else {} self._osfingerprinted = False self.os = None if "os" in self._extras: self.os = NmapOSFingerprint(self._extras["os"]) self._osfingerprinted = True else: self.os = NmapOSFingerprint({}) self._ipv4_addr = None self._ipv6_addr = None self._mac_addr = None self._vendor = None for addr in address: if addr["addrtype"] == "ipv4": self._ipv4_addr = addr["addr"] elif addr["addrtype"] == "ipv6": self._ipv6_addr = addr["addr"] elif addr["addrtype"] == "mac": self._mac_addr = addr["addr"] if "vendor" in addr: self._vendor = addr["vendor"] self._main_address = self._ipv4_addr or self._ipv6_addr or "" self._address = address def __eq__(self, other): """ Compare eq NmapHost based on : - hostnames - address - if an associated services has changed :return: boolean """ rval = False if self.__class__ == other.__class__ and self.id == other.id: rval = self.changed(other) == 0 return rval def __ne__(self, other): """ Compare ne NmapHost based on: - hostnames - address - if an associated services has changed :return: boolean """ rval = True if self.__class__ == other.__class__ and self.id == other.id: rval = self.changed(other) > 0 return rval def __repr__(self): """ String representing the object :return: string """ return "{0}: [{1} ({2}) - {3}]".format( self.__class__.__name__, self.address, " ".join(self._hostnames), self.status, ) def __hash__(self): """ Hash is needed to be able to use our object in sets :return: hash """ return ( hash(self.status) ^ hash(self.address) ^ hash(self._mac_addr) ^ hash(frozenset(self._services)) ^ hash(frozenset(" ".join(self._hostnames))) ) def changed(self, other): """ return the number of attribute who have changed :param other: NmapHost object to compare :return int """ return len(self.diff(other).changed()) @property def starttime(self): """ Accessor for the unix timestamp of when the scan was started :return: string """ return self._starttime @property def endtime(self): """ Accessor for the unix timestamp of when the scan ended :return: string """ return self._endtime @property def address(self): """ Accessor for the IP address of the scanned host :return: IP address as a string """ return self._main_address @address.setter def address(self, addrdict): """ Setter for the address dictionnary. :param addrdict: valid dict is {'addr': '1.1.1.1', 'addrtype': 'ipv4'} """ if addrdict["addrtype"] == "ipv4": self._ipv4_addr = addrdict["addr"] elif addrdict["addrtype"] == "ipv6": self._ipv6_addr = addrdict["addr"] elif addrdict["addrtype"] == "mac": self._mac_addr = addrdict["addr"] if "vendor" in addrdict: self._vendor = addrdict["vendor"] self._main_address = self._ipv4_addr or self._ipv6_addr or "" self._address = addrdict @property def ipv4(self): """ Accessor for the IPv4 address of the scanned host :return: IPv4 address as a string """ return self._ipv4_addr or "" @property def mac(self): """ Accessor for the MAC address of the scanned host :return: MAC address as a string """ return self._mac_addr or "" @property def vendor(self): """ Accessor for the vendor attribute of the scanned host :return: string (vendor) of empty string if no vendor defined """ return self._vendor or "" @property def ipv6(self): """ Accessor for the IPv6 address of the scanned host :return: IPv6 address as a string """ return self._ipv6_addr or "" @property def status(self): """ Accessor for the host's status (up, down, unknown...) :return: string """ return self._status["state"] @status.setter def status(self, statusdict): """ Setter for the status dictionnary. :param statusdict: valid dict is {"state": "open", "reason": "syn-ack", "reason_ttl": "0"} 'state' is the only mandatory key. """ self._status = statusdict def is_up(self): """ method to determine if host is up or not :return: bool """ rval = False if self.status == "up": rval = True return rval @property def hostnames(self): """ Accessor returning the list of hostnames (array of strings). :return: array of string """ return self._hostnames @property def services(self): """ Accessor for the array of scanned services for that host. An array of NmapService objects is returned. :return: array of NmapService """ return self._services def get_ports(self): """ Retrieve a list of the port used by each service of the NmapHost :return: list: of tuples (port,'proto') ie:[(22,'tcp'),(25, 'tcp')] """ return [(p.port, p.protocol) for p in self._services] def get_open_ports(self): """ Same as get_ports() but only for open ports :return: list: of tuples (port,'proto') ie:[(22,'tcp'),(25, 'tcp')] """ return [ (p.port, p.protocol) for p in self._services if p.state == "open" ] def get_service(self, portno, protocol="tcp"): """ :param portno: int the portnumber :param protocol='tcp': string ('tcp','udp') :return: NmapService or None """ plist = [ p for p in self._services if (p.port == portno and p.protocol == protocol) ] if len(plist) > 1: raise Exception("Duplicate services found in NmapHost object") return plist.pop() if len(plist) else None def get_service_byid(self, service_id): """ Returns a NmapService by providing its id. The id of a nmap service is a python tupl made of (protocol, port) """ rval = None for _tmpservice in self._services: if _tmpservice.id == service_id: rval = _tmpservice return rval def os_class_probabilities(self): """ Returns an array of possible OS class detected during the OS fingerprinting. :return: Array of NmapOSClass objects """ rval = [] if self.os is not None: rval = self.os.osclasses return rval def os_match_probabilities(self): """ Returns an array of possible OS match detected during the OS fingerprinting :return: array of NmapOSMatches objects """ rval = [] if self.os is not None: rval = self.os.osmatches return rval @property def os_fingerprinted(self): """ Specify if the host has OS fingerprint data available :return: Boolean """ return self._osfingerprinted @property def os_fingerprint(self): """ Returns the fingerprint of the scanned system. :return: string """ rval = "" if self.os is not None: rval = "\n".join(self.os.fingerprints) return rval def os_ports_used(self): """ Returns an array of the ports used for OS fingerprinting :return: array of ports used: [{'portid': '22', 'proto': 'tcp', 'state': 'open'},] """ rval = [] try: rval = self._extras["os"]["ports_used"] except (KeyError, TypeError): pass return rval @property def tcpsequence(self): """ Returns the difficulty to determine remotely predict the tcp sequencing. return: string """ rval = "" try: rval = self._extras["tcpsequence"]["difficulty"] except (KeyError, TypeError): pass return rval @property def ipsequence(self): """ Return the class of ip sequence of the remote hosts. :return: string """ rval = "" try: rval = self._extras["ipidsequence"]["class"] except (KeyError, TypeError): pass return rval @property def uptime(self): """ uptime of the remote host (if nmap was able to determine it) :return: string (in seconds) """ rval = 0 try: rval = int(self._extras["uptime"]["seconds"]) except (KeyError, TypeError): pass return rval @property def lastboot(self): """ Since when the host was booted. :return: string """ rval = "" try: rval = self._extras["uptime"]["lastboot"] except (KeyError, TypeError): pass return rval @property def distance(self): """ Number of hops to host :return: int """ rval = 0 try: rval = int(self._extras["distance"]["value"]) except (KeyError, TypeError): pass return rval @property def scripts_results(self): """ Scripts results specific to the scanned host :return: array of