├── README.txt └── sslScrape.py /README.txt: -------------------------------------------------------------------------------- 1 | # sslScrape 2 | SSLScrape | A scanning tool for scaping hostnames from SSL certificates. 3 | Written by Peter Kim and @bbuerhaus 4 | 5 | 6 | _________ _________.____ _________ 7 | / _____// _____/| | / _____/ ________________ ______ ____ 8 | \_____ \ \_____ \ | | \_____ \_/ ___\_ __ \__ \ \____ \_/ __ \ 9 | / \/ \| |___ / \ \___| | \// __ \| |_> > ___/ 10 | /_______ /_______ /|_______ \/_______ /\___ >__| (____ / __/ \___ > 11 | \/ \/ \/ \/ \/ \/|__| \/ 12 | 13 | Usage | python sslScrape.py [CIDR Range] 14 | E.X | python sslScrape.py 10.100.100.0/24 15 | 16 | Requirements: 17 | pip install ndg-httpsclient 18 | pip install python-masscan 19 | -------------------------------------------------------------------------------- /sslScrape.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #Description: SSLScrape is a tool that scans the internet and pulls hostnames from certificates. This tools can be used to scan cloud ranges to find hostnames for your systems. This tool is used for research purposes and please make sure to have proper approvals before scanning. 3 | 4 | def banner(): 5 | #Our banner, doubled slashes added for proper formatting when banner is shown in STDOUT. 6 | print "-" * 70 7 | print """ 8 | 9 | _________ _________.____ _________ 10 | / _____// _____/| | / _____/ ________________ ______ ____ 11 | \_____ \ \_____ \ | | \_____ \_/ ___\_ __ \__ \ \____ \_/ __ \ 12 | / \/ \| |___ / \ \___| | \// __ \| |_> > ___/ 13 | /_______ /_______ /|_______ \/_______ /\___ >__| (____ / __/ \___ > 14 | \/ \/ \/ \/ \/ \/|__| \/ 15 | 16 | SSLScrape | A scanning tool for scaping hostnames from SSL certificates. 17 | Written by Peter Kim and @bbuerhaus 18 | 19 | """ 20 | print "Usage | python sslScrape.py [CIDR Range]" 21 | print "E.X | python sslScrape.py 10.100.100.0/24" 22 | print "-" * 70 23 | 24 | 25 | import sys, socket, ssl, requests, ipaddress 26 | from requests.packages.urllib3.exceptions import InsecureRequestWarning, InsecurePlatformWarning, SNIMissingWarning 27 | from socket import socket 28 | from OpenSSL import SSL 29 | from ndg.httpsclient.subj_alt_name import SubjectAltName 30 | from pyasn1.codec.der import decoder as der_decoder 31 | import masscan, errno, os, signal 32 | from functools import wraps 33 | 34 | #pip install ndg-httpsclient 35 | #pip install python-masscan 36 | class TimeoutError(Exception): 37 | pass 38 | 39 | def timeout(seconds=10, error_message=os.strerror(errno.ETIME)): 40 | def decorator(func): 41 | def _handle_timeout(signum, frame): 42 | raise TimeoutError(error_message) 43 | 44 | def wrapper(*args, **kwargs): 45 | signal.signal(signal.SIGALRM, _handle_timeout) 46 | signal.alarm(seconds) 47 | try: 48 | result = func(*args, **kwargs) 49 | finally: 50 | signal.alarm(0) 51 | return result 52 | 53 | return wraps(func)(wrapper) 54 | 55 | return decorator 56 | 57 | 58 | requests.packages.urllib3.disable_warnings(InsecureRequestWarning) 59 | requests.packages.urllib3.disable_warnings(InsecurePlatformWarning) 60 | requests.packages.urllib3.disable_warnings(SNIMissingWarning) 61 | 62 | @timeout(10) 63 | def getDomainFromCert(ipAddr, port = 443): 64 | context = SSL.Context(SSL.TLSv1_METHOD) 65 | context.set_options(SSL.OP_NO_SSLv2) 66 | context.set_verify(SSL.VERIFY_NONE, callback) 67 | sock = socket() 68 | try: 69 | ssl_sock = SSL.Connection(context, sock) 70 | sock.settimeout(0.5) 71 | ssl_sock.connect((str(ipAddr), port)) 72 | except: 73 | return False 74 | # do handshake 75 | try: 76 | # reset timeout for handshake 77 | sock.settimeout(None) 78 | # perform handshake 79 | ssl_sock.do_handshake() 80 | # get cert data 81 | cert = ssl_sock.get_peer_certificate() 82 | name = cert.get_subject().commonName.decode() 83 | # try to save all cn/alt names 84 | try: 85 | alt = get_subj_alt_name(cert) 86 | #print "alt" + alt 87 | #if alt == "": 88 | # return [name] 89 | if not alt: 90 | alt.append(name) 91 | return alt 92 | except: 93 | # failed, just save the CN instead 94 | print "asdf" 95 | return [name] 96 | 97 | except: 98 | pass 99 | 100 | def get_subj_alt_name(peer_cert): 101 | dns_name = [] 102 | general_names = SubjectAltName() 103 | for i in range(peer_cert.get_extension_count()): 104 | ext = peer_cert.get_extension(i) 105 | ext_name = ext.get_short_name() 106 | if ext_name == "subjectAltName": 107 | ext_dat = ext.get_data() 108 | decoded_dat = der_decoder.decode(ext_dat, asn1Spec=general_names) 109 | 110 | for name in decoded_dat: 111 | if isinstance(name, SubjectAltName): 112 | for entry in range(len(name)): 113 | component = name.getComponentByPosition(entry) 114 | dns_name.append(str(component.getComponent())) 115 | return dns_name 116 | 117 | def callback(conn, cert, errno, depth, result): 118 | if depth == 0 and (errno == 9 or errno == 10): 119 | return False 120 | return True 121 | 122 | if __name__ == "__main__": 123 | banner() 124 | try: 125 | cidr = sys.argv[1:][0] 126 | except: 127 | sys.exit(1) 128 | mas = masscan.PortScanner() 129 | mas.scan(cidr, ports='443') 130 | for host in mas.all_hosts: 131 | host = str(host) 132 | try: 133 | print host + ":" + ",".join(getDomainFromCert(host)) 134 | except: 135 | print host + ":fail" 136 | 137 | --------------------------------------------------------------------------------