def _get_simulations(ep, protos): if ep["details"]["sims"]["results"] is not None: output.norm("\tHandshake Simulation:") for sim in ep["details"]["sims"]["results"]: name = f'{sim["client"]["name"]} {sim["client"]["version"]}' if "platform" in sim["client"]: name += f' / {sim["client"]["platform"]}' name = name.ljust(28) if sim["errorCode"] == 0: protocol = protos[sim["protocolId"]] ke = _get_key_exchange(sim, True) if ke is not None: suite_name = f'{sim["suiteName"]} - {ke}' else: suite_name = f'{sim["suiteName"]}' output.norm(f"\t\t{name} - {protocol} - {suite_name}") else: output.info(f"\t\t{name} - Simulation Failed") output.empty()
def _get_suite_info(proto: str, result: openssl_cipher_suites_plugin.CipherSuiteScanResult, url: str): output.norm(f"\t\t{proto}:") if len(result.accepted_cipher_list) > 0: for suite in result.accepted_cipher_list: name = openssl_cipher_suites_plugin.OPENSSL_TO_RFC_NAMES_MAPPING[ suite.ssl_version].get(suite.openssl_name, suite.openssl_name) if _is_cipher_suite_secure(suite, name): if "CBC" in name: output.info( f"\t\t {name.ljust(50)} - {suite.key_size}-bits") reporter.register( issue.Issue(Vulnerabilities.TLS_CBC_CIPHER_SUITE, url, {"cipher": name})) else: output.norm( f"\t\t {name.ljust(50)} - {suite.key_size}-bits") else: output.vuln(f"\t\t {name.ljust(50)} - {suite.key_size}-bits") reporter.register( issue.Issue(Vulnerabilities.TLS_INSECURE_CIPHER_SUITE, url, {"cipher": name})) output.norm( f"\t\t ({len(result.rejected_cipher_list)} suites rejected)") else: output.norm( f"\t\t (all suites ({len(result.rejected_cipher_list)}) rejected)" )
def display(msg: str, issue: Issue) -> None: if issue.vulnerability.display_all or not is_registered( issue.vulnerability): if issue.severity == Severity.CRITICAL or issue.severity == Severity.HIGH: output.vuln(msg) elif issue.severity == Severity.MEDIUM: output.warn(msg) else: output.info(msg) # if there's no evidence, default to the msg - better than nothing if issue.evidence is None: issue.evidence = msg.strip() register(issue)
def _get_vulnerability_info(ep, url): output.norm("\tProtocol & Vulnerability Information:") if "sniRequired" in ep["details"]: if ep["details"]["sniRequired"]: output.info("\t\tSNI Required: Yes") else: output.norm("\t\tSNI Required: No") if "drownVulnerable" in ep["details"]: if ep["details"]["drownVulnerable"]: output.vuln("\t\tDROWN: Vulnerable") servers = "" for dh in ep["details"]["drownHosts"]: servers += f'({dh["ip"]}:{dh["port"]} - {dh["status"]}) ' output.norm(f'\t\t\t{dh["ip"]}:{dh["port"]} - {dh["status"]}') output.norm( f'\t\t\t https://test.drownattack.com/?site={dh["ip"]}') reporter.register( issue.Issue( Vulnerabilities.TLS_DROWN, url, { "servers": servers, "ip": ep["ipAddress"] }, )) else: output.norm("\t\tDROWN: No") else: output.error("\t\tDROWN: Information Not Received") if "zeroRTTEnabled" in ep["details"]: if ep["details"]["zeroRTTEnabled"] == -2: output.error("\t\tTLS 1.3 0-RTT Support: Test Failed") elif ep["details"]["zeroRTTEnabled"] == -1: output.norm("\t\tTLS 1.3 0-RTT Support: Test Not Performed") elif ep["details"]["zeroRTTEnabled"] == 0: output.norm("\t\tTLS 1.3 0-RTT Support: No") elif ep["details"]["zeroRTTEnabled"] == 1: reporter.display( "\t\tTLS 1.3 0-RTT Support: Yes", issue.Issue( Vulnerabilities.TLS_VERSION_1_3_EARLY_DATA_ENABLED, url, {"ip": ep["ipAddress"]}, ), ) else: output.error( f'\t\tTLS 1.3 0-RTT Support: Unknown ({ep["details"]["zeroRTTEnabled"]})' ) else: output.error("\t\tTLS 1.3 0-RTT Support: Information Not Received") if "renegSupport" in ep["details"]: if ep["details"]["renegSupport"] & 1 != 0: reporter.display( "\t\tSecure Renegotiation: insecure client-initiated renegotiation supported", issue.Issue(Vulnerabilities.TLS_INSECURE_RENEG, url, {"ip": ep["ipAddress"]}), ) if ep["details"]["renegSupport"] & (1 << 1) != 0: output.norm( "\t\tSecure Renegotiation: secure renegotiation supported") if ep["details"]["renegSupport"] & (1 << 2) != 0: output.norm( "\t\tSecure Renegotiation: secure client-initiated renegotiation supported" ) if ep["details"]["renegSupport"] & (1 << 3) != 0: output.norm( '\t\tSecure Renegotiation: server requires secure renegotiation support"' ) else: output.error("\t\tSecure Renegotiation: Information Not Received") if "poodle" in ep["details"]: if ep["details"]["poodle"]: reporter.display( "\t\tPOODLE (SSL): Vulnerable", issue.Issue(Vulnerabilities.TLS_LEGACY_SSL_POODLE, url, {"ip": ep["ipAddress"]}), ) else: output.norm("\t\tPOODLE (SSL): No") else: output.error("\t\tPOODLE (SSL): Information Not Received") if "zombiePoodle" in ep["details"]: if ep["details"]["zombiePoodle"] == -1: output.error("\t\tZombie POODLE: Test Failed") elif ep["details"]["zombiePoodle"] == 0: output.error("\t\tZombie POODLE: Test Failed (Unknown)") elif ep["details"]["zombiePoodle"] == 1: output.norm("\t\tZombie POODLE: No") elif ep["details"]["zombiePoodle"] == 2: reporter.display( "\t\tZombie POODLE: Vulnerable - Not Exploitable", issue.Issue(Vulnerabilities.TLS_ZOMBIE_POODLE_NE, url, {"ip": ep["ipAddress"]}), ) elif ep["details"]["zombiePoodle"] == 3: output.vuln("\t\tZombie POODLE: Vulnerable - Exploitable") reporter.display( "\t\tZombie POODLE: Vulnerable - Exploitable", issue.Issue(Vulnerabilities.TLS_ZOMBIE_POODLE, url, {"ip": ep["ipAddress"]}), ) else: output.error( f'\t\tZombie POODLE: Unknown Response ({ep["details"]["zombiePoodle"]})' ) else: output.error("\t\tZombie POODLE: Information Not Received") if "goldenDoodle" in ep["details"]: if ep["details"]["goldenDoodle"] == -1: output.error("\t\tGOLDENDOODLE: Test Failed") elif ep["details"]["goldenDoodle"] == 0: output.error("\t\tGOLDENDOODLE: Test Failed (Unknown)") elif ep["details"]["goldenDoodle"] == 1: output.norm("\t\tGOLDENDOODLE: No") elif ep["details"]["goldenDoodle"] == 4: reporter.display( "\t\tGOLDENDOODLE: Vulnerable - Not Exploitable", issue.Issue(Vulnerabilities.TLS_GOLDENDOODLE_NE, url, {"ip": ep["ipAddress"]}), ) elif ep["details"]["goldenDoodle"] == 5: reporter.display( "\t\tGOLDENDOODLE: Vulnerable - Exploitable", issue.Issue(Vulnerabilities.TLS_GOLDENDOODLE, url, {"ip": ep["ipAddress"]}), ) else: output.error( f't\tGOLDENDOODLE: Unknown Response ({ep["details"]["goldenDoodle"]})' ) else: output.error("\t\tGOLDENDOODLE: Information Not Received") if "zeroLengthPaddingOracle" in ep["details"]: if ep["details"]["zeroLengthPaddingOracle"] == -1: output.error( "\t\tOpenSSL 0-Length Padding Oracle (CVE-2019-1559): Test Failed" ) elif ep["details"]["zeroLengthPaddingOracle"] == 0: output.error( "\t\tOpenSSL 0-Length Padding Oracle (CVE-2019-1559): Test Failed (Unknown)" ) elif ep["details"]["zeroLengthPaddingOracle"] == 1: output.norm( "\t\tOpenSSL 0-Length Padding Oracle (CVE-2019-1559): No") elif ep["details"]["zeroLengthPaddingOracle"] == 6: reporter.display( "\t\tOpenSSL 0-Length Padding Oracle (CVE-2019-1559): Vulnerable - Not Exploitable", issue.Issue( Vulnerabilities.TLS_OPENSSL_CVE_2019_1559_NE, url, {"ip": ep["ipAddress"]}, ), ) elif ep["details"]["zeroLengthPaddingOracle"] == 7: reporter.display( "\t\tOpenSSL 0-Length Padding Oracle (CVE-2019-1559): Vulnerable - Exploitable", issue.Issue( Vulnerabilities.TLS_OPENSSL_CVE_2019_1559, url, {"ip": ep["ipAddress"]}, ), ) else: output.error( f"\t\tOpenSSL 0-Length Padding Oracle (CVE-2019-1559): Unknown Response" f' ({ep["details"]["zeroLengthPaddingOracle"]})') else: output.error( "OpenSSL 0-Length Padding Oracle (CVE-2019-1559): Information Not Received" ) if "sleepingPoodle" in ep["details"]: if ep["details"]["sleepingPoodle"] == -1: output.error("\t\tSleeping POODLE: Test Failed") elif ep["details"]["sleepingPoodle"] == 0: output.error("\t\tSleeping POODLE: Test Failed (Unknown)") elif ep["details"]["sleepingPoodle"] == 1: output.norm("\t\tSleeping POODLE: No") elif ep["details"]["sleepingPoodle"] == 10: reporter.display( "\t\tSleeping POODLE: Vulnerable - Not Exploitable", issue.Issue(Vulnerabilities.TLS_SLEEPING_POODLE_NE, url, {"ip": ep["ipAddress"]}), ) elif ep["details"]["sleepingPoodle"] == 11: output.vuln("\t\tSleeping POODLE: Vulnerable - Exploitable") reporter.display( "\t\tSleeping POODLE: Vulnerable - Exploitable", issue.Issue(Vulnerabilities.TLS_SLEEPING_POODLE, url, {"ip": ep["ipAddress"]}), ) else: output.error( f'\t\tSleeping POODLE: Unknown Response ({ep["details"]["sleepingPoodle"]})' ) else: output.error("\t\tSleeping POODLE: Information Not Received") if "poodleTls" in ep["details"]: if ep["details"]["poodleTls"] == -3: output.info("\t\tPOODLE (TLS): Inconclusive (Timeout)") elif ep["details"]["poodleTls"] == -2: output.info("\t\tPOODLE (TLS): TLS Not Supported") elif ep["details"]["poodleTls"] == -1: output.error("\t\tPOODLE (TLS): Test Failed") elif ep["details"]["poodleTls"] == 0: output.error("\t\tPOODLE (TLS): Test Failed (Unknown)") elif ep["details"]["poodleTls"] == 1: output.norm("\t\tPOODLE (TLS): No") elif ep["details"]["poodleTls"] == 2: reporter.display( "\t\tPOODLE (TLS): Vulnerable", issue.Issue(Vulnerabilities.TLS_POODLE, url, {"ip": ep["ipAddress"]}), ) else: output.error( f'\t\tPOODLE (TLS): Unknown Response ({ep["details"]["poodleTls"]})' ) else: output.error("\t\tPOODLE (TLS): Information Not Received") if "fallbackScsv" in ep["details"]: if ep["details"]["fallbackScsv"]: output.norm("\t\tDowngrade Prevention: Yes") else: reporter.display( "\t\tDowngrade Prevention: No", issue.Issue( Vulnerabilities.TLS_FALLBACK_SCSV_MISSING, url, {"ip": ep["ipAddress"]}, ), ) else: output.error("\t\tDowngrade Prevention: Information Not Received") if "compressionMethods" in ep["details"]: if ep["details"]["compressionMethods"] & 1 != 0: reporter.display( "\t\tCompression: DEFLATE", issue.Issue( Vulnerabilities.TLS_COMPRESSION_ENABLED, url, {"ip": ep["ipAddress"]}, ), ) else: output.norm("\t\tCompression: No") else: output.error("\t\tCompression: Information Not Received") if "heartbeat" in ep["details"]: if ep["details"]["heartbeat"]: reporter.display( "\t\tHeartbeat: Enabled", issue.Issue(Vulnerabilities.TLS_HEARTBEAT_ENABLED, url, {"ip": ep["ipAddress"]}), ) else: output.norm("\t\tHeartbeat: Disabled") else: output.error("\t\tHeartbeat: Information Not Received") if "heartbleed" in ep["details"]: if ep["details"]["heartbleed"]: reporter.display( "\t\tHeartbleed: Vulnerable", issue.Issue(Vulnerabilities.TLS_HEARTBLEEDL, url, {"ip": ep["ipAddress"]}), ) else: output.norm("\t\tHeartbleed: No") else: output.error("\t\tHeartbleed: Information Not Received") if "ticketbleed" in ep["details"]: if ep["details"]["ticketbleed"] == -1: output.error("\t\tTicketbleed (CVE-2016-9244): Test Failed") elif ep["details"]["ticketbleed"] == 0: output.error( "\t\tTicketbleed (CVE-2016-9244): Test Failed (Unknown)") elif ep["details"]["ticketbleed"] == 1: output.norm("\t\tTicketbleed (CVE-2016-9244): No") elif ep["details"]["ticketbleed"] == 2: reporter.display( "\t\tTicketbleed (CVE-2016-9244): Vulnerable", issue.Issue(Vulnerabilities.TLS_TICKETBLEED, url, {"ip": ep["ipAddress"]}), ) else: output.error( f'\t\tTicketbleed (CVE-2016-9244): Unknown Response ({ep["details"]["ticketbleed"]})' ) else: output.error( "\t\tTicketbleed (CVE-2016-9244): Information Not Received") if "openSslCcs" in ep["details"]: if ep["details"]["openSslCcs"] == -1: output.error("\t\tOpenSSL CCS (CVE-2014-0224): Test Failed") elif ep["details"]["openSslCcs"] == 0: output.error( "\t\tOpenSSL CCS (CVE-2014-0224): Test Failed (Unknown)") elif ep["details"]["openSslCcs"] == 1: output.norm("\t\tOpenSSL CCS (CVE-2014-0224): No") elif ep["details"]["openSslCcs"] == 2: reporter.display( "\t\tOpenSSL CCS (CVE-2014-0224): Vulnerable - Not Exploitable", issue.Issue( Vulnerabilities.TLS_OPENSSL_CVE_2014_0224_NE, url, {"ip": ep["ipAddress"]}, ), ) elif ep["details"]["openSslCcs"] == 3: output.vuln("\t\tOpenSSL CCS (CVE-2014-0224): Vulnerable") reporter.display( "\t\tOpenSSL CCS (CVE-2014-0224): Vulnerable", issue.Issue( Vulnerabilities.TLS_OPENSSL_CVE_2014_0224, url, {"ip": ep["ipAddress"]}, ), ) else: output.error( f'\t\tOpenSSL CCS (CVE-2014-0224): Unknown Response ({ep["details"]["openSslCcs"]})' ) else: output.error( "\t\tOpenSSL CCS (CVE-2014-0224): Information Not Received") if "openSSLLuckyMinus20" in ep["details"]: if ep["details"]["openSSLLuckyMinus20"] == -1: output.error( "\t\tOpenSSL Padding Oracle (CVE-2016-2107): Test Failed") elif ep["details"]["openSSLLuckyMinus20"] == 0: output.error( "\t\tOpenSSL Padding Oracle (CVE-2016-2107): Test Failed (Unknown)" ) elif ep["details"]["openSSLLuckyMinus20"] == 1: output.norm("\t\tOpenSSL Padding Oracle (CVE-2016-2107): No") elif ep["details"]["openSSLLuckyMinus20"] == 2: reporter.display( "\t\tOpenSSL Padding Oracle (CVE-2016-2107): Vulnerable", issue.Issue( Vulnerabilities.TLS_OPENSSL_CVE_2016_2107, url, {"ip": ep["ipAddress"]}, ), ) else: output.error( f"\t\tOpenSSL Padding Oracle (CVE-2016-2107): Unknown Response " f'({ep["details"]["openSSLLuckyMinus20"]})') else: output.error( "\t\tOpenSSL Padding Oracle (CVE-2016-2107): Information Not Received" ) if "bleichenbacher" in ep["details"]: if ep["details"]["bleichenbacher"] == -1: output.error("\t\tROBOT: Test Failed") elif ep["details"]["bleichenbacher"] == 0: output.error("\t\tROBOT: Test Failed (Unknown)") elif ep["details"]["bleichenbacher"] == 1: output.norm("\t\tROBOT: No") elif ep["details"]["bleichenbacher"] == 2: reporter.display( "\t\tROBOT: Vulnerable - Not Exploitable", issue.Issue(Vulnerabilities.TLS_ROBOT_ORACLE_WEAK, url, {"ip": ep["ipAddress"]}), ) elif ep["details"]["bleichenbacher"] == 3: reporter.display( "\t\tROBOT: Vulnerable - Exploitable", issue.Issue( Vulnerabilities.TLS_ROBOT_ORACLE_STRONG, url, {"ip": ep["ipAddress"]}, ), ) elif ep["details"]["bleichenbacher"] == 4: output.norm("\t\tROBOT: Unknown - Inconsistent Results") else: output.error( f'\t\tROBOT: Unknown Response ({ep["details"]["bleichenbacher"]})' ) else: output.error("\t\tROBOT: Information Not Received") if "forwardSecrecy" in ep["details"]: if ep["details"]["forwardSecrecy"] & (1 << 2) != 0: output.norm("\t\tForward Secrecy: Yes (all simulated clients)") elif ep["details"]["forwardSecrecy"] & (1 << 1) != 0: output.info("\t\tForward Secrecy: Yes (modern clients)") elif ep["details"]["forwardSecrecy"] & 1 != 0: reporter.display( "\t\tForward Secrecy: Yes (limited support)", issue.Issue( Vulnerabilities.TLS_LIMITED_FORWARD_SECRECY, url, {"ip": ep["ipAddress"]}, ), ) else: output.vuln("\t\tForward Secrecy: No") else: output.error("\t\tForward Secrecy: Information Not Received") if "supportsAead" in ep["details"]: if ep["details"]["supportsAead"]: output.norm("\t\tAEAD Cipher Suites Supported: Yes") else: reporter.display( "\t\tAEAD Cipher Suites Supported: No", issue.Issue(Vulnerabilities.TLS_NO_AEAD_SUPPORT, url, {"ip": ep["ipAddress"]}), ) else: output.error( "\t\tAEAD Cipher Suites Supported: Information Not Received") if "supportsCBC" in ep["details"]: if ep["details"]["supportsCBC"]: output.info("\t\tCBC Cipher Suites Supported: Yes") else: output.norm("\t\tCBC Cipher Suites Supported: No") else: output.error( "\t\tCBC Cipher Suites Supported: Information Not Received") if "alpnProtocols" in ep["details"]: output.norm(f'\t\tALPN: {ep["details"]["alpnProtocols"]}') if "npnProtocols" in ep["details"]: output.norm(f'\t\tNPN: {ep["details"]["npnProtocols"]}') if "sessionResumption" in ep["details"]: if ep["details"]["sessionResumption"] == 0: output.norm("\t\tSession Resumption: Not Enabled / Empty Tickets") elif ep["details"]["sessionResumption"] == 1: output.norm("\t\tSession Resumption: Enabled / No Resumption") elif ep["details"]["sessionResumption"] == 2: reporter.display( "\t\tSession Resumption: Enabled", issue.Issue( Vulnerabilities.TLS_SESSION_RESP_ENABLED, url, {"ip": ep["ipAddress"]}, ), ) else: output.error( f'\t\tSession Resumption: Unknown Response ({ep["details"]["sessionResumption"]})' ) else: output.error("\t\tSession Resumption: Information Not Received") if "ocspStapling" in ep["details"]: if ep["details"]["ocspStapling"]: output.norm("\t\tOCSP Stapling: Yes") else: reporter.display( "\t\tOCSP Stapling: No", issue.Issue( Vulnerabilities.TLS_OCSP_STAPLE_MISSING, url, {"ip": ep["ipAddress"]}, ), ) else: output.error("\t\tOCSP Stapling: Information Not Received") if "miscIntolerance" in ep["details"]: if ep["details"]["miscIntolerance"] & 1 != 0: output.info("\t\tTLS Extension Intolerance: Yes") if ep["details"]["miscIntolerance"] & (1 << 1) != 0: output.warn("\t\tLong Handshake Intolerance: Yes") if ep["details"]["miscIntolerance"] & (1 << 2) != 0: output.warn("\t\tLong Handshake Intolerance: Workaround Success") if "protocolIntolerance" in ep["details"]: if ep["details"]["protocolIntolerance"] & 1 != 0: output.warn("\t\tProtocol Intolerance: TLS 1.0") if ep["details"]["protocolIntolerance"] & (1 << 1) != 0: output.warn("\t\tProtocol Intolerance: TLS 1.1") if ep["details"]["protocolIntolerance"] & (1 << 2) != 0: output.warn("\t\tProtocol Intolerance: TLS 1.2") if ep["details"]["protocolIntolerance"] & (1 << 3) != 0: output.warn("\t\tProtocol Intolerance: TLS 1.3") if ep["details"]["protocolIntolerance"] & (1 << 4) != 0: output.warn("\t\tProtocol Intolerance: TLS 1.152") if ep["details"]["protocolIntolerance"] & (1 << 5) != 0: output.warn("\t\tProtocol Intolerance: TLS 2.152") if "freak" in ep["details"]: if ep["details"]["freak"]: reporter.display( "\t\tFREAK: Vulnerable (512-bit key exchange supported)", issue.Issue(Vulnerabilities.TLS_FREAK, url, {"ip": ep["ipAddress"]}), ) else: output.norm("\t\tFREAK: No") else: output.error("\t\tFREAK: Information Not Received") if "logjam" in ep["details"]: if ep["details"]["logjam"]: reporter.display( "\t\tLogjam: Vulnerable", issue.Issue(Vulnerabilities.TLS_LOGJAM, url, {"ip": ep["ipAddress"]}), ) else: output.norm("\t\tLogjam: No") else: output.error("\t\tLogjam: Information Not Received") if "dhUsesKnownPrimes" in ep["details"]: if ep["details"]["dhUsesKnownPrimes"] == 0: output.norm("\t\tUses common DH primes: No") elif ep["details"]["dhUsesKnownPrimes"] == 1: output.warn("\t\tUses common DH primes: Yes (not weak)") reporter.display( "\t\tUses common DH primes: Yes (weak)", issue.Issue( Vulnerabilities.TLS_DH_KNOWN_PRIMES_STRONG, url, {"ip": ep["ipAddress"]}, ), ) elif ep["details"]["dhUsesKnownPrimes"] == 2: reporter.display( "\t\tUses common DH primes: Yes (weak)", issue.Issue( Vulnerabilities.TLS_DH_KNOWN_PRIMES_WEAK, url, {"ip": ep["ipAddress"]}, ), ) else: output.error( f'\t\tUses common DH primes: Unknown Response ({ep["details"]["dhUsesKnownPrimes"]})' ) if "dhYsReuse" in ep["details"]: if ep["details"]["dhYsReuse"]: reporter.display( "\t\tDH public server param (Ys) reuse: Yes", issue.Issue(Vulnerabilities.TLS_DH_PARAM_REUSE, url, {"ip": ep["ipAddress"]}), ) else: output.norm("\t\tDH public server param (Ys) reuse: No") if "ecdhParameterReuse" in ep["details"]: if ep["details"]["ecdhParameterReuse"]: reporter.display( "\t\tECDH Public Server Param Reuse: Yes", issue.Issue(Vulnerabilities.TLS_ECDH_PARAM_REUSE, url, {"ip": ep["ipAddress"]}), ) else: output.norm("\t\tECDH Public Server Param Reuse: No") output.empty()
def _get_protocol_info(ep, url): output.norm("Configuration Information:") output.norm("\tProtocol Support:") # check protocols protos = {} tls13_enabled = False for proto in ep["details"]["protocols"]: if proto["name"] == "SSL": # show a vuln for SSLvX reporter.display( f'\t\t{proto["name"]} {proto["version"]}', issue.Issue(Vulnerabilities.TLS_LEGACY_SSL_ENABLED, url, {"ip": ep["ipAddress"]}), ) elif proto["name"] == "TLS" and proto["version"] == "1.0": # show a warn for TLSv1.0 reporter.display( f'\t\t{proto["name"]} {proto["version"]}', issue.Issue( Vulnerabilities.TLS_VERSION_1_0_ENABLED, url, {"ip": ep["ipAddress"]}, ), ) elif proto["name"] == "TLS" and proto["version"] == "1.3": # capture TLS 1.3 status tls13_enabled = True output.norm(f'\t\t{proto["name"]} {proto["version"]}') else: output.norm(f'\t\t{proto["name"]} {proto["version"]}') protos[proto["id"]] = f'{proto["name"]} {proto["version"]}' if not tls13_enabled: reporter.display( "\t\tTLS 1.3 Is Not Enabled", issue.Issue( Vulnerabilities.TLS_VERSION_1_3_NOT_ENABLED, url, {"ip": ep["ipAddress"]}, ), ) output.empty() if "namedGroups" in ep["details"]: output.norm("\tNamed Group Support:") for group in ep["details"]["namedGroups"]["list"]: output.norm(f'\t\t{group["name"]} {group["bits"]}') output.empty() if "suites" in ep["details"]: output.norm("\tCipher Suite Support:") for proto_suites in ep["details"]["suites"]: output.norm(f'\t\t{protos[proto_suites["protocol"]]}') for suite in proto_suites["list"]: ke = _get_key_exchange(suite) strength = suite["cipherStrength"] if "3DES" in suite["name"]: # in this case, the effective strength is only 112 bits, # which is what we want to report. So override SSL Labs strength = 112 if ke is not None: suite_info = f'{suite["name"].ljust(50)} - {strength}-bits - {ke}' else: suite_info = f'{suite["name"].ljust(50)} - {strength}-bits' if _is_cipher_suite_secure(suite): if "CBC" in suite["name"]: output.info(f"\t\t {suite_info}") reporter.register( issue.Issue( Vulnerabilities.TLS_CBC_CIPHER_SUITE, url, {"cipher": suite_info}, )) else: output.norm(f"\t\t {suite_info}") else: output.vuln(f"\t\t {suite_info}") reporter.register( issue.Issue( Vulnerabilities.TLS_INSECURE_CIPHER_SUITE, url, {"cipher": suite_info}, )) output.empty() _get_simulations(ep, protos)
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()