Server IP : 85.214.239.14 / Your IP : 18.117.231.160 Web Server : Apache/2.4.62 (Debian) System : Linux h2886529.stratoserver.net 4.9.0 #1 SMP Tue Jan 9 19:45:01 MSK 2024 x86_64 User : www-data ( 33) PHP Version : 7.4.18 Disable Function : pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare, MySQL : OFF | cURL : OFF | WGET : ON | Perl : ON | Python : ON | Sudo : ON | Pkexec : OFF Directory : /proc/self/root/proc/2/root/proc/3/cwd/usr/lib/python3/dist-packages/ntlm_auth/ |
Upload File : |
# Copyright: (c) 2018, Jordan Borean (@jborean93) <jborean93@gmail.com> # MIT License (see LICENSE or https://opensource.org/licenses/MIT) import binascii import hashlib import hmac import struct import ntlm_auth.compute_keys as compkeys from ntlm_auth.constants import NegotiateFlags, SignSealConstants from ntlm_auth.rc4 import ARC4 class _NtlmMessageSignature1(object): EXPECTED_BODY_LENGTH = 16 def __init__(self, random_pad, checksum, seq_num): """ [MS-NLMP] v28.0 2016-07-14 2.2.2.9.1 NTLMSSP_MESSAGE_SIGNATURE This version of the NTLMSSP_MESSAGE_SIGNATURE structure MUST be used when the NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is not negotiated. :param random_pad: A 4-byte array that contains the random pad for the message :param checksum: A 4-byte array that contains the checksum for the message :param seq_num: A 32-bit unsigned integer that contains the NTLM sequence number for this application message """ self.version = b"\x01\x00\x00\x00" self.random_pad = random_pad self.checksum = checksum self.seq_num = seq_num def get_data(self): signature = self.version signature += self.random_pad signature += self.checksum signature += self.seq_num assert self.EXPECTED_BODY_LENGTH == len(signature), \ "BODY_LENGTH: %d != signature: %d" \ % (self.EXPECTED_BODY_LENGTH, len(signature)) return signature class _NtlmMessageSignature2(object): EXPECTED_BODY_LENGTH = 16 def __init__(self, checksum, seq_num): """ [MS-NLMP] v28.0 2016-07-14 2.2.2.9.2 NTLMSSP_MESSAGE_SIGNATURE for Extended Session Security This version of the NTLMSSP_MESSAGE_SIGNATURE structure MUST be used when the NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY flag is negotiated :param checksum: An 8-byte array that contains the checksum for the message :param seq_num: A 32-bit unsigned integer that contains the NTLM sequence number for this application message """ self.version = b"\x01\x00\x00\x00" self.checksum = checksum self.seq_num = seq_num def get_data(self): signature = self.version signature += self.checksum signature += self.seq_num assert self.EXPECTED_BODY_LENGTH == len(signature),\ "BODY_LENGTH: %d != signature: %d"\ % (self.EXPECTED_BODY_LENGTH, len(signature)) return signature class SessionSecurity(object): def __init__(self, negotiate_flags, exported_session_key, source="client"): """ Initialises a security session context that can be used by libraries that call ntlm-auth to sign and seal messages send to the server as well as verify and unseal messages that have been received from the server. This is similar to the GSS_Wrap functions specified in the MS-NLMP document which does the same task. :param negotiate_flags: The negotiate flag structure that has been negotiated with the server :param exported_session_key: A 128-bit session key used to derive signing and sealing keys :param source: The source of the message, only used in test scenarios when testing out a server sealing and unsealing """ self.negotiate_flags = negotiate_flags self.exported_session_key = exported_session_key self.outgoing_seq_num = 0 self.incoming_seq_num = 0 client_sealing_key = \ compkeys.get_seal_key(self.negotiate_flags, exported_session_key, SignSealConstants.CLIENT_SEALING) server_sealing_key = \ compkeys.get_seal_key(self.negotiate_flags, exported_session_key, SignSealConstants.SERVER_SEALING) if source == "client": self.outgoing_signing_key = \ compkeys.get_sign_key(exported_session_key, SignSealConstants.CLIENT_SIGNING) self.incoming_signing_key = \ compkeys.get_sign_key(exported_session_key, SignSealConstants.SERVER_SIGNING) self.outgoing_handle = ARC4(client_sealing_key) self.incoming_handle = ARC4(server_sealing_key) elif source == "server": self.outgoing_signing_key = \ compkeys.get_sign_key(exported_session_key, SignSealConstants.SERVER_SIGNING) self.incoming_signing_key = \ compkeys.get_sign_key(exported_session_key, SignSealConstants.CLIENT_SIGNING) self.outgoing_handle = ARC4(server_sealing_key) self.incoming_handle = ARC4(client_sealing_key) else: raise ValueError("Invalid source parameter %s, must be client " "or server" % source) def wrap(self, message): """ [MS-NLMP] v28.0 2016-07-14 3.4.6 GSS_WrapEx() Emulates the GSS_Wrap() implementation to sign and seal messages if the correct flags are set. :param message: The message data that will be wrapped :return message: The message that has been sealed if flags are set :return signature: The signature of the message, None if flags are not set """ if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL: encrypted_message = self._seal_message(message) signature = self._get_signature(message) message = encrypted_message elif self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN: signature = self._get_signature(message) else: signature = None return message, signature def unwrap(self, message, signature): """ [MS-NLMP] v28.0 2016-07-14 3.4.7 GSS_UnwrapEx() Emulates the GSS_Unwrap() implementation to unseal messages and verify the signature sent matches what has been computed locally. Will throw an Exception if the signature doesn't match :param message: The message data received from the server :param signature: The signature of the message :return message: The message that has been unsealed if flags are set """ if self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SEAL: message = self._unseal_message(message) self._verify_signature(message, signature) elif self.negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_SIGN: self._verify_signature(message, signature) return message def _seal_message(self, message): """ [MS-NLMP] v28.0 2016-07-14 3.4.3 Message Confidentiality Will generate an encrypted message using RC4 based on the ClientSealingKey :param message: The message to be sealed (encrypted) :return encrypted_message: The encrypted message """ encrypted_message = self.outgoing_handle.update(message) return encrypted_message def _unseal_message(self, message): """ [MS-NLMP] v28.0 2016-07-14 3.4.3 Message Confidentiality Will generate a dencrypted message using RC4 based on the ServerSealingKey :param message: The message to be unsealed (dencrypted) :return decrypted_message: The decrypted message """ decrypted_message = self.incoming_handle.update(message) return decrypted_message def _get_signature(self, message): """ [MS-NLMP] v28.0 2016-07-14 3.4.4 Message Signature Functions Will create the signature based on the message to send to the server. Depending on the negotiate_flags set this could either be an NTLMv1 signature or NTLMv2 with Extended Session Security signature. :param message: The message data that will be signed :return signature: Either _NtlmMessageSignature1 or _NtlmMessageSignature2 depending on the flags set """ signature = calc_signature(message, self.negotiate_flags, self.outgoing_signing_key, self.outgoing_seq_num, self.outgoing_handle) self.outgoing_seq_num += 1 return signature.get_data() def _verify_signature(self, message, signature): """ Will verify that the signature received from the server matches up with the expected signature computed locally. Will throw an exception if they do not match :param message: The message data that is received from the server :param signature: The signature of the message received from the server """ if self.negotiate_flags & \ NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: actual_checksum = signature[4:12] actual_seq_num = struct.unpack("<I", signature[12:16])[0] else: actual_checksum = signature[8:12] actual_seq_num = struct.unpack("<I", signature[12:16])[0] expected_signature = calc_signature(message, self.negotiate_flags, self.incoming_signing_key, self.incoming_seq_num, self.incoming_handle) expected_checksum = expected_signature.checksum expected_seq_num = struct.unpack("<I", expected_signature.seq_num)[0] if actual_checksum != expected_checksum: raise Exception("The signature checksum does not match, message " "has been altered") if actual_seq_num != expected_seq_num: raise Exception("The signature sequence number does not match up, " "message not received in the correct sequence") self.incoming_seq_num += 1 def calc_signature(message, negotiate_flags, signing_key, seq_num, handle): seq_num = struct.pack("<I", seq_num) if negotiate_flags & \ NegotiateFlags.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: checksum_hmac = hmac.new(signing_key, seq_num + message, digestmod=hashlib.md5) if negotiate_flags & NegotiateFlags.NTLMSSP_NEGOTIATE_KEY_EXCH: checksum = handle.update(checksum_hmac.digest()[:8]) else: checksum = checksum_hmac.digest()[:8] signature = _NtlmMessageSignature2(checksum, seq_num) else: message_crc = binascii.crc32(message) % (1 << 32) checksum = struct.pack("<I", message_crc) random_pad = handle.update(struct.pack("<I", 0)) checksum = handle.update(checksum) seq_num = handle.update(seq_num) random_pad = struct.pack("<I", 0) signature = _NtlmMessageSignature1(random_pad, checksum, seq_num) return signature