Coverage for /private/tmp/im/impacket/impacket/ntlm.py : 68%

Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved. # # This software is provided under under a slightly modified version # of the Apache Software License. See the accompanying LICENSE file # for more information. #
# This is important. NTLMv2 is not negotiated by the client or server. # It is used if set locally on both sides. Change this item if you don't want to use # NTLMv2 by default and fall back to NTLMv1 (with EXTENDED_SESSION_SECURITY or not) # Check the following links: # https://davenport.sourceforge.io/ntlm.html # https://blogs.msdn.microsoft.com/openspecification/2010/04/19/ntlm-keys-and-sundry-stuff/ # https://social.msdn.microsoft.com/Forums/c8f488ed-1b96-4e06-bd65-390aa41138d1/msnlmp-msntht-determining-ntlm-v1-or-v2-in-http-authentication?forum=os_specifications # So I'm setting a global variable to control this, this can also be set programmatically
use_ntlmv2=USE_NTLMv2): lmhash, nthash, use_ntlmv2=use_ntlmv2) else: return computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash, nthash, use_ntlmv2=use_ntlmv2) except Exception: LOG.critical("Warning: You don't have any crypto installed. You need pycryptodomex") LOG.critical("See https://pypi.org/project/pycryptodomex/")
# If set, requests 56-bit encryption. If the client sends NTLMSSP_NEGOTIATE_SEAL or NTLMSSP_NEGOTIATE_SIGN # with NTLMSSP_NEGOTIATE_56 to the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_56 to # the client in the CHALLENGE_MESSAGE. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 # are requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be # returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_56 if it is # supported. An alternate name for this field is NTLMSSP_NEGOTIATE_56.
# If set, requests an explicit key exchange. This capability SHOULD be used because it improves security for message # integrity or confidentiality. See sections 3.2.5.1.2, 3.2.5.2.1, and 3.2.5.2.2 for details. An alternate name for # this field is NTLMSSP_NEGOTIATE_KEY_EXCH.
# If set, requests 128-bit session key negotiation. An alternate name for this field is NTLMSSP_NEGOTIATE_128. # If the client sends NTLMSSP_NEGOTIATE_128 to the server in the NEGOTIATE_MESSAGE, the server MUST return # NTLMSSP_NEGOTIATE_128 to the client in the CHALLENGE_MESSAGE only if the client sets NTLMSSP_NEGOTIATE_SEAL or # NTLMSSP_NEGOTIATE_SIGN. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are # requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be # returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_128 if it # is supported. An alternate name for this field is NTLMSSP_NEGOTIATE_128
# If set, requests the protocol version number. The data corresponding to this flag is provided in the Version field # of the NEGOTIATE_MESSAGE, the CHALLENGE_MESSAGE, and the AUTHENTICATE_MESSAGE.<22> An alternate name for this field # is NTLMSSP_NEGOTIATE_VERSION
# If set, indicates that the TargetInfo fields in the CHALLENGE_MESSAGE (section 2.2.1.2) are populated. # An alternate name for this field is NTLMSSP_NEGOTIATE_TARGET_INFO.
# If set, requests the usage of the LMOWF (section 3.3). An alternate name for this field is # NTLMSSP_REQUEST_NON_NT_SESSION_KEY.
# If set, requests an identify level token. An alternate name for this field is NTLMSSP_NEGOTIATE_IDENTIFY
# If set, requests usage of the NTLM v2 session security. NTLM v2 session security is a misnomer because it is not # NTLM v2. It is NTLM v1 using the extended session security that is also in NTLM v2. NTLMSSP_NEGOTIATE_LM_KEY and # NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY # and NTLMSSP_NEGOTIATE_LM_KEY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be returned to the # client. NTLM v2 authentication session key generation MUST be supported by both the client and the DC in order to be # used, and extended session security signing and sealing requires support from the client and the server in order to # be used.<23> An alternate name for this field is NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
# If set, TargetName MUST be a server name. The data corresponding to this flag is provided by the server in the # TargetName field of the CHALLENGE_MESSAGE. If this bit is set, then NTLMSSP_TARGET_TYPE_DOMAIN MUST NOT be set. # This flag MUST be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field # is NTLMSSP_TARGET_TYPE_SERVER
# If set, TargetName MUST be a domain name. The data corresponding to this flag is provided by the server in the # TargetName field of the CHALLENGE_MESSAGE. If set, then NTLMSSP_TARGET_TYPE_SERVER MUST NOT be set. This flag MUST # be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field is # NTLMSSP_TARGET_TYPE_DOMAIN.
# If set, requests the presence of a signature block on all messages. NTLMSSP_NEGOTIATE_ALWAYS_SIGN MUST be set in the # NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. NTLMSSP_NEGOTIATE_ALWAYS_SIGN is overridden # by NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL, if they are supported. An alternate name for this field is # NTLMSSP_NEGOTIATE_ALWAYS_SIGN.
# This flag indicates whether the Workstation field is present. If this flag is not set, the Workstation field MUST be # ignored. If this flag is set, the length field of the Workstation field specifies whether the workstation name is # nonempty or not.<24> An alternate name for this field is NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED.
# If set, the domain name is provided (section 2.2.1.1).<25> An alternate name for this field is # NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
# If set, LM authentication is not allowed and only NT authentication is used.
# If set, requests usage of the NTLM v1 session security protocol. NTLMSSP_NEGOTIATE_NTLM MUST be set in the # NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate name for this field is # NTLMSSP_NEGOTIATE_NTLM
# If set, requests LAN Manager (LM) session key computation. NTLMSSP_NEGOTIATE_LM_KEY and # NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_LM_KEY and # NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be # returned to the client. NTLM v2 authentication session key generation MUST be supported by both the client and the # DC in order to be used, and extended session security signing and sealing requires support from the client and the # server to be used. An alternate name for this field is NTLMSSP_NEGOTIATE_LM_KEY.
# If set, requests connectionless authentication. If NTLMSSP_NEGOTIATE_DATAGRAM is set, then NTLMSSP_NEGOTIATE_KEY_EXCH # MUST always be set in the AUTHENTICATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate # name for this field is NTLMSSP_NEGOTIATE_DATAGRAM.
# If set, requests session key negotiation for message confidentiality. If the client sends NTLMSSP_NEGOTIATE_SEAL to # the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SEAL to the client in the # CHALLENGE_MESSAGE. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD always set NTLMSSP_NEGOTIATE_56 and # NTLMSSP_NEGOTIATE_128, if they are supported. An alternate name for this field is NTLMSSP_NEGOTIATE_SEAL.
# If set, requests session key negotiation for message signatures. If the client sends NTLMSSP_NEGOTIATE_SIGN to the # server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SIGN to the client in the CHALLENGE_MESSAGE. # An alternate name for this field is NTLMSSP_NEGOTIATE_SIGN.
# If set, a TargetName field of the CHALLENGE_MESSAGE (section 2.2.1.2) MUST be supplied. An alternate name for this # field is NTLMSSP_REQUEST_TARGET.
# If set, requests OEM character set encoding. An alternate name for this field is NTLM_NEGOTIATE_OEM. See bit A for # details.
# If set, requests Unicode character set encoding. An alternate name for this field is NTLMSSP_NEGOTIATE_UNICODE.
# AV_PAIR constants
return None
del self.fields[key]
return len(self.getData())
return len(self.getData())
for i in list(self.fields.keys()): print("%s: {%r}" % (i,self[i]))
# end with a NTLMSSP_AV_EOL
if self['os_version'] == '': return None else: mayor_v = struct.unpack('B',self['os_version'][0])[0] minor_v = struct.unpack('B',self['os_version'][1])[0] build_v = struct.unpack('H',self['os_version'][2:4]) return mayor_v,minor_v,build_v
('','"NTLMSSP\x00'), ('message_type','<L=1'), ('flags','<L'), ('domain_len','<H-domain_name'), ('domain_max_len','<H-domain_name'), ('domain_offset','<L=0'), ('host_len','<H-host_name'), ('host_maxlen','<H-host_name'), ('host_offset','<L=0'), ('os_version',':'), ('host_name',':'), ('domain_name',':'))
NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_KEY_EXCH| # NTLMSSP_LM_KEY | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_UNICODE | # NTLMSSP_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL | # NTLMSSP_TARGET | 0)
self['flags'] |= NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED self['flags'] |= NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED self['flags'] |= NTLMSSP_NEGOTIATE_VERSION version_len = 8 else: self['host_offset']=32 + version_len self['domain_offset']=32+len(self['host_name']) + version_len
Structure.fromString(self,data)
domain_offset = self['domain_offset'] domain_end = self['domain_len'] + domain_offset self['domain_name'] = data[ domain_offset : domain_end ]
host_offset = self['host_offset'] host_end = self['host_len'] + host_offset self['host_name'] = data[ host_offset : host_end ]
hasOsInfo = self['flags'] & NTLMSSP_NEGOTIATE_VERSION if len(data) >= 36 and hasOsInfo: self['os_version'] = data[32:40] else: self['os_version'] = ''
('','"NTLMSSP\x00'), ('message_type','<L=2'), ('domain_len','<H-domain_name'), ('domain_max_len','<H-domain_name'), ('domain_offset','<L=40'), ('flags','<L=0'), ('challenge','8s'), ('reserved','8s=""'), ('TargetInfoFields_len','<H-TargetInfoFields'), ('TargetInfoFields_max_len','<H-TargetInfoFields'), ('TargetInfoFields_offset','<L'), ('VersionLen','_-Version','self.checkVersion(self["flags"])'), ('Version',':'), ('domain_name',':'), ('TargetInfoFields',':'))
def checkVersion(flags): return 0
if self['TargetInfoFields'] is not None and type(self['TargetInfoFields']) is not bytes: raw_av_fields = self['TargetInfoFields'].getData() self['TargetInfoFields'] = raw_av_fields return Structure.getData(self)
('','"NTLMSSP\x00'), ('message_type','<L=3'), ('lanman_len','<H-lanman'), ('lanman_max_len','<H-lanman'), ('lanman_offset','<L'), ('ntlm_len','<H-ntlm'), ('ntlm_max_len','<H-ntlm'), ('ntlm_offset','<L'), ('domain_len','<H-domain_name'), ('domain_max_len','<H-domain_name'), ('domain_offset','<L'), ('user_len','<H-user_name'), ('user_max_len','<H-user_name'), ('user_offset','<L'), ('host_len','<H-host_name'), ('host_max_len','<H-host_name'), ('host_offset','<L'), ('session_key_len','<H-session_key'), ('session_key_max_len','<H-session_key'), ('session_key_offset','<L'), ('flags','<L'), ('VersionLen','_-Version','self.checkVersion(self["flags"])'), ('Version',':=""'), ('MICLen','_-MIC','self.checkMIC(self["flags"])'), ('MIC',':=""'), ('domain_name',':'), ('user_name',':'), ('host_name',':'), ('lanman',':'), ('ntlm',':'), ('session_key',':'))
# we think (beto & gera) that his flags force a memory conten leakage when a windows 2000 answers using # uninitializaed verifiers NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_KEY_EXCH| # NTLMSSP_LM_KEY | NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_UNICODE | # NTLMSSP_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_SEAL | # NTLMSSP_TARGET | 0) # Here we do the stuff self['lanman'] = get_ntlmv1_response(lmhash, challenge) self['ntlm'] = get_ntlmv1_response(nthash, challenge) else:
def checkVersion(flags): return 8
def checkMIC(flags): # TODO: Find a proper way to check the MIC is in there return 16
Structure.fromString(self,data) # [MS-NLMP] page 27 # Payload data can be present in any order within the Payload field, # with variable-length padding before or after the data
domain_offset = self['domain_offset'] domain_end = self['domain_len'] + domain_offset self['domain_name'] = data[ domain_offset : domain_end ]
host_offset = self['host_offset'] host_end = self['host_len'] + host_offset self['host_name'] = data[ host_offset: host_end ]
user_offset = self['user_offset'] user_end = self['user_len'] + user_offset self['user_name'] = data[ user_offset: user_end ]
ntlm_offset = self['ntlm_offset'] ntlm_end = self['ntlm_len'] + ntlm_offset self['ntlm'] = data[ ntlm_offset : ntlm_end ]
lanman_offset = self['lanman_offset'] lanman_end = self['lanman_len'] + lanman_offset self['lanman'] = data[ lanman_offset : lanman_end]
#if len(data) >= 36: # self['os_version'] = data[32:36] #else: # self['os_version'] = ''
self.parent = other
return str(self)
return len(self)
else: self.structure = self.MessageSignature
('Version','<L=1'), ('Checksum','<q'), ('SeqNum','<I'), )
('Version','<L=1'), ('RandomPad','<I=0'), ('Checksum','<I'), ('SeqNum','<I'), )
# Expand the key from a 7-byte password key into a 8-byte DES key key = bytes(key)
# High level functions to use NTLMSSP
# Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with # international characters. except: domain = domain.decode(encoding)
# Let's prepare a Type 1 NTLMSSP Message NTLMSSP_NEGOTIATE_SEAL NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_56
# We're not adding workstation / domain fields this time. Normally Windows clients don't add such information but, # we will save the workstation name to be used later.
# Safety check in case somebody sent password = None.. That's not allowed. Setting it to '' and hope for the best. password = ''
# Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with # international characters. except: user = user.decode(encoding) except: password = password.decode(encoding) except: domain = user.decode(encoding)
# Let's start with the original flags sent in the type1 message
# Token received and parsed. Depending on the authentication # method we will create a valid ChallengeResponse
clientChallenge, serverName, domain, user, password, lmhash, nthash, use_ntlmv2)
# Let's check the return flags # No extended session security, taking it out responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY # No support for 128 key len, taking it out responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_128 # No key exchange supported, taking it out # No sign available, taking it out # No sign available, taking it out # No sign available, taking it out
lmhash, nthash, use_ntlmv2)
# Special case for anonymous login
# If we set up key exchange, let's fill the right variables # not exactly what I call random tho :\ # exportedSessionKey = this is the key we should use to sign #exportedSessionKey = "A"*16 #print "keyExchangeKey %r" % keyExchangeKey # Let's generate the right session key based on the challenge flags #if responseFlags & NTLMSSP_NTLM2_KEY: # Extended session security enabled # if responseFlags & NTLMSSP_KEY_128: # Full key # exportedSessionKey = exportedSessionKey # elif responseFlags & NTLMSSP_KEY_56: # Only 56-bit key # exportedSessionKey = exportedSessionKey[:7] # else: # exportedSessionKey = exportedSessionKey[:5] #elif responseFlags & NTLMSSP_KEY_56: # No extended session security, just 56 bits key # exportedSessionKey = exportedSessionKey[:7] + '\xa0' #else: # exportedSessionKey = exportedSessionKey[:5] + '\xe5\x38\xb0'
else: # [MS-NLMP] page 46
else:
# NTLMv1 Algorithm
hash = MD4.new() hash.update(NTOWFv1(password, lmhash, nthash)) return hash.digest()
nthash='', use_ntlmv2=USE_NTLMv2): if user == '' and password == '': # Special case for anonymous authentication lmResponse = '' ntResponse = '' else: lmhash = LMOWFv1(password, lmhash, nthash) nthash = NTOWFv1(password, lmhash, nthash) if flags & NTLMSSP_NEGOTIATE_LM_KEY: ntResponse = '' lmResponse = get_ntlmv1_response(lmhash, serverChallenge) elif flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: md5 = hashlib.new('md5') chall = (serverChallenge + clientChallenge) md5.update(chall) ntResponse = ntlmssp_DES_encrypt(nthash, md5.digest()[:8]) lmResponse = clientChallenge + b'\x00'*16 else: ntResponse = get_ntlmv1_response(nthash,serverChallenge) lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
sessionBaseKey = generateSessionKeyV1(password, lmhash, nthash) return ntResponse, lmResponse, sessionBaseKey
# This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
return nthash
return lmhash
# This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html) except UnicodeDecodeError: import sys password = password.decode(sys.getfilesystemencoding()).encode('utf_16le')
# NTLMv2 Algorithm - as described in MS-NLMP Section 3.3.2
# Crypto Stuff
# [MS-NLMP] Section 3.4.4 # Returns the right messageSignature depending on the flags struct.unpack('<q', handle(hmac_md5(signingKey, struct.pack('<i', seqNum) + message)[:8]))[0] else: messageSignature['Version'] = 1 messageSignature['Checksum'] = struct.unpack('<q',hmac_md5(signingKey, struct.pack('<i',seqNum)+message)[:8])[0] messageSignature['SeqNum'] = seqNum seqNum += 1 else: messageSignature['Version'] = 1 messageSignature['Checksum'] = struct.pack('<I',binascii.crc32(message)& 0xFFFFFFFF) messageSignature['RandomPad'] = 0 messageSignature['RandomPad'] = handle(struct.pack('<I',messageSignature['RandomPad'])) messageSignature['Checksum'] = struct.unpack('<I',handle(messageSignature['Checksum']))[0] messageSignature['SeqNum'] = handle(b'\x00\x00\x00\x00') messageSignature['SeqNum'] = struct.unpack('<I',messageSignature['SeqNum'])[0] ^ seqNum messageSignature['RandomPad'] = 0
else: else: signKey = None
elif flags & NTLMSSP_NEGOTIATE_56: sealKey = randomSessionKey[:7] else: sealKey = randomSessionKey[:5]
else:
elif flags & NTLMSSP_NEGOTIATE_56: sealKey = randomSessionKey[:7] + b'\xa0' else: sealKey = randomSessionKey[:5] + b'\xe5\x38\xb0'
if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: if flags & NTLMSSP_NEGOTIATE_NTLM: keyExchangeKey = hmac_md5(sessionBaseKey, serverChallenge + lmChallengeResponse[:8]) else: keyExchangeKey = sessionBaseKey elif flags & NTLMSSP_NEGOTIATE_NTLM: if flags & NTLMSSP_NEGOTIATE_LM_KEY: keyExchangeKey = __DES_block(LMOWFv1(password, lmhash)[:7], lmChallengeResponse[:8]) + __DES_block( LMOWFv1(password, lmhash)[7] + b'\xBD\xBD\xBD\xBD\xBD\xBD', lmChallengeResponse[:8]) elif flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY: keyExchangeKey = LMOWFv1(password,lmhash)[:8] + b'\x00'*8 else: keyExchangeKey = sessionBaseKey else: raise Exception("Can't create a valid KXKEY!")
return keyExchangeKey
else:
return NTOWFv2( user, password, domain, lmhash)
nthash='', use_ntlmv2=USE_NTLMv2):
# In order to support SPN target name validation, we have to add this to the serverName av_pairs. Otherwise we will # get access denied # This is set at Local Security Policy -> Local Policies -> Security Options -> Server SPN target name validation # level else: aTime = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) ) av_pairs[NTLMSSP_AV_TIME] = aTime else: aTime = b'\x00'*8
serverName + b'\x00' * 4
# Special case for anonymous authentication
# Parent class for NTLM HTTP classes.
def get_instace(cls,msg_64): msg = None msg_type = 0 if msg_64 != '': msg = base64.b64decode(msg_64[5:]) # Remove the 'NTLM ' msg_type = ord(msg[8])
for _cls in NTLM_HTTP.__subclasses__(): if msg_type == _cls.MSG_TYPE: instance = _cls() instance.fromString(msg) return instance
# Message 0 means the first HTTP request e.g. 'GET /bla.png'
pass
NTLMAuthNegotiate.__init__(self)
NTLMAuthChallengeResponse.__init__(self) |