def process_task(self, target, command, args): OUT_FORMAT = ' {0:<35}{1}'.format sslConn = create_sslyze_connection(target, self._shared_settings) # Make sure OpenSSL was built with support for compression to avoid false negatives if 'zlib compression' not in sslConn.get_available_compression_methods(): raise RuntimeError('OpenSSL was not built with support for zlib / compression. Did you build nassl yourself ?') try: # Perform the SSL handshake sslConn.connect() compName = sslConn.get_current_compression_method() except ClientAuthenticationError: # The server asked for a client cert compName = sslConn.get_current_compression_method() finally: sslConn.close() # Text output if compName: compTxt = 'Supported' else: compTxt = 'Disabled' cmdTitle = 'Compression' txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)] txtOutput.append(OUT_FORMAT("DEFLATE Compression:", compTxt)) # XML output xmlOutput = Element(command, title=cmdTitle) if compName: xmlNode = Element('compressionMethod', type="DEFLATE") xmlOutput.append(xmlNode) return PluginBase.PluginResult(txtOutput, xmlOutput)
def process_task(self, target, command): """ Connects to the target server and tries to get acceptable CAs for client cert """ (_, _, _, ssl_version) = target ssl_conn = create_sslyze_connection(target, self._shared_settings, ssl_version) res = [] try: # Perform the SSL handshake ssl_conn.connect() except ClientCertificateRequested: # The server asked for a client cert res = ssl_conn.get_client_CA_list() finally: ssl_conn.close() text_output = [self.PLUGIN_TITLE_FORMAT(self.CMD_TITLE)] if res: xml_output = Element(command, title=self.CMD_TITLE, isProvided="True") for ca in res: text_output.append(self.FIELD_FORMAT('', str(ca))) ca_xml = Element('ca') ca_xml.text = ca xml_output.append(ca_xml) else: xml_output = Element(command, title=self.CMD_TITLE, isProvided="False") return PluginBase.PluginResult(text_output, xml_output)
def process_task(self, target, command, args): OUT_FORMAT = ' {0:<25} {1}'.format sslConn = create_sslyze_connection(target, self._shared_settings) try: # Perform the SSL handshake sslConn.connect() compName = sslConn.get_current_compression_name() except ClientAuthenticationError: # The server asked for a client cert compName = sslConn.get_current_compression_name() finally: sslConn.close() # Text output if compName: compTxt = 'Enabled ' + compName compXml = {'isSupported':'True','type':compName.strip('()')} else: compTxt = 'Disabled' compXml = {'isSupported':'False'} cmdTitle = 'Compression' txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)] txtOutput.append(OUT_FORMAT("Compression Support:", compTxt)) # XML output xmlNode = Element('compression', compXml) xmlOutput = Element(command, title = cmdTitle) xmlOutput.append(xmlNode) return PluginBase.PluginResult(txtOutput, xmlOutput)
def _test_ciphersuite(self, target, ssl_version, ssl_cipher): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) sslConn.set_cipher_list(ssl_cipher) try: # Perform the SSL handshake sslConn.connect() except SSLHandshakeRejected as e: return 'rejectedCipherSuites', ssl_cipher, None, None, str(e) except: raise else: ssl_cipher = sslConn.get_current_cipher_name() keysize = sslConn.get_current_cipher_bits() if 'ECDH' in ssl_cipher: dh_infos = sslConn.get_ecdh_param() elif 'DH' in ssl_cipher: dh_infos = sslConn.get_dh_param() else: dh_infos = None status_msg = sslConn.post_handshake_check() return 'acceptedCipherSuites', ssl_cipher, keysize, dh_infos, status_msg finally: sslConn.close()
def _get_cert(self, target, storePath): """ Connects to the target server and uses the supplied trust store to validate the server's certificate. Returns the server's certificate and OCSP response. """ (_, _, _, sslVersion) = target sslConn = create_sslyze_connection(target, self._shared_settings, sslVersion, sslVerifyLocations=storePath) # Enable OCSP stapling sslConn.set_tlsext_status_ocsp() try: # Perform the SSL handshake sslConn.connect() ocspResp = sslConn.get_tlsext_status_ocsp_resp() x509Cert = sslConn.get_peer_certificate() (_, verifyStr) = sslConn.get_certificate_chain_verify_result() except ClientCertificateRequested: # The server asked for a client cert # We can get the server cert anyway ocspResp = sslConn.get_tlsext_status_ocsp_resp() x509Cert = sslConn.get_peer_certificate() (_, verifyStr) = sslConn.get_certificate_chain_verify_result() finally: sslConn.close() return (x509Cert, verifyStr, ocspResp)
def _get_hsts_header(self, target): hstsHeader = None MAX_REDIRECT = 5 nb_redirect = 0 httpGetFormat = "GET {0} HTTP/1.0\r\nHost: {1}\r\n{2}Connection: close\r\n\r\n".format httpPath = "/" httpAppend = "" while nb_redirect < MAX_REDIRECT: sslConn = create_sslyze_connection(target, self._shared_settings) # Perform the SSL handshake sslConn.connect() sslConn.write(httpGetFormat(httpPath, target[0], httpAppend)) httpResp = parse_http_response(sslConn.read(2048)) sslConn.close() if httpResp.version == 9: # HTTP 0.9 => Probably not an HTTP response raise Exception("Server did not return an HTTP response") elif 300 <= httpResp.status < 400: redirectHeader = httpResp.getheader("Location", None) cookieHeader = httpResp.getheader("Set-Cookie", None) if redirectHeader is None: break o = urlparse(redirectHeader) httpPath = o.path # Handle absolute redirection URL if o.hostname: if o.port: port = o.port else: if o.scheme == "https": port = 443 elif o.scheme == "http": # We would have to use urllib for http: URLs raise Exception("Error: server sent a redirection to HTTP.") else: port = target[2] target = (o.hostname, o.hostname, port, target[3]) # Handle cookies if cookieHeader: cookie = Cookie.SimpleCookie(cookieHeader) if cookie: httpAppend = "Cookie:" + cookie.output(attrs=[], header="", sep=";") + "\r\n" nb_redirect += 1 else: hstsHeader = httpResp.getheader("strict-transport-security", None) break return hstsHeader
def _pref_ciphersuite(self, target, ssl_version): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) try: # Perform the SSL handshake sslConn.connect() ssl_cipher = sslConn.get_cipher_name() if 'ADH' in ssl_cipher or 'AECDH' in ssl_cipher: keysize = 'Anon' # Anonymous, let s not care about the key size else: keysize = str(sslConn.get_cipher_bits()) + ' bits' status_msg = sslConn.post_handshake_check() return ('preferredCipherSuite', ssl_cipher, keysize, status_msg) except: return None finally: sslConn.close()
def _get_cert(self, target): """ Connects to the target server and returns the server's certificate and OCSP response. """ (host, ip, port, sslVersion) = target sslConn = create_sslyze_connection(target, self._shared_settings, sslVersion, sslVerifyLocations=MOZILLA_CA_STORE) # Enable OCSP stapling sslConn.set_tlsext_status_ocsp() try: # Perform the SSL handshake sslConn.connect() ocspResp = sslConn.get_tlsext_status_ocsp_resp() x509Cert = sslConn.get_peer_certificate() (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result() except ClientAuthenticationError: # The server asked for a client cert # We can get the server cert anyway ocspResp = sslConn.get_tlsext_status_ocsp_resp() x509Cert = sslConn.get_peer_certificate() (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result() finally: sslConn.close() return (x509Cert, verifyStr, ocspResp)
def _get_cert(self, target, trustStoreList): """ Connects to the target server and returns the server's certificate Also performs verification against multiple trust stores. """ verifyResults = {} for trustStorePath in trustStoreList: (host, ip, port, sslVersion) = target sslConn = create_sslyze_connection(target, self._shared_settings, sslVersion, sslVerifyLocations=trustStorePath) try: # Perform the SSL handshake sslConn.connect() x509Cert = sslConn.get_peer_certificate() (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result() except ClientCertificateError: # The server asked for a client cert # We can get the server cert anyway x509Cert = sslConn.get_peer_certificate() (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result() finally: sslConn.close() verifyResults[trustStorePath] = verifyStr return (x509Cert, verifyResults)
def _get_cert(self, target, trustStoreList): """ Connects to the target server and returns the server's certificate Also performs verification against multiple trust stores. """ verifyResults = {} for trustStorePath in trustStoreList: (host, ip, port, sslVersion) = target sslConn = create_sslyze_connection( target, self._shared_settings, sslVersion, sslVerifyLocations=trustStorePath) try: # Perform the SSL handshake sslConn.connect() x509Cert = sslConn.get_peer_certificate() (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result() except ClientCertificateError: # The server asked for a client cert # We can get the server cert anyway x509Cert = sslConn.get_peer_certificate() (verifyCode, verifyStr) = sslConn.get_certificate_chain_verify_result() finally: sslConn.close() verifyResults[trustStorePath] = verifyStr return (x509Cert, verifyResults)
def _get_cert(self, target, store_path): """ Connects to the target server and uses the supplied trust store to validate the server's certificate. Returns the server's certificate and OCSP response. """ (_, _, _, ssl_version) = target ssl_conn = create_sslyze_connection(target, self._shared_settings, ssl_version, sslVerifyLocations=store_path) # Enable OCSP stapling ssl_conn.set_tlsext_status_ocsp() try: # Perform the SSL handshake ssl_conn.connect() ocsp_resp = ssl_conn.get_tlsext_status_ocsp_resp() x509_cert_chain = ssl_conn.get_peer_cert_chain() (_, verify_str) = ssl_conn.get_certificate_chain_verify_result() except ClientCertificateRequested: # The server asked for a client cert # We can get the server cert anyway ocsp_resp = ssl_conn.get_tlsext_status_ocsp_resp() x509_cert_chain = ssl_conn.get_peer_cert_chain() (_, verify_str) = ssl_conn.get_certificate_chain_verify_result() finally: ssl_conn.close() return x509_cert_chain, verify_str, ocsp_resp
def _test_ciphersuite(self, target, ssl_version, ssl_cipher): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) sslConn.set_cipher_list(ssl_cipher) try: # Perform the SSL handshake sslConn.connect() except SSLHandshakeRejected as e: return 'rejectedCipherSuites', ssl_cipher, None, None, str(e) except: raise else: ssl_cipher = sslConn.get_current_cipher_name() keysize = sslConn.get_current_cipher_bits() if 'ECDH' in ssl_cipher : dh_infos = sslConn.get_ecdh_param() elif 'DH' in ssl_cipher : dh_infos = sslConn.get_dh_param() else : dh_infos = None status_msg = sslConn.post_handshake_check() return 'acceptedCipherSuites', ssl_cipher, keysize, dh_infos, status_msg finally: sslConn.close()
def _pref_ciphersuite(self, target, ssl_version): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) try: # Perform the SSL handshake sslConn.connect() ssl_cipher = sslConn.get_current_cipher_name() keysize = sslConn.get_current_cipher_bits() if 'ECDH' in ssl_cipher: dh_infos = sslConn.get_ecdh_param() elif 'DH' in ssl_cipher: dh_infos = sslConn.get_dh_param() else: dh_infos = None status_msg = sslConn.post_handshake_check() return 'preferredCipherSuite', ssl_cipher, keysize, dh_infos, status_msg except: return None finally: sslConn.close()
def _pref_ciphersuite(self, target, ssl_version): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) try: # Perform the SSL handshake sslConn.connect() ssl_cipher = sslConn.get_current_cipher_name() keysize = sslConn.get_current_cipher_bits() if 'ECDH' in ssl_cipher : dh_infos = sslConn.get_ecdh_param() elif 'DH' in ssl_cipher : dh_infos = sslConn.get_dh_param() else : dh_infos = None status_msg = sslConn.post_handshake_check() return 'preferredCipherSuite', ssl_cipher, keysize, dh_infos, status_msg except: return None finally: sslConn.close()
def process_task(self, target, command, args): OUT_FORMAT = ' {0:<25} {1}'.format sslConn = create_sslyze_connection(target, self._shared_settings) try: # Perform the SSL handshake sslConn.connect() compName = sslConn.get_current_compression_name() except ClientAuthenticationError: # The server asked for a client cert compName = sslConn.get_current_compression_name() finally: sslConn.close() # Text output if compName: compTxt = 'Enabled ' + compName compXml = {'isSupported': 'True', 'type': compName.strip('()')} else: compTxt = 'Disabled' compXml = {'isSupported': 'False'} cmdTitle = 'Compression' txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)] txtOutput.append(OUT_FORMAT("Compression Support:", compTxt)) # XML output xmlNode = Element('compression', compXml) xmlOutput = Element(command, title=cmdTitle) xmlOutput.append(xmlNode) return PluginBase.PluginResult(txtOutput, xmlOutput)
def _test_ciphersuite(self, target, ssl_version, ssl_cipher): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) sslConn.set_cipher_list(ssl_cipher) try: # Perform the SSL handshake sslConn.connect() except SSLHandshakeRejected as e: return 'rejectedCipherSuites', ssl_cipher, None, str(e) except: raise else: ssl_cipher = sslConn.get_current_cipher_name() if 'ADH' in ssl_cipher or 'AECDH' in ssl_cipher: keysize = 'Anon' # Anonymous, let s not care about the key size else: keysize = str(sslConn.get_current_cipher_bits()) + ' bits' status_msg = sslConn.post_handshake_check() return 'acceptedCipherSuites', ssl_cipher, keysize, status_msg finally: sslConn.close()
def _pref_ciphersuite(self, target, ssl_version): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) # logging.debug("call _pref_ciphersuite(%s, %s)"%(target, ssl_version)) # Do not count -> nur Connections fuer accepted /rejected # self.log_connection_counter += 0 try: # Perform the SSL handshake sslConn.connect() ssl_cipher = sslConn.get_current_cipher_name() keysize = sslConn.get_current_cipher_bits() if 'ECDH' in ssl_cipher: dh_infos = sslConn.get_ecdh_param() elif 'DH' in ssl_cipher: dh_infos = sslConn.get_dh_param() else: dh_infos = None status_msg = sslConn.post_handshake_check() return [('preferredCipherSuite', ssl_cipher, keysize, dh_infos, status_msg)] except: return [] finally: sslConn.close()
def process_task(self, target, command, args): OUT_FORMAT = ' {0:<35}{1}'.format (host, ip, port, sslVersion) = target if sslVersion == SSLV23: # Could not determine the preferred SSL version - client cert was required ? sslVersion = TLSV1 # Default to TLS 1.0 target = (host, ip, port, sslVersion) sslConn = create_sslyze_connection(target, self._shared_settings) sslConn.sslVersion = sslVersion # Needed by the heartbleed payload # Awful hack #1: replace nassl.sslClient.do_handshake() with a heartbleed # checking SSL handshake so that all the SSLyze options # (startTLS, proxy, etc.) still work sslConn.do_handshake = new.instancemethod(do_handshake_with_heartbleed, sslConn, None) heartbleed = None try: # Perform the SSL handshake sslConn.connect() except HeartbleedSent: # Awful hack #2: directly read the underlying network socket heartbleed = sslConn._sock.recv(16381) finally: sslConn.close() # Text output if heartbleed is None: raise Exception("Error: connection failed.") elif '\x01\x01\x01\x01\x01\x01\x01\x01\x01' in heartbleed: # Server replied with our hearbeat payload heartbleedTxt = 'VULNERABLE - Server is vulnerable to Heartbleed' heartbleedXml = 'True' else: heartbleedTxt = 'OK - Not vulnerable to Heartbleed' heartbleedXml = 'False' cmdTitle = 'OpenSSL Heartbleed' txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)] txtOutput.append(OUT_FORMAT(heartbleedTxt, "")) # XML output xmlOutput = Element(command, title=cmdTitle) if heartbleed: xmlNode = Element('heartbleed', isVulnerable=heartbleedXml) xmlOutput.append(xmlNode) return PluginBase.PluginResult(txtOutput, xmlOutput)
def process_task(self, target, command, args): OUT_FORMAT = ' {0:<35}{1}'.format (host, ip, port, sslVersion) = target if sslVersion == SSLV23: # Could not determine the preferred SSL version - client cert was required ? sslVersion = TLSV1 # Default to TLS 1.0 target = (host, ip, port, sslVersion) sslConn = create_sslyze_connection(target, self._shared_settings) sslConn.sslVersion = sslVersion # Needed by the heartbleed payload # Awful hack #1: replace nassl.sslClient.do_handshake() with a heartbleed # checking SSL handshake so that all the SSLyze options # (startTLS, proxy, etc.) still work sslConn.do_handshake = new.instancemethod(do_handshake_with_heartbleed, sslConn, None) heartbleed = None try: # Perform the SSL handshake sslConn.connect() except HeartbleedSent: # Awful hack #2: directly read the underlying network socket heartbleed = sslConn._sock.recv(16381) finally: sslConn.close() # Text output if heartbleed is None: raise Exception("Error: connection failed.") elif '\x01\x01\x01\x01\x01\x01\x01\x01\x01' in heartbleed: # Server replied with our hearbeat payload heartbleedTxt = 'VULNERABLE' heartbleedXml = 'True' else: heartbleedTxt = 'NOT vulnerable' heartbleedXml = 'False' cmdTitle = 'Heartbleed' txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)] txtOutput.append(OUT_FORMAT("OpenSSL Heartbleed:", heartbleedTxt)) # XML output xmlOutput = Element(command, title=cmdTitle) if heartbleed: xmlNode = Element('heartbleed', isVulnerable=heartbleedXml) xmlOutput.append(xmlNode) return PluginBase.PluginResult(txtOutput, xmlOutput)
def _test_renegotiation(self, target): """ Checks whether the server honors session renegotiation requests and whether it supports secure renegotiation. """ sslConn = create_sslyze_connection(target, self._shared_settings) try: # Perform the SSL handshake sslConn.connect() secureReneg = sslConn.get_secure_renegotiation_support() try: # Let's try to renegotiate sslConn.do_renegotiate() clientReneg = True # Errors caused by a server rejecting the renegotiation except socket.error as e: if 'connection was forcibly closed' in str(e.args): clientReneg = False elif 'reset by peer' in str(e.args): clientReneg = False else: raise #except socket.timeout as e: # result_reneg = 'Rejected (timeout)' except OpenSSLError as e: if 'handshake failure' in str(e.args): clientReneg = False elif 'no renegotiation' in str(e.args): clientReneg = False elif 'tlsv1 unrecognized name' in str(e.args): # Yahoo's very own way of rejecting a renegotiation clientReneg = False else: raise # Should be last as socket errors are also IOError except IOError as e: if 'Nassl SSL handshake failed' in str(e.args): clientReneg = False else: raise finally: sslConn.close() return (clientReneg, secureReneg)
def _get_hsts_header(self, target): hstsHeader = None HTTP_GET_REQ = 'GET / HTTP/1.0\r\nHost: {0}\r\nConnection: close\r\n\r\n'.format(target[0]) sslConn = create_sslyze_connection(target, self._shared_settings) # Perform the SSL handshake sslConn.connect() sslConn.write(HTTP_GET_REQ) httpResp = parse_http_response(sslConn.read(2048)) sslConn.close() if httpResp.version == 9 : # HTTP 0.9 => Probably not an HTTP response raise Exception('Server did not return an HTTP response') else: hstsHeader = httpResp.getheader('strict-transport-security', None) return hstsHeader
def _get_hsts_header(self, target): hstsHeader = None HTTP_GET_REQ = 'GET / HTTP/1.0\r\nHost: {0}\r\nConnection: close\r\n\r\n'.format( target[0]) sslConn = create_sslyze_connection(target, self._shared_settings) # Perform the SSL handshake sslConn.connect() sslConn.write(HTTP_GET_REQ) httpResp = parse_http_response(sslConn.read(2048)) sslConn.close() if httpResp.version == 9: # HTTP 0.9 => Probably not an HTTP response raise Exception('Server did not return an HTTP response') else: hstsHeader = httpResp.getheader('strict-transport-security', None) return hstsHeader
def _test_ciphersuite(self, target, ssl_version, ssl_cipher, cipher_dict): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) sslConn.set_cipher_list(ssl_cipher) try: # Perform the SSL handshake sslConn.connect() except SSLHandshakeRejected as e: return 'rejectedCipherSuites', ssl_cipher, None, None, str(e) except: raise else: ssl_cipher = sslConn.get_current_cipher_name() keysize = sslConn.get_current_cipher_bits() if 'ECDH' in ssl_cipher: dh_infos = sslConn.get_ecdh_param() elif 'DH' in ssl_cipher: dh_infos = sslConn.get_dh_param() else: dh_infos = None status_msg = sslConn.post_handshake_check() # append *WEAK* if cipher is known to be vulnerable if ssl_cipher not in cipher_dict.get('whitelist'): for item in cipher_dict.get('blacklist'): if item in ssl_cipher: ssl_cipher += ' *WEAK*' break if '*WEAK*' not in ssl_cipher: ssl_cipher += ' (~Possibly Vulnerable~)' return 'acceptedCipherSuites', ssl_cipher, keysize, dh_infos, status_msg finally: sslConn.close()
def _test_ciphersuite(self, target, ssl_version, ssl_ciphers): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ # logging.debug("call _test_ciphersuite(%s, %s, %s)"%(target, ssl_version, ssl_ciphers)) self.log_connection_counter += 1 sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) sslConn.set_cipher_list(":".join(ssl_ciphers)) try: # Perform the SSL handshake sslConn.connect() except SSLHandshakeRejected as e: # if the ciphers are rejected it can be a multi result # logging.debug(" rejected %s" % ssl_ciphers) return [('rejectedCipherSuites', ssl_cipher, None, None, str(e)) for ssl_cipher in ssl_ciphers] except: raise else: ssl_cipher = sslConn.get_current_cipher_name() keysize = sslConn.get_current_cipher_bits() if 'ECDH' in ssl_cipher: dh_infos = sslConn.get_ecdh_param() elif 'DH' in ssl_cipher: dh_infos = sslConn.get_dh_param() else: dh_infos = None status_msg = sslConn.post_handshake_check() # if the cipher is accepted it is for sure a single result # logging.debug(" accepted %s in %s" % (ssl_cipher, ssl_ciphers)) return [('acceptedCipherSuites', ssl_cipher, keysize, dh_infos, status_msg)] finally: sslConn.close()
def _test_ciphersuite(self, target, ssl_version, ssl_cipher, cipher_dict): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) sslConn.set_cipher_list(ssl_cipher) try: # Perform the SSL handshake sslConn.connect() except SSLHandshakeRejected as e: return "rejectedCipherSuites", ssl_cipher, None, None, str(e) except: raise else: ssl_cipher = sslConn.get_current_cipher_name() keysize = sslConn.get_current_cipher_bits() if "ECDH" in ssl_cipher: dh_infos = sslConn.get_ecdh_param() elif "DH" in ssl_cipher: dh_infos = sslConn.get_dh_param() else: dh_infos = None status_msg = sslConn.post_handshake_check() # append *WEAK* if cipher is known to be vulnerable if ssl_cipher not in cipher_dict.get("whitelist"): for item in cipher_dict.get("blacklist"): if item in ssl_cipher: ssl_cipher += " *WEAK*" break if "*WEAK*" not in ssl_cipher: ssl_cipher += " (~Possibly Vulnerable~)" return "acceptedCipherSuites", ssl_cipher, keysize, dh_infos, status_msg finally: sslConn.close()
def process_task(self, target, command, args): OUT_FORMAT = ' {0:<35}{1}'.format sslConn = create_sslyze_connection(target, self._shared_settings) # Make sure OpenSSL was built with support for compression to avoid false negatives if 'zlib compression' not in sslConn.get_available_compression_methods( ): raise RuntimeError( 'OpenSSL was not built with support for zlib / compression. Did you build nassl yourself ?' ) try: # Perform the SSL handshake sslConn.connect() compName = sslConn.get_current_compression_method() except ClientCertificateRequested: # The server asked for a client cert compName = sslConn.get_current_compression_method() finally: sslConn.close() # Text output if compName: compTxt = 'Supported' else: compTxt = 'Disabled' cmdTitle = 'Compression' txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)] txtOutput.append(OUT_FORMAT("DEFLATE Compression:", compTxt)) # XML output xmlOutput = Element(command, title=cmdTitle) if compName: xmlNode = Element('compressionMethod', type="DEFLATE") xmlOutput.append(xmlNode) return PluginBase.PluginResult(txtOutput, xmlOutput)
def _resume_ssl_session(self, target, sslSession=None, tlsTicket=False): """ Connect to the server and returns the session object that was assigned for that connection. If ssl_session is given, tries to resume that session. """ sslConn = create_sslyze_connection(target, self._shared_settings) if not tlsTicket: # Need to disable TLS tickets to test session IDs, according to rfc5077: # If a ticket is presented by the client, the server MUST NOT attempt # to use the Session ID in the ClientHello for stateful session resumption sslConn.set_options(SSL_OP_NO_TICKET) # Turning off TLS tickets. if sslSession: sslConn.set_session(sslSession) try: # Perform the SSL handshake sslConn.connect() newSession = sslConn.get_session() # Get session data finally: sslConn.close() return newSession
def process_task(self, target, command, args): sslConn = create_sslyze_connection(target, self._shared_settings) # Make sure OpenSSL was built with support for compression to avoid false negatives if 'zlib compression' not in sslConn.get_available_compression_methods(): raise RuntimeError('OpenSSL was not built with support for zlib / compression. Did you build nassl yourself ?') try: # Perform the SSL handshake sslConn.connect() compName = sslConn.get_current_compression_method() except ClientCertificateRequested: # The server asked for a client cert compName = sslConn.get_current_compression_method() finally: sslConn.close() # Text output if compName: compTxt = 'VULNERABLE - Server supports Deflate compression' else: compTxt = 'OK - Compression disabled' cmdTitle = 'Deflate Compression' txtOutput = [self.PLUGIN_TITLE_FORMAT(cmdTitle)] txtOutput.append(self.FIELD_FORMAT(compTxt, "")) # XML output xmlOutput = Element(command, title=cmdTitle) if compName: xmlNode = Element('compressionMethod', type="DEFLATE", isSupported="True") xmlOutput.append(xmlNode) else: xmlNode = Element('compressionMethod', type="DEFLATE", isSupported="False") xmlOutput.append(xmlNode) return PluginBase.PluginResult(txtOutput, xmlOutput)
def _pref_ciphersuite(self, target, ssl_version): """ Initiates a SSL handshake with the server, using the SSL version and cipher suite specified. """ sslConn = create_sslyze_connection(target, self._shared_settings, ssl_version) try: # Perform the SSL handshake sslConn.connect() ssl_cipher = sslConn.get_cipher_name() if 'ADH' in ssl_cipher or 'AECDH' in ssl_cipher: keysize = 'Anon' # Anonymous, let s not care about the key size else: keysize = str(sslConn.get_cipher_bits())+' bits' status_msg = sslConn.post_handshake_check() return ('preferredCipherSuite', ssl_cipher, keysize, status_msg) except: return None finally: sslConn.close()
def _get_hsts_header(self, target): hstsHeader = None MAX_REDIRECT = 5 nb_redirect = 0 httpGetFormat = 'GET {0} HTTP/1.0\r\nHost: {1}\r\n{2}Connection: close\r\n\r\n'.format httpPath = '/' httpAppend = '' while nb_redirect < MAX_REDIRECT: sslConn = create_sslyze_connection(target, self._shared_settings) # Perform the SSL handshake sslConn.connect() sslConn.write(httpGetFormat(httpPath, target[0], httpAppend)) httpResp = parse_http_response(sslConn.read(2048)) sslConn.close() if httpResp.version == 9 : # HTTP 0.9 => Probably not an HTTP response raise Exception('Server did not return an HTTP response') else: hstsHeader = httpResp.getheader('strict-transport-security', None) # If there was no HSTS header, check if the server returned a redirection if hstsHeader is None and 300 <= httpResp.status < 400: redirectHeader = httpResp.getheader('Location', None) cookieHeader = httpResp.getheader('Set-Cookie', None) if redirectHeader is None: break o = urlparse(redirectHeader) httpPath = o.path # Handle absolute redirection URL if o.hostname: if o.port: port = o.port else: if o.scheme == 'https': port = 443 elif o.scheme == 'http': # We would have to use urllib for http: URLs raise Exception("Error: server sent a redirection to HTTP.") else: port = target[2] target = (o.hostname, o.hostname, port, target[3]) # Handle cookies if cookieHeader: cookie = Cookie.SimpleCookie(cookieHeader) if cookie: httpAppend = 'Cookie:' + cookie.output(attrs=[], header='', sep=';') + '\r\n' nb_redirect+=1 else: # If the server did not return a redirection just give up break return hstsHeader
def process_task(self, target, command, arg): (_, _, _, sslVersion) = target # Get the server's cert chain sslConn = create_sslyze_connection(target, self._shared_settings, sslVersion) try: # Perform the SSL handshake sslConn.connect() certChain = sslConn.get_peer_cert_chain() except ClientCertificateRequested: # The server asked for a client cert # We can get the server cert chain anyway certChain = sslConn.get_peer_cert_chain() finally: sslConn.close() outputXml = Element(command, title = self.CMD_TITLE) outputTxt = [self.PLUGIN_TITLE_FORMAT(self.CMD_TITLE)] # Is this cert chain affected ? leafNotAfter = datetime.datetime.strptime(certChain[0].as_dict()['validity']['notAfter'], "%b %d %H:%M:%S %Y %Z") if leafNotAfter.year < 2016: # Not affected - the certificate expires before 2016 outputTxt.append(self.FIELD_FORMAT('OK - Leaf certificate expires before 2016.', '')) outputXml.append(Element('chromeSha1Deprecation', isServerAffected = str(False))) else: certsWithSha1 = [] for cert in certChain: if self._is_root_cert(cert): # Ignore root certs as they are unaffected continue if "sha1" in cert.as_dict()['signatureAlgorithm']: certsWithSha1.append(cert) if certsWithSha1 == []: # Not affected - no certificates used SHA-1 in the chain outputTxt.append(self.FIELD_FORMAT('OK - Certificate chain does not contain any SHA-1 certificate.', '')) outputXml.append(Element('chromeSha1Deprecation', isServerAffected = str(False))) else: # Server is affected leafCertNotAfter = certChain[0].as_dict()['validity']['notAfter'] outputXml2 = Element('chromeSha1Deprecation', isServerAffected = str(True), leafCertificateNotAfter = leafCertNotAfter) chrome39Txt = 'OK' chrome40Txt = 'OK' if leafNotAfter.year == 2016 and leafNotAfter.month < 6: chrome41Txt = self.CHROME_MINOR_ERROR_TXT elif leafNotAfter.year == 2016 and leafNotAfter.month >= 6: chrome40Txt = self.CHROME_MINOR_ERROR_TXT chrome41Txt = self.CHROME_MINOR_ERROR_TXT else: # Certificate expires in 2017 chrome39Txt = self.CHROME_MINOR_ERROR_TXT chrome40Txt = self.CHROME_NEUTRAL_TXT chrome41Txt = self.CHROME_INSECURE_TXT # Text output certsWithSha1Txt = ['"{0}"'.format(PluginCertInfo._extract_subject_CN_or_OUN(cert)) for cert in certsWithSha1] outputTxt.append(self.FIELD_FORMAT("Chrome 39 behavior:", chrome39Txt)) outputTxt.append(self.FIELD_FORMAT("Chrome 40 behavior:", chrome40Txt)) outputTxt.append(self.FIELD_FORMAT("Chrome 41 behavior:", chrome41Txt)) outputTxt.append(self.FIELD_FORMAT("Leaf certificate notAfter field:", leafCertNotAfter)) outputTxt.append(self.FIELD_FORMAT("SHA1-signed certificates:", certsWithSha1Txt)) # XML output affectedCertsXml = Element('sha1SignedCertificates') for cert in certsWithSha1: affectedCertsXml.append(PluginCertInfo._format_cert_to_xml(cert, '', self._shared_settings['sni'])) outputXml2.append(affectedCertsXml) outputXml2.append(Element( 'chrome39', behavior = chrome39Txt, isAffected = str(False) if chrome39Txt is 'OK' else str(True))) outputXml2.append(Element( 'chrome40', behavior = chrome40Txt, isAffected = str(False) if chrome40Txt is 'OK' else str(True))) outputXml2.append(Element( 'chrome41', behavior = chrome41Txt, isAffected = str(True))) outputXml.append(outputXml2) return PluginBase.PluginResult(outputTxt, outputXml)
def process_task(self, target, command, arg): (_, _, _, sslVersion) = target # Get the server's cert chain sslConn = create_sslyze_connection(target, self._shared_settings, sslVersion) try: # Perform the SSL handshake sslConn.connect() certChain = sslConn.get_peer_cert_chain() except ClientCertificateRequested: # The server asked for a client cert # We can get the server cert chain anyway certChain = sslConn.get_peer_cert_chain() finally: sslConn.close() outputXml = Element(command, title=self.CMD_TITLE) outputTxt = [self.PLUGIN_TITLE_FORMAT(self.CMD_TITLE)] # Is this cert chain affected ? leafNotAfter = datetime.datetime.strptime( certChain[0].as_dict()['validity']['notAfter'], "%b %d %H:%M:%S %Y %Z") if leafNotAfter.year < 2016: # Not affected - the certificate expires before 2016 outputTxt.append( self.FIELD_FORMAT('OK - Leaf certificate expires before 2016.', '')) outputXml.append( Element('chromeSha1Deprecation', isServerAffected=str(False))) else: certsWithSha1 = [] for cert in certChain: if self._is_root_cert(cert): # Ignore root certs as they are unaffected continue if "sha1" in cert.as_dict()['signatureAlgorithm']: certsWithSha1.append(cert) if certsWithSha1 == []: # Not affected - no certificates used SHA-1 in the chain outputTxt.append( self.FIELD_FORMAT( 'OK - Certificate chain does not contain any SHA-1 certificate.', '')) outputXml.append( Element('chromeSha1Deprecation', isServerAffected=str(False))) else: # Server is affected leafCertNotAfter = certChain[0].as_dict( )['validity']['notAfter'] outputXml2 = Element('chromeSha1Deprecation', isServerAffected=str(True), leafCertificateNotAfter=leafCertNotAfter) chrome39Txt = 'OK' chrome40Txt = 'OK' if leafNotAfter.year == 2016 and leafNotAfter.month < 6: chrome41Txt = self.CHROME_MINOR_ERROR_TXT elif leafNotAfter.year == 2016 and leafNotAfter.month >= 6: chrome40Txt = self.CHROME_MINOR_ERROR_TXT chrome41Txt = self.CHROME_MINOR_ERROR_TXT else: # Certificate expires in 2017 chrome39Txt = self.CHROME_MINOR_ERROR_TXT chrome40Txt = self.CHROME_NEUTRAL_TXT chrome41Txt = self.CHROME_INSECURE_TXT # Text output certsWithSha1Txt = [ '"{0}"'.format( PluginCertInfo._extract_subject_CN_or_OUN(cert)) for cert in certsWithSha1 ] outputTxt.append( self.FIELD_FORMAT("Chrome 39 behavior:", chrome39Txt)) outputTxt.append( self.FIELD_FORMAT("Chrome 40 behavior:", chrome40Txt)) outputTxt.append( self.FIELD_FORMAT("Chrome 41 behavior:", chrome41Txt)) outputTxt.append( self.FIELD_FORMAT("Leaf certificate notAfter field:", leafCertNotAfter)) outputTxt.append( self.FIELD_FORMAT("SHA1-signed certificates:", certsWithSha1Txt)) # XML output affectedCertsXml = Element('sha1SignedCertificates') for cert in certsWithSha1: affectedCertsXml.append( PluginCertInfo._format_cert_to_xml( cert, '', self._shared_settings['sni'])) outputXml2.append(affectedCertsXml) outputXml2.append( Element('chrome39', behavior=chrome39Txt, isAffected=str(False) if chrome39Txt is 'OK' else str(True))) outputXml2.append( Element('chrome40', behavior=chrome40Txt, isAffected=str(False) if chrome40Txt is 'OK' else str(True))) outputXml2.append( Element('chrome41', behavior=chrome41Txt, isAffected=str(True))) outputXml.append(outputXml2) return PluginBase.PluginResult(outputTxt, outputXml)
def _get_hsts_header(self, target): hstsHeader = None MAX_REDIRECT = 5 nb_redirect = 0 httpGetFormat = 'GET {0} HTTP/1.0\r\nHost: {1}\r\n{2}Connection: close\r\n\r\n'.format httpPath = '/' httpAppend = '' while nb_redirect < MAX_REDIRECT: sslConn = create_sslyze_connection(target, self._shared_settings) # Perform the SSL handshake sslConn.connect() sslConn.write(httpGetFormat(httpPath, target[0], httpAppend)) httpResp = parse_http_response(sslConn.read(2048)) sslConn.close() if httpResp.version == 9: # HTTP 0.9 => Probably not an HTTP response raise Exception('Server did not return an HTTP response') else: hstsHeader = httpResp.getheader('strict-transport-security', False) # If there was no HSTS header, check if the server returned a redirection if hstsHeader is None and 300 <= httpResp.status < 400: redirectHeader = httpResp.getheader('Location', None) cookieHeader = httpResp.getheader('Set-Cookie', None) if redirectHeader is None: break o = urlparse(redirectHeader) httpPath = o.path # Handle absolute redirection URL if o.hostname: if o.port: port = o.port else: if o.scheme == 'https': port = 443 elif o.scheme == 'http': # We would have to use urllib for http: URLs raise Exception( "Error: server sent a redirection to HTTP.") else: port = target[2] target = (o.hostname, o.hostname, port, target[3]) # Handle cookies if cookieHeader: cookie = Cookie.SimpleCookie(cookieHeader) if cookie: httpAppend = 'Cookie:' + cookie.output( attrs=[], header='', sep=';') + '\r\n' nb_redirect += 1 else: # If the server did not return a redirection just give up break return hstsHeader