savon-noir / python-libnmap

libnmap is a python library to run nmap scans, parse and diff scan results. It supports python 2.7 up to 3.8. It's wonderful.
https://libnmap.readthedocs.org
Other
488 stars 183 forks source link

Script results may contain "None" dict keys #124

Open happyc0ding opened 3 years ago

happyc0ding commented 3 years ago

When parsing Nmap XML files with service detection I ran into an interesting scenario: Let's assume I have the following script output in a file: <script id="http-server-header" output="CerberusFTPServer/11.0"><elem>CerberusFTPServer/11.0</elem></script> This will result in the following object in the attribute services of NmapHost (NmapService): {'id': 'http-server-header', 'output': 'CerberusFTPServer/11.0', 'elements': {None: 'CerberusFTPServer/11.0'}} As the output shows, the key inside elements is None. This may lead to problems when processing the data with other software, i.e. elasticsearch.

In comparison other elements within the XML have a key attribute which seems to be used like here: <script id="http-methods" output="&#xa; Supported Methods: GET HEAD POST OPTIONS"><table key="Supported Methods"><elem>GET</elem><elem>HEAD</elem><elem>POST</elem><elem>OPTIONS</elem></table></script> This results in: {'id': 'http-methods', 'output': '\n Supported Methods: GET HEAD POST OPTIONS', 'elements': {'Supported Methods': {None: ['GET', 'HEAD', 'POST', 'OPTIONS']}}} (Please note the key inside Supported Methods is also None.)

Tested with libnmap versions 0.7.0 and 0.7.2. Nmap version 7.80.

0x303 commented 1 year ago

I experienced this same issue. This only seems to happen with certain NSE scan modules.

The data above (for the http=methods NSE scan results) SHOULD look like this {'id': 'http-methods', 'output': '\n Supported Methods: GET HEAD POST OPTIONS', 'elements': {'Supported Methods': ['GET', 'HEAD', 'POST', 'OPTIONS']}} Where the Supported Methods key has an array as its value rather than a dictionary (object).

This same issue also occurs in the ssl-cert NSE scan within the extensions sub-key.

0x303 commented 1 year ago

To be more specific, I have identified that the problem seems to be occurring in the the elements attribute of an NSE object. I think you can access it by like this:

nmap_process = NmapProcess(targets=target_list)
nmap_process_output = NmapParser.parse(nmap_process.stdout)

hosts = nmap_process_output.hosts

for host in hosts:
  services = host.services
  for service in services:
    nse_results = service.script_results

    for nse_script in nse_results:
      nse_id = nse_script.get('id')
      nse_output = nse_script.get('output')
      nse_elements = nse_script.get('elements') # THIS IS WHERE THE PROBLEM APPEARS TO BE