2

I've been working on a Python program that searches through multiple ranges of IP addresses and checks for an SSL certificate/reads certain info off of it and then writes it to a CSV file.

The trouble I'm having with it now is that some of the IP addresses I'm going to be searching through may have multiple domain names on the same IP address. I've been looking around to try and come up with some type of solution for this, but there doesn't seem to be much documentation on checking IP addresses with SNI in OpenSSL

Also, another issue I'm having is that I want to grab the server type(eg. apache, nginx, etc..) from the certificate, but OpenSSL doesn't seem to provide that info. Curl on the other hand does, and I'm actually using curl to establish whether or not a cert is found on an IP address -- I just don't know how I would be able to grab that information from curl's output.

If anyone can give me some input as to how I would implement the two features listed above, I'd really appreciate it

Here is the code I have so far(excuse the really long hardcoded threading -- I haven't had a chance to clean it up):

from subprocess import *
import time
import ssl
import OpenSSL
import threading
import sys
import csv

def main():
    global IP_list
    IP_list = []

    global certInfoHolder
    certInfoHolder = []

    getRanges()


def getRanges():
    print 'Enter a range(ex. From: 192.168.1.0 , To: 192.168.1.10)'
    starting_IP = raw_input('From: ')
    ending_IP = raw_input('To: ')


    ip_ranges = ipRange(starting_IP, ending_IP)
    addMore = raw_input('Do you want to add another IP range?Y/N')
    addmore = addMore.lower()
    if addMore == 'y' or addMore == 'yes':
        getRanges()

    elif addMore == 'n' or addMore =='no':
        print 'Done gathering IP Addresses'
        createdThreads = 0
        threadSplit = len(IP_list) / 10

        #Splitting the work up between the threads
        thread_1_list = IP_list[0:threadSplit]
        thread_2_list = IP_list[threadSplit:(threadSplit*2)]
        thread_3_list = IP_list[(threadSplit*2):(threadSplit*3)]
        thread_4_list = IP_list[(threadSplit*3):(threadSplit*4)]
        thread_5_list = IP_list[(threadSplit*4):(threadSplit*5)]
        thread_6_list = IP_list[(threadSplit*5):(threadSplit*6)]
        thread_7_list = IP_list[(threadSplit*6):(threadSplit*7)]
        thread_8_list = IP_list[(threadSplit*7):(threadSplit*8)]
        thread_9_list = IP_list[(threadSplit*8):(threadSplit*9)]
        thread_10_list = IP_list[(threadSplit*9):(threadSplit*10)]


        print '5 Threads..Splitting the work up to: ' , threadSplit
        for address in range(threadSplit):
            print address
            thread_1 = getCertInfo(thread_1_list[address])
            thread_2 = getCertInfo(thread_2_list[address])
            thread_3 = getCertInfo(thread_3_list[address])
            thread_4 = getCertInfo(thread_4_list[address])
            thread_5 = getCertInfo(thread_5_list[address])
            thread_6 = getCertInfo(thread_6_list[address])
            thread_7 = getCertInfo(thread_7_list[address])
            thread_8 = getCertInfo(thread_8_list[address])
            thread_9 = getCertInfo(thread_9_list[address])
            thread_10 = getCertInfo(thread_10_list[address])
            thread_1.start()
            thread_2.start()
            thread_3.start()
            thread_4.start()
            thread_5.start()
            thread_6.start()
            thread_7.start()
            thread_8.start()
            thread_9.start()
            thread_10.start()
            thread_1.join()
            thread_2.join()
            thread_3.join()
            thread_4.join()
            thread_5.join()
            thread_6.join()
            thread_7.join()
            thread_8.join()
            thread_9.join()
            thread_10.join()
            if address == threadSplit-1:
                for address in range(threadSplit,len(thread_5_list)):
                     thread_10 = getCertInfo(thread_10_list[address])
                     thread_10.start()
                     thread_10.join()

        c = csv.writer(open("AInfo.csv", "a"))
        CIH = certInfoHolder

        for info in CIH:
            c.writerow([info[0], info[1], info[2], info[3], info[4]])

        print 'DONE'



def ipRange(start_ip, end_ip):
    start = list(map(int, start_ip.split(".")))
    end = list(map(int, end_ip.split(".")))
    temp = start

    IP_list.append(start_ip)
    while temp != end:
        start[3] += 1
        for i in (3, 2, 1):
            if temp[i] == 256:
                temp[i] = 0
                temp[i-1] += 1        
        IP = ".".join(map(str, temp))
        IP_list.append(IP)
    print 'IP_List size', len(IP_list)


class getCertInfo(threading.Thread):
     def __init__(self,IP):
         threading.Thread.__init__(self)
         self.IP_check=IP

     def run(self):
        try:
            #Using curl to check for a timeout
            self.getCert = check_output('curl --max-time 2 '+self.IP_check,
            stderr=STDOUT,
            shell=True)
            #OpenSSL get server certificate
            self.server_certificate = ssl.get_server_certificate((self.IP_check, 443))
            self.x509 = OpenSSL.crypto.load_certificate(OpenSSL.crypto.FILETYPE_PEM, self.server_certificate)

            #Formatting expiration date and time
            self.eDateT = str(self.x509.get_notAfter())
            #173.252.110.27
            self.certInfo = self.x509.get_subject()
            self.commonName = self.certInfo.commonName
            self.companyName = self.certInfo.O
            self.serialNumber = self.x509.get_serial_number()
            self.x  = [str(self.IP_check),str(self.companyName),str(self.eDateT),
                       str(self.commonName),str(self.serialNumber)]
            certInfoHolder.append(self.x)

        except CalledProcessError as detail:
            print str(detail) + '   ' + self.IP_check +'\n'
            pass
Joe
  • 1,850
  • 1
  • 13
  • 15
  • [`subprocess.check_output()`](http://docs.python.org/2/library/subprocess.html#subprocess.check_output) will allow you to more easily scrape the results of a `curl` call. – yurisich Jun 19 '13 at 17:27
  • [`socket.gethostbyaddr()`](http://stackoverflow.com/a/2575779/881224) *may* be what you're looking for with DNS lookups. – yurisich Jun 19 '13 at 17:29

1 Answers1

1

SNI

You should be able to get there with Python 3.x series, 3.2+ if I understand correctly.

If you're stuck with Python 2, look at what python-requests does with two optional dependencies, ndg-httpsclient and pyasn1.

My understanding is that you can't really do much with plain Python <= 2.7.8 due to devs' perplexing view that SNI is somehow a feature of Python

EDIT

Thanks to PEP466, Python 2.7.9 contains ssl module backported from Python 3.4 and you have all the OpenSSL features.

Other projects

Perhaps sslyze (github) can do what you want already?

Dima Tisnek
  • 11,241
  • 4
  • 68
  • 120