def check_ipv6_connection() -> str: prefix = "IPv6 -> Internet:" url = "https://ipv6.icanhazip.com/" try: res = _check_connection(url) if not checkers.is_ipv6(res): res = "(Unavailable)" except Exception: res = "(Unavailable)" reporter.register_info("ipv6", res) return f"{prefix} {res}"
def scan(args: Namespace, url: str, domain: str): output.norm( f"Beginning SSL scan using sslyze {__version__} (this could take a minute or two)" ) output.empty() ips = basic.get_ips(domain) for ip in ips: try: conn_tester = server_connectivity_tester.ServerConnectivityTester( hostname=domain, port=utils.get_port(url), ip_address=ip) output.norm(f"IP: {conn_tester.ip_address}:{conn_tester.port}") server_info = conn_tester.perform() scanner = synchronous_scanner.SynchronousScanner() cinfo = scanner.run_scan_command( server_info, certificate_info_plugin.CertificateInfoScanCommand()) cinfo = typing.cast( certificate_info_plugin.CertificateInfoScanResult, cinfo) # print info on the server cert _get_leaf_cert_info(cinfo.verified_certificate_chain[0]) # get all but the first element _get_cert_chain(cinfo.verified_certificate_chain[1:], url) # list the root stores this is trusted by trust = "" for t in _get_trusted_root_stores(cinfo): trust += f"{t} (trusted) " output.norm(f"\tRoot Stores: {trust}") output.empty() # get info for the various versions of SSL/TLS output.norm("\tCipher Suite Support:") sslv2 = scanner.run_scan_command( server_info, openssl_cipher_suites_plugin.Sslv20ScanCommand()) sslv2 = typing.cast( openssl_cipher_suites_plugin.CipherSuiteScanResult, sslv2) _get_suite_info("SSLv2", sslv2, url) sslv3 = scanner.run_scan_command( server_info, openssl_cipher_suites_plugin.Sslv30ScanCommand()) sslv3 = typing.cast( openssl_cipher_suites_plugin.CipherSuiteScanResult, sslv3) _get_suite_info("SSLv3", sslv3, url) tls10 = scanner.run_scan_command( server_info, openssl_cipher_suites_plugin.Tlsv10ScanCommand()) tls10 = typing.cast( openssl_cipher_suites_plugin.CipherSuiteScanResult, tls10) _get_suite_info("TLSv1.0", tls10, url) tls11 = scanner.run_scan_command( server_info, openssl_cipher_suites_plugin.Tlsv11ScanCommand()) tls11 = typing.cast( openssl_cipher_suites_plugin.CipherSuiteScanResult, tls11) _get_suite_info("TLSv1.1", tls11, url) tls12 = scanner.run_scan_command( server_info, openssl_cipher_suites_plugin.Tlsv12ScanCommand()) tls12 = typing.cast( openssl_cipher_suites_plugin.CipherSuiteScanResult, tls12) _get_suite_info("TLSv1.2", tls12, url) tls13 = scanner.run_scan_command( server_info, openssl_cipher_suites_plugin.Tlsv13ScanCommand()) tls13 = typing.cast( openssl_cipher_suites_plugin.CipherSuiteScanResult, tls13) _get_suite_info("TLSv1.3", tls13, url) output.empty() # check compression compression = scanner.run_scan_command( server_info, compression_plugin.CompressionScanCommand()) compression = typing.cast(compression_plugin.CompressionScanResult, compression) if compression.compression_name is not None: reporter.display( f"\tCompression: {compression.compression_name}", issue.Issue(Vulnerabilities.TLS_COMPRESSION_ENABLED, url, {}), ) else: output.norm("\tCompression: None") # check TLS_FALLBACK_SCSV fallback = scanner.run_scan_command( server_info, fallback_scsv_plugin.FallbackScsvScanCommand()) fallback = typing.cast(fallback_scsv_plugin.FallbackScsvScanResult, fallback) if fallback.supports_fallback_scsv: output.norm("\tDowngrade Prevention: Yes") else: reporter.display( "\tDowngrade Prevention: No", issue.Issue(Vulnerabilities.TLS_FALLBACK_SCSV_MISSING, url, {}), ) # check Heartbleed heartbleed = scanner.run_scan_command( server_info, heartbleed_plugin.HeartbleedScanCommand()) heartbleed = typing.cast(heartbleed_plugin.HeartbleedScanResult, heartbleed) if heartbleed.is_vulnerable_to_heartbleed: reporter.display( "\tHeartbleed: Vulnerable", issue.Issue(Vulnerabilities.TLS_HEARTBLEED, url, {}), ) else: output.norm("\tHeartbleed: No") # check OpenSSL CCS injection vulnerability (CVE-2014-0224) openssl_ccs = scanner.run_scan_command( server_info, openssl_ccs_injection_plugin.OpenSslCcsInjectionScanCommand(), ) openssl_ccs = typing.cast( openssl_ccs_injection_plugin.OpenSslCcsInjectionScanResult, openssl_ccs) if openssl_ccs.is_vulnerable_to_ccs_injection: reporter.display( "\tOpenSSL CCS (CVE-2014-0224): Vulnerable", issue.Issue(Vulnerabilities.TLS_OPENSSL_CVE_2014_0224, url, {}), ) else: output.norm("\tOpenSSL CCS (CVE-2014-0224): No") # check SessionRenegotiation sr = scanner.run_scan_command( server_info, session_renegotiation_plugin.SessionRenegotiationScanCommand(), ) sr = typing.cast( session_renegotiation_plugin.SessionRenegotiationScanResult, sr) if sr.accepts_client_renegotiation: output.norm( "\tSecure Renegotiation: client-initiated renegotiation supported" ) if sr.supports_secure_renegotiation: output.norm( "\tSecure Renegotiation: secure renegotiation supported") # check SessionResumption resump = scanner.run_scan_command( server_info, session_resumption_plugin.SessionResumptionSupportScanCommand( ), ) resump = typing.cast( session_resumption_plugin.SessionResumptionSupportScanResult, resump) output.norm( f"\tSession Resumption Tickets Supported: {resump.is_ticket_resumption_supported}" ) output.norm( f"\tSession Resumption: {resump.successful_resumptions_nb} of " f"{resump.attempted_resumptions_nb} successful") # check ROBOT robot = scanner.run_scan_command(server_info, robot_plugin.RobotScanCommand()) robot = typing.cast(robot_plugin.RobotScanResult, robot) if (robot.robot_result_enum == robot_plugin.RobotScanResultEnum.VULNERABLE_WEAK_ORACLE): reporter.display( "\tROBOT: Vulnerable - Not Exploitable", issue.Issue(Vulnerabilities.TLS_ROBOT_ORACLE_WEAK, url, {}), ) elif (robot.robot_result_enum == robot_plugin.RobotScanResultEnum.VULNERABLE_STRONG_ORACLE): reporter.display( "\tROBOT: Vulnerable - Exploitable", issue.Issue(Vulnerabilities.TLS_ROBOT_ORACLE_STRONG, url, {}), ) elif (robot.robot_result_enum == robot_plugin.RobotScanResultEnum. UNKNOWN_INCONSISTENT_RESULTS): output.error("\tROBOT: Test Failed (Inconsistent Results)") else: output.norm("\tROBOT: No") # check TLS 1.3 Early Data ed = scanner.run_scan_command( server_info, early_data_plugin.EarlyDataScanCommand()) ed = typing.cast(early_data_plugin.EarlyDataScanResult, ed) if ed.is_early_data_supported: output.info("\tTLS 1.3 0-RTT Support: Yes") else: output.norm("\tTLS 1.3 0-RTT Support: No") if cinfo.ocsp_response_status is not None: output.norm("\tOCSP Stapling: Yes") else: reporter.display( "\tOCSP Stapling: No", issue.Issue(Vulnerabilities.TLS_OCSP_STAPLE_MISSING, url, {}), ) output.empty() except server_connectivity_tester.ServerConnectivityError as error: output.debug_exception() if checkers.is_ipv6(ip): output.error( "\tError connecting to IPv6 IP. Please ensure that your system is configured properly." ) output.error(f"\tConnection failed ({str(error)})") output.empty()
def scan(session: Session): ips = basic.get_ips(session.domain) for ip in ips: conn = None count = 0 try: count = 0 conn_tester = server_connectivity_tester.ServerConnectivityTester( hostname=session.domain, port=utils.get_port(session.url), ip_address=ip) output.norm( f"TLS Session Request Limit: Checking number of requests accepted using 3DES suites " f"(IP: {conn_tester.ip_address}:{conn_tester.port})") server_info = conn_tester.perform() conn = ssl_connection_configurator.SslConnectionConfigurator.get_connection( ssl_version=OpenSslVersionEnum.SSLV23, server_info=server_info, should_use_legacy_openssl=True, openssl_cipher_string="3DES", should_ignore_client_auth=True, ssl_verify_locations=None, ) conn.connect() req = ("HEAD / HTTP/1.1\r\n" "Host: {host}\r\n" "User-Agent: {user_agent}\r\n" "Accept: */*\r\n" "Connection: keep-alive\r\n\r\n".format( host=session.domain, user_agent=network.YAWAST_UA)) ossl_name = conn.ssl_client.get_current_cipher_name() name = OPENSSL_TO_RFC_NAMES_MAPPING[OpenSslVersionEnum.TLSV1].get( ossl_name, ossl_name) print(" ", end="", flush=True) print(f"(using {name})", end="", flush=True) for i in range(0, 10000): conn.ssl_client.write(req) http_response_parser.HttpResponseParser.parse_from_ssl_connection( conn.ssl_client) count += 1 if i % 20: print(".", end="", flush=True) output.empty() reporter.display( f"\tTLS Session Request Limit: Connection not terminated after {count} requests; " f"possibly vulnerable to SWEET32", issue.Issue(Vulnerabilities.TLS_SWEET32, session.url, {}), ) except ssl_connection.SslHandshakeRejected as error: output.debug_exception() output.empty() output.norm(f"\tServer rejected our connection ({str(error)})") output.empty() except IOError as error: output.debug_exception() output.empty() if count > 0: output.norm( f"\tTLS Session Request Limit: Connection terminated after {count} requests ({str(error)})" ) else: output.norm( "\tTLS Session Request Limit: Server does not support 3DES cipher suites" ) output.empty() except server_connectivity_tester.ServerConnectivityError as error: output.debug_exception() output.empty() if checkers.is_ipv6(ip): output.error( "\tError connecting to IPv6 IP. Please ensure that your system is configured properly." ) output.error(f"\tConnection failed ({str(error)})") output.empty() finally: if conn is not None: conn.close() output.empty()