def _encode_smb2(self, cur): # serialize all chained Smb2 commands into one buffer original_message_buf = array.array('B') original_message_cur = core.Cursor(original_message_buf, 0) for smb_frame in self.parent: smb_frame.encode(original_message_cur) if self.original_message_size is None: self.original_message_size = len(original_message_buf) self.original_message_size_hole(self.original_message_size) (self.ciphertext, crypto_hmac) = self.encryption_context.encrypt( original_message_buf, self.additional_authenticated_data_buf, self.nonce) cur.encode_bytes(self.ciphertext) # fill in the signature hole sig_cur = core.Cursor(cur.array, self.signature_offset) if self.signature is None: self.signature = crypto_hmac sig_cur.encode_bytes(self.signature) # fill in the header aad_cur = core.Cursor(cur.array, self.crypto_header_offset) aad_cur.encode_bytes(self.additional_authenticated_data_buf) # fill in the wire nonce if self.wire_nonce is None: self.wire_nonce = self.nonce self.wire_nonce_hole(pad_right(self.wire_nonce, 16))
def _encode_header(self, cur): # look up the encryption context if not specified if self.encryption_context is None and self.parent is not None: self.encryption_context = self.parent.conn.encryption_context( self.session_id) cur.encode_bytes(self.protocol_id) # the signature will be written in _encode_smb2 self.signature_offset = cur.offset cur.advanceto(cur + 16) # the crypto header will be written in _encode_smb2 self.crypto_header_offset = cur.offset # save a space for the wire nonce self.wire_nonce_hole = cur.hole.encode_bytes('\0' * 16) cur.advanceto(cur + 16) # the following fields are part of AdditionalAuthenticatedData and are # used as inputs to the AES cipher aad_cur = core.Cursor(self.additional_authenticated_data_buf, 0) # nonce field size is 16 bytes right padded with zeros self.nonce = pad_right(self.nonce, 16) aad_cur.encode_bytes(self.nonce) self.original_message_size_hole = aad_cur.hole.encode_uint32le(0) if self.reserved is None: self.reserved = 0 aad_cur.encode_uint16le(self.reserved) # reserved aad_cur.encode_uint16le(self.flags) aad_cur.encode_uint64le(self.session_id)
def ComputeResponsev2(NegFlg, ResponseKeyNT, ResponseKeyLM, ServerChallenge, ClientChallenge, Time=None, ServerName=None, av_pairs=None): if Time is None: Time = nttime.NtTime(nttime.datetime.now()) if ServerName is None: ServerName = "SERVER" ServerName = ServerName.encode("utf-16-le") TimeBuf = array.array("B") cur = core.Cursor(TimeBuf, 0) cur.encode_uint64le(Time) Responseversion = "\x01" HiResponseversion = "\x01" ntlmv2_client_challenge = NTLMv2ClientChallenge() ntlmv2_client_challenge.time_stamp = Time ntlmv2_client_challenge.challenge_from_client = ClientChallenge if av_pairs is not None: ntlmv2_client_challenge.av_pairs = av_pairs temp = encode_frame(ntlmv2_client_challenge).tostring() NTProofStr = HMAC.new(ResponseKeyNT, ServerChallenge + temp, MD5).digest() NtChallengeResponse = NTProofStr + temp LmChallengeResponse = HMAC.new(ResponseKeyLM, ServerChallenge + ClientChallenge, MD5).digest() +\ ClientChallenge SessionBaseKey = HMAC.new(ResponseKeyNT, NTProofStr, MD5).digest() return NtChallengeResponse, LmChallengeResponse, SessionBaseKey
def _encode_smb2(self, cur): # serialize all chained Smb2 commands into one buffer original_message_buf = array.array('B') original_message_cur = core.Cursor(original_message_buf, 0) for smb_frame in self.parent: smb_frame.encode(original_message_cur) self.original_message_size = len(original_message_buf) self.original_message_size_hole(self.original_message_size) crypto_header = cur.array[self.crypto_header_start:self. crypto_header_end] (self.ciphertext, self.signature) = self.encryption_context.encrypt( original_message_buf, crypto_header, self.nonce) cur.encode_bytes(self.ciphertext) # fill in the signature hole sig_cur = core.Cursor(cur.array, self.signature_offset) sig_cur.encode_bytes(self.signature)
def negotiate(self): ntlm = Ntlm() neg = NtLmNegotiateMessage(ntlm) neg.negotiate_flags = self.neg_flags neg.domain_name = self.domain neg.version = self.version self.negotiate_buffer = array.array('B') ntlm.encode(core.Cursor(self.negotiate_buffer, 0)) self.negotiate_message = ntlm return self.negotiate_buffer
def derive_key(key, label, context): message = array.array('B') cur = core.Cursor(message, 0) cur.encode_uint32be(1) cur.encode_bytes(label) cur.encode_uint8be(0) cur.encode_uint8be(0) cur.encode_bytes(context) cur.encode_uint32be(len(key) * 8) return sha256_hmac(key, message)
def authenticate(self, challenge_buf): # parse the challenge message self.challenge_buffer = challenge_buf ntlm_challenge = Ntlm() ntlm_challenge.decode(core.Cursor(challenge_buf, 0)) self.server_challenge = ntlm_challenge.message.server_challenge self.challenge_message = ntlm_challenge # build the auth message ntlm = Ntlm() auth = NtLmAuthenticateMessage(ntlm) auth.negotiate_flags = self.auth_flags auth.version = self.version auth.domain_name = self.domain auth.user_name = self.username # perform the NTLM if self.ntlm_version == NTLMv1: self.ntlmv1() elif self.ntlm_version == NTLMv2: self.ntlmv2() else: raise NotImplementedError("Unknown NTLM version {0}".format( self.ntlm_version)) # fill in the challenge responses auth.nt_challenge_response = self.nt_challenge_response auth.lm_challenge_response = self.lm_challenge_response # generate the session key if requested session_key = self.session_key() if session_key is not None: auth.encrypted_random_session_key = session_key self.authenticate_buffer = array.array('B') ntlm.encode(core.Cursor(self.authenticate_buffer, 0)) self.authenticate_message = ntlm return self.authenticate_buffer
def _decode_smb2(self, cur): self.encrypted_data = cur.decode_bytes(self.original_message_size) crypto_header = cur.array[self.crypto_header_start:self. crypto_header_end] self.plaintext = self.encryption_context.decrypt( self.encrypted_data, self.signature, crypto_header, self.nonce) # scan through the plaintext for chained messages pt_cur = core.Cursor(self.plaintext, 0) end = pt_cur + len(self.plaintext) with pt_cur.bounded(pt_cur, end): while (pt_cur < end): start = pt_cur.offset message = smb2.Smb2(self.parent) message.decode(pt_cur) message.buf = pt_cur.array[start:pt_cur.offset]
def encode_frame(frame): buffer = array.array('B') frame.encode(core.Cursor(buffer, 0)) return buffer