def test_succeeds_when_client_auth_failed(self): # Given a server that requires client authentication try: with VulnerableOpenSslServer( client_auth_config= ClientAuthenticationServerConfigurationEnum.REQUIRED ) as server: # And the client does NOT provide a client certificate server_test = ServerConnectivityTester( hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info = server_test.perform() # The plugin works even when a client cert was not supplied plugin = CompressionPlugin() plugin_result = plugin.process_task(server_info, CompressionScanCommand()) except NotOnLinux64Error: logging.warning('WARNING: Not on Linux - skipping test') return self.assertFalse(plugin_result.compression_name) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_synchronous_scanner(self): server_info = ServerConnectivityInfo(hostname='www.google.com') server_info.test_connectivity_to_server() sync_scanner = SynchronousScanner() plugin_result = sync_scanner.run_scan_command(server_info, CompressionScanCommand()) self.assertTrue(plugin_result.as_text()) self.assertTrue(plugin_result.as_xml())
def test_synchronous_scanner(self): server_test = ServerConnectivityTester(hostname='www.google.com') server_info = server_test.perform() sync_scanner = SynchronousScanner() plugin_result = sync_scanner.run_scan_command(server_info, CompressionScanCommand()) assert plugin_result.as_text() assert plugin_result.as_xml()
def run_compression_command(self, server_info, synchronous_scanner): command = CompressionScanCommand() try: scan_result = synchronous_scanner.run_scan_command( server_info, command) #print('Compression obtained for ',server_info) return scan_result.compression_name except: #print('Compression obtained for ',server_info) return None
def test_compression_disabled(self): server_info = ServerConnectivityInfo(hostname=u'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())
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_compression_disabled(self): server_test = ServerConnectivityTester(hostname='www.google.com') server_info = server_test.perform() plugin = CompressionPlugin() plugin_result = plugin.process_task(server_info, CompressionScanCommand()) assert not plugin_result.compression_name assert plugin_result.as_text() assert plugin_result.as_xml() # Ensure the results are pickable so the ConcurrentScanner can receive them via a Queue assert pickle.dumps(plugin_result)
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_succeeds_when_client_auth_failed(self): # Given a server that requires client authentication with LegacyOpenSslServer( client_auth_config=ClientAuthConfigEnum.REQUIRED) as server: # And the client does NOT provide a client certificate server_test = ServerConnectivityTester( hostname=server.hostname, ip_address=server.ip_address, port=server.port) server_info = server_test.perform() # The plugin works even when a client cert was not supplied plugin = CompressionPlugin() plugin_result = plugin.process_task(server_info, CompressionScanCommand()) assert not plugin_result.compression_name assert plugin_result.as_text() assert plugin_result.as_xml()
def executePerDomainAction(self, domain): """ This plugin's per-domain action is to run a barrage of sslyze certificate tests Params: domain (str) """ from sslyze.plugins.certificate_info_plugin import CertificateInfoScanCommand from sslyze.plugins.compression_plugin import CompressionScanCommand from sslyze.plugins.session_renegotiation_plugin import SessionRenegotiationScanCommand from sslyze.server_connectivity_tester import ServerConnectivityTester from sslyze.server_connectivity_tester import ServerConnectivityError from sslyze.synchronous_scanner import SynchronousScanner try: sslyze_conn_test = ServerConnectivityTester(hostname=domain) sslyze_server_info = sslyze_conn_test.perform() sslyze_scanner = SynchronousScanner() sslyze_results = sslyze_scanner.run_scan_command( sslyze_server_info, CertificateInfoScanCommand()) sslyze_result_lines = sslyze_results.as_text() for line in sslyze_result_lines: self.logger.info(line) sslyze_results = sslyze_scanner.run_scan_command( sslyze_server_info, SessionRenegotiationScanCommand()) sslyze_result_lines = sslyze_results.as_text() for line in sslyze_result_lines: self.logger.info(line) sslyze_results = sslyze_scanner.run_scan_command( sslyze_server_info, CompressionScanCommand()) sslyze_result_lines = sslyze_results.as_text() for line in sslyze_result_lines: self.logger.info(line) except ServerConnectivityError as e: # Could not establish a TLS/SSL connection to the server self.logger.error( f'sslyze ended early, could not connect to {e.server_info.hostname}: {e.error_message}' ) print( f'sslyze ended early, could not connect to {e.server_info.hostname}: {e.error_message}' )
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 main(): if len(sys.argv) < 2: print("Error: please provide a domain") exit(-1) hostname = sys.argv[1] """ Testing connectivity to the server """ try: server_info = ServerConnectivityInfo(hostname) server_info.test_connectivity_to_server() print( "[*] Connection established. \n[.] Starting tests on {} \n".format( hostname)) except ServerConnectivityError as e: raise RuntimeError("Error when connecting to {}: {}".format( hostname, e.error_msg)) scanner = SynchronousScanner() """ Creating an output file """ output = open("/root/PycharmProjects/SSL-TLS-Tool/output/" + hostname, "w") output.write("##############################################\n") output.write("Output result for host: {}\n".format(hostname)) output.write("Start {}\n".format(datetime.datetime.now())) output.write("##############################################\n\n") """ Certificate: """ scan_result = scanner.run_scan_command(server_info, CertificateInfoScanCommand()) for e in scan_result.as_text(): output.write(e + "\n") """ Protocols and Ciphers Suits: """ run_command(scanner, server_info, Tlsv10ScanCommand(), output) run_command(scanner, server_info, Tlsv11ScanCommand(), output) run_command(scanner, server_info, Tlsv12ScanCommand(), output) run_command(scanner, server_info, Sslv20ScanCommand(), output) run_command(scanner, server_info, Sslv30ScanCommand(), output) """ Testing vulnerabilities: """ run_command(scanner, server_info, DrownScanCommand(), output) run_command(scanner, server_info, PoodleSslScanCommand(), output) run_command(scanner, server_info, HeartbleedScanCommand(), output) run_command(scanner, server_info, OpenSslCcsInjectionScanCommand(), output) run_command(scanner, server_info, CompressionScanCommand(), output) run_command(scanner, server_info, FallbackScsvScanCommand(), output) run_command(scanner, server_info, SessionRenegotiationScanCommand(), output) run_command(scanner, server_info, SessionResumptionSupportScanCommand(), output) run_command(scanner, server_info, SessionResumptionRateScanCommand(), output) """ Closing """ output.close() print("\n[*] Check output file for more details") print("[*] Test completed!")
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)