Exemple #1
0
def get_cbt_data(response):
    """
    Create Channel Binding for TLS data

    See:
      - https://tools.ietf.org/html/rfc5929
      - https://github.com/jborean93/ntlm-auth#ntlmv2
      - https://github.com/requests/requests-ntlm/pull/116#discussion_r325961121
      - https://support.microsoft.com/en-za/help/976918/authentication-failure-from-non-windows-ntlm-or-kerberos-servers  # noqa

    :param response: HTTP Response object
    """

    cert_hash_bytes = get_server_cert(response)
    if not cert_hash_bytes:
        logger.debug("server cert not found, channel binding tokens (CBT) wont be used")
        return None

    channel_binding_type = b"tls-server-end-point"  # https://tools.ietf.org/html/rfc5929#section-4
    data_type = GssChannelBindingsStruct.APPLICATION_DATA

    cbt_data = GssChannelBindingsStruct()
    cbt_data[data_type] = b":".join([channel_binding_type, cert_hash_bytes])
    logger.debug("cbt data: %s", cbt_data.get_data())
    return cbt_data
Exemple #2
0
    def _get_channel_bindings_value(server_certificate_hash):
        """
        Get's the MD5 hash of the gss_channel_bindings_struct to add to the
        AV_PAIR MSV_AV_CHANNEL_BINDINGS. This method takes in the SHA256 hash
        (Hash of the DER encoded certificate of the server we are connecting
        to) and add's it to the gss_channel_bindings_struct. It then gets the
        MD5 hash and converts this to a byte array in preparation of adding it
        to the AV_PAIR structure.

        :param server_certificate_hash: The SHA256 hash of the server
            certificate (DER encoded) NTLM is authenticated to
        :return channel_bindings: An MD5 hash of the
            gss_channel_bindings_struct to add to the AV_PAIR
            MsvChannelBindings
        """
        # Channel Binding Tokens support, used for NTLMv2
        # Decode the SHA256 certificate hash
        certificate_digest = base64.b16decode(server_certificate_hash)

        # Initialise the GssChannelBindingsStruct and add the
        # certificate_digest to the application_data field
        gss_channel_bindings = GssChannelBindingsStruct()
        gss_channel_bindings[gss_channel_bindings.APPLICATION_DATA] = \
            b'tls-server-end-point:' + certificate_digest

        # Get the gss_channel_bindings_struct and create an MD5 hash
        channel_bindings_struct_data = gss_channel_bindings.get_data()
        channel_bindings = hashlib.md5(channel_bindings_struct_data).digest()

        return channel_bindings
    def _get_channel_bindings_value(server_certificate_hash):
        """
        https://msdn.microsoft.com/en-us/library/windows/desktop/dd919963%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
        https://blogs.msdn.microsoft.com/openspecification/2013/03/26/ntlm-and-channel-binding-hash-aka-extended-protection-for-authentication/

        Get's the MD5 hash of the gss_channel_bindings_struct to add to the AV_PAIR MSV_AV_CHANNEL_BINDINGS.
        This method takes in the SHA256 hash (Hash of the DER encoded certificate of the server we are connecting to)
        and add's it to the gss_channel_bindings_struct. It then gets the MD5 hash and converts this to a
        byte array in preparation of adding it to the AV_PAIR structure.

        :param server_certificate_hash: The SHA256 hash of the server certificate (DER encoded) NTLM is authenticated to
        :return channel_bindings: An MD5 hash of the gss_channel_bindings_struct to add to the AV_PAIR MsvChannelBindings
        """
        # Channel Binding Tokens support, used for NTLMv2
        # Decode the SHA256 certificate hash
        certificate_digest = base64.b16decode(server_certificate_hash)

        # Initialise the GssChannelBindingsStruct and add the certificate_digest to the application_data field
        gss_channel_bindings = GssChannelBindingsStruct()
        gss_channel_bindings[gss_channel_bindings.APPLICATION_DATA] = 'tls-server-end-point:'.encode() + certificate_digest

        # Get the gss_channel_bindings_struct and create an MD5 hash
        channel_bindings_struct_data = gss_channel_bindings.get_data()
        channel_bindings_hash = hashlib.md5(channel_bindings_struct_data).hexdigest()

        try:
            cbt_value = bytearray.fromhex(channel_bindings_hash)
        except TypeError:
            # Work-around for Python 2.6 bug
            cbt_value = bytearray.fromhex(unicode(channel_bindings_hash))

        channel_bindings = bytes(cbt_value)
        return channel_bindings
Exemple #4
0
 def test_application_data(self):
     struct = GssChannelBindingsStruct()
     struct[GssChannelBindingsStruct.APPLICATION_DATA] = b"abc"
     expected = b"\x00\x00\x00\x00" \
                b"\x00\x00\x00\x00" \
                b"\x00\x00\x00\x00" \
                b"\x00\x00\x00\x00" \
                b"\x03\x00\x00\x00" \
                b"\x61\x62\x63"
     actual = struct.get_data()
     assert actual == expected
Exemple #5
0
 def init_context(self):
     cbt_struct = None
     if self.cbt_app_data:
         cbt_struct = GssChannelBindingsStruct()
         cbt_struct[cbt_struct.APPLICATION_DATA] = self.cbt_app_data
     self._context = NtlmContext(self.username, self.password, self.domain,
                                 cbt_data=cbt_struct)
Exemple #6
0
 def test_full_data(self):
     struct = GssChannelBindingsStruct()
     struct[GssChannelBindingsStruct.INITIATOR_ADDTYPE] = 2
     struct[GssChannelBindingsStruct.INITIATOR_ADDRESS] = b"abc"
     struct[GssChannelBindingsStruct.ACCEPTOR_ADDRTYPE] = 4
     struct[GssChannelBindingsStruct.ACCEPTOR_ADDRESS] = b"def"
     struct[GssChannelBindingsStruct.APPLICATION_DATA] = b"ghi"
     expected = b"\x02\x00\x00\x00" \
                b"\x03\x00\x00\x00" \
                b"\x61\x62\x63" \
                b"\x04\x00\x00\x00" \
                b"\x03\x00\x00\x00" \
                b"\x64\x65\x66" \
                b"\x03\x00\x00\x00" \
                b"\x67\x68\x69"
     actual = struct.get_data()
     assert actual == expected
    def _get_channel_bindings_value(server_certificate_hash):
        """
        https://msdn.microsoft.com/en-us/library/windows/desktop/dd919963%28v=vs.85%29.aspx?f=255&MSPPError=-2147217396
        https://blogs.msdn.microsoft.com/openspecification/2013/03/26/ntlm-and-channel-binding-hash-aka-extended-protection-for-authentication/

        Get's the MD5 hash of the gss_channel_bindings_struct to add to the AV_PAIR MSV_AV_CHANNEL_BINDINGS.
        This method takes in the SHA256 hash (Hash of the DER encoded certificate of the server we are connecting to)
        and add's it to the gss_channel_bindings_struct. It then gets the MD5 hash and converts this to a
        byte array in preparation of adding it to the AV_PAIR structure.

        :param server_certificate_hash: The SHA256 hash of the server certificate (DER encoded) NTLM is authenticated to
        :return channel_bindings: An MD5 hash of the gss_channel_bindings_struct to add to the AV_PAIR MsvChannelBindings
        """
        # Channel Binding Tokens support, used for NTLMv2
        # Decode the SHA256 certificate hash
        certificate_digest = base64.b16decode(server_certificate_hash)

        # Initialise the GssChannelBindingsStruct and add the certificate_digest to the application_data field
        gss_channel_bindings = GssChannelBindingsStruct()
        gss_channel_bindings[
            gss_channel_bindings.
            APPLICATION_DATA] = 'tls-server-end-point:'.encode(
            ) + certificate_digest

        # Get the gss_channel_bindings_struct and create an MD5 hash
        channel_bindings_struct_data = gss_channel_bindings.get_data()
        channel_bindings_hash = hashlib.md5(
            channel_bindings_struct_data).hexdigest()

        try:
            cbt_value = bytearray.fromhex(channel_bindings_hash)
        except TypeError:
            # Work-around for Python 2.6 bug
            cbt_value = bytearray.fromhex(unicode(channel_bindings_hash))

        channel_bindings = bytes(cbt_value)
        return channel_bindings
Exemple #8
0
    def retry_with_ntlm_auth(self, auth_header_field, auth_header, response,
                             auth_type, args):
        try:
            cert_hash = self._get_server_cert(response)
            cbt_data = GssChannelBindingsStruct()
            cbt_data[cbt_data.APPLICATION_DATA] = b"tls-server-end-point:" + \
                                                  base64.b16decode(cert_hash)
        except Exception:
            cbt_data = None

        context = NtlmContext(self.username,
                              self.password,
                              self.domain,
                              cbt_data=cbt_data,
                              ntlm_compatibility=self.ntlm_compatibility)

        # Consume the original response contents and release the connection for
        # later
        response.content
        response.raw.release_conn()

        # Create the negotiate request
        msg1_req = response.request.copy()
        msg1 = context.step()
        msg1_header = "%s %s" % (auth_type, base64.b64encode(msg1).decode())
        msg1_req.headers[auth_header] = msg1_header

        # Send the negotiate request and receive the challenge message
        disable_stream_args = dict(args, stream=False)
        msg2_resp = response.connection.send(msg1_req, **disable_stream_args)
        msg2_resp.content
        msg2_resp.raw.release_conn()

        # Parse the challenge response in the ntlm_context
        msg2_header = msg2_resp.headers[auth_header_field]
        msg2 = msg2_header.replace(auth_type + ' ', '')
        msg3 = context.step(base64.b64decode(msg2))

        # Create the authenticate request
        msg3_req = msg2_resp.request.copy()
        msg3_header = auth_type + ' ' + base64.b64encode(msg3).decode()
        msg3_req.headers[auth_header] = msg3_header

        # Send the authenticate request
        final_response = msg2_resp.connection.send(msg3_req, **args)
        final_response.history.append(response)
        final_response.history.append(msg2_resp)

        return final_response
Exemple #9
0
    def _create_auth1_message_ntlm(self, domain, user, pw, certificate):
        domain = domain or None
        workstation = None
        cbt_data = None
        ntlm_compatibility = 1

        if certificate is not None:
            ntlm_compatibility = 3

            cbt_data = GssChannelBindingsStruct()
            cbt_data[cbt_data.APPLICATION_DATA] = \
              b'tls-server-end-point:' + hashlib.sha256(
                  certificate).digest()

        self._ctx = NtlmContext(user, pw, domain, workstation, cbt_data,
                                ntlm_compatibility)

        payload = b64encode(self._ctx.step()).decode('ascii')

        self._method = METHOD_NTLM

        return Result(True, self._method, payload)
    def get_nt_challenge_response(self,
                                  lm_challenge_response,
                                  server_certificate_hash=None,
                                  cbt_data=None):
        """
        [MS-NLMP] v28.0 2016-07-14

        3.3.1 - NTLM v1 Authentication
        3.3.2 - NTLM v2 Authentication

        This method returns the NtChallengeResponse key based on the
        ntlm_compatibility chosen and the target_info supplied by the
        CHALLENGE_MESSAGE. It is quite different from what is set in the
        document as it combines the NTLMv1, NTLM2 and NTLMv2 methods into one
        and calls separate methods based on the ntlm_compatibility value
        chosen.

        :param lm_challenge_response: The LmChallengeResponse calculated
            beforehand, used to get the key_exchange_key value
        :param server_certificate_hash: This is deprecated and will be removed
            in a future version, use cbt_data instead
        :param cbt_data: The GssChannelBindingsStruct to bind in the NTLM
            response
        :return response: (NtChallengeResponse) - The NT response to the server
            challenge. Computed by the client
        :return session_base_key: (SessionBaseKey) - A session key calculated
            from the user password challenge
        :return target_info: (AV_PAIR) - The AV_PAIR structure used in the
            nt_challenge calculations
        """
        if self._negotiate_flags & \
                NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY and \
                self._ntlm_compatibility < 3:
            # The compatibility level is less than 3 which means it doesn't
            # support NTLMv2 but we want extended security so use NTLM2 which
            # is different from NTLMv2
            # [MS-NLMP] - 3.3.1 NTLMv1 Authentication
            response, session_base_key = \
                self._get_NTLM2_response(self._password,
                                         self._server_challenge,
                                         self._client_challenge)
            lm_hash = comphash._lmowfv1(self._password)
            key_exchange_key = \
                compkeys._get_exchange_key_ntlm_v1(self._negotiate_flags,
                                                   session_base_key,
                                                   self._server_challenge,
                                                   lm_challenge_response,
                                                   lm_hash)
            target_info = None

        elif 0 <= self._ntlm_compatibility < 3:
            response, session_base_key = \
                self._get_NTLMv1_response(self._password,
                                          self._server_challenge)

            lm_hash = comphash._lmowfv1(self._password)
            key_exchange_key = \
                compkeys._get_exchange_key_ntlm_v1(self._negotiate_flags,
                                                   session_base_key,
                                                   self._server_challenge,
                                                   lm_challenge_response,
                                                   lm_hash)
            target_info = None

        else:
            if self._server_target_info is None:
                target_info = ntlm_auth.messages.TargetInfo()
            else:
                target_info = self._server_target_info

            if target_info[AvId.MSV_AV_TIMESTAMP] is None:
                timestamp = get_windows_timestamp()
            else:
                timestamp = target_info[AvId.MSV_AV_TIMESTAMP]

                # [MS-NLMP] If the CHALLENGE_MESSAGE TargetInfo field has an
                # MsvAvTimestamp present, the client SHOULD provide a MIC
                target_info[AvId.MSV_AV_FLAGS] = \
                    struct.pack("<L", AvFlags.MIC_PROVIDED)

            if server_certificate_hash is not None and cbt_data is None:
                warnings.warn(
                    "Manually creating the cbt stuct from the cert "
                    "hash will be removed in a newer version of "
                    "ntlm-auth. Send the actual CBT struct using "
                    "cbt_data instead", DeprecationWarning)
                certificate_digest = base64.b16decode(server_certificate_hash)

                cbt_data = GssChannelBindingsStruct()
                cbt_data[cbt_data.APPLICATION_DATA] = \
                    b'tls-server-end-point:' + certificate_digest

            if cbt_data is not None:
                cbt_bytes = cbt_data.get_data()
                cbt_hash = hashlib.md5(cbt_bytes).digest()
                target_info[AvId.MSV_AV_CHANNEL_BINDINGS] = cbt_hash

            response, session_base_key = \
                self._get_NTLMv2_response(self._user_name, self._password,
                                          self._domain_name,
                                          self._server_challenge,
                                          self._client_challenge,
                                          timestamp, target_info)

            key_exchange_key = \
                compkeys._get_exchange_key_ntlm_v2(session_base_key)

        return response, key_exchange_key, target_info
Exemple #11
0
    def test_ntlm_context_with_mic(self, monkeypatch):
        monkeypatch.setattr('os.urandom', lambda s: b"\xaa" * 8)
        monkeypatch.setattr('ntlm_auth.messages.get_version',
                            lambda s: b"\x05\x01\x28\x0A\x00\x00\x00\x0F")
        monkeypatch.setattr('ntlm_auth.messages.get_random_export_session_key',
                            lambda: b"\x55" * 16)
        monkeypatch.setattr('ntlm_auth.compute_response.get_windows_timestamp',
                            lambda: b"\x00" * 8)

        ch = 'E3CA49271E5089CC48CE82109F1324F41DBEDDC29A777410C738F7868C4FF405'
        cbt_data = GssChannelBindingsStruct()
        cbt_data[cbt_data.APPLICATION_DATA] = b"tls-server-end-point:" + \
                                              base64.b16decode(ch)
        ntlm_context = NtlmContext("User",
                                   "Password",
                                   "Domain",
                                   "COMPUTER",
                                   cbt_data=cbt_data)
        ntlm_context.reset_rc4_state(
        )  # Verifies it won't fail when the session security isn't set up.

        actual_nego = ntlm_context.step()
        expected_nego = b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" \
                        b"\x01\x00\x00\x00\x31\xb0\x88\xe2" \
                        b"\x06\x00\x06\x00\x28\x00\x00\x00" \
                        b"\x08\x00\x08\x00\x2e\x00\x00\x00" \
                        b"\x05\x01\x28\x0a\x00\x00\x00\x0f" \
                        b"\x44\x6f\x6d\x61\x69\x6e\x43\x4f" \
                        b"\x4d\x50\x55\x54\x45\x52"
        assert actual_nego == expected_nego
        assert not ntlm_context.mic_present
        assert not ntlm_context.complete

        challenge_msg = b"\x4E\x54\x4C\x4D\x53\x53\x50\x00" \
                        b"\x02\x00\x00\x00\x00\x00\x00\x00" \
                        b"\x38\x00\x00\x00\x33\x82\x8A\xE2" \
                        b"\x01\x23\x45\x67\x89\xAB\xCD\xEF" \
                        b"\x00\x00\x00\x00\x00\x00\x00\x00" \
                        b"\x30\x00\x30\x00\x38\x00\x00\x00" \
                        b"\x06\x01\xB1\x1D\x00\x00\x00\x0F" \
                        b"\x02\x00\x0C\x00\x44\x00\x6F\x00" \
                        b"\x6D\x00\x61\x00\x69\x00\x6E\x00" \
                        b"\x01\x00\x0C\x00\x53\x00\x65\x00" \
                        b"\x72\x00\x76\x00\x65\x00\x72\x00" \
                        b"\x07\x00\x08\x00\x00\x00\x00\x00" \
                        b"\x00\x00\x00\x00\x00\x00\x00\x00"
        actual_auth = ntlm_context.step(challenge_msg)
        expected_auth = b'\x4E\x54\x4C\x4D\x53\x53\x50\x00' \
                        b'\x03\x00\x00\x00\x18\x00\x18\x00' \
                        b'\x7C\x00\x00\x00\x7C\x00\x7C\x00' \
                        b'\x94\x00\x00\x00\x0C\x00\x0C\x00' \
                        b'\x58\x00\x00\x00\x08\x00\x08\x00' \
                        b'\x64\x00\x00\x00\x10\x00\x10\x00' \
                        b'\x6C\x00\x00\x00\x10\x00\x10\x00' \
                        b'\x10\x01\x00\x00\x31\x82\x8A\xE2' \
                        b'\x05\x01\x28\x0A\x00\x00\x00\x0F' \
                        b'\xC4\x45\x2C\xF7\xA8\x1E\x4D\x11' \
                        b'\xD0\x78\x18\x94\x09\x57\x5D\x9E' \
                        b'\x44\x00\x6F\x00\x6D\x00\x61\x00' \
                        b'\x69\x00\x6E\x00\x55\x00\x73\x00' \
                        b'\x65\x00\x72\x00\x43\x00\x4F\x00' \
                        b'\x4D\x00\x50\x00\x55\x00\x54\x00' \
                        b'\x45\x00\x52\x00\x00\x00\x00\x00' \
                        b'\x00\x00\x00\x00\x00\x00\x00\x00' \
                        b'\x00\x00\x00\x00\x00\x00\x00\x00' \
                        b'\x00\x00\x00\x00\xA1\x3D\x03\x8A' \
                        b'\xD0\xCA\x02\x64\x33\x89\x7C\x33' \
                        b'\x5E\x0F\x56\xDF\x01\x01\x00\x00' \
                        b'\x00\x00\x00\x00\x00\x00\x00\x00' \
                        b'\x00\x00\x00\x00\xAA\xAA\xAA\xAA' \
                        b'\xAA\xAA\xAA\xAA\x00\x00\x00\x00' \
                        b'\x02\x00\x0C\x00\x44\x00\x6F\x00' \
                        b'\x6D\x00\x61\x00\x69\x00\x6E\x00' \
                        b'\x01\x00\x0C\x00\x53\x00\x65\x00' \
                        b'\x72\x00\x76\x00\x65\x00\x72\x00' \
                        b'\x07\x00\x08\x00\x00\x00\x00\x00' \
                        b'\x00\x00\x00\x00\x06\x00\x04\x00' \
                        b'\x02\x00\x00\x00\x0A\x00\x10\x00' \
                        b'\x6E\xA1\x9D\xF0\x66\xDA\x46\x22' \
                        b'\x05\x1F\x9C\x4F\x92\xC6\xDF\x74' \
                        b'\x00\x00\x00\x00\x00\x00\x00\x00' \
                        b'\x1D\x08\x89\xD1\xA5\xEE\xED\x21' \
                        b'\x91\x9E\x1A\xB8\x27\xC3\x0B\x17'

        assert actual_auth == expected_auth
        assert ntlm_context.complete
        assert ntlm_context.mic_present

        request_msg = b"test req"
        response_msg = b"test res"
        actual_wrapped = ntlm_context.wrap(request_msg)
        expected_wrapped = b"\x01\x00\x00\x00\xbc\xe3\x23\xa1" \
                           b"\x72\x06\x23\x78\x00\x00\x00\x00" \
                           b"\x70\x80\x1e\x11\xfe\x6b\x3a\xad"
        assert actual_wrapped == expected_wrapped

        server_sec = SessionSecurity(
            ntlm_context._session_security.negotiate_flags,
            ntlm_context._session_security.exported_session_key, "server")
        server_unwrap = server_sec.unwrap(actual_wrapped[16:],
                                          actual_wrapped[0:16])
        assert server_unwrap == request_msg

        response_wrapped = server_sec.wrap(response_msg)

        actual_unwrap = ntlm_context.unwrap(response_wrapped[1] +
                                            response_wrapped[0])
        assert actual_unwrap == response_msg

        msg = b"Hello"
        actual_sig1 = ntlm_context.sign(msg)
        expected_sig1 = b"\x01\x00\x00\x00\x08\xF0\x0D\x86\x34\x05\x1A\x1D\x01\x00\x00\x00"
        assert actual_sig1 == expected_sig1
        server_sec.verify_signature(msg, actual_sig1)

        actual_sig2 = ntlm_context.sign(msg)
        expected_sig2 = b"\x01\x00\x00\x00\x07\x64\x0C\x30\x1C\xD7\x76\xF0\x02\x00\x00\x00"
        assert actual_sig2 == expected_sig2
        server_sec.verify_signature(msg, actual_sig2)

        ntlm_context.reset_rc4_state()
        actual_sig3 = ntlm_context.sign(msg)
        expected_sig3 = b"\x01\x00\x00\x00\x1E\xD4\xA3\xE5\xE8\x05\x74\x01\x03\x00\x00\x00"
        assert actual_sig3 == expected_sig3

        server_sec.reset_rc4_state(outgoing=False)
        server_sec.verify_signature(msg, actual_sig3)

        server_sig = server_sec.get_signature(msg)
        ntlm_context.verify(msg, server_sig)
Exemple #12
0
    def test_ntlm_context(self, monkeypatch):
        monkeypatch.setattr('os.urandom', lambda s: b"\xaa" * 8)
        monkeypatch.setattr('ntlm_auth.messages.get_version',
                            lambda s: b"\x05\x01\x28\x0A\x00\x00\x00\x0F")
        monkeypatch.setattr('ntlm_auth.messages.get_random_export_session_key',
                            lambda: b"\x55" * 16)
        monkeypatch.setattr('ntlm_auth.compute_response.get_windows_timestamp',
                            lambda: b"\x00" * 8)

        ch = 'E3CA49271E5089CC48CE82109F1324F41DBEDDC29A777410C738F7868C4FF405'
        cbt_data = GssChannelBindingsStruct()
        cbt_data[cbt_data.APPLICATION_DATA] = b"tls-server-end-point:" + \
                                              base64.b16decode(ch)
        ntlm_context = NtlmContext("User",
                                   "Password",
                                   "Domain",
                                   "COMPUTER",
                                   cbt_data=cbt_data)
        actual_nego = ntlm_context.step()
        expected_nego = b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" \
                        b"\x01\x00\x00\x00\x31\xb0\x88\xe2" \
                        b"\x06\x00\x06\x00\x28\x00\x00\x00" \
                        b"\x08\x00\x08\x00\x2e\x00\x00\x00" \
                        b"\x05\x01\x28\x0a\x00\x00\x00\x0f" \
                        b"\x44\x6f\x6d\x61\x69\x6e\x43\x4f" \
                        b"\x4d\x50\x55\x54\x45\x52"
        assert actual_nego == expected_nego
        assert not ntlm_context.mic_present
        assert not ntlm_context.complete

        challenge_msg = b"\x4e\x54\x4c\x4d\x53\x53\x50\x00" \
                        b"\x02\x00\x00\x00\x2f\x82\x88\xe2" \
                        b"\x38\x00\x00\x00\x33\x82\x8a\xe2" \
                        b"\x01\x23\x45\x67\x89\xab\xcd\xef" \
                        b"\x00\x00\x00\x00\x00\x00\x00\x00" \
                        b"\x24\x00\x24\x00\x44\x00\x00\x00" \
                        b"\x06\x00\x70\x17\x00\x00\x00\x0f" \
                        b"\x53\x00\x65\x00\x72\x00\x76\x00" \
                        b"\x65\x00\x72\x00\x02\x00\x0c\x00" \
                        b"\x44\x00\x6f\x00\x6d\x00\x61\x00" \
                        b"\x69\x00\x6e\x00\x01\x00\x0c\x00" \
                        b"\x53\x00\x65\x00\x72\x00\x76\x00" \
                        b"\x65\x00\x72\x00\x00\x00\x00\x00"
        actual_auth = ntlm_context.step(challenge_msg)
        expected_auth = b'\x4e\x54\x4c\x4d\x53\x53\x50\x00' \
                        b'\x03\x00\x00\x00\x18\x00\x18\x00' \
                        b'\x6c\x00\x00\x00\x68\x00\x68\x00' \
                        b'\x84\x00\x00\x00\x0c\x00\x0c\x00' \
                        b'\x48\x00\x00\x00\x08\x00\x08\x00' \
                        b'\x54\x00\x00\x00\x10\x00\x10\x00' \
                        b'\x5c\x00\x00\x00\x10\x00\x10\x00' \
                        b'\xec\x00\x00\x00\x31\x82\x8a\xe2' \
                        b'\x05\x01\x28\x0a\x00\x00\x00\x0f' \
                        b'\x44\x00\x6f\x00\x6d\x00\x61\x00' \
                        b'\x69\x00\x6e\x00\x55\x00\x73\x00' \
                        b'\x65\x00\x72\x00\x43\x00\x4f\x00' \
                        b'\x4d\x00\x50\x00\x55\x00\x54\x00' \
                        b'\x45\x00\x52\x00\x86\xc3\x50\x97' \
                        b'\xac\x9c\xec\x10\x25\x54\x76\x4a' \
                        b'\x57\xcc\xcc\x19\xaa\xaa\xaa\xaa' \
                        b'\xaa\xaa\xaa\xaa\x04\x10\xc4\x7a' \
                        b'\xcf\x19\x97\x89\xde\x7f\x20\x11' \
                        b'\x95\x7a\xea\x50\x01\x01\x00\x00' \
                        b'\x00\x00\x00\x00\x00\x00\x00\x00' \
                        b'\x00\x00\x00\x00\xaa\xaa\xaa\xaa' \
                        b'\xaa\xaa\xaa\xaa\x00\x00\x00\x00' \
                        b'\x02\x00\x0c\x00\x44\x00\x6f\x00' \
                        b'\x6d\x00\x61\x00\x69\x00\x6e\x00' \
                        b'\x01\x00\x0c\x00\x53\x00\x65\x00' \
                        b'\x72\x00\x76\x00\x65\x00\x72\x00' \
                        b'\x0a\x00\x10\x00\x6e\xa1\x9d\xf0' \
                        b'\x66\xda\x46\x22\x05\x1f\x9c\x4f' \
                        b'\x92\xc6\xdf\x74\x00\x00\x00\x00' \
                        b'\x00\x00\x00\x00\xe5\x69\x95\x1d' \
                        b'\x15\xd4\x73\x5f\x49\xe1\x4c\xf9' \
                        b'\xa7\xd3\xe6\x72'

        assert actual_auth == expected_auth
        assert ntlm_context.complete
        assert not ntlm_context.mic_present

        request_msg = b"test req"
        response_msg = b"test res"
        actual_wrapped = ntlm_context.wrap(request_msg)
        expected_wrapped = b"\x01\x00\x00\x00\xbc\xe3\x23\xa1" \
                           b"\x72\x06\x23\x78\x00\x00\x00\x00" \
                           b"\x70\x80\x1e\x11\xfe\x6b\x3a\xad"
        assert actual_wrapped == expected_wrapped

        server_sec = SessionSecurity(
            ntlm_context._session_security.negotiate_flags,
            ntlm_context._session_security.exported_session_key, "server")
        server_unwrap = server_sec.unwrap(actual_wrapped[16:],
                                          actual_wrapped[0:16])
        assert server_unwrap == request_msg

        response_wrapped = server_sec.wrap(response_msg)

        actual_unwrap = ntlm_context.unwrap(response_wrapped[1] +
                                            response_wrapped[0])
        assert actual_unwrap == response_msg