예제 #1
0
    def _check_vulnerabilities(self):
        errors = []

        result = self._scan(
            HeartbleedScanCommand())  # type: HeartbleedScanResult

        if result.is_vulnerable_to_heartbleed:
            errors.append(f"Server is vulnerable to Heartbleed attack")

        result = self._scan(OpenSslCcsInjectionScanCommand()
                            )  # type: OpenSslCcsInjectionScanResult

        if result.is_vulnerable_to_ccs_injection:
            errors.append(
                f"Server is vulnerable to OpenSSL CCS Injection (CVE-2014-0224)"
            )

        result = self._scan(RobotScanCommand())  # type: RobotScanResult

        if result.robot_result_enum in [
                RobotScanResultEnum.VULNERABLE_WEAK_ORACLE,
                RobotScanResultEnum.VULNERABLE_STRONG_ORACLE,
        ]:
            errors.append(f"Server is vulnerable to ROBOT attack.")

        return errors
예제 #2
0
    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 = HeartbleedPlugin()
                plugin_result = plugin.process_task(server_info,
                                                    HeartbleedScanCommand())

        except NotOnLinux64Error:
            logging.warning('WARNING: Not on Linux - skipping test')
            return

        self.assertTrue(plugin_result.is_vulnerable_to_heartbleed)
        self.assertTrue(plugin_result.as_text())
        self.assertTrue(plugin_result.as_xml())
예제 #3
0
 def run_heartbleed_command(self, server_info, synchronous_scanner):
     command = HeartbleedScanCommand()
     try:
         scan_result = synchronous_scanner.run_scan_command(
             server_info, command)
         #print('heartbleed obtained for ',server_info)
         return scan_result.is_vulnerable_to_heartbleed
     except:
         #print('heartbleed obtained for ',server_info)
         return None
    def test_heartbleed_good(self):
        server_info = ServerConnectivityInfo(hostname=u'www.google.com')
        server_info.test_connectivity_to_server()

        plugin = HeartbleedPlugin()
        plugin_result = plugin.process_task(server_info,
                                            HeartbleedScanCommand())

        self.assertFalse(plugin_result.is_vulnerable_to_heartbleed)

        self.assertTrue(plugin_result.as_text())
        self.assertTrue(plugin_result.as_xml())
예제 #5
0
def retrieve_ssl_vulnerabilities_for_tcp_service(
        self,
        org_uuid=None,
        service_uuid=None,
        scan_uuid=None,
):
    """
    This performs various SSL vulnerability scans on the tcp service
    :param org_uuid: The UUID of the organization to collect information on behalf of.
    :param service_uuid: The UUID of the network service to retrieve the SSL certificate for.
    :param scan_uuid: The UUID of the network service scan that this SSL certificate retrieval is associated
    with.
    :return: None
    """
    ip_address, port, protocol = self.get_endpoint_information(service_uuid)
    ssl_vulnerabilities_record = SslVulnerabilitiesModel.from_database_model_uuid(
        uuid=scan_uuid,
        db_session=self.db_session
    )
    server_info = ServerConnectivityInfo(hostname=ip_address, ip_address=ip_address, port=port)
    try:
        server_info.test_connectivity_to_server()
    except ServerConnectivityError as e:
        # Could not establish an SSL connection to the server
        logger.error(
            "Error making an SSL connection to the server while looking for vulnerabilities, something went really wrong."
        )
    synchronous_scanner = SynchronousScanner()

    fallback_scsv_command = FallbackScsvScanCommand()
    fallback_scsv_result = synchronous_scanner.run_scan_command(server_info, fallback_scsv_command)
    ssl_vulnerabilities_record.supports_fallback_scsv = fallback_scsv_result.supports_fallback_scsv

    heartbleed_command = HeartbleedScanCommand()
    heartbleed_result = synchronous_scanner.run_scan_command(server_info, heartbleed_command)
    ssl_vulnerabilities_record.is_vulnerable_to_heartbleed = heartbleed_result.is_vulnerable_to_heartbleed

    openssl_css_injection_command = OpenSslCcsInjectionScanCommand()
    openssl_css_injection_result = synchronous_scanner.run_scan_command(server_info, openssl_css_injection_command)
    ssl_vulnerabilities_record.is_vulnerable_to_ccs_injection = openssl_css_injection_result.is_vulnerable_to_ccs_injection

    session_renegotion_command = SessionRenegotiationScanCommand()
    session_renegotion_result = synchronous_scanner.run_scan_command(server_info, session_renegotion_command)
    ssl_vulnerabilities_record.accepts_client_renegotiation = session_renegotion_result.accepts_client_renegotiation
    ssl_vulnerabilities_record.supports_secure_renegotiation = session_renegotion_result.supports_secure_renegotiation

    session_resumption_support_command = SessionResumptionSupportScanCommand()
    session_resumption_support_result = synchronous_scanner.run_scan_command(server_info, session_resumption_support_command)
    ssl_vulnerabilities_record.is_ticket_resumption_supported = session_resumption_support_result.is_ticket_resumption_supported

    ssl_vulnerabilities_record.save(org_uuid)
예제 #6
0
    def test_heartbleed_good(self):
        server_test = ServerConnectivityTester(hostname='www.google.com')
        server_info = server_test.perform()

        plugin = HeartbleedPlugin()
        plugin_result = plugin.process_task(server_info, HeartbleedScanCommand())

        self.assertFalse(plugin_result.is_vulnerable_to_heartbleed)

        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))
예제 #7
0
    def test_heartbleed_bad(self):
        with VulnerableOpenSslServer() as server:
            server_test = ServerConnectivityTester(hostname=server.hostname, ip_address=server.ip_address,
                                                 port=server.port)
            server_info = server_test.perform()

            plugin = HeartbleedPlugin()
            plugin_result = plugin.process_task(server_info, HeartbleedScanCommand())

        self.assertTrue(plugin_result.is_vulnerable_to_heartbleed)
        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))
예제 #8
0
    def ssl_scan(self):
        print("Running SSL Scan")
        try:
            server_info = ServerConnectivityInfo(
                hostname=self.options["TARGET"])
            server_info.test_connectivity_to_server()
            synchronous_scanner = SynchronousScanner()

            # TLS 1.0
            command = Tlsv10ScanCommand()
            scan_result = synchronous_scanner.run_scan_command(
                server_info, command)
            print("Available TLSv1.0 Ciphers:")
            for cipher in scan_result.accepted_cipher_list:
                print('    {}'.format(cipher.name))

            # TLSv1.2
            command = Tlsv12ScanCommand()
            scan_result = synchronous_scanner.run_scan_command(
                server_info, command)
            print("Available TLSv1.2 Ciphers:")
            for cipher in scan_result.accepted_cipher_list:
                print('    {}'.format(cipher.name))

            # Certificate information
            command = CertificateInfoScanCommand()
            scan_result = synchronous_scanner.run_scan_command(
                server_info, command)
            for entry in scan_result.as_text():
                print(entry)

            # Heartbleed vulnerability info
            command = HeartbleedScanCommand()
            scan_result = synchronous_scanner.run_scan_command(
                server_info, command)
            for entry in scan_result.as_text():
                print(entry)

            # HTTP Headers info
            command = HttpHeadersScanCommand()
            scan_result = synchronous_scanner.run_scan_command(
                server_info, command)
            for entry in scan_result.as_text():
                print(entry)

        except Exception as e:
            self.handle_exception(e, "Error running SSL scan")
            pass
예제 #9
0
    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 = HeartbleedPlugin()
            plugin_result = plugin.process_task(server_info,
                                                HeartbleedScanCommand())

        assert plugin_result.is_vulnerable_to_heartbleed
        assert plugin_result.as_text()
        assert plugin_result.as_xml()
예제 #10
0
    def test_heartbleed_bad(self):
        try:
            with VulnerableOpenSslServer() as server:
                server_info = ServerConnectivityInfo(hostname=server.hostname, ip_address=server.ip_address,
                                                     port=server.port)
                server_info.test_connectivity_to_server()

                plugin = HeartbleedPlugin()
                plugin_result = plugin.process_task(server_info, HeartbleedScanCommand())
        except NotOnLinux64Error:
            # The test suite only has the vulnerable OpenSSL version compiled for Linux 64 bits
            logging.warning('WARNING: Not on Linux - skipping test_heartbleed_bad() test')
            return

        self.assertTrue(plugin_result.is_vulnerable_to_heartbleed)
        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))
예제 #11
0
    def test_heartbleed_bad(self):
        try:
            server = VulnerableOpenSslServer(port=8011)
        except NotOnLinux64Error:
            # The test suite only has the vulnerable OpenSSL version compiled for Linux 64 bits
            logging.warning(
                'WARNING: Not on Linux - skipping test_heartbleed_bad() test')
            return

        server.start()
        server_info = ServerConnectivityInfo(hostname=server.hostname,
                                             ip_address=server.ip_address,
                                             port=server.port)
        server_info.test_connectivity_to_server()

        plugin = HeartbleedPlugin()
        plugin_result = plugin.process_task(server_info,
                                            HeartbleedScanCommand())
        server.terminate()

        self.assertTrue(plugin_result.is_vulnerable_to_heartbleed)
        self.assertTrue(plugin_result.as_text())
        self.assertTrue(plugin_result.as_xml())
예제 #12
0
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!")
예제 #13
0
 def __init__(self):
     super().__init__(HeartbleedScanCommand())
예제 #14
0
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)
예제 #15
0
def run(url):
    scan_result = {
        "name": __plugin__,
        "sequence": SEQUENCE,
        "result": [],
    }
    error_result = {
        "name": __plugin__,
        "sequence": SEQUENCE,
        "result": [],
    }
    error_result["result"] = [{
        "name":
        "Error",
        "result": [{
            "name": f"{__plugin__} can't scan this website"
        }]
    }]
    result_map = {
        "https": {
            "name": "Enabled HTTPS",
            "sequence": 0,
            "result": False
        },
        "effective": {
            "name": "Effective",
            "sequence": 1,
            "result": False
        },
        "match": {
            "name": "Leaf certificate subject matches hostname",
            "sequence": 2,
            "result": False
        },
        "signature": {
            "name": "Signature security (use SHA256)",
            "sequence": 3,
            "result": False
        },
        "public": {
            "name": "Public key security (use ECDSA_256+ or RSA_2048+)",
            "sequence": 4,
            "result": False,
        },
        "tls1_2": {
            "name": "Support TLS1.2",
            "sequence": 5,
            "result": False
        },
        "pfs": {
            "name": "Perfect Forward Secrecy (PFS)",
            "sequence": 6,
            "result": False
        },
        "ats": {
            "name": "App Transport Security (ATS)",
            "sequence": 7,
            "result": False
        },
        "ccs": {
            "name": "CCS Injection",
            "sequence": 8,
            "result": False
        },
        "heartbleed": {
            "name": "HeartBleed",
            "sequence": 9,
            "result": False
        },
    }
    mini_length = 256
    start_time = None
    end_time = None

    try:
        server_tester = ServerConnectivityTester(hostname=url.netloc,
                                                 port=url.port)
        server_info = server_tester.perform()
    except:
        return error_result

    synchronous_scanner = SynchronousScanner()
    certificate_result = synchronous_scanner.run_scan_command(
        server_info, CertificateInfoScanCommand())
    cipher_result = synchronous_scanner.run_scan_command(
        server_info, Tlsv12ScanCommand())
    ccs_result = synchronous_scanner.run_scan_command(
        server_info, OpenSslCcsInjectionScanCommand())
    heartbleed_result = synchronous_scanner.run_scan_command(
        server_info, HeartbleedScanCommand())

    if certificate_result.leaf_certificate_subject_matches_hostname:
        result_map["match"]["result"] = True

    for result in certificate_result.as_text():
        result_list = [x.strip() for x in result.split(": ")]
        if len(result_list) == 2:
            result_map["https"]["result"] = True
            if result_list[0] == "Public Key Algorithm":
                if result_list[1] == "_RSAPublicKey":
                    mini_length = 2048
            if result_list[0] == "Key Size":
                if int(result_list[1]) >= mini_length:
                    result_map["public"]["result"] = True
            if result_list[0] == "Signature Algorithm":
                if result_list[1] == "sha256":
                    result_map["signature"]["result"] = True
            if result_list[0] == "Not Before":
                start_time = result_list[1]
            if result_list[0] == "Not After":
                end_time = result_list[1]

    if start_time and end_time:
        if (datetime.strptime(start_time, "%Y-%m-%d %H:%M:%S") <
                datetime.now() and datetime.strptime(
                    end_time, "%Y-%m-%d %H:%M:%S") > datetime.now()):
            result_map["effective"]["result"] = True
    cipher_list = [
        cipher.name for cipher in cipher_result.accepted_cipher_list
    ]
    if cipher_list:
        result_map["tls1_2"]["result"] = True
        for cipher in cipher_list:
            if "DHE" in cipher:
                result_map["pfs"]["result"] = True
        if set(cipher_list).intersection(ATS_CIPHER_SET):
            result_map["ats"]["result"] = True
    if not ccs_result.is_vulnerable_to_ccs_injection:
        result_map["ccs"]["result"] = True
    if not heartbleed_result.is_vulnerable_to_heartbleed:
        result_map["heartbleed"]["result"] = True

    scan_result["result"] = sorted([item for item in result_map.values()],
                                   key=lambda x: x.get("sequence", 0))

    return scan_result
예제 #16
0
 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)
예제 #17
0
    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))