TOOLS |

Parse Nmap XML to get SSL Certificate details

Extract SSL certificate details from a range of IP addresses using Nmap XML and a simple python script.

The python script parses the Nmap XML output from the ssl-cert.nse script and produces csv output with the target SSL certificate details.

libssl-dev package

When compiling Nmap you need the libssl-dev package installed. Nmap nse scripts such as ssl-cert will not work without it.

Once this is installed ./configure, make, make install to install the latest version of Nmap.

apt-get install libssl-dev

Once the package is installed go ahead and install Nmap from source. Extract the source into a folder, configure and install.

Testing the SSL cert parse script

For a quick test of the SSL cert parse script I grabbed the top 25 computing sites from Alexa.

Start Nmap with the ssl-cert nse script. The -iL option loads the list 25 target host names with the -oX producing the Nmap XML results.

nmap -iL top25-tech.txt -sV -p 443 -oX nmap-results-top25 --script=ssl-cert

Python script

Once the scan has completed, the python script below can be used to parse the Nmap XML and produce the csv output. The results can be loaded into a spreadsheet, or parsed further, depending on your needs.

testuser@ubuntu:~$ python nmap-ssl-certs.py nmap-results-top25.xml
 
150.101.195.240,www.google.com,Google Inc,US,2014-05-07,2014-08-05
31.13.70.17,*.facebook.com,Facebook, Inc.,US,2014-02-28,2015-04-13
150.101.195.212,*.google.com,Google Inc,US,2014-05-07,2014-08-05
74.125.237.149,mail.google.com,Google Inc,US,2014-05-07,2014-08-05
98.139.183.24,www.yahoo.com,Yahoo Inc.,US,2014-04-09,2015-04-09
198.35.26.96,*.wikipedia.org,Wikimedia Foundation, Inc.,US,2012-10-21,2016-01-20
199.59.148.82,twitter.com,Twitter, Inc.,US,2014-04-08,2016-05-09
216.52.242.80,www.linkedin.com,LinkedIn Corporation,US,2013-12-19,2016-12-30
98.136.189.41,*.login.yahoo.com,Yahoo Inc.,US,2014-04-08,2015-04-09
65.55.143.19,mail.live.com,Microsoft Corporation,US,2013-05-21,2015-05-22
150.101.195.216,*.google.com,Google Inc,US,2014-05-07,2014-08-05
150.101.195.227,*.google.com,Google Inc,US,2014-05-07,2014-08-05
119.160.243.163,search.yahoo.com,Yahoo Inc.,US,2014-04-08,2015-04-09
192.0.82.252,wordpress.com,Automattic, Inc.,US,2014-04-16,2016-04-16
204.79.197.200,*.bing.com,Microsoft Corporation,US,2014-05-20,2016-05-19
54.225.139.43,*.pinterest.com,Pinterest Inc,US,2014-04-09,2017-04-13
66.235.120.127,,,,,
150.101.195.249,*.google.com,Google Inc,US,2014-05-07,2014-08-05
65.55.206.228,,,,,
66.211.169.66,paypal.com,PayPal, Inc.,US,2013-01-09,2015-01-11
134.170.188.221,microsoft.com,,,2013-06-20,2015-06-20
17.172.224.47,apple.com,Apple Inc.,US,2012-11-13,2014-11-03
23.23.110.81,*.imgur.com,Imgur, Inc.,US,2013-06-25,2016-08-31
198.252.206.140,*.stackexchange.com,Stack Exchange, Inc.,US,2013-07-02,2016-07-06
68.71.220.3,,,,,

The script is simple but it works. It should be pretty easy to read allowing modification to parse other NSE scripts and results from the Nmap XML output.

Parse XML data

There are many ways to parse XML data. The xml.dom method used here seems to be one of the more straightforward for parsing the Nmap XML. Another option could include using ElementTree, or even using xmlstarlet in bash as seen on this stack.exchange post.

#!/usr/bin/env python
import xml.dom.minidom
import sys
import getopt
try: 
    scandata = sys.argv[1]
except:
    print "*** You need to supply an Nmap XML file ***"
if scandata:
    doc = xml.dom.minidom.parse(scandata)
    output = []
    for host in doc.getElementsByTagName("host"):
        ip = ''
        commonName = ''
        organizationName = ''
        countryName = ''
        notBefore = ''
        notAfter = ''
        addresses = host.getElementsByTagName("address")
        ip = addresses[0].getAttribute("addr")                         # Get IP address from addr element 
        scripts = host.getElementsByTagName("script")
        for script in scripts:
              for elem in script.getElementsByTagName("elem"):         # Get cert details for each target 
                 try:
                    if elem.getAttribute("key") == 'commonName':
                       if commonName == '':                            # Only get the first commonName 
                           commonName =  elem.childNodes[0].nodeValue
                 except:
                    pass
                 try:
                    if elem.getAttribute("key") == 'organizationName':
                       if organizationName == '': 
                           organizationName =  elem.childNodes[0].nodeValue
                 except:
                    pass
                 try:
                    if elem.getAttribute("key") == 'countryName':
                       countryName =  elem.childNodes[0].nodeValue
                 except:
                    pass
                 try:
                    if elem.getAttribute("key") == 'notBefore':
                       notBefore =  elem.childNodes[0].nodeValue
                       notBefore = notBefore.split('T')[0]
                 except:
                    pass
                 try:
                    if elem.getAttribute("key") == 'notAfter':
                       notAfter =  elem.childNodes[0].nodeValue
                       notAfter = notAfter.split('T')[0]
                 except:
                    pass
        output.append(ip + ',' + commonName + ',' + organizationName + ',' + countryName + ',' + notBefore + ',' + notAfter)
    for i in output:
        print i

Nmap XML to CSV

Not specifically tied to the SSL results; we have another script that converts Nmap XML to CSV. This is an easy to use script that can be adapted to achieve the output needed for reporting.

Different organisations have different reporting requirements so this simple script was created to enable anyone to modify it as required with minimal python knowledge.

https://github.com/hackertarget/nmap-csv-xlsx