Exemple #1
0
def scan_serial(scanner, server_info, data, options):

    logging.debug("\tRunning scans in serial.")
    logging.debug("\t\tSSLv2 scan.")
    sslv2 = scanner.run_scan_command(server_info, Sslv20ScanCommand())
    logging.debug("\t\tSSLv3 scan.")
    sslv3 = scanner.run_scan_command(server_info, Sslv30ScanCommand())
    logging.debug("\t\tTLSv1.0 scan.")
    tlsv1 = scanner.run_scan_command(server_info, Tlsv10ScanCommand())
    logging.debug("\t\tTLSv1.1 scan.")
    tlsv1_1 = scanner.run_scan_command(server_info, Tlsv11ScanCommand())
    logging.debug("\t\tTLSv1.2 scan.")
    tlsv1_2 = scanner.run_scan_command(server_info, Tlsv12ScanCommand())
    logging.debug("\t\tTLSv1.3 scan.")
    tlsv1_3 = scanner.run_scan_command(server_info, Tlsv13ScanCommand())

    certs = None
    if options.get("sslyze_certs", True) is True:

        try:
            logging.debug("\t\tCertificate information scan.")
            certs = scanner.run_scan_command(server_info,
                                             CertificateInfoScanCommand())
        # Let generic exceptions bubble up.
        except idna.core.InvalidCodepoint:
            logging.warn(utils.format_last_exception())
            data['errors'].append("Invalid certificate/OCSP for this domain.")
            certs = None
    else:
        certs = None

    logging.debug("\tDone scanning.")

    return sslv2, sslv3, tlsv1, tlsv1_1, tlsv1_2, tlsv1_3, certs
Exemple #2
0
    def test_sslv2_enabled(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 = OpenSslCipherSuitesPlugin()
                plugin_result = plugin.process_task(server_info, Sslv20ScanCommand())
        except NotOnLinux64Error:
            # The test suite only has the vulnerable OpenSSL version compiled for Linux 64 bits
            logging.warning('WARNING: Not on Linux - skipping test_sslv2_enabled() test')
            return

        # The embedded server does not have a preference
        self.assertFalse(plugin_result.preferred_cipher)

        accepted_cipher_name_list = [cipher.name for cipher in plugin_result.accepted_cipher_list]
        self.assertEqual({'SSL_CK_RC4_128_EXPORT40_WITH_MD5', 'SSL_CK_IDEA_128_CBC_WITH_MD5',
                          'SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5', 'SSL_CK_DES_192_EDE3_CBC_WITH_MD5',
                          'SSL_CK_DES_192_EDE3_CBC_WITH_MD5', 'SSL_CK_RC4_128_WITH_MD5',
                          'SSL_CK_RC2_128_CBC_WITH_MD5', 'SSL_CK_DES_64_CBC_WITH_MD5'},
                         set(accepted_cipher_name_list))

        self.assertTrue(plugin_result.accepted_cipher_list)
        self.assertFalse(plugin_result.rejected_cipher_list)
        self.assertFalse(plugin_result.errored_cipher_list)

        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))
Exemple #3
0
    def __init__(self, host, port, proxy=None):
        """
        :param proxy: (dict) Default: None; Set this one up if you wish to use
                a proxy to hit your target host. E.g.:
                {
                    "server":"someproxy.com",
                    "port":6000,
                    "user":"******",
                    "pass":"******"
                }
        """
        self.host = host
        self.port = port
        self.policies = {
            "ssl2.0": {
                "allowed": False,
                "command": Sslv20ScanCommand()
            },
            "ssl3.0": {
                "allowed": False,
                "command": Sslv30ScanCommand()
            },
            "tls1.0": {
                "allowed": False,
                "command": Tlsv10ScanCommand()
            },
            "tls1.1": {
                "allowed": False,
                "command": Tlsv11ScanCommand()
            },
            "tls1.2": {
                "allowed": True,
                "command": Tlsv12ScanCommand()
            },
            "tls1.3": {
                "allowed": True,
                "command": Tlsv13ScanCommand()
            },
        }

        if not isinstance(host, str) or not isinstance(port, int):
            raise TypeError('EncryptionCheck class not properly initialized.')

        # Proxy setup
        if proxy is not None:
            if not ("server" in proxy and "port" in proxy):
                raise ValueError('Invalid proxy settings detected.')
            proxy_server = proxy['server']
            proxy_port = proxy['port']
            proxy_user = proxy.get('user', None)
            proxy_pass = proxy.get('pass', None)
            tunnel_settings = HttpConnectTunnelingSettings(
                proxy_server,
                proxy_port,
                basic_auth_user=proxy_user,
                basic_auth_password=proxy_pass)
        else:
            tunnel_settings = None
        self.tunnel = tunnel_settings
        self.proxy = proxy
Exemple #4
0
    def test_sslv2_enabled(self):
        with LegacyOpenSslServer() as server:
            server_test = ServerConnectivityTester(
                hostname=server.hostname,
                ip_address=server.ip_address,
                port=server.port)
            server_info = server_test.perform()

            plugin = OpenSslCipherSuitesPlugin()
            plugin_result = plugin.process_task(server_info,
                                                Sslv20ScanCommand())

        # The embedded server does not have a preference
        assert not plugin_result.preferred_cipher

        accepted_cipher_name_list = [
            cipher.name for cipher in plugin_result.accepted_cipher_list
        ]
        assert {
            'SSL_CK_RC4_128_EXPORT40_WITH_MD5', 'SSL_CK_IDEA_128_CBC_WITH_MD5',
            'SSL_CK_RC2_128_CBC_EXPORT40_WITH_MD5',
            'SSL_CK_DES_192_EDE3_CBC_WITH_MD5',
            'SSL_CK_DES_192_EDE3_CBC_WITH_MD5', 'SSL_CK_RC4_128_WITH_MD5',
            'SSL_CK_RC2_128_CBC_WITH_MD5', 'SSL_CK_DES_64_CBC_WITH_MD5'
        } == set(accepted_cipher_name_list)

        assert plugin_result.accepted_cipher_list
        assert not plugin_result.rejected_cipher_list
        assert not plugin_result.errored_cipher_list

        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)
Exemple #5
0
def scan_serial(scanner, server_info, data, options):
    errors = 0

    def run_scan(scan_type, command, errors):
        if (errors >= 2):
            return None, errors
        logging.debug("\t\t{} scan.".format(scan_type))
        result = None
        try:
            result = scanner.run_scan_command(server_info, command)
        except Exception as err:
            logging.warning("{}: Error during {} scan.".format(
                server_info.hostname, scan_type))
            logging.debug("{}: Exception during {} scan: {}".format(
                server_info.hostname, scan_type, err))
            errors = errors + 1
        return result, errors

    logging.debug("\tRunning scans in serial.")
    sslv2, errors = run_scan("SSLv2", Sslv20ScanCommand(), errors)
    sslv3, errors = run_scan("SSLv3", Sslv30ScanCommand(), errors)
    tlsv1, errors = run_scan("TLSv1.0", Tlsv10ScanCommand(), errors)
    tlsv1_1, errors = run_scan("TLSv1.1", Tlsv11ScanCommand(), errors)
    tlsv1_2, errors = run_scan("TLSv1.2", Tlsv12ScanCommand(), errors)
    tlsv1_3, errors = run_scan("TLSv1.3", Tlsv13ScanCommand(), errors)

    certs = None
    if errors < 2 and options.get("sslyze_certs", True) is True:
        try:
            logging.debug("\t\tCertificate information scan.")
            certs = scanner.run_scan_command(
                server_info, CertificateInfoScanCommand(ca_file=CA_FILE))
        except idna.core.InvalidCodepoint:
            logging.warning(utils.format_last_exception())
            data['errors'].append("Invalid certificate/OCSP for this domain.")
            certs = None
        except Exception as err:
            logging.warning(
                "{}: Error during certificate information scan.".format(
                    server_info.hostname))
            logging.debug(
                "{}: Exception during certificate information scan: {}".format(
                    server_info.hostname, err))
    else:
        certs = None

    reneg = None
    if options.get("sslyze_reneg", True) is True:
        reneg, errors = run_scan("Renegotiation",
                                 SessionRenegotiationScanCommand(), errors)
    else:
        reneg = None

    logging.debug("\tDone scanning.")

    return sslv2, sslv3, tlsv1, tlsv1_1, tlsv1_2, tlsv1_3, certs, reneg
    def test_sslv2_disabled(self):
        server_info = ServerConnectivityInfo(hostname=u'www.google.com')
        server_info.test_connectivity_to_server()

        plugin = OpenSslCipherSuitesPlugin()
        plugin_result = plugin.process_task(server_info, Sslv20ScanCommand())

        self.assertIsNone(plugin_result.preferred_cipher)
        self.assertFalse(plugin_result.accepted_cipher_list)
        self.assertTrue(plugin_result.rejected_cipher_list)
        self.assertFalse(plugin_result.errored_cipher_list)

        self.assertTrue(plugin_result.as_text())
        self.assertTrue(plugin_result.as_xml())
Exemple #7
0
def check_tcp_service_for_ssl_protocol_cipher_support(
        self,
        org_uuid=None,
        service_uuid=None,
        ssl_protocol=None,
        scan_uuid=None
):
    """
    Check to see what ciphers this TCP service supports for the given SSL protocol.
    :param org_uuid: The UUID of the organization to collect information on behalf of.
    :param service_uuid: The UUID of the network service to check for SSL support.
    :param ssl_protocol: The SSL protocol to check
    :param scan_uuid: The UUID of the network service scan that this SSL version check is associated
    with.
    :return: None
    """
    ip_address, port, protocol = self.get_endpoint_information(service_uuid)
    server_info = ServerConnectivityInfo(hostname=ip_address, ip_address=ip_address, port=port)
    synchronous_scanner = SynchronousScanner()
    command = None
    if ssl_protocol == 'PROTOCOL_TLSv1' or ssl_protocol == 'PROTOCOL_TLS':
        command = Tlsv10ScanCommand()
    elif ssl_protocol == 'PROTOCOL_TLSv1_1':
        command = Tlsv11ScanCommand()
    elif ssl_protocol == 'PROTOCOL_TLSv1_2':
        command = Tlsv12ScanCommand()
    elif ssl_protocol == 'PROTOCOL_SSLv23':
        command = Sslv20ScanCommand()
    elif ssl_protocol == 'PROTOCOL_SSLv3':
        command = Sslv30ScanCommand()
    else:
        raise ValueError(
            "Not sure how to run scan command for SSL protocol of %s."
            % (ssl_protocol,)
        )
    cipher_scan_result = synchronous_scanner.run_scan_command(server_info, command)
    ssl_support_record = SslSupportModel.from_database_model_uuid(
        uuid=scan_uuid,
        db_session=self.db_session,
        ssl_version=ssl_protocol,
        supported=True,
    )
    ssl_support_record.accepted_ciphers = [ cipher.name for cipher in cipher_scan_result.accepted_cipher_list ]
    ssl_support_record.rejected_ciphers = [ cipher.name for cipher in cipher_scan_result.rejected_cipher_list ]
    ssl_support_record.errored_ciphers = [ cipher.name for cipher in cipher_scan_result.errored_cipher_list ]
    if cipher_scan_result.preferred_cipher is not None:
        ssl_support_record.preferred_cipher = cipher_scan_result.preferred_cipher.name
    else:
        ssl_support_record.preferred_cipher = None
    ssl_support_record.save(org_uuid)
Exemple #8
0
def concurrent_scan(site_info):
    # Setup the server to scan and ensure it is online/reachable
    server_info = server_connectivity_tester(site_info.name)

    if server_info:
        synchronous_scanner = SynchronousScanner()

        cert_info_plugin = CertificateInfoPlugin()
        plugin_result = cert_info_plugin.process_task(
            server_info, CertificateInfoScanCommand())
        #not plugin_result.verified_certificate_chain or
        #not plugin_result.leaf_certificate_subject_matches_hostname some sites' certs CN is with "www." so the result here is false
        if plugin_result.verified_certificate_chain and site_info.name not in str(
                plugin_result.verified_certificate_chain[0].subject):
            site_info.cert_trusted = "False"
            print("not trusted: " + site_info.name)
            print(plugin_result.__dict__)
        # elif not plugin_result.verified_certificate_chain:
        #     site_info.cert_trusted = "False"
        #     print("not trusted: " + site_info.name)
        #     print(plugin_result.__dict__)
        else:
            site_info.cert_trusted = "True"
            scan_result1 = synchronous_scanner.run_scan_command(
                server_info, Sslv20ScanCommand())
            if len(scan_result1.accepted_cipher_list) > 0:
                site_info.sslv2 = "True"
            scan_result2 = synchronous_scanner.run_scan_command(
                server_info, Sslv30ScanCommand())
            if len(scan_result2.accepted_cipher_list) > 0:
                site_info.sslv3 = "True"
            scan_result3 = synchronous_scanner.run_scan_command(
                server_info, Tlsv10ScanCommand())
            if len(scan_result3.accepted_cipher_list) > 0:
                site_info.tlsv1 = "True"
            scan_result4 = synchronous_scanner.run_scan_command(
                server_info, Tlsv11ScanCommand())
            if len(scan_result4.accepted_cipher_list) > 0:
                site_info.tlsv11 = "True"
            scan_result5 = synchronous_scanner.run_scan_command(
                server_info, Tlsv12ScanCommand())
            if len(scan_result5.accepted_cipher_list) > 0:
                site_info.tlsv12 = "True"
            scan_result6 = synchronous_scanner.run_scan_command(
                server_info, Tlsv13ScanCommand())
            if len(scan_result6.accepted_cipher_list) > 0:
                site_info.tlsv13 = "True"

            recheck_cert(site_info)
Exemple #9
0
    def test_sslv2_disabled(self):
        server_info = ServerConnectivityInfo(hostname='www.google.com')
        server_info.test_connectivity_to_server()

        plugin = OpenSslCipherSuitesPlugin()
        plugin_result = plugin.process_task(server_info, Sslv20ScanCommand())

        self.assertIsNone(plugin_result.preferred_cipher)
        self.assertFalse(plugin_result.accepted_cipher_list)
        self.assertTrue(plugin_result.rejected_cipher_list)
        self.assertFalse(plugin_result.errored_cipher_list)

        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))
Exemple #10
0
    def test_sslv2_disabled(self):
        server_test = ServerConnectivityTester(hostname='www.google.com')
        server_info = server_test.perform()

        plugin = OpenSslCipherSuitesPlugin()
        plugin_result = plugin.process_task(server_info, Sslv20ScanCommand())

        assert plugin_result.preferred_cipher is None
        assert not plugin_result.accepted_cipher_list
        assert plugin_result.rejected_cipher_list
        assert not plugin_result.errored_cipher_list

        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)
Exemple #11
0
 def run_cipher_suite_commands(self, server_info, synchronous_scanner):
     cipher_scan_results = {}
     commands = [
         Sslv20ScanCommand(),
         Sslv30ScanCommand(),
         Tlsv10ScanCommand(),
         Tlsv11ScanCommand(),
         Tlsv12ScanCommand(),
         Tlsv13ScanCommand()
     ]
     for command in commands:
         scan_result = synchronous_scanner.run_scan_command(
             server_info, command)
         ciphers = []
         for cipher in scan_result.accepted_cipher_list:
             ciphers.append({
                 "name": cipher.name,
                 "key_size": cipher.key_size,
                 "is_anonymous": cipher.is_anonymous
             })
         cipher_scan_results[scan_result.scan_command.get_title()] = ciphers
     #print('ciphers obtained for ',server_info)
     return cipher_scan_results
Exemple #12
0
from sslyze.server_connectivity_tester import ServerConnectivityTester, \
    ServerConnectivityError, ConnectionToServerTimedOut
from sslyze.ssl_settings import TlsWrappedProtocolEnum
from sslyze.plugins.openssl_cipher_suites_plugin import Sslv20ScanCommand, \
    Sslv30ScanCommand, Tlsv10ScanCommand, Tlsv11ScanCommand, \
    Tlsv12ScanCommand, Tlsv13ScanCommand
from sslyze.synchronous_scanner import SynchronousScanner

from . import results
from .errors import ConnectionError

# Policy prohibits the use of SSL 2.0/3.0 and TLS 1.0
ciphersuites = {
    "policy": [
        Sslv20ScanCommand(),
        Sslv30ScanCommand(),
        Tlsv10ScanCommand(),
        Tlsv11ScanCommand()
    ],
    "full": [
        Sslv20ScanCommand(),
        Sslv30ScanCommand(),
        Tlsv10ScanCommand(),
        Tlsv11ScanCommand(),
        Tlsv12ScanCommand(),
        Tlsv13ScanCommand()
    ]
}

# sslyze config
Exemple #13
0
def test_endpoint_for_tls_settings(httpEndpoint):

    # Setup the server to scan and ensure it is online/reachable
    hostname = httpEndpoint.get_endpoint_url()
    try:
        server_info = ServerConnectivityInfo(hostname=hostname)
        server_info.test_connectivity_to_server()
    except ServerConnectivityError as e:
        # Could not establish an SSL connection to the server
        raise RuntimeError('Error when connecting to {}: {}'.format(
            hostname, e.error_msg))

    # Run one scan command synchronously to list the server's SSL 2.0 cipher suites
    print(u'\nRunning one scan command synchronously...')
    synchronous_scanner = SynchronousScanner()
    command = Sslv20ScanCommand()
    scan_result = synchronous_scanner.run_scan_command(server_info, command)
    print('All the TLS 1.0 Ciphers: \n')
    print('\n Accepted Cipher List: \n')
    accepted_cipher_suite_list = []
    for cipher in scan_result.accepted_cipher_list:
        print(u'    {}'.format(cipher.name))
        accepted_cipher_suite_list.append(cipher.name)

    if len(scan_result.accepted_cipher_list) > 0:
        httpEndpoint.set_ssl_two_zero_enbled(True)
        httpEndpoint.set_ssl_two_zero_supported_cipher_list(
            accepted_cipher_suite_list)
    else:
        httpEndpoint.set_ssl_two_zero_enbled(False)
    #if scan_result.preferred_cipher is not None:
    #    print('\n Preffered Cipher =: \n')
    #    print(u'    {}'.format(scan_result.preferred_cipher.name))

    # Run one scan command synchronously to list the server's SSL 3.0 cipher suites
    print(u'\nRunning one scan command synchronously...')
    synchronous_scanner = SynchronousScanner()
    command = Sslv30ScanCommand()
    scan_result = synchronous_scanner.run_scan_command(server_info, command)
    print('All the TLS 1.0 Ciphers: \n')
    print('\n Accepted Cipher List: \n')
    accepted_cipher_suite_list = []
    for cipher in scan_result.accepted_cipher_list:
        print(u'    {}'.format(cipher.name))
        accepted_cipher_suite_list.append(cipher.name)

    if len(scan_result.accepted_cipher_list) > 0:
        httpEndpoint.set_ssl_three_zero_enbled(True)
        httpEndpoint.set_ssl_three_zero_supported_cipher_list(
            accepted_cipher_suite_list)
    else:
        httpEndpoint.set_ssl_three_zero_enbled(False)
    #if scan_result.preferred_cipher is not None:
    #    print('\n Preffered Cipher =: \n')
    #    print(u'    {}'.format(scan_result.preferred_cipher.name))

    # Run one scan command synchronously to list the server's TLS 1.0 cipher suites
    print(u'\nRunning one scan command synchronously...')
    synchronous_scanner = SynchronousScanner()
    command = Tlsv10ScanCommand()
    scan_result = synchronous_scanner.run_scan_command(server_info, command)
    print('All the TLS 1.0 Ciphers: \n')
    print('\n Accepted Cipher List: \n')
    accepted_cipher_suite_list = []
    for cipher in scan_result.accepted_cipher_list:
        print(u'    {}'.format(cipher.name))
        accepted_cipher_suite_list.append(cipher.name)

    if len(scan_result.accepted_cipher_list) > 0:
        httpEndpoint.set_tls_one_zero_enbled(True)
        httpEndpoint.set_tls_one_zero_supported_cipher_list(
            accepted_cipher_suite_list)
    else:
        httpEndpoint.set_tls_one_zero_enbled(False)
    #if scan_result.preferred_cipher is not None:
    #    print('\n Preffered Cipher =: \n')
    #    print(u'    {}'.format(scan_result.preferred_cipher.name))

    command = Tlsv11ScanCommand()
    scan_result = synchronous_scanner.run_scan_command(server_info, command)
    accepted_cipher_suite_list = []
    for cipher in scan_result.accepted_cipher_list:
        print(u'    {}'.format(cipher.name))
        accepted_cipher_suite_list.append(cipher.name)

    if len(scan_result.accepted_cipher_list) > 0:
        httpEndpoint.set_tls_one_one_enbled(True)
        httpEndpoint.set_tls_one_one_supported_cipher_list(
            accepted_cipher_suite_list)
    else:
        httpEndpoint.set_tls_one_one_enbled(False)
    #if scan_result.preferred_cipher is not None:
    #    print('\n Preffered Cipher =: \n')
    #    print(u'    {}'.format(scan_result.preferred_cipher.name))

    command = Tlsv12ScanCommand()
    scan_result = synchronous_scanner.run_scan_command(server_info, command)
    accepted_cipher_suite_list = []
    for cipher in scan_result.accepted_cipher_list:
        print(u'    {}'.format(cipher.name))
        accepted_cipher_suite_list.append(cipher.name)

    if len(scan_result.accepted_cipher_list) > 0:
        httpEndpoint.set_tls_one_two_enbled(True)
        httpEndpoint.set_tls_one_two_supported_cipher_list(
            accepted_cipher_suite_list)
    else:
        httpEndpoint.set_tls_one_two_enbled(False)
    #if scan_result.preferred_cipher is not None:
    #    print('\n Preffered Cipher =: \n')
    #    print(u'    {}'.format(scan_result.preferred_cipher.name))

    return httpEndpoint
Exemple #14
0
def scan_parallel(scanner, server_info, data, options):
    logging.debug("\tRunning scans in parallel.")

    def queue(command):
        try:
            return scanner.queue_scan_command(server_info, command)
        except OSError as err:
            text = ("OSError - likely too many processes and open files.")
            data['errors'].append(text)
            logging.warn("%s\n%s" % (text, utils.format_last_exception()))
            return None, None, None, None, None, None, None
        except Exception as err:
            text = ("Unknown exception queueing sslyze command.\n%s" %
                    utils.format_last_exception())
            data['errors'].append(text)
            logging.warn(text)
            return None, None, None, None, None, None, None

    # Initialize commands and result containers
    sslv2, sslv3, tlsv1, tlsv1_1, tlsv1_2, tlsv1_3, certs = None, None, None, None, None, None

    # Queue them all up
    queue(Sslv20ScanCommand())
    queue(Sslv30ScanCommand())
    queue(Tlsv10ScanCommand())
    queue(Tlsv11ScanCommand())
    queue(Tlsv12ScanCommand())
    queue(Tlsv13ScanCommand())

    if options.get("sslyze-certs", True) is True:
        queue(CertificateInfoScanCommand())

    # Reassign them back to predictable places after they're all done
    was_error = False
    for result in scanner.get_results():
        try:
            if isinstance(result, PluginRaisedExceptionScanResult):
                error = ("Scan command failed: %s" % result.as_text())
                logging.warn(error)
                data['errors'].append(error)
                return None, None, None, None, None, None, None

            if type(result.scan_command) == Sslv20ScanCommand:
                sslv2 = result
            elif type(result.scan_command) == Sslv30ScanCommand:
                sslv3 = result
            elif type(result.scan_command) == Tlsv10ScanCommand:
                tlsv1 = result
            elif type(result.scan_command) == Tlsv11ScanCommand:
                tlsv1_1 = result
            elif type(result.scan_command) == Tlsv12ScanCommand:
                tlsv1_2 = result
            elif type(result.scan_command) == Tlsv13ScanCommand:
                tlsv1_3 = result
            elif type(result.scan_command) == CertificateInfoScanCommand:
                certs = result
            else:
                error = "Couldn't match scan result with command! %s" % result
                logging.warn("\t%s" % error)
                data['errors'].append(error)
                was_error = True

        except Exception as err:
            was_error = True
            text = ("Exception inside async scanner result processing.\n%s" %
                    utils.format_last_exception())
            data['errors'].append(text)
            logging.warn("\t%s" % text)

    # There was an error during async processing.
    if was_error:
        return None, None, None, None, None, None, None

    logging.debug("\tDone scanning.")

    return sslv2, sslv3, tlsv1, tlsv1_1, tlsv1_2, tlsv1_3, certs
Exemple #15
0
def concurrent_scanner(hn):
    # Setup the server to scan and ensure it is online/reachable
    server_info = server_connectivity_tester(hn)
    if server_info is 'error':
        return

    # Run multiple scan commands concurrently.
    concurrent_scanner = ConcurrentScanner()

    # Queue some scan commands
    print('\nQueuing some commands...')
    concurrent_scanner.queue_scan_command(server_info,
                                          CertificateInfoScanCommand())
    concurrent_scanner.queue_scan_command(server_info, Tlsv13ScanCommand())
    concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand())
    concurrent_scanner.queue_scan_command(server_info, Tlsv11ScanCommand())
    concurrent_scanner.queue_scan_command(server_info, Tlsv10ScanCommand())
    concurrent_scanner.queue_scan_command(server_info, Sslv30ScanCommand())
    concurrent_scanner.queue_scan_command(server_info, Sslv20ScanCommand())

    # Process the results
    print('\nProcessing results...')
    for scan_result in concurrent_scanner.get_results():
        # これからスキャンする情報(コマンド)を表示
        print(
            f'\nReceived result for "{scan_result.scan_command.get_title()}" '
            f'on {scan_result.server_info.hostname}')

        # A scan command can fail (as a bug); it is returned as a PluginRaisedExceptionResult
        # スキャンコマンドのエラー
        if isinstance(scan_result, PluginRaisedExceptionScanResult):
            ##raise RuntimeError(f'Scan command failed: {scan_result.scan_command.get_title()}')
            print(
                f'Scan command failed: {scan_result.scan_command.get_title()}')
            continue

        # Each scan result has attributes with the information yo're looking for
        # All these attributes are documented within each scan command's module
        if isinstance(scan_result.scan_command, Sslv20ScanCommand):
            # Cipher suitesリスト(ssl2.0)を表示
            for cipher in scan_result.accepted_cipher_list:
                print(f'    {cipher.name}')
                sql = "INSERT INTO CipherSuite(hostname, SSL20) values(?, ?)"
                data = [(hn, cipher.name)]
                cur.executemany(sql, data)

        if isinstance(scan_result.scan_command, Sslv30ScanCommand):
            # Cipher suitesリスト(ssl3.0)を表示
            for cipher in scan_result.accepted_cipher_list:
                print(f'    {cipher.name}')
                sql = "INSERT INTO CipherSuite(hostname, SSL30) values(?, ?)"
                data = [(hn, cipher.name)]
                cur.executemany(sql, data)

        if isinstance(scan_result.scan_command, Tlsv10ScanCommand):
            # Cipher suitesリスト(tls1.0)を表示
            for cipher in scan_result.accepted_cipher_list:
                print(f'    {cipher.name}')
                sql = "INSERT INTO CipherSuite(hostname, TLS10) values(?, ?)"
                data = [(hn, cipher.name)]
                cur.executemany(sql, data)

        if isinstance(scan_result.scan_command, Tlsv11ScanCommand):
            # Cipher suitesリスト(tls1.1)を表示
            for cipher in scan_result.accepted_cipher_list:
                print(f'    {cipher.name}')
                sql = "INSERT INTO CipherSuite(hostname, TLS11) values(?, ?)"
                data = [(hn, cipher.name)]
                cur.executemany(sql, data)

        if isinstance(scan_result.scan_command, Tlsv12ScanCommand):
            # Cipher suitesリスト(tls1.2)を表示
            for cipher in scan_result.accepted_cipher_list:
                print(f'    {cipher.name}')
                sql = "INSERT INTO CipherSuite(hostname, TLS12) values(?, ?)"
                data = [(hn, cipher.name)]
                cur.executemany(sql, data)

        if isinstance(scan_result.scan_command, Tlsv13ScanCommand):
            # Cipher suitesリスト(tls1.3)を表示
            for cipher in scan_result.accepted_cipher_list:
                print(f'    {cipher.name}')
                sql = "INSERT INTO CipherSuite(hostname, TLS13) values(?, ?)"
                data = [(hn, cipher.name)]
                cur.executemany(sql, data)

        elif isinstance(scan_result.scan_command, CertificateInfoScanCommand):
            # Print the Common Names within the verified certificate chain
            # 証明書情報を表示
            if not scan_result.verified_certificate_chain:
                print('Error: certificate chain is not trusted!')
                cur.execute("INSERT INTO CertInfo(hostname) values(?)", [hn])

            else:
                print('Certificate chain common names:')
                for cert in scan_result.verified_certificate_chain:
                    cert_common_names_check = cert.subject.get_attributes_for_oid(
                        NameOID.COMMON_NAME)
                    if cert_common_names_check:
                        cert_common_names = cert_common_names_check[0].value
                    else:
                        cert_common_names = ''
                    cert_publickey = CertificateUtils.get_public_key_type(cert)
                    cert_keysize = cert.public_key().key_size
                    cert_sig_algo = cert.signature_algorithm_oid
                    cert_leaf_ev = scan_result.leaf_certificate_is_ev  # leafのみ

                    # Policy type 判定未完成↓
                    """
                    try:
                        cert_policy = cert.extensions.get_extension_for_oid(ExtensionOID.CERTIFICATE_POLICIES).value
                    except ExtensionNotFound:
                        continue
                    OV = '2.23.140.1.2.2'
                    DV = '2.23.140.1.2.1'
                    if OV in cert_policy:
                        cert_policy_type = 'OV'
                    if DV in cert_policy:
                        cert_policy_type = 'DV'
                    else:
                        cert_policy_type = ''
                    """

                    cert_ov_check = cert.subject.get_attributes_for_oid(
                        NameOID.ORGANIZATION_NAME)
                    if cert_ov_check:
                        cert_ov = cert_ov_check[0].value
                    else:
                        cert_ov = ''
                    print(f'   {cert_common_names}')
                    print(f'   {cert_publickey}')
                    print(f'   {cert_keysize}')
                    print(f'   {cert_sig_algo._name}')
                    # print(f'   {cert_policy_type}')
                    print(f'   {cert_leaf_ev}')
                    print(f'   {cert_ov}')

                    sql = "INSERT INTO CertInfo(hostname, commonname, publickey, keysize, signature, certtype, ov) values(?, ?, ?, ?, ?, ?, ?)"
                    data = [
                        (hn, cert_common_names, cert_publickey, cert_keysize,
                         cert_sig_algo._name, cert_leaf_ev, cert_ov)
                    ]
                    cur.executemany(sql, data)
Exemple #16
0
def get_supported_tls_cipher_suites(hostname):
    server_info = get_ssl_server_info(hostname)
    concurrent_scanner = ConcurrentScanner()
    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,
                                          FallbackScsvScanCommand())

    for scan_result in concurrent_scanner.get_results():
        # A scan command can fail (as a bug); it is returned as a PluginRaisedExceptionResult
        if isinstance(scan_result, PluginRaisedExceptionScanResult):
            raise RuntimeError(
                f'Scan command failed: {scan_result.scan_command.get_title()}')

        if isinstance(scan_result.scan_command, Sslv20ScanCommand):
            accepted_ssl2 = [
                cipher.name for cipher in scan_result.accepted_cipher_list
            ]
            denied_ssl2 = [
                cipher.name for cipher in scan_result.rejected_cipher_list
            ]
            errored_ssl2 = [
                cipher.name for cipher in scan_result.errored_cipher_list
            ]
        if isinstance(scan_result.scan_command, Sslv30ScanCommand):
            accepted_ssl3 = [
                cipher.name for cipher in scan_result.accepted_cipher_list
            ]
            denied_ssl3 = [
                cipher.name for cipher in scan_result.rejected_cipher_list
            ]
            errored_ssl3 = [
                cipher.name for cipher in scan_result.errored_cipher_list
            ]
        if isinstance(scan_result.scan_command, Tlsv10ScanCommand):
            accepted_tls10 = [
                cipher.name for cipher in scan_result.accepted_cipher_list
            ]
            denied_tls10 = [
                cipher.name for cipher in scan_result.rejected_cipher_list
            ]
            errored_tls10 = [
                cipher.name for cipher in scan_result.errored_cipher_list
            ]
        if isinstance(scan_result.scan_command, Tlsv11ScanCommand):
            accepted_tls11 = [
                cipher.name for cipher in scan_result.accepted_cipher_list
            ]
            denied_tls11 = [
                cipher.name for cipher in scan_result.rejected_cipher_list
            ]
            errored_tls11 = [
                cipher.name for cipher in scan_result.errored_cipher_list
            ]
        if isinstance(scan_result.scan_command, Tlsv12ScanCommand):
            accepted_tls12 = [
                cipher.name for cipher in scan_result.accepted_cipher_list
            ]
            denied_tls12 = [
                cipher.name for cipher in scan_result.rejected_cipher_list
            ]
            errored_tls12 = [
                cipher.name for cipher in scan_result.errored_cipher_list
            ]
        if isinstance(scan_result.scan_command, Tlsv13ScanCommand):
            accepted_tls13 = [
                cipher.name for cipher in scan_result.accepted_cipher_list
            ]
            denied_tls13 = [
                cipher.name for cipher in scan_result.rejected_cipher_list
            ]
            errored_tls13 = [
                cipher.name for cipher in scan_result.errored_cipher_list
            ]
        if isinstance(scan_result.scan_command, FallbackScsvScanCommand):
            supports_fallback_scsv = scan_result.supports_fallback_scsv

    return {
        'accepted_ssl2': accepted_ssl2,
        'denied_ssl2': denied_ssl2,
        'errored_ssl2': errored_ssl2,
        'accepted_ssl3': accepted_ssl3,
        'denied_ssl3': denied_ssl3,
        'errored_ssl3': errored_ssl3,
        'accepted_tls10': accepted_tls10,
        'denied_tls10': denied_tls10,
        'errored_tls10': errored_tls10,
        'accepted_tls11': accepted_tls11,
        'denied_tls11': denied_tls11,
        'errored_tls11': errored_tls11,
        'accepted_tls12': accepted_tls12,
        'denied_tls12': denied_tls12,
        'errored_tls12': errored_tls12,
        'accepted_tls13': accepted_tls13,
        'denied_tls13': denied_tls13,
        'errored_tls13': errored_tls13,
        'supports_fallback_scsv': supports_fallback_scsv
    }
Exemple #17
0
def attack_host(results, host_name):
    print("Running forward_secrecy_attack.py host name: {}".format(host_name))
    expected_tls1_2_suites = ['TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384', 'TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256']

    try:
        server_tester = ServerConnectivityTester(
            hostname=host_name,
            port=443,
            tls_wrapped_protocol=TlsWrappedProtocolEnum.HTTPS)

        server_info = server_tester.perform()
    except ServerConnectivityError as e:
        results.append(AttackResult('10.13', host_name, False, e))
        return

    synchronous_scanner = SynchronousScanner()

    tls1_3_scan_result = synchronous_scanner.run_scan_command(server_info, Tlsv13ScanCommand())
    tls1_3_accepted_ciphers = tls1_3_scan_result.accepted_cipher_list

    tls1_2_scan_result = synchronous_scanner.run_scan_command(server_info, Tlsv12ScanCommand())
    tls1_2_accepted_ciphers = tls1_2_scan_result.accepted_cipher_list
    tls1_2_accepted_cipher_names = cipher_list_to_string_list(tls1_2_accepted_ciphers)

    tls1_1_scan_result = synchronous_scanner.run_scan_command(server_info, Tlsv11ScanCommand())
    tls1_1_accepted_ciphers = tls1_1_scan_result.accepted_cipher_list

    tls1_0_scan_result = synchronous_scanner.run_scan_command(server_info, Tlsv10ScanCommand())
    tls1_0_accepted_ciphers = tls1_0_scan_result.accepted_cipher_list

    ssl3_0_scan_result = synchronous_scanner.run_scan_command(server_info, Sslv30ScanCommand())
    ssl3_0_accepted_ciphers = ssl3_0_scan_result.accepted_cipher_list

    ssl2_0_scan_result = synchronous_scanner.run_scan_command(server_info, Sslv20ScanCommand())
    ssl2_0_accepted_ciphers = ssl2_0_scan_result.accepted_cipher_list

    # Determine result
    result = list_equal(tls1_2_accepted_cipher_names, expected_tls1_2_suites) and \
        len(tls1_3_accepted_ciphers) == 0 and \
        len(tls1_1_accepted_ciphers) == 0 and \
        len(tls1_0_accepted_ciphers) == 0 and \
        len(ssl3_0_accepted_ciphers) == 0 and \
        len(ssl3_0_accepted_ciphers) == 0

    # Build details
    details = ''
    if len(tls1_3_accepted_ciphers) != 0:
        details += 'TLS 1.3 should not be supported '

    if not list_equal(tls1_2_accepted_cipher_names, expected_tls1_2_suites):
        details += ' TLS 1.2 supporting ' + str(tls1_2_accepted_cipher_names) \
                   + ', should only be ' + str(expected_tls1_2_suites) + ' '

    if len(tls1_1_accepted_ciphers) != 0:
        details += 'TLS 1.1 should not be supported '

    if len(tls1_0_accepted_ciphers) != 0:
        details += 'TLS 1.0 should not be supported '

    if len(ssl3_0_accepted_ciphers) != 0:
        details += 'SSL 3.0 should not be supported '

    if len(ssl2_0_accepted_ciphers) != 0:
        details += 'SSL 2.0 should not be supported '

    if details == '':
        details = 'Cipher suites are correct'

    results.append(AttackResult('forward_secrecy', host_name, result, details))


# attack_host([], 'google.co.uk')
Exemple #18
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!")
Exemple #19
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))
Exemple #20
0
    def process_task(self, analysis_info):
        # Init
        target_info = OTG_CRYPST_001.__get_info_from_target_url(analysis_info.get_target())
        vulnerabilities = []
        if not target_info['https']:
            vulnerabilities.append('The target is not using HTTPS')
        else:
            server_info = ServerConnectivityInfo(hostname=target_info['server'], port=target_info['port'])
            server_info.test_connectivity_to_server()

            # -- Check

            # Checks heartbleed (CVE-2014-0160)
            plugin = HeartbleedPlugin()
            heartbleed_vulnerability = plugin.process_task(server_info, 'heartbleed').is_vulnerable_to_heartbleed
            if heartbleed_vulnerability:
                vulnerabilities.append('Heartbleed vulnerability (CVE-2014-0160)')

            # Checks OpenSSL CCS injection vulnerability (CVE-2014-0224)
            plugin = OpenSslCcsInjectionPlugin()
            css_injection_vulnerability = plugin.process_task(server_info, 'openssl_ccs').is_vulnerable_to_ccs_injection
            if css_injection_vulnerability:
                vulnerabilities.append('OpenSSL CCS injection vulnerability (CVE-2014-0224)')

            # LOGJAM vulnerability (CVE-2015-4000)
            plugin = OpenSslCipherSuitesPlugin()
            ciphersuites_result = plugin.process_task(server_info, Tlsv10ScanCommand())
            re_dhe = re.compile('[A-Z]*_DHE_[A-Z]*_EXPORT')
            accepted_cipher_name_list = [cipher.name for cipher in ciphersuites_result.accepted_cipher_list]
            logjam_vulnerability = False
            if not len(re_dhe.findall((",").join(accepted_cipher_name_list))) == 0:
                logjam_vulnerability = True
            try:
                if ciphersuites_result.preferred_cipher and \
                not ciphersuites_result.preferred_cipher.dh_info['GroupSize'] >= 2048:
                    logjam_vulnerability = True
            except Exception:
                logjam_vulnerability = True

            if logjam_vulnerability:
                vulnerabilities.append('LOGJAM vulnerability (CVE-2015-4000)')

            # CRIME (CVE-2012-4929) & BREACH (CVE-2013-3587)
            plugin = CompressionPlugin()
            compression_name_result = plugin.process_task(server_info, 'compression').compression_name
            if compression_name_result is not None:
                vulnerabilities.append('CRIME (CVE-2012-4929) & BREACH (CVE-2013-3587)')

            #  SSL client renogotaiation
            plugin = SessionRenegotiationPlugin()
            reneg_result = plugin.process_task(server_info, 'reneg')
            if reneg_result.accepts_client_renegotiation:
                vulnerabilities.append('SSL client renogotaiation supported')

            # POODLE (CVE-2014-3566), BEAST (CVE-2011-3389) and weak SSL protocols
            weak_protocols = []
            for protocol in [Sslv20ScanCommand(), Sslv30ScanCommand(), Tlsv10ScanCommand()]:
                plugin = OpenSslCipherSuitesPlugin()
                plugin_result = plugin.process_task(server_info, protocol)
                if len(plugin_result.accepted_cipher_list) > 0:
                    weak_protocols.append(protocol.get_cli_argument())
            if len(weak_protocols) > 0:
                vulnerabilities.append('POODLE (CVE-2014-3566), BEAST (CVE-2011-3389) and weak SSL protocols ' +
                                       str(json.dumps(weak_protocols)))

            # Minimum cipher strength requirements (>= 128 bits) not satisfied
            weak_ciphers = set()
            for protocol in [Tlsv11ScanCommand(), Tlsv12ScanCommand()]:
                plugin = OpenSslCipherSuitesPlugin()
                plugin_result = plugin.process_task(server_info, protocol)
                accepted_cipher_key_dict = {cipher.name: cipher.key_size for cipher in plugin_result.accepted_cipher_list}
                for cipher in accepted_cipher_key_dict:
                    if accepted_cipher_key_dict[cipher] < 128:
                        weak_ciphers.add(cipher)
            if len(weak_ciphers) > 0:
                vulnerabilities.append('Minimum cipher strength requirements (>= 128 bits) not satisfied ' +
                                       str(list(weak_ciphers)))

            # SSL/TLS perfect cipher suites
            not_perfect_ciphers = set()
            for protocol in [Tlsv11ScanCommand(), Tlsv12ScanCommand()]:
                plugin = OpenSslCipherSuitesPlugin()
                plugin_result = plugin.process_task(server_info, protocol)
                accepted_cipher_key_arr = [cipher.name for cipher in plugin_result.accepted_cipher_list]
                for accepted_cipher_key in accepted_cipher_key_arr:
                    if accepted_cipher_key not in not_perfect_ciphers and \
                                    accepted_cipher_key not in Analysis.PERFECT_CIPHER_SUITES:
                        not_perfect_ciphers.add(accepted_cipher_key)
            if len(not_perfect_ciphers) > 0:
                vulnerabilities.append('SSL/TLS perfect cipher suites not satisfied ' +
                                       str(list(not_perfect_ciphers)))

            # Certificate key is > 1024 bits
            plugin = CertificateInfoPlugin()
            plugin_certificate_result = plugin.process_task(server_info, CertificateInfoScanCommand())
            key_size = plugin_certificate_result.certificate_chain[0].as_dict['subjectPublicKeyInfo']['publicKeySize']
            if int(key_size) <= 1024:
                vulnerabilities.append('Certificate key is <= 1024 bits')

            # X509 Hostname validation
            plugin = CertificateInfoPlugin()
            plugin_certificate_result = plugin.process_task(server_info, CertificateInfoScanCommand())
            if plugin_certificate_result.hostname_validation_result is HostnameValidationResultEnum.NAME_DOES_NOT_MATCH:
                vulnerabilities.append('X509 Hostname validation failed')

            # Check wildcard certificates
            plugin = CertificateInfoPlugin()
            plugin_certificate_result = plugin.process_task(server_info, CertificateInfoScanCommand())
            # Common Name
            cn = plugin_certificate_result.certificate_chain[0].as_dict['subject']['commonName']
            if '*' in cn:
                vulnerabilities.append('Wildcards are not allowed in CN')
            # Subject Alternative Name
            try:
                san_list = plugin_certificate_result.certificate_chain[0].as_dict['extensions']\
                                                                             ['X509v3 Subject Alternative Name']['DNS']
                san_with_asterisk = [san for san in san_list if '*' in san]
                if len(san_with_asterisk) > 0:
                    vulnerabilities.append('Wildcards are not allowed in SAN')
            except KeyError:
                # Nothing to do because X509v3 Subject Alternative Name not found
                pass

            # Check SAN with IP address
            plugin = CertificateInfoPlugin()
            plugin_certificate_result = plugin.process_task(server_info, CertificateInfoScanCommand())
            # Subject Alternative Name
            try:
                san_list = plugin_certificate_result.certificate_chain[0].as_dict['extensions']\
                                                                                 ['X509v3 Subject Alternative Name']['IP']
                ip_match_list = [ip for ip in san_list if OTG_CRYPST_001.__isIPv4(ip)]
                if len(ip_match_list) > 0:
                    vulnerabilities.append('IPs are not allowed in SAN')
            except KeyError:
                # Nothing to do because X509v3 Subject Alternative Name not found
                pass

        # Prepare output
        if len(vulnerabilities) > 0:
            msg = str(vulnerabilities)
            status = OwaspStepBase.status.error.value
        else:
            msg = 'Passed.'
            status = OwaspStepBase.status.passed.value

        # Return
        return OwaspStepBase.StepResult(title=OTG_CRYPST_001.get_interface().title,
                                        description=OTG_CRYPST_001.get_interface().description,
                                        msg=msg, status=status)
def handler(event, context):
    """Handler for all Lambda events

    The event parameter is a dictionary containing the following keys
    and value types:
    * hostname - A string containing the hostname to be scanned.  For
      example, "dhs.gov".
    * port - An integer specifying the port to be scanned.  If omitted
      then the default value of 443 is used.
    * timeout - An integer denoting the number of seconds to wait when
      creating a connection.  If omitted then the default value of 5
      is used.
    * starttls_smtp - A boolean value denoting whether to try to use
      STARTTLS after connecting to an SMTP server.  This option should
      be True is connecting to an SMTP host and otherwise False.  If
      omitted then the default value of False is used.
    * scan_tlsv10 - A boolean value denoting whether to scan for TLS
      version 1.0 ciphers. If omitted then the default value of False
      is used.
    * scan_tlsv11 - A boolean value denoting whether to scan for TLS
      version 1.1 ciphers. If omitted then the default value of False
      is used.
    * scan_tlsv12 - A boolean value denoting whether to scan for TLS
      version 1.2 ciphers. If omitted then the default value of False
      is used.
    * scan_tlsv13 - A boolean value denoting whether to scan for TLS
      version 1.3 ciphers. If omitted then the default value of False
      is used.
    * scan_sslv20 - A boolean value denoting whether to scan for SSL
      version 2.0 ciphers. If omitted then the default value of False
      is used.
    * scan_sslv30 - A boolean value denoting whether to scan for SSL
      version 3.0 ciphers. If omitted then the default value of False
      is used.
    * scan_cert_info - A boolean value denoting whether to return
      certificate information. If omitted then the default value of
      False is used.

    Parameters
    ----------
    event : dict
        A dictionary containing the scan parameters, as described
        above.

    context : LambdaContext
        The context for the Lambda function.  See the corresponding
        AWS documentation for more details:
        https://docs.aws.amazon.com/lambda/latest/dg/python-context-object.html

    Returns
    -------
    OrderedDict
        An OrderedDict specifying the fields of the
        trustymail.domain.Domain object resulting from the scan
        activity.
    """
    logging.info('AWS Event was: {}'.format(event))

    # Extract some variables from the event dictionary
    hostname = event['hostname']
    port = event.get('port', 443)
    timeout = event.get('timeout', 5)
    starttls_smtp = event.get('starttls_smtp', False)
    scan_tlsv10 = event.get('scan_tlsv10', False)
    scan_tlsv11 = event.get('scan_tlsv11', False)
    scan_tlsv12 = event.get('scan_tlsv12', False)
    scan_tlsv13 = event.get('scan_tlsv13', False)
    scan_sslv20 = event.get('scan_sslv20', False)
    scan_sslv30 = event.get('scan_sslv30', False)
    scan_cert_info = event.get('scan_cert_info', False)

    # Initialize sslyze
    protocol = TlsWrappedProtocolEnum.PLAIN_TLS
    if starttls_smtp:
        protocol = TlsWrappedProtocolEnum.STARTTLS_SMTP

    try:
        server_tester = ServerConnectivityTester(hostname=hostname,
                                                 port=port,
                                                 tls_wrapped_protocol=protocol)
        server_info = server_tester.perform(network_timeout=timeout)
    except ServerConnectivityError:
        logging.error('Unable to connect to {}:{}'.format(hostname, port),
                      exc_info=True, stack_info=True)
        return None
    except Exception:
        logging.error('Unable to connect to {}:{}'.format(hostname, port),
                      exc_info=True, stack_info=True)
        return None

    scanner = SynchronousScanner(network_timeout=timeout)

    # Perform the scans
    if scan_tlsv10:
        logging.debug('Performing TLSv1.0 scan')
        tlsv10 = scanner.run_scan_command(server_info, Tlsv10ScanCommand())
        logging.debug('tlsv10 = {}'.format(tlsv10))
    if scan_tlsv11:
        logging.debug('Performing TLSv1.1 scan')
        tlsv11 = scanner.run_scan_command(server_info, Tlsv11ScanCommand())
        logging.debug('tlsv11 = {}'.format(tlsv11))
    if scan_tlsv12:
        logging.debug('Performing TLSv1.2 scan')
        tlsv12 = scanner.run_scan_command(server_info, Tlsv12ScanCommand())
        logging.debug('tlsv12 = {}'.format(tlsv12))
    if scan_tlsv13:
        logging.debug('Performing TLSv1.3 scan')
        tlsv13 = scanner.run_scan_command(server_info, Tlsv13ScanCommand())
        logging.debug('tlsv13 = {}'.format(tlsv13))
    if scan_sslv20:
        logging.debug('Performing SSLv2 scan')
        sslv20 = scanner.run_scan_command(server_info, Sslv20ScanCommand())
        logging.debug('sslv20 = {}'.format(sslv20))
    if scan_sslv30:
        logging.debug('Performing SSLv3 scan')
        sslv30 = scanner.run_scan_command(server_info, Sslv30ScanCommand())
        logging.debug('sslv30 = {}'.format(sslv30))
    if scan_cert_info:
        logging.debug('Performing certificate scan')
        cert_info = scanner.run_scan_command(server_info,
                                             CertificateInfoScanCommand())
        logging.debug('cert_info = {}'.format(cert_info))

    return None
Exemple #22
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)