Exemplo n.º 1
0
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()
Exemplo n.º 2
0
def check_local_ip_disclosure(session: Session) -> List[Result]:
    def _send_http_10_get(
        con: Union[SslConnection, socket.socket]
    ) -> Tuple[str, HTTPResponse]:
        req = (
            "HEAD / HTTP/1.0\r\n"
            "User-Agent: {user_agent}\r\n"
            "Accept: */*\r\n\r\n".format(user_agent=network.YAWAST_UA)
        )

        if type(con) is SslConnection:
            con.ssl_client.write(req.encode("utf_8"))

            res = http_response_parser.HttpResponseParser.parse_from_ssl_connection(
                con.ssl_client
            )
        else:
            con.sendall(req.encode("utf_8"))

            res = http_response_parser.HttpResponseParser.parse_from_socket(con)

        return req, res

    def _resp_to_str(res: HTTPResponse) -> str:
        ver = "1.1" if res.version == 11 else "1.0"
        body = f"HTTP/{ver} {res.code} {res.reason}\r\n"
        for k, val in res.headers.items():
            body += f"{k}: {val}\r\n"

        return body

    def _get_ip(res: HTTPResponse) -> Union[str, None]:
        loc = res.getheader("Location")
        if loc is not None:
            # it's a redirect, check to see if there's an IP in it
            parsed = urlparse(loc)
            domain = utils.get_domain(parsed.netloc)

            if utils.is_ip(domain):
                # it's an IP, now, is it private?
                if utils.is_private_ip(domain):
                    return domain
                else:
                    return None

        return None

    def _get_result(client, prt):
        req, resp = _send_http_10_get(client)
        ip = _get_ip(resp)

        if ip is not None:
            results.append(
                Result(
                    f"Private IP Found: {ip} via HTTP 1.0 Redirect",
                    Vln.SERVER_INT_IP_EXP_HTTP10,
                    session.url,
                    {
                        "request": req,
                        "response": _resp_to_str(resp),
                        "ip": {ip},
                        "port": prt,
                    },
                )
            )

    results: List[Result] = []

    if session.url_parsed.scheme == "https":
        conn_tester = server_connectivity_tester.ServerConnectivityTester(
            hostname=session.domain, port=utils.get_port(session.url)
        )

        server_info = conn_tester.perform()

        conn = ssl_connection_configurator.SslConnectionConfigurator.get_connection(
            ssl_version=OpenSslVersionEnum.SSLV23,
            server_info=server_info,
            should_ignore_client_auth=True,
            ssl_verify_locations=None,
            should_use_legacy_openssl=False,
        )

        try:
            conn.connect()

            _get_result(conn, utils.get_port(session.url))
        except Exception:
            output.debug_exception()

    if session.supports_http:
        url = session.get_http_url()
        port = utils.get_port(url)
        conn = socket.socket()
        conn.connect((utils.get_domain(url), port))

        try:
            _get_result(conn, port)
        except Exception:
            output.debug_exception()

    return results
Exemplo n.º 3
0
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()