def __init__(self, user_name, password, nthash, lmhash, domain_name, workstation, challenge_message, ntlm_compatibility, server_certificate_hash): self.signature = NTLM_SIGNATURE self.message_type = struct.pack('<L', MessageTypes.NTLM_AUTHENTICATE) self.negotiate_flags = challenge_message.negotiate_flags self.version = get_version(self.negotiate_flags) self.mic = None if domain_name is None: self.domain_name = '' else: self.domain_name = domain_name if workstation is None: self.workstation = '' else: self.workstation = workstation if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE: self.negotiate_flags -= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM encoding_value = 'utf-16-le' else: encoding_value = 'ascii' self.domain_name = self.domain_name.encode(encoding_value) self.user_name = user_name.encode(encoding_value) self.workstation = self.workstation.encode(encoding_value) compute_response = ComputeResponse(user_name, password, nthash, lmhash, domain_name, challenge_message, ntlm_compatibility) self.lm_challenge_response = compute_response.get_lm_challenge_response( ) self.nt_challenge_response, key_exchange_key, target_info = compute_response.get_nt_challenge_response( self.lm_challenge_response, server_certificate_hash) self.target_info = target_info if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH: self.exported_session_key = get_random_export_session_key() rc4_handle = ARC4(key_exchange_key) self.encrypted_random_session_key = rc4_handle.update( self.exported_session_key) else: self.exported_session_key = key_exchange_key self.encrypted_random_session_key = b'' self.negotiate_flags = struct.pack('<I', self.negotiate_flags)
def __init__(self, user_name, password, domain_name, workstation, challenge_message, ntlm_compatibility, server_certificate_hash): """ [MS-NLMP] v28.0 2016-07-14 2.2.1.3 AUTHENTICATE_MESSAGE The AUTHENTICATE_MESSAGE defines an NTLM authenticate message that is sent from the client to the server after the CHALLENGE_MESSAGE is processed by the client. :param user_name: The user name of the user we are trying to authenticate with :param password: The password of the user we are trying to authenticate with :param domain_name: The domain name of the user account we are authenticated with, default is None :param workstation: The workstation we are using to authenticate with, default is None :param challenge_message: A ChallengeMessage object that was received from the server after the negotiate_message :param ntlm_compatibility: The Lan Manager Compatibility Level, used to determine what NTLM auth version to use, see Ntlm in ntlm.py for more details :param server_certificate_hash: The SHA256 hash string of the server certificate (DER encoded) NTLM is authenticating to. This is used to add to the gss_channel_bindings_struct for Channel Binding Tokens support. If none is passed through then ntlm-auth will not use Channel Binding Tokens when authenticating with the server which could cause issues if it is set to only authenticate when these are present. This is only used for NTLMv2 authentication. Message Attributes (Attributes used to compute the message structure): signature: An 8-byte character array that MUST contain the ASCII string 'NTLMSSP\0' message_type: A 32-bit unsigned integer that indicates the message type. This field must be set to 0x00000003 negotiate_flags: A NEGOTIATE strucutre that contains a set of bit flags. These flags are the choices the client has made from the CHALLENGE_MESSAGE options version: Contains the windows version info of the client. It is used only debugging purposes and are only set when NTLMSSP_NEGOTIATE_VERSION flag is set mic: The message integrity for the NEGOTIATE_MESSAGE, CHALLENGE_MESSAGE and AUTHENTICATE_MESSAGE lm_challenge_response: An LM_RESPONSE of LMv2_RESPONSE structure that contains the computed LM response to the challenge nt_challenge_response: An NTLM_RESPONSE or NTLMv2_RESPONSE structure that contains the computed NT response to the challenge domain_name: The domain or computer name hosting the user account, MUST be encoded in the negotiated character set user_name: The name of the user to be authenticated, MUST be encoded in the negotiated character set workstation: The name of the computer to which the user is logged on, MUST Be encoded in the negotiated character set encrypted_random_session_key: The client's encrypted random session key Non-Message Attributes (Attributes not used in auth message): exported_session_key: A randomly generated session key based on other keys, used to derive the SIGNKEY and SEALKEY target_info: The AV_PAIR structure used in the nt response calculation """ self.signature = NTLM_SIGNATURE self.message_type = struct.pack('<L', MessageTypes.NTLM_AUTHENTICATE) self.negotiate_flags = challenge_message.negotiate_flags self.version = get_version(self.negotiate_flags) self.mic = None if domain_name is None: self.domain_name = '' else: self.domain_name = domain_name if workstation is None: self.workstation = '' else: self.workstation = workstation if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_UNICODE: self.negotiate_flags -= NegotiateFlags.NTLMSSP_NEGOTIATE_OEM encoding_value = 'utf-16-le' else: encoding_value = 'ascii' self.domain_name = self.domain_name.encode(encoding_value) self.user_name = user_name.encode(encoding_value) self.workstation = self.workstation.encode(encoding_value) compute_response = ComputeResponse(user_name, password, domain_name, challenge_message, ntlm_compatibility) self.lm_challenge_response = \ compute_response.get_lm_challenge_response() self.nt_challenge_response, key_exchange_key, target_info = \ compute_response.get_nt_challenge_response( self.lm_challenge_response, server_certificate_hash) self.target_info = target_info if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH: self.exported_session_key = get_random_export_session_key() rc4_handle = ARC4(key_exchange_key) self.encrypted_random_session_key = \ rc4_handle.update(self.exported_session_key) else: self.exported_session_key = key_exchange_key self.encrypted_random_session_key = b'' self.negotiate_flags = struct.pack('<I', self.negotiate_flags)