Ejemplo n.º 1
0
def scan_cipher_lists(addresses, concurrent=16):
    # prepare scanner
    s = ConcurrentScanner(max_processes_nb=concurrent)
    for addr in addresses:
        ip, port = split_host_port(addr)
        server_info = ServerConnectivityInfo(hostname=addr,
                                             ip_address=ip,
                                             port=port)
        for cmd in scan_commands():
            s.queue_scan_command(server_info, cmd)

    # execute
    for result in s.get_results():
        addr = result.server_info.hostname
        if not isinstance(result, CipherSuiteScanResult):
            logging.info('failed to get results for %s', addr)
            continue
        logging.info('results for %s', addr)
        for cipher in result.accepted_cipher_list:
            output_cipher(addr, cipher, label='accepted')
        output_cipher(addr, result.preferred_cipher, label='preferred')
Ejemplo n.º 2
0
def demo_concurrent_scanner():
    # Setup the server to scan and ensure it is online/reachable
    server_info = demo_server_connectivity_tester()

    # Run multiple scan commands concurrently. It is much faster than the SynchronousScanner
    concurrent_scanner = ConcurrentScanner()

    # Queue some scan commands
    print('\nQueuing some commands...')
    concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand())
    concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand())

    # Process the results
    print('\nProcessing results...')
    for scan_result in concurrent_scanner.get_results():
        # All scan results have the corresponding scan_command and server_info as an attribute
        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()}')

        # 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, Tlsv12ScanCommand):
            for cipher in scan_result.accepted_cipher_list:
                print(f'    {cipher.name}')

        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!')
            else:
                print('Certificate chain common names:')
                for cert in scan_result.verified_certificate_chain:
                    cert_common_names = cert.subject.get_attributes_for_oid(NameOID.COMMON_NAME)
                    print(f'   {cert_common_names[0].value}')
Ejemplo n.º 3
0
    def test_concurrent_scanner(self):
        server_info = ServerConnectivityInfo(hostname='www.google.com')
        server_info.test_connectivity_to_server()

        # Queue some scan commands that are quick
        concurrent_scanner = ConcurrentScanner()
        concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand())
        concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand())
        concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand())

        # Process the results
        nb_results = 0
        for plugin_result in concurrent_scanner.get_results():
            self.assertTrue(plugin_result.as_text())
            self.assertTrue(plugin_result.as_xml())
            nb_results +=1

        self.assertEquals(nb_results, 3)
Ejemplo n.º 4
0
    def test_concurrent_scanner(self):
        server_test = ServerConnectivityTester(hostname='www.google.com')
        server_info = server_test.perform()

        # Queue some scan commands that are quick
        concurrent_scanner = ConcurrentScanner()
        concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand())
        concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand())
        concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand())

        # Process the results
        nb_results = 0
        for plugin_result in concurrent_scanner.get_results():
            self.assertTrue(plugin_result.as_text())
            self.assertTrue(plugin_result.as_xml())
            nb_results +=1

        self.assertEqual(nb_results, 3)
Ejemplo n.º 5
0
    def test_concurrent_scanner(self):
        server_test = ServerConnectivityTester(hostname='www.google.com')
        server_info = server_test.perform()

        # Queue some scan commands that are quick
        concurrent_scanner = ConcurrentScanner()
        concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand())
        concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand())
        concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand())

        # Process the results
        nb_results = 0
        for plugin_result in concurrent_scanner.get_results():
            assert plugin_result.as_text()
            assert plugin_result.as_xml()
            nb_results += 1

        assert nb_results == 3
Ejemplo n.º 6
0
 def module_run(self, hostportsip):
     for host, port, ip_address in hostportsip:
         self.heading('{0}:{1} ({2})'.format(host, port, ip_address), level=0)
         port = int(port)
         try:
             tls_wrapped_protocol = self.STARTTLS_PROTOCOL_DICT[port]
         except KeyError:
             self.error("Protocol not found for port {}".format(port))
             continue
         try:
             server_info = ServerConnectivityInfo(hostname=host,
                                                  port=port,
                                                  ip_address=ip_address,
                                                  tls_wrapped_protocol=tls_wrapped_protocol)
             server_info.test_connectivity_to_server()
         except ServerConnectivityError as e:
             self.error("Could not connect to {0}:{1}: {2}".format(host, port, e))
             continue
         concurrent_scanner = ConcurrentScanner()
         concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand())
         concurrent_scanner.queue_scan_command(server_info, CompressionScanCommand())
         concurrent_scanner.queue_scan_command(server_info, FallbackScsvScanCommand())
         concurrent_scanner.queue_scan_command(server_info, HeartbleedScanCommand())
         concurrent_scanner.queue_scan_command(server_info, RobotScanCommand())
         concurrent_scanner.queue_scan_command(server_info, OpenSslCcsInjectionScanCommand())
         concurrent_scanner.queue_scan_command(server_info, SessionResumptionSupportScanCommand())
         for scan_result in concurrent_scanner.get_results():
             data = None
             if isinstance(scan_result, HeartbleedScanResult):
                 if scan_result.is_vulnerable_to_heartbleed:
                     data = {'reference': 'VULNERABLE - HEARTBLEED - Server is vulnerable to Heartbleed',
                             'example': '\n'.join(scan_result.as_text())}
             elif isinstance(scan_result, RobotScanResult):
                 if scan_result.robot_result_enum == RobotScanResultEnum.VULNERABLE_STRONG_ORACLE:
                     data = {'reference': 'VULNERABLE - ROBOT - Strong oracle, a real attack is possible',
                             'example': '\n'.join(scan_result.as_text())}
                 elif scan_result.robot_result_enum == RobotScanResultEnum.VULNERABLE_WEAK_ORACLE:
                     data = {'reference': 'VULNERABLE - ROBOT - Weak oracle, the attack would take too long',
                             'example': '\n'.join(scan_result.as_text())}
             elif isinstance(scan_result, CompressionScanResult):
                 if scan_result.compression_name:
                     data = {'reference': "VULNERABLE - Server supports Deflate compression",
                             'example': '\n'.join(scan_result.as_text())}
             elif isinstance(scan_result, FallbackScsvScanResult):
                 if scan_result.supports_fallback_scsv:
                     data = {'reference': "VULNERABLE - Signaling cipher suite not supported",
                             'example': '\n'.join(scan_result.as_text())}
                     data = None
             elif isinstance(scan_result, OpenSslCcsInjectionScanResult):
                 if scan_result.is_vulnerable_to_ccs_injection:
                     data = {'reference': 'VULNERABLE - Server is vulnerable to OpenSSL CCS injection',
                             'example': '\n'.join(scan_result.as_text())}
             elif isinstance(scan_result, SessionRenegotiationScanResult):
                 if scan_result.accepts_client_renegotiation:
                     data = {'reference': 'VULNERABLE - Server honors client-initiated renegotiations',
                             'example': '\n'.join(scan_result.as_text())}
             elif isinstance(scan_result, PluginRaisedExceptionScanResult):
                 self.error('Scan command failed: {}'.format(scan_result.as_text()))
                 continue
             if data:
                 data['host'] = host
                 data['category'] = 'TLS vulnerability'
                 for key in sorted(data.keys()):
                     self.output('%s: %s' % (key.title(), data[key]))
                 self.add_vulnerabilities(**data)
                 self.output(self.ruler*50)
Ejemplo n.º 7
0
def start_scanner(session, scan_id, with_progressbar=False):
    """
	takes database session and project id, creates a scan id and start scanning for all targets belonging to project
	"""
    logger.log(1, 'create_server_info called')
    logger.debug('enumerating targets')

    total_results = 0

    network_retries = 3
    network_timeout = 5
    max_processes_nb = 12
    max_processes_per_hostname_nb = 3

    scan = session.query(Scan).get(scan_id)
    concurrent_scanner = ConcurrentScanner(scan.network_retries,
                                           scan.network_timeout,
                                           scan.max_processes_nb,
                                           scan.max_processes_per_hostname_nb)
    for target in enum_targets(session, scan_id, with_progressbar):
        try:
            server_info = create_server_info(target)
        except Exception as e:
            logger.exception('Connecting to server failed')
            tci = TargetConnectivityInfo()
            tci.scan_id = scan.id
            tci.target_id = target.id
            tci.is_connectivity_ok = False
            session.add(tci)
            session.commit()
            continue

        server_info.target_id = target.id  #importent to keep track of the id fof the target!
        tci = TargetConnectivityInfo()
        tci.scan_id = scan.id
        tci.target_id = target.id
        tci.is_connectivity_ok = True
        session.add(tci)
        session.commit()

        logger.debug('Creating scan result')

        logger.debug('Enqueueing server for a scan')
        commands = []
        for res in session.query(ScanCommand.command).filter(
                scan_id == scan_id).distinct(ScanCommand.command).all():
            for r in res:
                commands.append(r)

        if len(commands) == 0:
            raise Exception('Scan doesnt have any commands!')

        for command in commands:
            for c in command_map[command]:
                concurrent_scanner.queue_scan_command(server_info, c())
                total_results += 1

    logger.debug('Starting scanner!')

    for scan_result in get_results(concurrent_scanner, with_progressbar,
                                   total_results):
        logger.debug(
            f'\nReceived result for "{scan_result.scan_command.get_title()}" '
            f'on {scan_result.server_info.hostname}')
        logger.debug('ID: %s' % scan_result.server_info.target_id)

        if isinstance(scan_result, PluginRaisedExceptionScanResult):
            logger.info('Scan command failed: %s' %
                        scan_result.scan_command.get_title())
            f = FailedCommands()
            f.scan_id = scan.id
            f.target_id = target.id
            f.error_message = scan_result.error_message
            f.failed_command = command_map_rev[type(scan_result.scan_command)]

            session.add(f)
            session.commit()

        elif isinstance(scan_result.scan_command, CertificateInfoScanCommand):
            res = CertificateInfoScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id

            res.certificate_matches_hostname = scan_result.certificate_matches_hostname
            res.is_leaf_certificate_ev = scan_result.is_leaf_certificate_ev
            res.certificate_has_must_staple_extension = scan_result.certificate_has_must_staple_extension
            res.certificate_included_scts_count = scan_result.certificate_included_scts_count
            #ocsp_response = Column(Boolean)
            res.ocsp_response_status = scan_result.ocsp_response_status
            res.is_ocsp_response_trusted = scan_result.is_ocsp_response_trusted
            res.has_sha1_in_certificate_chain = scan_result.has_sha1_in_certificate_chain
            res.has_anchor_in_certificate_chain = scan_result.has_anchor_in_certificate_chain

            session.add(res)

            session.commit()
            session.refresh(res)

            idx = 0
            for certdata in scan_result.certificate_chain:
                cert = Certificate.from_result(
                    res.id, idx,
                    certdata.public_bytes(serialization.Encoding.PEM))
                idx += 1
                session.add(cert)
            for valres in scan_result.path_validation_result_list:
                #pvr = PathValidationResult.from_result(res.id, valres)
                ts = TrustStore.from_result(res.id, valres.trust_store)
                pvr = PathValidationResult()

                pvr.certificateinfoscanresult_id = res.id
                pvr.trust_store = ts
                pvr.verify_string = valres.verify_string
                pvr.is_certificate_trusted = valres.is_certificate_trusted

                session.add(pvr)

            for valres in scan_result.path_validation_error_list:
                pvre = PathValidationError()
                pvre.certificateinfoscanresult_id = res.id
                ts = TrustStore.from_result(res.id, valres.trust_store)
                pvre.trust_store = ts

                session.add(pvre)

            if scan_result.successful_trust_store is not None:
                ts = TrustStore.from_result(res.id,
                                            scan_result.successful_trust_store)
                res.successful_trust_store = ts

            if scan_result.path_validation_error_list is not None:
                for valres in scan_result.path_validation_error_list:
                    pvre = PathValidationError.from_result(res.id, valres)
                    session.add(pvre)

            session.commit()

        elif isinstance(
                scan_result.scan_command,
            (Sslv20ScanCommand, Sslv30ScanCommand, Tlsv10ScanCommand,
             Tlsv11ScanCommand, Tlsv12ScanCommand, Tlsv13ScanCommand)):
            res = CipherSuiteScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            session.add(res)

            session.commit()
            session.refresh(res)

            for acres in scan_result.accepted_cipher_list:
                ac = AcceptedCipherSuite.from_result(acres)
                session.add(ac)
                res.accepted_cipher_list.append(ac)

            session.add(res)
            session.commit()

        elif isinstance(scan_result.scan_command, CompressionScanCommand):
            res = CompressionScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            #resoning for line below: documentation sais that None will be returned for compression_name
            # if no compression was set. Problem is: None is also returned in SQL when joining tables :(
            res.compression_name = scan_result.compression_name if scan_result.compression_name is not None else 'N/A'
            session.add(res)
            session.commit()

        elif isinstance(scan_result.scan_command, FallbackScsvScanCommand):
            res = FallbackScsvScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            res.supports_fallback_scsv = scan_result.supports_fallback_scsv
            session.add(res)
            session.commit()

        elif isinstance(scan_result.scan_command, HeartbleedScanCommand):
            res = HeartbleedScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            res.is_vulnerable_to_heartbleed = scan_result.is_vulnerable_to_heartbleed
            session.add(res)
            session.commit()

        elif isinstance(scan_result.scan_command,
                        OpenSslCcsInjectionScanCommand):
            res = OpenSslCcsInjectionScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            res.is_vulnerable_to_ccs_injection = scan_result.is_vulnerable_to_ccs_injection
            session.add(res)
            session.commit()

        elif isinstance(scan_result.scan_command,
                        SessionRenegotiationScanCommand):
            res = SessionRenegotiationScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            res.accepts_client_renegotiation = scan_result.accepts_client_renegotiation
            res.supports_secure_renegotiation = scan_result.supports_secure_renegotiation
            session.add(res)
            session.commit()

        elif isinstance(scan_result.scan_command,
                        SessionResumptionSupportScanCommand):
            res = SessionResumptionSupportScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            res.attempted_resumptions_nb = scan_result.attempted_resumptions_nb
            res.successful_resumptions_nb = scan_result.successful_resumptions_nb
            res.failed_resumptions_nb = scan_result.failed_resumptions_nb
            res.ticket_resumption_failed_reason = scan_result.ticket_resumption_failed_reason
            #res.ticket_resumption_exception = scan_result.ticket_resumption_exception
            session.add(res)
            session.commit()
            session.refresh(res)
            for errortext in scan_result.errored_resumptions_list:
                err = SessionResumptionErrors()
                err.resumption_id = res.id
                err.error = errortext
                session.add(err)
                res.errored_resumptions_list.append(err)

            session.add(res)
            session.commit()

        elif isinstance(scan_result.scan_command, RobotScanCommand):
            res = RobotScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            res.robot_result_enum = scan_result.robot_result_enum
            session.add(res)
            session.commit()

        elif isinstance(scan_result.scan_command, EarlyDataScanCommand):
            res = EarlyDataScanResult()
            res.scan_id = scan_id
            res.target_id = scan_result.server_info.target_id
            res.robot_result_enum = scan_result.is_early_data_supported
            session.add(res)
            session.commit()

    session.commit()
Ejemplo n.º 8
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
    }
Ejemplo n.º 9
0
def main() -> None:
    global global_scanner

    # For py2exe builds
    freeze_support()

    # Handle SIGINT to terminate processes
    signal.signal(signal.SIGINT, sigint_handler)
    start_time = time()

    plugins_repository = PluginsRepository()
    available_plugins = plugins_repository.get_available_plugins()
    available_commands = plugins_repository.get_available_commands()

    # Create the command line parser and the list of available options
    sslyze_parser = CommandLineParser(available_plugins, __version__)
    try:
        good_server_list, malformed_server_list, args_command_list = sslyze_parser.parse_command_line(
        )
    except CommandLineParsingError as e:
        print(e.get_error_msg())
        return

    output_hub = OutputHub()
    output_hub.command_line_parsed(available_plugins, args_command_list,
                                   malformed_server_list)

    # Initialize the pool of processes that will run each plugin
    if args_command_list.https_tunnel or args_command_list.slow_connection:
        # Maximum one process to not kill the proxy or the connection
        global_scanner = ConcurrentScanner(max_processes_nb=1)
    else:
        global_scanner = ConcurrentScanner()

    # Figure out which hosts are up and fill the task queue with work to do
    connectivity_tester = ConcurrentServerConnectivityTester(good_server_list)
    connectivity_tester.start_connectivity_testing()

    # Store and print servers we were able to connect to
    online_servers_list = []
    for server_connectivity_info in connectivity_tester.get_reachable_servers(
    ):
        online_servers_list.append(server_connectivity_info)
        output_hub.server_connectivity_test_succeeded(server_connectivity_info)

        # Send tasks to worker processes
        for scan_command_class in available_commands:
            if getattr(args_command_list,
                       scan_command_class.get_cli_argument()):
                # Get this command's optional argument if there's any
                optional_args = {}
                for optional_arg_name in scan_command_class.get_optional_arguments(
                ):
                    # Was this option set ?
                    if getattr(args_command_list, optional_arg_name):
                        optional_args[optional_arg_name] = getattr(
                            args_command_list, optional_arg_name)
                scan_command = scan_command_class(
                    **optional_args)  # type: ignore

                global_scanner.queue_scan_command(server_connectivity_info,
                                                  scan_command)

    # Store and print servers we were NOT able to connect to
    for connectivity_exception in connectivity_tester.get_invalid_servers():
        output_hub.server_connectivity_test_failed(connectivity_exception)

    # Keep track of how many tasks have to be performed for each target
    task_num = 0
    output_hub.scans_started()
    for scan_command_class in available_commands:
        if getattr(args_command_list, scan_command_class.get_cli_argument()):
            task_num += 1

    # Each host has a list of results
    result_dict: Dict[Text, List[PluginScanResult]] = {}
    # We cannot use the server_info object directly as its address will change due to multiprocessing
    RESULT_KEY_FORMAT = '{hostname}:{ip_address}:{port}'
    for server_info in online_servers_list:
        result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname,
                                             ip_address=server_info.ip_address,
                                             port=server_info.port)] = []

    # Process the results as they come
    for plugin_result in global_scanner.get_results():
        server_info = plugin_result.server_info
        result_dict[RESULT_KEY_FORMAT.format(
            hostname=server_info.hostname,
            ip_address=server_info.ip_address,
            port=server_info.port)].append(plugin_result)

        plugin_result_list = result_dict[RESULT_KEY_FORMAT.format(
            hostname=server_info.hostname,
            ip_address=server_info.ip_address,
            port=server_info.port)]

        if len(plugin_result_list) == task_num:
            # Done with this server; send the result to the output hub
            output_hub.server_scan_completed(
                CompletedServerScan(server_info, plugin_result_list))

    # All done
    exec_time = time() - start_time
    output_hub.scans_completed(exec_time)
Ejemplo n.º 10
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))
def sslyzeScan(threadname, connection, url):

    logfile_connection = 'log/' + scriptname + '-error-connections.log'
    logfile_other = 'log/' + scriptname + '-error-other.log'
    logfile_scan = 'log/' + scriptname + '-error-other.log'

    has_ip = 0
    is_reachable = 0

    has_ip = getIP(url)

    if has_ip:
        try:
            server_tester = ServerConnectivityTester(hostname=url)
            server_info = server_tester.perform()
            is_reachable = 1
        except ServerConnectivityError:
            with open(logfile_connection, 'a') as log:
                log.write('Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                          ', ' + threadname + ': Could not connect to host: ' +
                          url + '\n')
        except Exception:
            with open(logfile_other, 'a') as log:
                log.write('Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                          ', ' + threadname + ': Thrown error for host: ' +
                          url + '\n')
    else:
        with open(logfile_connection, 'a') as log:
            log.write('Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") + ', ' +
                      threadname + ': Could not resolve host: ' + url + '\n')

    if (is_reachable):
        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,
                                              HeartbleedScanCommand())
        concurrent_scanner.queue_scan_command(server_info,
                                              HttpHeadersScanCommand())
        concurrent_scanner.queue_scan_command(server_info,
                                              CertificateInfoScanCommand())

        # Process the 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):
                with open(logfile_scan, 'a') as log:
                    log.write('Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                              ', Scan command failed: {}'.format(
                                  scan_result.as_text()) + '\n')

            if isinstance(scan_result.scan_command, Sslv20ScanCommand):
                ssl_version = "sslv2"
                try:
                    if len(scan_result.accepted_cipher_list) == 0:
                        supports_sslv2 = 0
                    else:
                        supports_sslv2 = 1
                        for cipher in scan_result.accepted_cipher_list:
                            cipher = (u'{}'.format(cipher.name))
                            sql_command = (
                                'insert into ' + tbl_supported_ciphers +
                                '(url,cipher,version) values (%s,%s,%s)')
                            sql_data = (url, cipher, ssl_version)
                            cur0 = connection.cursor()
                            cur0.execute(sql_command, sql_data)
                            connection.commit()
                            cur0.close()
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get sslv2 attributes for host: ' +
                            url + '\n')
                    supports_sslv2 = 0

            if isinstance(scan_result.scan_command, Sslv30ScanCommand):
                ssl_version = "sslv3"
                try:
                    if len(scan_result.accepted_cipher_list) == 0:
                        supports_sslv3 = 0
                    else:
                        supports_sslv3 = 1
                        for cipher in scan_result.accepted_cipher_list:
                            cipher = (u'{}'.format(cipher.name))
                            sql_command = (
                                'insert into ' + tbl_supported_ciphers +
                                '(url,cipher,version) values (%s,%s,%s)')
                            sql_data = (url, cipher, ssl_version)
                            cur0 = connection.cursor()
                            cur0.execute(sql_command, sql_data)
                            connection.commit()
                            cur0.close()
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get sslv3 attributes for host: ' +
                            url + '\n')
                    supports_sslv3 = 0

            if isinstance(scan_result.scan_command, Tlsv10ScanCommand):
                ssl_version = "tlsv10"
                try:
                    if len(scan_result.accepted_cipher_list) == 0:
                        supports_tlsv10 = 0
                    else:
                        supports_tlsv10 = 1
                        for cipher in scan_result.accepted_cipher_list:
                            cipher = (u'{}'.format(cipher.name))
                            sql_command = (
                                'insert into ' + tbl_supported_ciphers +
                                '(url,cipher,version) values (%s,%s,%s)')
                            sql_data = (url, cipher, ssl_version)
                            cur0 = connection.cursor()
                            cur0.execute(sql_command, sql_data)
                            connection.commit()
                            cur0.close()
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get tlsv10 attributes for host: ' +
                            url + '\n')
                    supports_tlsv10 = 0

            if isinstance(scan_result.scan_command, Tlsv11ScanCommand):
                ssl_version = "tlsv11"
                try:
                    if len(scan_result.accepted_cipher_list) == 0:
                        supports_tlsv11 = 0
                    else:
                        supports_tlsv11 = 1
                        for cipher in scan_result.accepted_cipher_list:
                            cipher = (u'{}'.format(cipher.name))
                            sql_command = (
                                'insert into ' + tbl_supported_ciphers +
                                '(url,cipher,version) values (%s,%s,%s)')
                            sql_data = (url, cipher, ssl_version)
                            cur0 = connection.cursor()
                            cur0.execute(sql_command, sql_data)
                            connection.commit()
                            cur0.close()
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get tlsv11 attributes for host: ' +
                            url + '\n')
                    supports_tlsv11 = 0

            if isinstance(scan_result.scan_command, Tlsv12ScanCommand):
                ssl_version = "tlsv12"
                try:
                    if len(scan_result.accepted_cipher_list) == 0:
                        supports_tlsv12 = 0
                    else:
                        supports_tlsv12 = 1
                        for cipher in scan_result.accepted_cipher_list:
                            cipher = (u'{}'.format(cipher.name))
                            sql_command = (
                                'insert into ' + tbl_supported_ciphers +
                                '(url,cipher,version) values (%s,%s,%s)')
                            sql_data = (url, cipher, ssl_version)
                            cur0 = connection.cursor()
                            cur0.execute(sql_command, sql_data)
                            connection.commit()
                            cur0.close()
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get tlsv12 attributes for host: ' +
                            url + '\n')
                    supports_tlsv12 = 0

            if isinstance(scan_result.scan_command, Tlsv13ScanCommand):
                ssl_version = "tlsv13"
                try:
                    if len(scan_result.accepted_cipher_list) == 0:
                        supports_tlsv13 = 0
                    else:
                        supports_tlsv13 = 1
                        for cipher in scan_result.accepted_cipher_list:
                            cipher = (u'{}'.format(cipher.name))
                            sql_command = (
                                'insert into ' + tbl_supported_ciphers +
                                '(url,cipher,version) values (%s,%s,%s)')
                            sql_data = (url, cipher, ssl_version)
                            cur0 = connection.cursor()
                            cur0.execute(sql_command, sql_data)
                            connection.commit()
                            cur0.close()
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get tlsv13 attributes for host: ' +
                            url + '\n')
                    supports_tlsv13 = 0

            if isinstance(scan_result.scan_command, HeartbleedScanCommand):
                vulnerable_heartbleed = 0
                try:
                    if (scan_result.is_vulnerable_to_heartbleed):
                        vulnerable_heartbleed = 1
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get heartbleed attribute for host: ' +
                            url + '\n')
                    vulnerable_heartbleed = 0

            if isinstance(scan_result.scan_command, HttpHeadersScanCommand):
                hsts_preload_set = 0
                hsts_include_subdomains_set = 0
                hsts_max_age_set = 0
                hsts_supported = 0
                hpkp_supported = 0

                try:
                    if (scan_result.hsts_header):
                        hsts_supported = 1
                        if (scan_result.hsts_header.preload):
                            hsts_preload_set = 1
                        if (scan_result.hsts_header.include_subdomains
                            ) == True:
                            hsts_include_subdomains_set = 1
                        hsts_max_age_set = scan_result.hsts_header.max_age
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get hsts attributes for host: ' +
                            url + '\n')
                    hsts_preload_set = 0
                    hsts_include_subdomains_set = 0
                    hsts_max_age_set = 0
                    hsts_supported = 0

                try:
                    if (scan_result.hpkp_header):
                        hpkp_supported = 1
                except AttributeError:
                    hpkp_supported = 0

            if isinstance(scan_result.scan_command,
                          CertificateInfoScanCommand):
                chain_is_trusted = 0
                try:
                    if (scan_result.verified_certificate_chain):
                        chain_is_trusted = 1
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get hpkp attributes for host: ' +
                            url + '\n')
                    chain_is_trusted = 0

                cert_matches_hostname = 0
                cert_is_ev = False
                try:
                    CertificateUtils.matches_hostname(
                        scan_result.certificate_chain[0],
                        server_info.tls_server_name_indication)
                    cert_matches_hostname = 1
                except CertificateError:
                    cert_matches_hostname = 0
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get certificate_chain attribute for host: '
                            + url + '\n')
                try:
                    cert_is_ev = TrustStoresRepository.get_default(
                    ).get_main_store().is_extended_validation(
                        scan_result.certificate_chain[0])
                except AttributeError:
                    with open(logfile_scan, 'a') as log:
                        log.write(
                            'Error, ' + time.strftime("%Y-%m-%d %H:%M:%S") +
                            ', ' + threadname +
                            ': Could not get extended_validation attribute for host: '
                            + url + '\n')

        sql_cmd = (
            'insert into ' + tbl_ssl_options +
            '(url,heartbleed_vulnerable,hsts_supported,hsts_preload_set,hsts_include_subdomains_set,hsts_max_age_set,hpkp_supported,chain_is_trusted,match_hostname,is_ev,sslv2,sslv3,tlsv10,tlsv11,tlsv12,tlsv13) values (%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s)'
        )
        sql_dat = (url, vulnerable_heartbleed, hsts_supported,
                   hsts_preload_set, hsts_include_subdomains_set,
                   hsts_max_age_set, hpkp_supported, chain_is_trusted,
                   cert_matches_hostname, cert_is_ev, supports_sslv2,
                   supports_sslv3, supports_tlsv10, supports_tlsv11,
                   supports_tlsv12, supports_tlsv13)
        cur = connection.cursor()
        cur.execute(sql_cmd, sql_dat)
        connection.commit()
        cur.close()
Ejemplo n.º 12
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)
Ejemplo n.º 13
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)
Ejemplo n.º 14
0
def scan(targets: List[object_models.TargetWithExtra],
         command_names: Optional[str] = None) -> List[ScanResult]:
    logger.info(
        f"SC0002 New scan initiated with sslyze version {sslyze_version} for target {targets}"
    )

    if command_names is None:
        commands = scan_commands.from_names_to_scan_commands(
            SslyzeConfig.limit_scan_to_scan_commands_names)
    else:
        commands = scan_commands.from_names_to_scan_commands(command_names)

    domain_results = []

    for target in targets:
        domain_result = ScanResult(target)

        try:
            server_tester = ServerConnectivityTester(
                hostname=target.target_definition.hostname,
                port=target.target_definition.port,
                ip_address=target.target_definition.ip_address,
                tls_wrapped_protocol=target.target_definition.protocol)

            server_info = server_tester.perform(
                network_timeout=connectivity_timeout)
        except ServerConnectivityError as e:
            error_msg = f"NT0001 Cannot establish connectivity to target {target} with error {e}"
            logger.warning(error_msg)
            domain_result.msg += error_msg + '\n'
            domain_results.append(domain_result)
            continue
        except Exception as e:
            error_msg = f"NT0002 Unknown exception in establishing connection to target {target} with error {e}"
            logger.warning(error_msg)
            domain_result.msg += error_msg + '\n'
            domain_results.append(domain_result)
            continue

        scan_results = set()

        if SslyzeConfig.asynchronous_scanning:
            logger.debug("Using SSLyze asynchronous scanner")
            scanner = ConcurrentScanner(
                network_timeout=scanner_plugin_network_timeout)
            for scan_command in commands:
                scanner.queue_scan_command(server_info, scan_command())

            for scan_result in scanner.get_results():
                # todo: put some error msg to db
                # todo: handle errors, maybe already solved by PluginRaisedExceptionScanResult
                scan_results.add(scan_result)

        else:
            logger.debug("Using SSLyze synchronous scanner")
            scanner = SynchronousScanner(
                network_timeout=scanner_plugin_network_timeout)
            for scan_command in commands:
                try:
                    scan_result = scanner.run_scan_command(
                        server_info, scan_command())
                    scan_results.add(scan_result)
                except Exception as e:
                    # todo: put some error msg to db
                    # todo: handle errors, maybe already solved by PluginRaisedExceptionScanResult
                    logger.exception(e)

        for scan_result in scan_results:
            scan_command_title = scan_result.scan_command.get_title()

            if isinstance(scan_result, PluginRaisedExceptionScanResult):
                error_msg = f"SC0003 Scan command failed: {target}, {scan_result.as_text()}"
                domain_result.msg += error_msg + '\n'
                logger.warning(error_msg)
                continue

            scan_result_dicts = scan_result_to_dicts(scan_result)
            domain_result.plugin_results[
                scan_command_title] = scan_result_dicts[1]
            domain_result.server_info = scan_result_dicts[0]

        domain_results.append(domain_result)

    return domain_results
Ejemplo n.º 15
0
def main():
    global global_scanner

    # For py2exe builds
    freeze_support()

    # Handle SIGINT to terminate processes
    signal.signal(signal.SIGINT, sigint_handler)
    start_time = time()

    plugins_repository = PluginsRepository()
    available_plugins = plugins_repository.get_available_plugins()
    available_commands = plugins_repository.get_available_commands()

    # Create the command line parser and the list of available options
    sslyze_parser = CommandLineParser(available_plugins, __version__)
    try:
        good_server_list, bad_server_list, args_command_list = sslyze_parser.parse_command_line()
    except CommandLineParsingError as e:
        print(e.get_error_msg())
        return

    output_hub = OutputHub()
    output_hub.command_line_parsed(available_plugins, args_command_list)


    # Initialize the pool of processes that will run each plugin
    if args_command_list.https_tunnel:
        # Maximum one process to not kill the proxy
        global_scanner  = ConcurrentScanner(args_command_list.nb_retries, args_command_list.timeout, max_processes_nb=1)
    else:
        global_scanner = ConcurrentScanner(args_command_list.nb_retries, args_command_list.timeout)


    # Figure out which hosts are up and fill the task queue with work to do
    connectivity_tester = ServersConnectivityTester(good_server_list)
    connectivity_tester.start_connectivity_testing(network_timeout=args_command_list.timeout)

    # Store and print server whose command line string was bad
    for failed_scan in bad_server_list:
        output_hub.server_connectivity_test_failed(failed_scan)

    # Store and print servers we were able to connect to
    online_servers_list = []
    for server_connectivity_info in connectivity_tester.get_reachable_servers():
        online_servers_list.append(server_connectivity_info)
        output_hub.server_connectivity_test_succeeded(server_connectivity_info)

        # Send tasks to worker processes
        for scan_command_class in available_commands:
            if getattr(args_command_list, scan_command_class.get_cli_argument()):
                # Get this command's optional argument if there's any
                optional_args = {}
                for optional_arg_name in scan_command_class.get_optional_arguments():
                    # Was this option set ?
                    if getattr(args_command_list, optional_arg_name):
                        optional_args[optional_arg_name] = getattr(args_command_list, optional_arg_name)
                scan_command = scan_command_class(**optional_args)

                global_scanner.queue_scan_command(server_connectivity_info, scan_command)


    # Store and print servers we were NOT able to connect to
    for tentative_server_info, exception in connectivity_tester.get_invalid_servers():
        failed_scan = FailedServerScan(tentative_server_info.server_string, exception)
        output_hub.server_connectivity_test_failed(failed_scan)


    # Keep track of how many tasks have to be performed for each target
    task_num = 0
    output_hub.scans_started()
    for scan_command_class in available_commands:
        if getattr(args_command_list, scan_command_class.get_cli_argument()):
            task_num += 1


    # Each host has a list of results
    result_dict = {}
    # We cannot use the server_info object directly as its address will change due to multiprocessing
    RESULT_KEY_FORMAT = '{hostname}:{ip_address}:{port}'
    for server_info in online_servers_list:
        result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address,
                                             port=server_info.port)] = []

    # Process the results as they come
    for plugin_result in global_scanner.get_results():
        server_info = plugin_result.server_info
        result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname, ip_address=server_info.ip_address,
                                             port=server_info.port)].append(plugin_result)

        plugin_result_list = result_dict[RESULT_KEY_FORMAT.format(hostname=server_info.hostname,
                                                                  ip_address=server_info.ip_address,
                                                                  port=server_info.port)]

        if len(plugin_result_list) == task_num:
            # Done with this server; send the result to the output hub
            output_hub.server_scan_completed(CompletedServerScan(server_info, plugin_result_list))

    # All done
    exec_time = time()-start_time
    output_hub.scans_completed(exec_time)
Ejemplo n.º 16
0
            hostname, e.error_msg))

    # Example 1: Run one scan command synchronously to list the server's TLS 1.0 cipher suites
    print('\nRunning one scan command synchronously...')
    synchronous_scanner = SynchronousScanner()
    command = Tlsv10ScanCommand()
    scan_result = synchronous_scanner.run_scan_command(server_info, command)
    for cipher in scan_result.accepted_cipher_list:
        print('    {}'.format(cipher.name))

    # Example 2: Run multiple scan commands concurrently. It is of course much faster than the SynchronousScanner
    concurrent_scanner = ConcurrentScanner()

    # Queue some scan commands
    print('\nQueuing some commands...')
    concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand())
    concurrent_scanner.queue_scan_command(server_info,
                                          SessionRenegotiationScanCommand())
    concurrent_scanner.queue_scan_command(server_info,
                                          CertificateInfoScanCommand())

    # Process the results
    reneg_result = None
    print('\nProcessing results...')
    for scan_result in concurrent_scanner.get_results():
        # All scan results have the corresponding scan_command and server_info as an attribute
        print('\nReceived scan result for {} on host {}'.format(
            scan_result.scan_command.__class__.__name__,
            scan_result.server_info.hostname))

        # Sometimes a scan command can unexpectedly fail (as a bug); it is returned as a PluginRaisedExceptionResult
Ejemplo n.º 17
0
    # Example 1: Run one scan command synchronously to list the server's TLS 1.0 cipher suites
    print('\nRunning one scan command synchronously...')
    synchronous_scanner = SynchronousScanner()
    command = Tlsv10ScanCommand()
    scan_result = synchronous_scanner.run_scan_command(server_info, command)
    for cipher in scan_result.accepted_cipher_list:
        print('    {}'.format(cipher.name))


    # Example 2: Run multiple scan commands concurrently. It is of course much faster than the SynchronousScanner
    concurrent_scanner = ConcurrentScanner()

    # Queue some scan commands
    print('\nQueuing some commands...')
    concurrent_scanner.queue_scan_command(server_info, Tlsv12ScanCommand())
    concurrent_scanner.queue_scan_command(server_info, SessionRenegotiationScanCommand())
    concurrent_scanner.queue_scan_command(server_info, CertificateInfoScanCommand())

    # Process the results
    reneg_result = None
    print('\nProcessing results...')
    for scan_result in concurrent_scanner.get_results():
        # All scan results have the corresponding scan_command and server_info as an attribute
        print('\nReceived scan result for {} on host {}'.format(scan_result.scan_command.__class__.__name__,
                                                                 scan_result.server_info.hostname))

        # Sometimes a scan command can unexpectedly fail (as a bug); it is returned as a PluginRaisedExceptionResult
        if isinstance(scan_result, PluginRaisedExceptionScanResult):
            raise RuntimeError('Scan command failed: {}'.format(scan_result.as_text()))