Example #1
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
Example #2
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
Example #3
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
Example #4
0
    def test_tls_1_3_cipher_suites(self):
        server_info = ServerConnectivityInfo(hostname='www.cloudflare.com')
        server_info.test_connectivity_to_server()

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

        accepted_cipher_name_list = [cipher.name for cipher in plugin_result.accepted_cipher_list]
        self.assertEqual({'TLS13-AES-128-GCM-SHA256', 'TLS13-AES-256-GCM-SHA384', 'TLS13-CHACHA20-POLY1305-SHA256'},
                         set(accepted_cipher_name_list))
Example #5
0
    def test_tls_1_3_cipher_suites(self):
        server_test = ServerConnectivityTester(hostname='www.cloudflare.com')
        server_info = server_test.perform()

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

        accepted_cipher_name_list = [
            cipher.name for cipher in plugin_result.accepted_cipher_list
        ]
        assert {'TLS_CHACHA20_POLY1305_SHA256', 'TLS_AES_256_GCM_SHA384', 'TLS_AES_128_GCM_SHA256'} == \
            set(accepted_cipher_name_list)
Example #6
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)
    def test_tls_1_3_cipher_suites(self):
        server_info = ServerConnectivityInfo(hostname='www.cloudflare.com')
        server_info.test_connectivity_to_server()

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

        accepted_cipher_name_list = [
            cipher.name for cipher in plugin_result.accepted_cipher_list
        ]

        # TODO(AD): Update to TLS 1.3 draft 23 and re-enable this test
        return
        self.assertEqual(
            {
                'TLS_CHACHA20_POLY1305_SHA256', 'TLS_AES_256_GCM_SHA384',
                'TLS_AES_128_GCM_SHA256'
            }, set(accepted_cipher_name_list))
Example #8
0
    def test_succeeds_when_client_auth_failed_tls_1_3(self):
        # Given a TLS 1.3 server that requires client authentication
        with ModernOpenSslServer(
                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()

            # OpenSslCipherSuitesPlugin works even when a client cert was not supplied
            plugin = OpenSslCipherSuitesPlugin()
            plugin_result = plugin.process_task(server_info,
                                                Tlsv13ScanCommand())

        assert plugin_result.accepted_cipher_list
        assert plugin_result.as_text()
        assert plugin_result.as_xml()
Example #9
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
Example #10
0
# 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
SynchronousScanner.DEFAULT_NETWORK_RETRIES = 1
SynchronousScanner.DEFAULT_NETWORK_TIMEOUT = 3

ERROR_MSG_CONNECTION_TIMEOUT = 'TCP connection to {}:{} timed-out'.format
ERROR_MSG_UNKNOWN_CONNECTION = \
    'TCP connection to {}:{} encountered unknown error'.format


def scan(name, ip, port, view, suite):
    """ Five inputs: web site name, ip, port
    split-dns view, and cipher suite """
Example #11
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
Example #12
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
    }
Example #13
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')
Example #14
0
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
Example #15
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)
Example #16
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)