Ejemplo n.º 1
0
    def do_ssl2_iis_handshake(self) -> None:
        if self._sock is None:
            # TODO: Auto create a socket ?
            raise IOError(
                'Internal socket set to None; cannot perform handshake.')

        while True:
            try:
                self._ssl.do_handshake()
                self._is_handshake_completed = True
                # Handshake was successful
                return

            except WantReadError:
                # OpenSSL is expecting more data from the peer
                # Send available handshake data to the peer
                lengh_to_read = self._network_bio.pending()
                while lengh_to_read:
                    # Get the data from the SSL engine
                    handshake_data_out = self._network_bio.read(lengh_to_read)

                    if 'SSLv2 read server verify A' in self._ssl.state_string_long(
                    ):
                        # Awful h4ck for SSLv2 when connecting to IIS7 (like in the 90s)
                        # OpenSSL sends the client's CMK and data message in the same packet without
                        # waiting for the server's response, causing IIS 7 to hang on the connection.
                        # This workaround forces our client to send the CMK message, then wait for the server's
                        # response, and then send the data packet
                        # if '\x02' in handshake_data_out[2]:  # Make sure we're looking at the CMK message
                        message_type = handshake_data_out[2]
                        IS_PYTHON_2 = sys.version_info < (3, 0)
                        if IS_PYTHON_2:
                            message_type = ord(message_type)

                        if message_type == 2:  # Make sure we're looking at the CMK message
                            # cmk_size = handshake_data_out[0:2]
                            if IS_PYTHON_2:
                                first_byte = ord(handshake_data_out[0])
                                second_byte = ord(handshake_data_out[1])
                            else:
                                first_byte = int(handshake_data_out[0])
                                second_byte = int(handshake_data_out[1])
                            first_byte = (first_byte & 0x7f) << 8
                            size = first_byte + second_byte
                            # Manually split the two records to force them to be sent separately
                            cmk_packet = handshake_data_out[0:size + 2]
                            data_packet = handshake_data_out[size + 2::]
                            self._sock.send(cmk_packet)

                            handshake_data_in = self._sock.recv(
                                self._DEFAULT_BUFFER_SIZE)
                            # print repr(handshake_data_in)
                            if len(handshake_data_in) == 0:
                                raise IOError(
                                    'Nassl SSL handshake failed: peer did not send data back.'
                                )
                            # Pass the data to the SSL engine
                            self._network_bio.write(handshake_data_in)
                            handshake_data_out = data_packet

                    # Send it to the peer
                    self._sock.send(handshake_data_out)
                    lengh_to_read = self._network_bio.pending()

                handshake_data_in = self._sock.recv(self._DEFAULT_BUFFER_SIZE)
                if len(handshake_data_in) == 0:
                    raise IOError(
                        'Nassl SSL handshake failed: peer did not send data back.'
                    )
                # Pass the data to the SSL engine
                self._network_bio.write(handshake_data_in)

            except WantX509LookupError:
                # Server asked for a client certificate and we didn't provide one
                raise ClientCertificateRequested(self.get_client_CA_list())
Ejemplo n.º 2
0
def _send_robot_payload(
    server_info: ServerConnectivityInfo,
    tls_version_to_use: TlsVersionEnum,
    rsa_cipher_string: str,
    robot_payload_enum: RobotPmsPaddingPayloadEnum,
    robot_should_finish_handshake: bool,
    rsa_modulus: int,
    rsa_exponent: int,
) -> str:
    # Do a handshake which each record and keep track of what the server returned
    ssl_connection = server_info.get_preconfigured_tls_connection(
        override_tls_version=tls_version_to_use)

    # Replace nassl.sslClient.do_handshake() with a ROBOT checking SSL handshake so that all the SSLyze
    # options (startTLS, proxy, etc.) still work
    ssl_connection.ssl_client.do_handshake = types.MethodType(  # type: ignore
        do_handshake_with_robot, ssl_connection.ssl_client)
    ssl_connection.ssl_client.set_cipher_list(rsa_cipher_string)

    # Compute the  payload
    tls_parser_tls_version: tls_parser.tls_version.TlsVersionEnum
    if tls_version_to_use == TlsVersionEnum.SSL_3_0:
        tls_parser_tls_version = tls_parser.tls_version.TlsVersionEnum.SSLV3
    elif tls_version_to_use == TlsVersionEnum.TLS_1_0:
        tls_parser_tls_version = tls_parser.tls_version.TlsVersionEnum.TLSV1
    elif tls_version_to_use == TlsVersionEnum.TLS_1_1:
        tls_parser_tls_version = tls_parser.tls_version.TlsVersionEnum.TLSV1_1
    elif tls_version_to_use == TlsVersionEnum.TLS_1_2:
        tls_parser_tls_version = tls_parser.tls_version.TlsVersionEnum.TLSV1_2
    else:
        raise ValueError("Should never happen")

    cke_payload = _RobotTlsRecordPayloads.get_client_key_exchange_record(
        robot_payload_enum, tls_parser_tls_version, rsa_modulus, rsa_exponent)

    # H4ck: we need to pass some arguments to the handshake but there is no simple way to do it; we use an attribute
    ssl_connection.ssl_client._robot_cke_record = cke_payload  # type: ignore
    ssl_connection.ssl_client._robot_should_finish_handshake = robot_should_finish_handshake  # type: ignore

    server_response = ""
    try:
        # Start the SSL handshake
        ssl_connection.connect()
    except ServerResponseToRobot as e:
        # Should always be thrown
        server_response = e.server_response
    except socket.timeout:
        # https://github.com/nabla-c0d3/sslyze/issues/361
        server_response = "Connection timed out"
    except ServerRejectedTlsHandshake:
        if server_info.tls_probing_result.client_auth_requirement != ClientAuthRequirementEnum.DISABLED:
            # This error happens when scanning an nginx server with client authentication required;
            # If the server asks for a client cert, we cannot check for ROBOT as the check needs to complete full
            # handshakes. https://github.com/nabla-c0d3/sslyze/issues/484
            raise ClientCertificateRequested(ca_list=[])
        else:
            raise
    finally:
        ssl_connection.close()

    return server_response