python-libnmap icon indicating copy to clipboard operation
python-libnmap copied to clipboard

Script results may contain "None" dict keys

Open happyc0ding opened this issue 4 years ago • 2 comments

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.

happyc0ding avatar Feb 25 '21 15:02 happyc0ding

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 avatar Apr 11 '23 00:04 0x303

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

0x303 avatar Apr 11 '23 00:04 0x303