def init_sslyze(hostname, port, starttls_smtp, options, sync=False): global network_timeout network_timeout = int(options.get("network_timeout", network_timeout)) tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if starttls_smtp: tls_wrapped_protocol = TlsWrappedProtocolEnum.STARTTLS_SMTP try: # logging.debug("\tTesting connectivity with timeout of %is." % network_timeout) server_tester = ServerConnectivityTester( hostname=hostname, port=port, tls_wrapped_protocol=tls_wrapped_protocol) server_info = server_tester.perform(network_timeout=network_timeout) except ServerConnectivityError as err: logging.warn("\tServer connectivity not established during test.") return None, None except Exception as err: utils.notify(err) logging.warn( "\tUnknown exception when performing server connectivity info.") return None, None if sync: scanner = SynchronousScanner(network_timeout=network_timeout) else: scanner = ConcurrentScanner(network_timeout=network_timeout) return server_info, scanner
def scan_cipher_lists(addresses, concurrent=16): # prepare scanner s = ConcurrentScanner(max_processes_nb=concurrent) for addr in addresses: ip, port = split_host_port(addr) server_info = ServerConnectivityInfo(hostname=addr, ip_address=ip, port=port) for cmd in scan_commands(): s.queue_scan_command(server_info, cmd) # execute for result in s.get_results(): addr = result.server_info.hostname if not isinstance(result, CipherSuiteScanResult): logging.info('failed to get results for %s', addr) continue logging.info('results for %s', addr) for cipher in result.accepted_cipher_list: output_cipher(addr, cipher, label='accepted') output_cipher(addr, result.preferred_cipher, label='preferred')
def test_concurrent_scanner(self): server_info = ServerConnectivityInfo(hostname='www.google.com') server_info.test_connectivity_to_server() # Queue some scan commands that are quick concurrent_scanner = ConcurrentScanner() concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand()) concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand()) # Process the results nb_results = 0 for plugin_result in concurrent_scanner.get_results(): self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) nb_results +=1 self.assertEquals(nb_results, 3)
def test_concurrent_scanner(self): server_test = ServerConnectivityTester(hostname='www.google.com') server_info = server_test.perform() # Queue some scan commands that are quick concurrent_scanner = ConcurrentScanner() concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand()) concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand()) # Process the results nb_results = 0 for plugin_result in concurrent_scanner.get_results(): assert plugin_result.as_text() assert plugin_result.as_xml() nb_results += 1 assert nb_results == 3
def test_concurrent_scanner(self): server_test = ServerConnectivityTester(hostname='www.google.com') server_info = server_test.perform() # Queue some scan commands that are quick concurrent_scanner = ConcurrentScanner() concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand()) concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand()) # Process the results nb_results = 0 for plugin_result in concurrent_scanner.get_results(): self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml()) nb_results +=1 self.assertEqual(nb_results, 3)
def init_sslyze(hostname, options, sync=False): global network_timeout network_timeout = int(options.get("network_timeout", network_timeout)) try: server_info = sslyze.server_connectivity.ServerConnectivityInfo( hostname=hostname, port=443) except sslyze.server_connectivity.ServerConnectivityError as error: logging.warn( "\tServer connectivity not established during initialization.") return None, None except Exception as err: utils.notify(err) logging.warn( "\tUnknown exception when initializing server connectivity info.") return None, None try: # logging.debug("\tTesting connectivity with timeout of %is." % network_timeout) server_info.test_connectivity_to_server( network_timeout=network_timeout) except sslyze.server_connectivity.ServerConnectivityError as err: logging.warn("\tServer connectivity not established during test.") return None, None except Exception as err: utils.notify(err) logging.warn( "\tUnknown exception when performing server connectivity info.") return None, None if sync: scanner = SynchronousScanner(network_timeout=network_timeout) else: scanner = ConcurrentScanner(network_timeout=network_timeout) return server_info, scanner
def demo_concurrent_scanner(): # Setup the server to scan and ensure it is online/reachable server_info = demo_server_connectivity_tester() # Run multiple scan commands concurrently. It is much faster than the SynchronousScanner concurrent_scanner = ConcurrentScanner() # Queue some scan commands print('\nQueuing some commands...') concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand()) concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) # Process the results print('\nProcessing results...') for scan_result in concurrent_scanner.get_results(): # All scan results have the corresponding scan_command and server_info as an attribute print(f'\nReceived result for "{scan_result.scan_command.get_title()}" ' f'on {scan_result.server_info.hostname}') # A scan command can fail (as a bug); it is returned as a PluginRaisedExceptionResult if isinstance(scan_result, PluginRaisedExceptionScanResult): raise RuntimeError(f'Scan command failed: {scan_result.scan_command.get_title()}') # Each scan result has attributes with the information yo're looking for # All these attributes are documented within each scan command's module if isinstance(scan_result.scan_command, Tlsv12ScanCommand): for cipher in scan_result.accepted_cipher_list: print(f' {cipher.name}') elif isinstance(scan_result.scan_command, CertificateInfoScanCommand): # Print the Common Names within the verified certificate chain if not scan_result.verified_certificate_chain: print('Error: certificate chain is not trusted!') else: print('Certificate chain common names:') for cert in scan_result.verified_certificate_chain: cert_common_names = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME) print(f' {cert_common_names[0].value}')
def start_scanner(session, scan_id, with_progressbar=False): """ takes database session and project id, creates a scan id and start scanning for all targets belonging to project """ logger.log(1, 'create_server_info called') logger.debug('enumerating targets') total_results = 0 network_retries = 3 network_timeout = 5 max_processes_nb = 12 max_processes_per_hostname_nb = 3 scan = session.query(Scan).get(scan_id) concurrent_scanner = ConcurrentScanner(scan.network_retries, scan.network_timeout, scan.max_processes_nb, scan.max_processes_per_hostname_nb) for target in enum_targets(session, scan_id, with_progressbar): try: server_info = create_server_info(target) except Exception as e: logger.exception('Connecting to server failed') tci = TargetConnectivityInfo() tci.scan_id = scan.id tci.target_id = target.id tci.is_connectivity_ok = False session.add(tci) session.commit() continue server_info.target_id = target.id #importent to keep track of the id fof the target! tci = TargetConnectivityInfo() tci.scan_id = scan.id tci.target_id = target.id tci.is_connectivity_ok = True session.add(tci) session.commit() logger.debug('Creating scan result') logger.debug('Enqueueing server for a scan') commands = [] for res in session.query(ScanCommand.command).filter( scan_id == scan_id).distinct(ScanCommand.command).all(): for r in res: commands.append(r) if len(commands) == 0: raise Exception('Scan doesnt have any commands!') for command in commands: for c in command_map[command]: concurrent_scanner.queue_scan_command(server_info, c()) total_results += 1 logger.debug('Starting scanner!') for scan_result in get_results(concurrent_scanner, with_progressbar, total_results): logger.debug( f'\nReceived result for "{scan_result.scan_command.get_title()}" ' f'on {scan_result.server_info.hostname}') logger.debug('ID: %s' % scan_result.server_info.target_id) if isinstance(scan_result, PluginRaisedExceptionScanResult): logger.info('Scan command failed: %s' % scan_result.scan_command.get_title()) f = FailedCommands() f.scan_id = scan.id f.target_id = target.id f.error_message = scan_result.error_message f.failed_command = command_map_rev[type(scan_result.scan_command)] session.add(f) session.commit() elif isinstance(scan_result.scan_command, CertificateInfoScanCommand): res = CertificateInfoScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id res.certificate_matches_hostname = scan_result.certificate_matches_hostname res.is_leaf_certificate_ev = scan_result.is_leaf_certificate_ev res.certificate_has_must_staple_extension = scan_result.certificate_has_must_staple_extension res.certificate_included_scts_count = scan_result.certificate_included_scts_count #ocsp_response = Column(Boolean) res.ocsp_response_status = scan_result.ocsp_response_status res.is_ocsp_response_trusted = scan_result.is_ocsp_response_trusted res.has_sha1_in_certificate_chain = scan_result.has_sha1_in_certificate_chain res.has_anchor_in_certificate_chain = scan_result.has_anchor_in_certificate_chain session.add(res) session.commit() session.refresh(res) idx = 0 for certdata in scan_result.certificate_chain: cert = Certificate.from_result( res.id, idx, certdata.public_bytes(serialization.Encoding.PEM)) idx += 1 session.add(cert) for valres in scan_result.path_validation_result_list: #pvr = PathValidationResult.from_result(res.id, valres) ts = TrustStore.from_result(res.id, valres.trust_store) pvr = PathValidationResult() pvr.certificateinfoscanresult_id = res.id pvr.trust_store = ts pvr.verify_string = valres.verify_string pvr.is_certificate_trusted = valres.is_certificate_trusted session.add(pvr) for valres in scan_result.path_validation_error_list: pvre = PathValidationError() pvre.certificateinfoscanresult_id = res.id ts = TrustStore.from_result(res.id, valres.trust_store) pvre.trust_store = ts session.add(pvre) if scan_result.successful_trust_store is not None: ts = TrustStore.from_result(res.id, scan_result.successful_trust_store) res.successful_trust_store = ts if scan_result.path_validation_error_list is not None: for valres in scan_result.path_validation_error_list: pvre = PathValidationError.from_result(res.id, valres) session.add(pvre) session.commit() elif isinstance( scan_result.scan_command, (Sslv20ScanCommand, Sslv30ScanCommand, Tlsv10ScanCommand, Tlsv11ScanCommand, Tlsv12ScanCommand, Tlsv13ScanCommand)): res = CipherSuiteScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id session.add(res) session.commit() session.refresh(res) for acres in scan_result.accepted_cipher_list: ac = AcceptedCipherSuite.from_result(acres) session.add(ac) res.accepted_cipher_list.append(ac) session.add(res) session.commit() elif isinstance(scan_result.scan_command, CompressionScanCommand): res = CompressionScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id #resoning for line below: documentation sais that None will be returned for compression_name # if no compression was set. Problem is: None is also returned in SQL when joining tables :( res.compression_name = scan_result.compression_name if scan_result.compression_name is not None else 'N/A' session.add(res) session.commit() elif isinstance(scan_result.scan_command, FallbackScsvScanCommand): res = FallbackScsvScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id res.supports_fallback_scsv = scan_result.supports_fallback_scsv session.add(res) session.commit() elif isinstance(scan_result.scan_command, HeartbleedScanCommand): res = HeartbleedScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id res.is_vulnerable_to_heartbleed = scan_result.is_vulnerable_to_heartbleed session.add(res) session.commit() elif isinstance(scan_result.scan_command, OpenSslCcsInjectionScanCommand): res = OpenSslCcsInjectionScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id res.is_vulnerable_to_ccs_injection = scan_result.is_vulnerable_to_ccs_injection session.add(res) session.commit() elif isinstance(scan_result.scan_command, SessionRenegotiationScanCommand): res = SessionRenegotiationScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id res.accepts_client_renegotiation = scan_result.accepts_client_renegotiation res.supports_secure_renegotiation = scan_result.supports_secure_renegotiation session.add(res) session.commit() elif isinstance(scan_result.scan_command, SessionResumptionSupportScanCommand): res = SessionResumptionSupportScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id res.attempted_resumptions_nb = scan_result.attempted_resumptions_nb res.successful_resumptions_nb = scan_result.successful_resumptions_nb res.failed_resumptions_nb = scan_result.failed_resumptions_nb res.ticket_resumption_failed_reason = scan_result.ticket_resumption_failed_reason #res.ticket_resumption_exception = scan_result.ticket_resumption_exception session.add(res) session.commit() session.refresh(res) for errortext in scan_result.errored_resumptions_list: err = SessionResumptionErrors() err.resumption_id = res.id err.error = errortext session.add(err) res.errored_resumptions_list.append(err) session.add(res) session.commit() elif isinstance(scan_result.scan_command, RobotScanCommand): res = RobotScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id res.robot_result_enum = scan_result.robot_result_enum session.add(res) session.commit() elif isinstance(scan_result.scan_command, EarlyDataScanCommand): res = EarlyDataScanResult() res.scan_id = scan_id res.target_id = scan_result.server_info.target_id res.robot_result_enum = scan_result.is_early_data_supported session.add(res) session.commit() session.commit()
def get_supported_tls_cipher_suites(hostname): server_info = get_ssl_server_info(hostname) concurrent_scanner = ConcurrentScanner() concurrent_scanner.queue_scan_command(server_info, Sslv20ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Sslv30ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv10ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv11ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv13ScanCommand()) concurrent_scanner.queue_scan_command(server_info, FallbackScsvScanCommand()) for scan_result in concurrent_scanner.get_results(): # A scan command can fail (as a bug); it is returned as a PluginRaisedExceptionResult if isinstance(scan_result, PluginRaisedExceptionScanResult): raise RuntimeError( f'Scan command failed: {scan_result.scan_command.get_title()}') if isinstance(scan_result.scan_command, Sslv20ScanCommand): accepted_ssl2 = [ cipher.name for cipher in scan_result.accepted_cipher_list ] denied_ssl2 = [ cipher.name for cipher in scan_result.rejected_cipher_list ] errored_ssl2 = [ cipher.name for cipher in scan_result.errored_cipher_list ] if isinstance(scan_result.scan_command, Sslv30ScanCommand): accepted_ssl3 = [ cipher.name for cipher in scan_result.accepted_cipher_list ] denied_ssl3 = [ cipher.name for cipher in scan_result.rejected_cipher_list ] errored_ssl3 = [ cipher.name for cipher in scan_result.errored_cipher_list ] if isinstance(scan_result.scan_command, Tlsv10ScanCommand): accepted_tls10 = [ cipher.name for cipher in scan_result.accepted_cipher_list ] denied_tls10 = [ cipher.name for cipher in scan_result.rejected_cipher_list ] errored_tls10 = [ cipher.name for cipher in scan_result.errored_cipher_list ] if isinstance(scan_result.scan_command, Tlsv11ScanCommand): accepted_tls11 = [ cipher.name for cipher in scan_result.accepted_cipher_list ] denied_tls11 = [ cipher.name for cipher in scan_result.rejected_cipher_list ] errored_tls11 = [ cipher.name for cipher in scan_result.errored_cipher_list ] if isinstance(scan_result.scan_command, Tlsv12ScanCommand): accepted_tls12 = [ cipher.name for cipher in scan_result.accepted_cipher_list ] denied_tls12 = [ cipher.name for cipher in scan_result.rejected_cipher_list ] errored_tls12 = [ cipher.name for cipher in scan_result.errored_cipher_list ] if isinstance(scan_result.scan_command, Tlsv13ScanCommand): accepted_tls13 = [ cipher.name for cipher in scan_result.accepted_cipher_list ] denied_tls13 = [ cipher.name for cipher in scan_result.rejected_cipher_list ] errored_tls13 = [ cipher.name for cipher in scan_result.errored_cipher_list ] if isinstance(scan_result.scan_command, FallbackScsvScanCommand): supports_fallback_scsv = scan_result.supports_fallback_scsv return { 'accepted_ssl2': accepted_ssl2, 'denied_ssl2': denied_ssl2, 'errored_ssl2': errored_ssl2, 'accepted_ssl3': accepted_ssl3, 'denied_ssl3': denied_ssl3, 'errored_ssl3': errored_ssl3, 'accepted_tls10': accepted_tls10, 'denied_tls10': denied_tls10, 'errored_tls10': errored_tls10, 'accepted_tls11': accepted_tls11, 'denied_tls11': denied_tls11, 'errored_tls11': errored_tls11, 'accepted_tls12': accepted_tls12, 'denied_tls12': denied_tls12, 'errored_tls12': errored_tls12, 'accepted_tls13': accepted_tls13, 'denied_tls13': denied_tls13, 'errored_tls13': errored_tls13, 'supports_fallback_scsv': supports_fallback_scsv }
def main() -> None: global global_scanner # For py2exe builds freeze_support() # Handle SIGINT to terminate processes signal.signal(signal.SIGINT, sigint_handler) start_time = time() plugins_repository = PluginsRepository() available_plugins = plugins_repository.get_available_plugins() available_commands = plugins_repository.get_available_commands() # Create the command line parser and the list of available options sslyze_parser = CommandLineParser(available_plugins, __version__) try: good_server_list, malformed_server_list, args_command_list = sslyze_parser.parse_command_line( ) except CommandLineParsingError as e: print(e.get_error_msg()) return output_hub = OutputHub() output_hub.command_line_parsed(available_plugins, args_command_list, malformed_server_list) # Initialize the pool of processes that will run each plugin if args_command_list.https_tunnel or args_command_list.slow_connection: # Maximum one process to not kill the proxy or the connection global_scanner = ConcurrentScanner(max_processes_nb=1) else: global_scanner = ConcurrentScanner() # Figure out which hosts are up and fill the task queue with work to do connectivity_tester = ConcurrentServerConnectivityTester(good_server_list) connectivity_tester.start_connectivity_testing() # Store and print servers we were able to connect to online_servers_list = [] for server_connectivity_info in connectivity_tester.get_reachable_servers( ): online_servers_list.append(server_connectivity_info) output_hub.server_connectivity_test_succeeded(server_connectivity_info) # Send tasks to worker processes for scan_command_class in available_commands: if getattr(args_command_list, scan_command_class.get_cli_argument()): # Get this command's optional argument if there's any optional_args = {} for optional_arg_name in scan_command_class.get_optional_arguments( ): # Was this option set ? if getattr(args_command_list, optional_arg_name): optional_args[optional_arg_name] = getattr( args_command_list, optional_arg_name) scan_command = scan_command_class( **optional_args) # type: ignore global_scanner.queue_scan_command(server_connectivity_info, scan_command) # Store and print servers we were NOT able to connect to for connectivity_exception in connectivity_tester.get_invalid_servers(): output_hub.server_connectivity_test_failed(connectivity_exception) # Keep track of how many tasks have to be performed for each target task_num = 0 output_hub.scans_started() for scan_command_class in available_commands: if getattr(args_command_list, scan_command_class.get_cli_argument()): task_num += 1 # Each host has a list of results result_dict: Dict[Text, List[PluginScanResult]] = {} # We cannot use the server_info object directly as its address will change due to multiprocessing RESULT_KEY_FORMAT = '{hostname}:{ip_address}:{port}' for server_info in online_servers_list: result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] = [] # Process the results as they come for plugin_result in global_scanner.get_results(): server_info = plugin_result.server_info result_dict[RESULT_KEY_FORMAT.format( hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)].append(plugin_result) plugin_result_list = result_dict[RESULT_KEY_FORMAT.format( hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] if len(plugin_result_list) == task_num: # Done with this server; send the result to the output hub output_hub.server_scan_completed( CompletedServerScan(server_info, plugin_result_list)) # All done exec_time = time() - start_time output_hub.scans_completed(exec_time)
def test_ssl_basic(self, hostname, port=443): ''' Uses the `ServerConnectivityTester` functionality of SSlyze to perform a basic test. Port defaults to 443 unless provided otherwise hostname is mandatory | test ssl basic | hostname | port (optional | ''' try: tester = ServerConnectivityTester(hostname=hostname, port=port) server_info = tester.perform() scanner = ConcurrentScanner() # scanner.queue_scan_command(info, certificate_info_plugin.CertificateInfoScanCommand()) scanner.queue_scan_command(server_info, Sslv20ScanCommand()) scanner.queue_scan_command(server_info, Sslv30ScanCommand()) scanner.queue_scan_command(server_info, Tlsv10ScanCommand()) scanner.queue_scan_command(server_info, Tlsv10ScanCommand()) scanner.queue_scan_command(server_info, Tlsv11ScanCommand()) scanner.queue_scan_command(server_info, Tlsv12ScanCommand()) scanner.queue_scan_command(server_info, HeartbleedScanCommand()) scanner.queue_scan_command(server_info, RobotScanCommand()) # scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) for scan_result in scanner.get_results(): # logger.info("Scan result for: {} on hostname: {}".format(scan_result.scan_command.__class__.__name__, scan_result.server_info.hostname)) if isinstance(scan_result, PluginRaisedExceptionScanResult): raise Exception("Scan Command Failed: {}".format( scan_result.as_text())) if isinstance(scan_result.scan_command, Sslv20ScanCommand): if scan_result.accepted_cipher_list: logger.warn("SSLv2 ciphersuites accepted") for suite in scan_result.accepted_cipher_list: logger.info("\t{}".format(suite.name)) else: logger.info("SSLv2 ciphersuites not accepted") if isinstance(scan_result.scan_command, Sslv30ScanCommand): if scan_result.accepted_cipher_list: logger.warn("SSLv3 Cipher Suites accepted") for suite in scan_result.accepted_cipher_list: logger.info("\t{}".format(suite.name)) else: logger.info("SSLv3 ciphersuites not accepted") if isinstance(scan_result.scan_command, Tlsv10ScanCommand): if scan_result.accepted_cipher_list: logger.warn("TLSv1 Cipher Suites accepted") for suite in scan_result.accepted_cipher_list: logger.info("\t{}".format(suite.name)) else: logger.info("TLSv1 ciphersuites not accepted") if isinstance(scan_result.scan_command, Tlsv11ScanCommand): if scan_result.accepted_cipher_list: logger.info("TLSv1.1 Cipher Suites accepted") for suite in scan_result.accepted_cipher_list: logger.info("\t{}".format(suite.name)) else: logger.info("TLSv1.1 ciphersuites not accepted") if isinstance(scan_result.scan_command, Tlsv12ScanCommand): if scan_result.accepted_cipher_list: logger.info("TLSv1.2 Cipher Suites accepted") for suite in scan_result.accepted_cipher_list: logger.info("\t{}".format(suite.name)) else: logger.info("TLSv1.2 ciphersuites not accepted") if isinstance(scan_result.scan_command, HeartbleedScanCommand): if scan_result.is_vulnerable_to_heartbleed: logger.warn( "Server TLS implementation is vulnerable to Heartbleed" ) else: logger.info( "Server TLS Implementation not vulnerable to Heartbleed" ) if isinstance(scan_result.scan_command, RobotScanCommand): logger.info("Test for ROBOT Vulnerability") if scan_result.robot_result_enum.NOT_VULNERABLE_NO_ORACLE: logger.info( "\tNot Vulnerable: The server supports RSA cipher suites but does not act as an oracle" ) elif scan_result.robot_result_enum.VULNERABLE_WEAK_ORACLE: logger.warn( "\tVulnerable: The server is vulnerable but the attack would take too long" ) elif scan_result.robot_result_enum.VULNERABLE_STRONG_ORACLE: logger.warn( "\tVulnerable: The server is vulnerable and real attacks are feasible" ) elif scan_result.robot_result_enum.NOT_VULNERABLE_RSA_NOT_SUPPORTED: logger.info( "\tNot Vulnerable: The server does not supports RSA cipher suites" ) else: logger.info( "\tUnable to determine if implementation is vulnerable" ) # if isinstance(scan_result.scan_command, CertificateInfoScanCommand): # logger.info(u'Server Certificate CN: {}'.format( # dict(scan_result.certificate_chain[0])[u'subject'][u'commonName'] # )) except ServerConnectivityError as e: logger.error('Error when trying to connect to {}: {}'.format( e.server_info.hostname, e.error_message))
def sslyzeScan(threadname, connection, url): logfile_connection = 'log/' + scriptname + '-error-connections.log' logfile_other = 'log/' + scriptname + '-error-other.log' logfile_scan = 'log/' + scriptname + '-error-other.log' has_ip = 0 is_reachable = 0 has_ip = getIP(url) if has_ip: try: server_tester = ServerConnectivityTester(hostname=url) server_info = server_tester.perform() is_reachable = 1 except ServerConnectivityError: with open(logfile_connection, 'a') as log: log.write('Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not connect to host: ' + url + '\n') except Exception: with open(logfile_other, 'a') as log: log.write('Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Thrown error for host: ' + url + '\n') else: with open(logfile_connection, 'a') as log: log.write('Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not resolve host: ' + url + '\n') if (is_reachable): concurrent_scanner = ConcurrentScanner() concurrent_scanner.queue_scan_command(server_info, Sslv20ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Sslv30ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv10ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv11ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv13ScanCommand()) concurrent_scanner.queue_scan_command(server_info, HeartbleedScanCommand()) concurrent_scanner.queue_scan_command(server_info, HttpHeadersScanCommand()) concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) # Process the results for scan_result in concurrent_scanner.get_results(): # Sometimes a scan command can unexpectedly fail (as a bug); it is returned as a PluginRaisedExceptionResult if isinstance(scan_result, PluginRaisedExceptionScanResult): with open(logfile_scan, 'a') as log: log.write('Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', Scan command failed: {}'.format( scan_result.as_text()) + '\n') if isinstance(scan_result.scan_command, Sslv20ScanCommand): ssl_version = "sslv2" try: if len(scan_result.accepted_cipher_list) == 0: supports_sslv2 = 0 else: supports_sslv2 = 1 for cipher in scan_result.accepted_cipher_list: cipher = (u'{}'.format(cipher.name)) sql_command = ( 'insert into ' + tbl_supported_ciphers + '(url,cipher,version) values (%s,%s,%s)') sql_data = (url, cipher, ssl_version) cur0 = connection.cursor() cur0.execute(sql_command, sql_data) connection.commit() cur0.close() except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get sslv2 attributes for host: ' + url + '\n') supports_sslv2 = 0 if isinstance(scan_result.scan_command, Sslv30ScanCommand): ssl_version = "sslv3" try: if len(scan_result.accepted_cipher_list) == 0: supports_sslv3 = 0 else: supports_sslv3 = 1 for cipher in scan_result.accepted_cipher_list: cipher = (u'{}'.format(cipher.name)) sql_command = ( 'insert into ' + tbl_supported_ciphers + '(url,cipher,version) values (%s,%s,%s)') sql_data = (url, cipher, ssl_version) cur0 = connection.cursor() cur0.execute(sql_command, sql_data) connection.commit() cur0.close() except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get sslv3 attributes for host: ' + url + '\n') supports_sslv3 = 0 if isinstance(scan_result.scan_command, Tlsv10ScanCommand): ssl_version = "tlsv10" try: if len(scan_result.accepted_cipher_list) == 0: supports_tlsv10 = 0 else: supports_tlsv10 = 1 for cipher in scan_result.accepted_cipher_list: cipher = (u'{}'.format(cipher.name)) sql_command = ( 'insert into ' + tbl_supported_ciphers + '(url,cipher,version) values (%s,%s,%s)') sql_data = (url, cipher, ssl_version) cur0 = connection.cursor() cur0.execute(sql_command, sql_data) connection.commit() cur0.close() except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get tlsv10 attributes for host: ' + url + '\n') supports_tlsv10 = 0 if isinstance(scan_result.scan_command, Tlsv11ScanCommand): ssl_version = "tlsv11" try: if len(scan_result.accepted_cipher_list) == 0: supports_tlsv11 = 0 else: supports_tlsv11 = 1 for cipher in scan_result.accepted_cipher_list: cipher = (u'{}'.format(cipher.name)) sql_command = ( 'insert into ' + tbl_supported_ciphers + '(url,cipher,version) values (%s,%s,%s)') sql_data = (url, cipher, ssl_version) cur0 = connection.cursor() cur0.execute(sql_command, sql_data) connection.commit() cur0.close() except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get tlsv11 attributes for host: ' + url + '\n') supports_tlsv11 = 0 if isinstance(scan_result.scan_command, Tlsv12ScanCommand): ssl_version = "tlsv12" try: if len(scan_result.accepted_cipher_list) == 0: supports_tlsv12 = 0 else: supports_tlsv12 = 1 for cipher in scan_result.accepted_cipher_list: cipher = (u'{}'.format(cipher.name)) sql_command = ( 'insert into ' + tbl_supported_ciphers + '(url,cipher,version) values (%s,%s,%s)') sql_data = (url, cipher, ssl_version) cur0 = connection.cursor() cur0.execute(sql_command, sql_data) connection.commit() cur0.close() except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get tlsv12 attributes for host: ' + url + '\n') supports_tlsv12 = 0 if isinstance(scan_result.scan_command, Tlsv13ScanCommand): ssl_version = "tlsv13" try: if len(scan_result.accepted_cipher_list) == 0: supports_tlsv13 = 0 else: supports_tlsv13 = 1 for cipher in scan_result.accepted_cipher_list: cipher = (u'{}'.format(cipher.name)) sql_command = ( 'insert into ' + tbl_supported_ciphers + '(url,cipher,version) values (%s,%s,%s)') sql_data = (url, cipher, ssl_version) cur0 = connection.cursor() cur0.execute(sql_command, sql_data) connection.commit() cur0.close() except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get tlsv13 attributes for host: ' + url + '\n') supports_tlsv13 = 0 if isinstance(scan_result.scan_command, HeartbleedScanCommand): vulnerable_heartbleed = 0 try: if (scan_result.is_vulnerable_to_heartbleed): vulnerable_heartbleed = 1 except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get heartbleed attribute for host: ' + url + '\n') vulnerable_heartbleed = 0 if isinstance(scan_result.scan_command, HttpHeadersScanCommand): hsts_preload_set = 0 hsts_include_subdomains_set = 0 hsts_max_age_set = 0 hsts_supported = 0 hpkp_supported = 0 try: if (scan_result.hsts_header): hsts_supported = 1 if (scan_result.hsts_header.preload): hsts_preload_set = 1 if (scan_result.hsts_header.include_subdomains ) == True: hsts_include_subdomains_set = 1 hsts_max_age_set = scan_result.hsts_header.max_age except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get hsts attributes for host: ' + url + '\n') hsts_preload_set = 0 hsts_include_subdomains_set = 0 hsts_max_age_set = 0 hsts_supported = 0 try: if (scan_result.hpkp_header): hpkp_supported = 1 except AttributeError: hpkp_supported = 0 if isinstance(scan_result.scan_command, CertificateInfoScanCommand): chain_is_trusted = 0 try: if (scan_result.verified_certificate_chain): chain_is_trusted = 1 except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get hpkp attributes for host: ' + url + '\n') chain_is_trusted = 0 cert_matches_hostname = 0 cert_is_ev = False try: CertificateUtils.matches_hostname( scan_result.certificate_chain[0], server_info.tls_server_name_indication) cert_matches_hostname = 1 except CertificateError: cert_matches_hostname = 0 except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get certificate_chain attribute for host: ' + url + '\n') try: cert_is_ev = TrustStoresRepository.get_default( ).get_main_store().is_extended_validation( scan_result.certificate_chain[0]) except AttributeError: with open(logfile_scan, 'a') as log: log.write( 'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' + threadname + ': Could not get extended_validation attribute for host: ' + url + '\n') sql_cmd = ( 'insert into ' + tbl_ssl_options + '(url,heartbleed_vulnerable,hsts_supported,hsts_preload_set,hsts_include_subdomains_set,hsts_max_age_set,hpkp_supported,chain_is_trusted,match_hostname,is_ev,sslv2,sslv3,tlsv10,tlsv11,tlsv12,tlsv13) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)' ) sql_dat = (url, vulnerable_heartbleed, hsts_supported, hsts_preload_set, hsts_include_subdomains_set, hsts_max_age_set, hpkp_supported, chain_is_trusted, cert_matches_hostname, cert_is_ev, supports_sslv2, supports_sslv3, supports_tlsv10, supports_tlsv11, supports_tlsv12, supports_tlsv13) cur = connection.cursor() cur.execute(sql_cmd, sql_dat) connection.commit() cur.close()
def check( hostname_user_input): try: print(u'hostname_user_input: '+hostname_user_input) # Strip http(s) m = re.search('^(https?://)?(.*?)(/.*)?$', hostname_user_input) if m.group(2): hostname_user_input = m.group(2) else: raise RuntimeError(u'Please provide non-empty host name!') server_tester = ServerConnectivityTester(hostname_user_input) server_info = server_tester.perform(network_timeout=10) # Could not establish an SSL connection to the server except ServerConnectivityError as e: raise RuntimeError(u'Error when connecting to {}: {}!'.format(hostname_user_input, e.error_message)) # No SSL used except IOError as e: raise RuntimeError(u'Protocol does not use SSL/TLS!') # If the call to test_connectivity_to_server() returns successfully, the server_info is then ready to be used for scanning the server. # The ConcurrentScanner uses a pool of processes to run ScanCommands concurrently. # It is very fast when scanning a large number of servers, and it has a dispatching mechanism to avoid DOS-ing a single server against which multiple ScanCommand are run at the same time. # The commands can be queued using the queue_scan_command() method, and the results can later be retrieved using the get_results() method: # Ref: https://nabla-c0d3.github.io/sslyze/documentation/running-scan-commands.html concurrent_scanner = ConcurrentScanner() # Put scans in queue - Put desired scans here # ROBOT concurrent_scanner.queue_scan_command(server_info, RobotScanCommand()) # Heartbleed concurrent_scanner.queue_scan_command(server_info, HeartbleedScanCommand()) # Detecting deprecated/weak ciphers concurrent_scanner.queue_scan_command(server_info, Sslv20ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Sslv30ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv10ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv11ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv13ScanCommand()) concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand()) # Process the results robot_txt = 'Scan could not be executed' heartbleed_txt = 'Scan could not be executed' drown_txt = 'Scan could not be executed' poodle_txt = 'Scan could not be executed' beast_txt = 'Scan could not be executed' compression_text = 'Scan could not be executed' lucky_text = 'Scan could not be executed' potential_weak_ciphers = set() print(u'\nProcessing results...') for scan_result in concurrent_scanner.get_results(): # Sometimes a scan command can unexpectedly fail (as a bug); it is returned as a PluginRaisedExceptionResult if isinstance(scan_result, PluginRaisedExceptionScanResult): raise RuntimeError(u'Scan command failed: Scan could not be executed!') continue # Each scan result has attributes with the information you're looking for, specific to each scan command # All these attributes are documented within each scan command's module if isinstance(scan_result.scan_command, RobotScanCommand): result_enum = scan_result.robot_result_enum if result_enum == RobotScanResultEnum.VULNERABLE_STRONG_ORACLE: robot_txt = 'Vulnerable - Strong oracle, a real attack is possible' elif result_enum == RobotScanResultEnum.VULNERABLE_WEAK_ORACLE: robot_txt = 'Vulnerable - Weak oracle, the attack would take too long' elif result_enum == RobotScanResultEnum.NOT_VULNERABLE_NO_ORACLE: robot_txt = 'Not vulnerable' elif result_enum == RobotScanResultEnum.NOT_VULNERABLE_RSA_NOT_SUPPORTED: robot_txt = 'Not vulnerable, RSA cipher suites not supported' elif result_enum == RobotScanResultEnum.UNKNOWN_INCONSISTENT_RESULTS: robot_txt = 'Unknown - Received inconsistent results' # Process CRIME elif isinstance(scan_result.scan_command, CompressionScanCommand): compression_text = "Vulnerable" result_compression = scan_result.compression_name if "None" == str(result_compression): compression_text = "Not vulnerable" # Process Heartbleed elif isinstance(scan_result.scan_command, HeartbleedScanCommand): result_heartbleed = scan_result.is_vulnerable_to_heartbleed heartbleed_txt = 'Not vulnerable' if result_heartbleed == True: heartbleed_txt = 'Vulnerable' # Process POODLE elif isinstance(scan_result.scan_command, Sslv30ScanCommand): poodle_txt = 'Not vulnerable' for cipher in scan_result.accepted_cipher_list: potential_weak_ciphers.add(cipher.name) if 'CBC' in cipher.name: poodle_txt = 'Vulnerable' beast_txt = "Not mitigated on server-side" # Process DROWN (a server is vulnerable to DROWN if it allows SSLv2 connections) Ref = https://drownattack.com/ elif isinstance(scan_result.scan_command, Sslv20ScanCommand): drown_txt = 'Not vulnerable' for cipher in scan_result.accepted_cipher_list: potential_weak_ciphers.add(cipher.name) drown_txt = 'Vulnerable' if 'CBC' in cipher.name: beast_txt = "Not mitigated on server-side" # Collect deprecated/weak ciphers elif isinstance(scan_result.scan_command, Tlsv10ScanCommand): beast_txt = "Not vulnerable" for cipher in scan_result.accepted_cipher_list: potential_weak_ciphers.add(cipher.name) if 'CBC' in cipher.name: beast_txt = "Not mitigated on server-side" ## Check for tls version and ciphers not sufficient to detect lucky13 vulnerability elif isinstance(scan_result.scan_command, Tlsv11ScanCommand): #if lucky_text != 'Vulnerable': # lucky_text = 'Not vulnerable' for cipher in scan_result.accepted_cipher_list: potential_weak_ciphers.add(cipher.name) # if 'CBC' in cipher.name: # lucky_text = 'Vulnerable' elif isinstance(scan_result.scan_command, Tlsv12ScanCommand): #if lucky_text != 'Vulnerable': # lucky_text = 'Not vulnerable' for cipher in scan_result.accepted_cipher_list: potential_weak_ciphers.add(cipher.name) # if 'CBC' in cipher.name: # lucky_text = 'Vulnerable' elif isinstance(scan_result.scan_command, Tlsv13ScanCommand): for cipher in scan_result.accepted_cipher_list: potential_weak_ciphers.add(cipher.name) # Process weak ciphers weak_ciphers = getWeakCiphers(potential_weak_ciphers) print("potential_weak_ciphers:") print(potential_weak_ciphers) print("\nweak_ciphers:") print(weak_ciphers) res = collections.OrderedDict() res["BEAST"] = str(beast_txt) res["CRIME"] = str(compression_text) res["DROWN"] = str(drown_txt) res["HEARTBLEED"] = str(heartbleed_txt) res["POODLE"] = str(poodle_txt) res["ROBOT"] = str(robot_txt) res["WEAKCIPHERS"] = 'Not vulnerable' if len(weak_ciphers) == 0 else '\n'.join(str(s) for s in weak_ciphers) #res["LUCKY13"] = str(lucky_text) details = getCertiDetails(hostname_user_input, potential_weak_ciphers) return (res, details)
def concurrent_scanner(hn): # Setup the server to scan and ensure it is online/reachable server_info = server_connectivity_tester(hn) if server_info is 'error': return # Run multiple scan commands concurrently. concurrent_scanner = ConcurrentScanner() # Queue some scan commands print('\nQueuing some commands...') concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv13ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv11ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Tlsv10ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Sslv30ScanCommand()) concurrent_scanner.queue_scan_command(server_info, Sslv20ScanCommand()) # Process the results print('\nProcessing results...') for scan_result in concurrent_scanner.get_results(): # これからスキャンする情報(コマンド)を表示 print( f'\nReceived result for "{scan_result.scan_command.get_title()}" ' f'on {scan_result.server_info.hostname}') # A scan command can fail (as a bug); it is returned as a PluginRaisedExceptionResult # スキャンコマンドのエラー if isinstance(scan_result, PluginRaisedExceptionScanResult): ##raise RuntimeError(f'Scan command failed: {scan_result.scan_command.get_title()}') print( f'Scan command failed: {scan_result.scan_command.get_title()}') continue # Each scan result has attributes with the information yo're looking for # All these attributes are documented within each scan command's module if isinstance(scan_result.scan_command, Sslv20ScanCommand): # Cipher suitesリスト(ssl2.0)を表示 for cipher in scan_result.accepted_cipher_list: print(f' {cipher.name}') sql = "INSERT INTO CipherSuite(hostname, SSL20) values(?, ?)" data = [(hn, cipher.name)] cur.executemany(sql, data) if isinstance(scan_result.scan_command, Sslv30ScanCommand): # Cipher suitesリスト(ssl3.0)を表示 for cipher in scan_result.accepted_cipher_list: print(f' {cipher.name}') sql = "INSERT INTO CipherSuite(hostname, SSL30) values(?, ?)" data = [(hn, cipher.name)] cur.executemany(sql, data) if isinstance(scan_result.scan_command, Tlsv10ScanCommand): # Cipher suitesリスト(tls1.0)を表示 for cipher in scan_result.accepted_cipher_list: print(f' {cipher.name}') sql = "INSERT INTO CipherSuite(hostname, TLS10) values(?, ?)" data = [(hn, cipher.name)] cur.executemany(sql, data) if isinstance(scan_result.scan_command, Tlsv11ScanCommand): # Cipher suitesリスト(tls1.1)を表示 for cipher in scan_result.accepted_cipher_list: print(f' {cipher.name}') sql = "INSERT INTO CipherSuite(hostname, TLS11) values(?, ?)" data = [(hn, cipher.name)] cur.executemany(sql, data) if isinstance(scan_result.scan_command, Tlsv12ScanCommand): # Cipher suitesリスト(tls1.2)を表示 for cipher in scan_result.accepted_cipher_list: print(f' {cipher.name}') sql = "INSERT INTO CipherSuite(hostname, TLS12) values(?, ?)" data = [(hn, cipher.name)] cur.executemany(sql, data) if isinstance(scan_result.scan_command, Tlsv13ScanCommand): # Cipher suitesリスト(tls1.3)を表示 for cipher in scan_result.accepted_cipher_list: print(f' {cipher.name}') sql = "INSERT INTO CipherSuite(hostname, TLS13) values(?, ?)" data = [(hn, cipher.name)] cur.executemany(sql, data) elif isinstance(scan_result.scan_command, CertificateInfoScanCommand): # Print the Common Names within the verified certificate chain # 証明書情報を表示 if not scan_result.verified_certificate_chain: print('Error: certificate chain is not trusted!') cur.execute("INSERT INTO CertInfo(hostname) values(?)", [hn]) else: print('Certificate chain common names:') for cert in scan_result.verified_certificate_chain: cert_common_names_check = cert.subject.get_attributes_for_oid( NameOID.COMMON_NAME) if cert_common_names_check: cert_common_names = cert_common_names_check[0].value else: cert_common_names = '' cert_publickey = CertificateUtils.get_public_key_type(cert) cert_keysize = cert.public_key().key_size cert_sig_algo = cert.signature_algorithm_oid cert_leaf_ev = scan_result.leaf_certificate_is_ev # leafのみ # Policy type 判定未完成↓ """ try: cert_policy = cert.extensions.get_extension_for_oid(ExtensionOID.CERTIFICATE_POLICIES).value except ExtensionNotFound: continue OV = '2.23.140.1.2.2' DV = '2.23.140.1.2.1' if OV in cert_policy: cert_policy_type = 'OV' if DV in cert_policy: cert_policy_type = 'DV' else: cert_policy_type = '' """ cert_ov_check = cert.subject.get_attributes_for_oid( NameOID.ORGANIZATION_NAME) if cert_ov_check: cert_ov = cert_ov_check[0].value else: cert_ov = '' print(f' {cert_common_names}') print(f' {cert_publickey}') print(f' {cert_keysize}') print(f' {cert_sig_algo._name}') # print(f' {cert_policy_type}') print(f' {cert_leaf_ev}') print(f' {cert_ov}') sql = "INSERT INTO CertInfo(hostname, commonname, publickey, keysize, signature, certtype, ov) values(?, ?, ?, ?, ?, ?, ?)" data = [ (hn, cert_common_names, cert_publickey, cert_keysize, cert_sig_algo._name, cert_leaf_ev, cert_ov) ] cur.executemany(sql, data)
def scan(targets: List[object_models.TargetWithExtra], command_names: Optional[str] = None) -> List[ScanResult]: logger.info( f"SC0002 New scan initiated with sslyze version {sslyze_version} for target {targets}" ) if command_names is None: commands = scan_commands.from_names_to_scan_commands( SslyzeConfig.limit_scan_to_scan_commands_names) else: commands = scan_commands.from_names_to_scan_commands(command_names) domain_results = [] for target in targets: domain_result = ScanResult(target) try: server_tester = ServerConnectivityTester( hostname=target.target_definition.hostname, port=target.target_definition.port, ip_address=target.target_definition.ip_address, tls_wrapped_protocol=target.target_definition.protocol) server_info = server_tester.perform( network_timeout=connectivity_timeout) except ServerConnectivityError as e: error_msg = f"NT0001 Cannot establish connectivity to target {target} with error {e}" logger.warning(error_msg) domain_result.msg += error_msg + '\n' domain_results.append(domain_result) continue except Exception as e: error_msg = f"NT0002 Unknown exception in establishing connection to target {target} with error {e}" logger.warning(error_msg) domain_result.msg += error_msg + '\n' domain_results.append(domain_result) continue scan_results = set() if SslyzeConfig.asynchronous_scanning: logger.debug("Using SSLyze asynchronous scanner") scanner = ConcurrentScanner( network_timeout=scanner_plugin_network_timeout) for scan_command in commands: scanner.queue_scan_command(server_info, scan_command()) for scan_result in scanner.get_results(): # todo: put some error msg to db # todo: handle errors, maybe already solved by PluginRaisedExceptionScanResult scan_results.add(scan_result) else: logger.debug("Using SSLyze synchronous scanner") scanner = SynchronousScanner( network_timeout=scanner_plugin_network_timeout) for scan_command in commands: try: scan_result = scanner.run_scan_command( server_info, scan_command()) scan_results.add(scan_result) except Exception as e: # todo: put some error msg to db # todo: handle errors, maybe already solved by PluginRaisedExceptionScanResult logger.exception(e) for scan_result in scan_results: scan_command_title = scan_result.scan_command.get_title() if isinstance(scan_result, PluginRaisedExceptionScanResult): error_msg = f"SC0003 Scan command failed: {target}, {scan_result.as_text()}" domain_result.msg += error_msg + '\n' logger.warning(error_msg) continue scan_result_dicts = scan_result_to_dicts(scan_result) domain_result.plugin_results[ scan_command_title] = scan_result_dicts[1] domain_result.server_info = scan_result_dicts[0] domain_results.append(domain_result) return domain_results
def main(): global global_scanner # For py2exe builds freeze_support() # Handle SIGINT to terminate processes signal.signal(signal.SIGINT, sigint_handler) start_time = time() plugins_repository = PluginsRepository() available_plugins = plugins_repository.get_available_plugins() available_commands = plugins_repository.get_available_commands() # Create the command line parser and the list of available options sslyze_parser = CommandLineParser(available_plugins, __version__) try: good_server_list, bad_server_list, args_command_list = sslyze_parser.parse_command_line() except CommandLineParsingError as e: print(e.get_error_msg()) return output_hub = OutputHub() output_hub.command_line_parsed(available_plugins, args_command_list) # Initialize the pool of processes that will run each plugin if args_command_list.https_tunnel: # Maximum one process to not kill the proxy global_scanner = ConcurrentScanner(args_command_list.nb_retries, args_command_list.timeout, max_processes_nb=1) else: global_scanner = ConcurrentScanner(args_command_list.nb_retries, args_command_list.timeout) # Figure out which hosts are up and fill the task queue with work to do connectivity_tester = ServersConnectivityTester(good_server_list) connectivity_tester.start_connectivity_testing(network_timeout=args_command_list.timeout) # Store and print server whose command line string was bad for failed_scan in bad_server_list: output_hub.server_connectivity_test_failed(failed_scan) # Store and print servers we were able to connect to online_servers_list = [] for server_connectivity_info in connectivity_tester.get_reachable_servers(): online_servers_list.append(server_connectivity_info) output_hub.server_connectivity_test_succeeded(server_connectivity_info) # Send tasks to worker processes for scan_command_class in available_commands: if getattr(args_command_list, scan_command_class.get_cli_argument()): # Get this command's optional argument if there's any optional_args = {} for optional_arg_name in scan_command_class.get_optional_arguments(): # Was this option set ? if getattr(args_command_list, optional_arg_name): optional_args[optional_arg_name] = getattr(args_command_list, optional_arg_name) scan_command = scan_command_class(**optional_args) global_scanner.queue_scan_command(server_connectivity_info, scan_command) # Store and print servers we were NOT able to connect to for tentative_server_info, exception in connectivity_tester.get_invalid_servers(): failed_scan = FailedServerScan(tentative_server_info.server_string, exception) output_hub.server_connectivity_test_failed(failed_scan) # Keep track of how many tasks have to be performed for each target task_num = 0 output_hub.scans_started() for scan_command_class in available_commands: if getattr(args_command_list, scan_command_class.get_cli_argument()): task_num += 1 # Each host has a list of results result_dict = {} # We cannot use the server_info object directly as its address will change due to multiprocessing RESULT_KEY_FORMAT = '{hostname}:{ip_address}:{port}' for server_info in online_servers_list: result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] = [] # Process the results as they come for plugin_result in global_scanner.get_results(): server_info = plugin_result.server_info result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)].append(plugin_result) plugin_result_list = result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address, port=server_info.port)] if len(plugin_result_list) == task_num: # Done with this server; send the result to the output hub output_hub.server_scan_completed(CompletedServerScan(server_info, plugin_result_list)) # All done exec_time = time()-start_time output_hub.scans_completed(exec_time)
def module_run(self, hostportsip): for host, port, ip_address in hostportsip: self.heading('{0}:{1} ({2})'.format(host, port, ip_address), level=0) port = int(port) try: tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[port] except KeyError: self.error("Protocol not found for port {}".format(port)) continue try: server_info = ServerConnectivityInfo(hostname=host, port=port, ip_address=ip_address, tls_wrapped_protocol=tls_wrapped_protocol) server_info.test_connectivity_to_server() except ServerConnectivityError as e: self.error("Could not connect to {0}:{1}: {2}".format(host, port, e)) continue concurrent_scanner = ConcurrentScanner() concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand()) concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand()) concurrent_scanner.queue_scan_command(server_info, FallbackScsvScanCommand()) concurrent_scanner.queue_scan_command(server_info, HeartbleedScanCommand()) concurrent_scanner.queue_scan_command(server_info, RobotScanCommand()) concurrent_scanner.queue_scan_command(server_info, OpenSslCcsInjectionScanCommand()) concurrent_scanner.queue_scan_command(server_info, SessionResumptionSupportScanCommand()) for scan_result in concurrent_scanner.get_results(): data = None if isinstance(scan_result, HeartbleedScanResult): if scan_result.is_vulnerable_to_heartbleed: data = {'reference': 'VULNERABLE - HEARTBLEED - Server is vulnerable to Heartbleed', 'example': '\n'.join(scan_result.as_text())} elif isinstance(scan_result, RobotScanResult): if scan_result.robot_result_enum == RobotScanResultEnum.VULNERABLE_STRONG_ORACLE: data = {'reference': 'VULNERABLE - ROBOT - Strong oracle, a real attack is possible', 'example': '\n'.join(scan_result.as_text())} elif scan_result.robot_result_enum == RobotScanResultEnum.VULNERABLE_WEAK_ORACLE: data = {'reference': 'VULNERABLE - ROBOT - Weak oracle, the attack would take too long', 'example': '\n'.join(scan_result.as_text())} elif isinstance(scan_result, CompressionScanResult): if scan_result.compression_name: data = {'reference': "VULNERABLE - Server supports Deflate compression", 'example': '\n'.join(scan_result.as_text())} elif isinstance(scan_result, FallbackScsvScanResult): if scan_result.supports_fallback_scsv: data = {'reference': "VULNERABLE - Signaling cipher suite not supported", 'example': '\n'.join(scan_result.as_text())} data = None elif isinstance(scan_result, OpenSslCcsInjectionScanResult): if scan_result.is_vulnerable_to_ccs_injection: data = {'reference': 'VULNERABLE - Server is vulnerable to OpenSSL CCS injection', 'example': '\n'.join(scan_result.as_text())} elif isinstance(scan_result, SessionRenegotiationScanResult): if scan_result.accepts_client_renegotiation: data = {'reference': 'VULNERABLE - Server honors client-initiated renegotiations', 'example': '\n'.join(scan_result.as_text())} elif isinstance(scan_result, PluginRaisedExceptionScanResult): self.error('Scan command failed: {}'.format(scan_result.as_text())) continue if data: data['host'] = host data['category'] = 'TLS vulnerability' for key in sorted(data.keys()): self.output('%s: %s' % (key.title(), data[key])) self.add_vulnerabilities(**data) self.output(self.ruler*50)
def init_sslyze(hostname, port, starttls_smtp, options, sync=False): global network_timeout, CA_FILE network_timeout = int(options.get("network_timeout", network_timeout)) if options.get('ca_file'): CA_FILE = options['ca_file'] tls_wrapped_protocol = TlsWrappedProtocolEnum.PLAIN_TLS if starttls_smtp: tls_wrapped_protocol = TlsWrappedProtocolEnum.STARTTLS_SMTP try: # logging.debug("\tTesting connectivity with timeout of %is." % network_timeout) server_tester = ServerConnectivityTester( hostname=hostname, port=port, tls_wrapped_protocol=tls_wrapped_protocol) server_info = server_tester.perform(network_timeout=network_timeout) except ServerConnectivityError: # Usually pshtt has already established that we can connect to the site, so let's try again a couple of times try: logging.debug( "\t{}:{} Server connectivity check failed. Trying again...". format(hostname, port)) time.sleep(10) server_tester = ServerConnectivityTester( hostname=hostname, port=port, tls_wrapped_protocol=tls_wrapped_protocol) server_info = server_tester.perform( network_timeout=(network_timeout * 2)) except Exception as err: try: logging.debug( "\t{}:{} Server connectivity check failed. Trying again..." .format(hostname, port)) time.sleep(30) server_tester = ServerConnectivityTester( hostname=hostname, port=port, tls_wrapped_protocol=tls_wrapped_protocol) server_info = server_tester.perform( network_timeout=(network_timeout * 2)) except Exception as err: logging.warning( "\t{}:{} Server connectivity not established during test.". format(hostname, port)) return None, None except dns.exception.DNSException as err: logging.warning( "\t{}:{} DNS exception when performing sslyze server connectivity info check." .format(hostname, port)) logging.debug("\t:{}:{} DNS exception: {}".format(hostname, port, err)) return None, None except Exception as err: utils.notify(err) logging.warning( "\t{}:{} Unknown exception when performing server connectivity info." .format(hostname, port)) return None, None if sync: scanner = SynchronousScanner(network_timeout=network_timeout) else: scanner = ConcurrentScanner(network_timeout=network_timeout) return server_info, scanner
server_info.test_connectivity_to_server() except ServerConnectivityError as e: # Could not establish an SSL connection to the server raise RuntimeError('Error when connecting to {}: {}'.format( hostname, e.error_msg)) # Example 1: Run one scan command synchronously to list the server's TLS 1.0 cipher suites print('\nRunning one scan command synchronously...') synchronous_scanner = SynchronousScanner() command = Tlsv10ScanCommand() scan_result = synchronous_scanner.run_scan_command(server_info, command) for cipher in scan_result.accepted_cipher_list: print(' {}'.format(cipher.name)) # Example 2: Run multiple scan commands concurrently. It is of course much faster than the SynchronousScanner concurrent_scanner = ConcurrentScanner() # Queue some scan commands print('\nQueuing some commands...') concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand()) concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand()) concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) # Process the results reneg_result = None print('\nProcessing results...') for scan_result in concurrent_scanner.get_results(): # All scan results have the corresponding scan_command and server_info as an attribute print('\nReceived scan result for {} on host {}'.format(
except ServerConnectivityError as e: # Could not establish an SSL connection to the server raise RuntimeError('Error when connecting to {}: {}'.format(hostname, e.error_msg)) # Example 1: Run one scan command synchronously to list the server's TLS 1.0 cipher suites print('\nRunning one scan command synchronously...') synchronous_scanner = SynchronousScanner() command = Tlsv10ScanCommand() scan_result = synchronous_scanner.run_scan_command(server_info, command) for cipher in scan_result.accepted_cipher_list: print(' {}'.format(cipher.name)) # Example 2: Run multiple scan commands concurrently. It is of course much faster than the SynchronousScanner concurrent_scanner = ConcurrentScanner() # Queue some scan commands print('\nQueuing some commands...') concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand()) concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand()) concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand()) # Process the results reneg_result = None print('\nProcessing results...') for scan_result in concurrent_scanner.get_results(): # All scan results have the corresponding scan_command and server_info as an attribute print('\nReceived scan result for {} on host {}'.format(scan_result.scan_command.__class__.__name__, scan_result.server_info.hostname))