def test_sha1_chain(self): # The test server no longer works return server_info = ServerConnectivityInfo(hostname='sha1-2017.badssl.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.has_sha1_in_certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_hsts_enabled(self): server_info = ServerConnectivityInfo(hostname=u'hsts.badssl.com') server_info.test_connectivity_to_server() plugin = HttpHeadersPlugin() plugin_result = plugin.process_task(server_info, 'http_headers') self.assertTrue(plugin_result.hsts_header) self.assertFalse(plugin_result.hpkp_header) self.assertIsNone(plugin_result.is_valid_pin_configured) self.assertIsNone(plugin_result.is_backup_pin_configured) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_hpkp_enabled(self): server_info = ServerConnectivityInfo(hostname=u'github.com') server_info.test_connectivity_to_server() plugin = HttpHeadersPlugin() plugin_result = plugin.process_task(server_info, 'http_headers') self.assertTrue(plugin_result.hpkp_header) self.assertTrue(plugin_result.is_valid_pin_configured) self.assertTrue(plugin_result.is_backup_pin_configured) self.assertTrue(plugin_result.verified_certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def get_cert(site_json): hostname = get_hostname(site_json['hostname']) try: server_info = ServerConnectivityInfo(hostname=hostname) server_info.test_connectivity_to_server() command = CertificateInfoScanCommand() synchronous_scanner = SynchronousScanner() scan_result = synchronous_scanner.run_scan_command(server_info, command) except ServerConnectivityError: return None return scan_result
def test_resumption(self): server_info = ServerConnectivityInfo(hostname=u'www.google.com') server_info.test_connectivity_to_server() plugin = SessionResumptionPlugin() plugin_result = plugin.process_task(server_info, 'resum') self.assertTrue(plugin_result.is_ticket_resumption_supported) self.assertTrue(plugin_result.attempted_resumptions_nb) self.assertTrue(plugin_result.successful_resumptions_nb) self.assertFalse(plugin_result.errored_resumptions_list) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def enumerate_cipher_suites_for_ssl_service( self, org_uuid=None, network_service_uuid=None, network_service_scan_uuid=None, ): """ Enumerate all of the cipher suites that the given SSL/TLS service supports. :param org_uuid: The UUID of the organization to enumerate cipher suites on behalf of. :param network_service_uuid: The UUID of the network service that is being scanned. :param network_service_scan_uuid: The UUID of the network service scan that this enumeration is a part of. :return: None """ logger.info( "Now enumerating supported cipher suites for network service %s." % (network_service_uuid,) ) ip_address, port, protocol = self.get_endpoint_information(network_service_uuid) server_info = ServerConnectivityInfo(hostname=ip_address, ip_address=ip_address, port=port) try: server_info.test_connectivity_to_server() except ServerConnectivityError as e: logger.warning( "ServerConnectivityError thrown when attempting to inspect SSL at %s:%s: %s" % (ip_address, port, e.message) ) return scanner = SynchronousScanner() network_service_scan = NetworkServiceScan.by_uuid(db_session=self.db_session, uuid=network_service_scan_uuid) bulk_query = BulkElasticsearchQuery() for ssl_protocol, command in get_ssl_cipher_suite_commands(): result = scanner.run_scan_command(server_info, command()) ssl_support_record = SslSupportModel.from_database_model( network_service_scan, ssl_version=ssl_protocol, supported=len(result.accepted_cipher_list) > 0, ) ssl_support_record.accepted_ciphers = [cipher.name for cipher in result.accepted_cipher_list] ssl_support_record.rejected_ciphers = [cipher.name for cipher in result.rejected_cipher_list] ssl_support_record.errored_ciphers = [cipher.name for cipher in result.errored_cipher_list] ssl_support_record.preferred_cipher = result.preferred_cipher.name if result.preferred_cipher else None bulk_query.add_model_for_indexing(model=ssl_support_record, index=org_uuid) logger.info("All cipher suite information converted to Elasticsearch data. Now updating via bulk query.") bulk_query.save() logger.info( "Bulk query completed. SSL cipher suites enumerated for network service %s." % (network_service_uuid,) )
def test_dh_info(self): server_info = ServerConnectivityInfo(hostname='dh1024.badssl.com') server_info.test_connectivity_to_server() plugin = OpenSslCipherSuitesPlugin() plugin_result = plugin.process_task(server_info, Tlsv12ScanCommand()) self.assertTrue(plugin_result.preferred_cipher) self.assertEquals(plugin_result.preferred_cipher.dh_info['GroupSize'], '1024') self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_unicode_certificate(self): server_info = ServerConnectivityInfo(hostname='เพย์สบาย.th') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_fallback_good(self): server_info = ServerConnectivityInfo(hostname='www.google.com') server_info.test_connectivity_to_server() plugin = FallbackScsvPlugin() plugin_result = plugin.process_task(server_info, FallbackScsvScanCommand()) self.assertTrue(plugin_result.supports_fallback_scsv) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_expect_ct_enabled(self): # Github was the only server I could find with expect-ct header set server_info = ServerConnectivityInfo(hostname='github.com') server_info.test_connectivity_to_server() plugin = HttpHeadersPlugin() plugin_result = plugin.process_task(server_info, HttpHeadersScanCommand()) self.assertTrue(plugin_result.expect_ct_header) self.assertTrue(plugin_result.expect_ct_header.max_age >= 0) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) self.assertTrue(pickle.dumps(plugin_result))
def test_certificate_with_no_subject(self): server_info = ServerConnectivityInfo(hostname='no-subject.badssl.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.verified_certificate_chain) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_xmpp_to(self): server_info = ServerConnectivityInfo( hostname='talk.google.com', tls_wrapped_protocol=TlsWrappedProtocolEnum.STARTTLS_XMPP, xmpp_to_hostname='gmail.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertEqual(len(plugin_result.certificate_chain), 2) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_smtp_custom_port(self): server_info = ServerConnectivityInfo( hostname='smtp.gmail.com', port=587, tls_wrapped_protocol=TlsWrappedProtocolEnum.STARTTLS_SMTP) server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertEqual(len(plugin_result.certificate_chain), 2) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_ipv6(self): if not self._is_ipv6_available(): logging.warning('WARNING: IPv6 not available - skipping test') return server_info = ServerConnectivityInfo(hostname='www.google.com', ip_address='2607:f8b0:4005:804::2004') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertEquals(len(plugin_result.certificate_chain), 3) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_tls_1_3_cipher_suites(self): server_info = ServerConnectivityInfo(hostname='www.cloudflare.com') server_info.test_connectivity_to_server() plugin = OpenSslCipherSuitesPlugin() plugin_result = plugin.process_task(server_info, Tlsv13ScanCommand()) accepted_cipher_name_list = [ cipher.name for cipher in plugin_result.accepted_cipher_list ] self.assertEqual( { 'TLS_CHACHA20_POLY1305_SHA256', 'TLS_AES_256_GCM_SHA384', 'TLS_AES_128_GCM_SHA256' }, set(accepted_cipher_name_list))
def test_ecdsa_certificate(self): server_info = ServerConnectivityInfo(hostname='www.cloudflare.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertGreaterEqual(len(plugin_result.certificate_chain), 1) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_compression_disabled(self): server_info = ServerConnectivityInfo(hostname='www.google.com') server_info.test_connectivity_to_server() plugin = CompressionPlugin() plugin_result = plugin.process_task(server_info, CompressionScanCommand()) self.assertFalse(plugin_result.compression_name) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_rc4_md5_cipher_suites(self): server_info = ServerConnectivityInfo(hostname='rc4-md5.badssl.com') server_info.test_connectivity_to_server() plugin = OpenSslCipherSuitesPlugin() plugin_result = plugin.process_task(server_info, 'tlsv1_2') accepted_cipher_name_list = [ cipher.name for cipher in plugin_result.accepted_cipher_list ] self.assertEquals({'TLS_RSA_WITH_RC4_128_MD5'}, set(accepted_cipher_name_list)) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_certificate_with_scts(self): server_info = ServerConnectivityInfo(hostname='www.apple.com') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertEqual(plugin_result.certificate_included_scts_count, 3) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_renegotiation_good(self): server_info = ServerConnectivityInfo(hostname='www.google.com') server_info.test_connectivity_to_server() plugin = SessionRenegotiationPlugin() plugin_result = plugin.process_task(server_info, SessionRenegotiationScanCommand()) self.assertFalse(plugin_result.accepts_client_renegotiation) self.assertTrue(plugin_result.supports_secure_renegotiation) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def ssl_scan(self): print("Running SSL Scan") try: server_info = ServerConnectivityInfo( hostname=self.options["TARGET"]) server_info.test_connectivity_to_server() synchronous_scanner = SynchronousScanner() # TLS 1.0 command = Tlsv10ScanCommand() scan_result = synchronous_scanner.run_scan_command( server_info, command) print("Available TLSv1.0 Ciphers:") for cipher in scan_result.accepted_cipher_list: print(' {}'.format(cipher.name)) # TLSv1.2 command = Tlsv12ScanCommand() scan_result = synchronous_scanner.run_scan_command( server_info, command) print("Available TLSv1.2 Ciphers:") for cipher in scan_result.accepted_cipher_list: print(' {}'.format(cipher.name)) # Certificate information command = CertificateInfoScanCommand() scan_result = synchronous_scanner.run_scan_command( server_info, command) for entry in scan_result.as_text(): print(entry) # Heartbleed vulnerability info command = HeartbleedScanCommand() scan_result = synchronous_scanner.run_scan_command( server_info, command) for entry in scan_result.as_text(): print(entry) # HTTP Headers info command = HttpHeadersScanCommand() scan_result = synchronous_scanner.run_scan_command( server_info, command) for entry in scan_result.as_text(): print(entry) except Exception as e: self.handle_exception(e, "Error running SSL scan") pass
def test_tls_1_3_cipher_suites(self): server_info = ServerConnectivityInfo( hostname='tls13.crypto.mozilla.org') server_info.test_connectivity_to_server() plugin = OpenSslCipherSuitesPlugin() plugin_result = plugin.process_task(server_info, Tlsv13ScanCommand()) accepted_cipher_name_list = [ cipher.name for cipher in plugin_result.accepted_cipher_list ] self.assertEqual( { 'TLS13-AES-128-GCM-SHA256', 'TLS13-AES-256-GCM-SHA384', 'TLS13-CHACHA20-POLY1305-SHA256' }, set(accepted_cipher_name_list))
def test_not_trusted_by_mozilla_but_trusted_by_microsoft(self): server_info = ServerConnectivityInfo( hostname='webmail.russia.nasa.gov') server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertEqual(plugin_result.successful_trust_store.name, 'Windows') self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_rc4_md5_cipher_suites(self): server_info = ServerConnectivityInfo(hostname='rc4-md5.badssl.com') server_info.test_connectivity_to_server() plugin = OpenSslCipherSuitesPlugin() plugin_result = plugin.process_task(server_info, Tlsv12ScanCommand()) accepted_cipher_name_list = [cipher.name for cipher in plugin_result.accepted_cipher_list] self.assertEqual({'TLS_RSA_WITH_RC4_128_MD5'}, set(accepted_cipher_name_list)) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_ca_file(self): server_info = ServerConnectivityInfo(hostname='www.hotmail.com') server_info.test_connectivity_to_server() ca_file_path = os.path.join(os.path.dirname(__file__), '..', 'utils', 'wildcard-self-signed.pem') plugin = CertificateInfoPlugin() plugin_result = plugin.process_task( server_info, CertificateInfoScanCommand(ca_file=ca_file_path)) self.assertEqual(len(plugin_result.path_validation_result_list), 6) for path_validation_result in plugin_result.path_validation_result_list: if path_validation_result.trust_store.name == 'Custom --ca_file': self.assertFalse(path_validation_result.is_certificate_trusted) else: self.assertTrue(path_validation_result.is_certificate_trusted)
def test_rc4_cipher_suites(self): server_info = ServerConnectivityInfo(hostname=u'rc4.badssl.com') server_info.test_connectivity_to_server() plugin = OpenSslCipherSuitesPlugin() plugin_result = plugin.process_task(server_info, Tlsv12ScanCommand()) accepted_cipher_name_list = [ cipher.name for cipher in plugin_result.accepted_cipher_list ] self.assertEquals( {'TLS_ECDHE_RSA_WITH_RC4_128_SHA', 'TLS_RSA_WITH_RC4_128_SHA'}, set(accepted_cipher_name_list)) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def _generate_scan_jobs_for_server_scan( server_scan_request: ServerScanRequest, server_connectivity_result: ServerTlsProbingResult, ) -> Tuple[Dict[ScanCommand, List[ScanJob]], Dict[ScanCommand, ScanCommandAttempt]]: all_scan_jobs_per_scan_cmd: Dict[ScanCommand, List[ScanJob]] = {} scan_command_errors_during_queuing: Dict[ScanCommand, ScanCommandAttempt] = {} for scan_cmd in server_scan_request.scan_commands: implementation_cls = ScanCommandsRepository.get_implementation_cls( scan_cmd) scan_cmd_extra_args = getattr( server_scan_request.scan_commands_extra_arguments, scan_cmd, None) try: jobs_for_scan_cmd = implementation_cls.scan_jobs_for_scan_command( server_info=ServerConnectivityInfo( server_location=server_scan_request.server_location, network_configuration=server_scan_request. network_configuration, tls_probing_result=server_connectivity_result, ), extra_arguments=scan_cmd_extra_args, ) all_scan_jobs_per_scan_cmd[scan_cmd] = jobs_for_scan_cmd # Process exceptions and instantly "complete" the scan command if the call to create the jobs failed except ScanCommandWrongUsageError as e: scan_command_attempt_cls = get_scan_command_attempt_cls(scan_cmd) errored_attempt = scan_command_attempt_cls( status=ScanCommandAttemptStatusEnum.ERROR, error_reason=ScanCommandErrorReasonEnum.WRONG_USAGE, error_trace=TracebackException.from_exception(e), result=None, ) scan_command_errors_during_queuing[scan_cmd] = errored_attempt except Exception as e: scan_command_attempt_cls = get_scan_command_attempt_cls(scan_cmd) errored_attempt = scan_command_attempt_cls( status=ScanCommandAttemptStatusEnum.ERROR, error_reason=ScanCommandErrorReasonEnum.BUG_IN_SSLYZE, error_trace=TracebackException.from_exception(e), result=None, ) scan_command_errors_during_queuing[scan_cmd] = errored_attempt return all_scan_jobs_per_scan_cmd, scan_command_errors_during_queuing
def test_sslv3_enabled(self): try: with VulnerableOpenSslServer() as server: server_info = ServerConnectivityInfo(hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info.test_connectivity_to_server() plugin = OpenSslCipherSuitesPlugin() plugin_result = plugin.process_task(server_info, Sslv30ScanCommand()) except NotOnLinux64Error: # The test suite only has the vulnerable OpenSSL version compiled for Linux 64 bits logging.warning('WARNING: Not on Linux - skipping test_sslv3_enabled() test') return # The embedded server does not have a preference self.assertFalse(plugin_result.preferred_cipher) accepted_cipher_name_list = [cipher.name for cipher in plugin_result.accepted_cipher_list] self.assertEqual({'TLS_DHE_RSA_EXPORT_WITH_DES40_CBC_SHA', 'TLS_RSA_WITH_3DES_EDE_CBC_SHA', 'TLS_DH_anon_WITH_AES_128_CBC_SHA', 'TLS_ECDH_anon_WITH_AES_128_CBC_SHA', 'TLS_DH_anon_WITH_SEED_CBC_SHA', 'TLS_RSA_EXPORT_WITH_RC2_CBC_40_MD5', 'TLS_ECDHE_RSA_WITH_NULL_SHA', 'TLS_ECDHE_RSA_WITH_RC4_128_SHA', 'TLS_DH_anon_WITH_AES_256_CBC_SHA', 'TLS_DH_anon_WITH_CAMELLIA_128_CBC_SHA', 'TLS_ECDH_anon_WITH_RC4_128_SHA', 'TLS_DH_anon_WITH_3DES_EDE_CBC_SHA', 'TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA', 'TLS_DH_anon_EXPORT_WITH_RC4_40_MD5', 'TLS_RSA_EXPORT_WITH_DES40_CBC_SHA', 'TLS_ECDH_anon_WITH_NULL_SHA', 'TLS_DH_anon_WITH_CAMELLIA_256_CBC_SHA', 'TLS_RSA_WITH_RC4_128_SHA', 'TLS_RSA_EXPORT_WITH_RC4_40_MD5', 'TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA', 'TLS_RSA_WITH_NULL_MD5', 'TLS_DH_anon_EXPORT_WITH_DES40_CBC_SHA', 'TLS_DH_anon_WITH_DES_CBC_SHA', 'TLS_RSA_WITH_SEED_CBC_SHA', 'TLS_RSA_WITH_DES_CBC_SHA', 'TLS_ECDH_anon_WITH_AES_256_CBC_SHA', 'TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA', 'TLS_RSA_WITH_CAMELLIA_256_CBC_SHA', 'TLS_RSA_WITH_AES_256_CBC_SHA', 'TLS_RSA_WITH_RC4_128_MD5', 'TLS_RSA_WITH_CAMELLIA_128_CBC_SHA', 'TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA', 'TLS_RSA_WITH_NULL_SHA', 'TLS_RSA_WITH_IDEA_CBC_SHA', 'TLS_RSA_WITH_AES_128_CBC_SHA', 'TLS_DH_anon_WITH_RC4_128_MD5'}, set(accepted_cipher_name_list)) self.assertTrue(plugin_result.accepted_cipher_list) self.assertTrue(plugin_result.rejected_cipher_list) self.assertFalse(plugin_result.errored_cipher_list) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_sslv2_disabled(self): server_info = ServerConnectivityInfo(hostname='www.google.com') server_info.test_connectivity_to_server() plugin = OpenSslCipherSuitesPlugin() plugin_result = plugin.process_task(server_info, Sslv20ScanCommand()) self.assertIsNone(plugin_result.preferred_cipher) self.assertFalse(plugin_result.accepted_cipher_list) self.assertTrue(plugin_result.rejected_cipher_list) self.assertFalse(plugin_result.errored_cipher_list) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue self.assertTrue(pickle.dumps(plugin_result))
def test_starttls(self): for hostname, protocol in [ ('imap.comcast.net', TlsWrappedProtocolEnum.STARTTLS_IMAP), ('pop.comcast.net', TlsWrappedProtocolEnum.STARTTLS_POP3), ('ldap.uchicago.edu', TlsWrappedProtocolEnum.STARTTLS_LDAP), ('jabber.org', TlsWrappedProtocolEnum.STARTTLS_XMPP_SERVER), # Some Heroku Postgres instance I created ('ec2-54-75-226-17.eu-west-1.compute.amazonaws.com', TlsWrappedProtocolEnum.STARTTLS_POSTGRES) ]: server_info = ServerConnectivityInfo(hostname=hostname, tls_wrapped_protocol=protocol) server_info.test_connectivity_to_server() plugin = CertificateInfoPlugin() plugin_result = plugin.process_task(server_info, CertificateInfoScanCommand()) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())