1 # Copyright (c) 2003-2016 CORE Security Technologies:
3 # This software is provided under under a slightly modified version
4 # of the Apache Software License. See the accompanying LICENSE file
5 # for more information.
16 from impacket.structure import Structure
17 from impacket import LOG
20 # This is important. NTLMv2 is not negotiated by the client or server.
21 # It is used if set locally on both sides. Change this item if you don't want to use
22 # NTLMv2 by default and fall back to NTLMv1 (with EXTENDED_SESSION_SECURITY or not)
23 # Check the following links:
24 # http://davenport.sourceforge.net/ntlm.html
25 # http://blogs.msdn.com/b/openspecification/archive/2010/04/20/ntlm-keys-and-sundry-stuff.aspx
26 # http://social.msdn.microsoft.com/Forums/en-US/os_interopscenarios/thread/c8f488ed-1b96-4e06-bd65-390aa41138d1/
27 # So I'm setting a global variable to control this, this can also be set programmatically
29 USE_NTLMv2 = True # if false will fall back to NTLMv1 (or NTLMv1 with ESS a.k.a NTLM2)
32 def computeResponse(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='', nthash='',
33 use_ntlmv2=USE_NTLMv2):
35 return computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password,
36 lmhash, nthash, use_ntlmv2=use_ntlmv2)
38 return computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password,
39 lmhash, nthash, use_ntlmv2=use_ntlmv2)
42 from Crypto.Cipher import ARC4
43 from Crypto.Cipher import DES
44 from Crypto.Hash import MD4
49 LOG.critical("Warning: You don't have any crypto installed. You need PyCrypto")
50 LOG.critical("See http://www.pycrypto.org/")
56 NTLM_AUTH_PKT_INTEGRITY = 5
57 NTLM_AUTH_PKT_PRIVACY = 6
59 # If set, requests 56-bit encryption. If the client sends NTLMSSP_NEGOTIATE_SEAL or NTLMSSP_NEGOTIATE_SIGN
60 # with NTLMSSP_NEGOTIATE_56 to the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_56 to
61 # the client in the CHALLENGE_MESSAGE. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128
62 # are requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be
63 # returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_56 if it is
64 # supported. An alternate name for this field is NTLMSSP_NEGOTIATE_56.
65 NTLMSSP_NEGOTIATE_56 = 0x80000000
67 # If set, requests an explicit key exchange. This capability SHOULD be used because it improves security for message
68 # 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
69 # this field is NTLMSSP_NEGOTIATE_KEY_EXCH.
70 NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000
72 # If set, requests 128-bit session key negotiation. An alternate name for this field is NTLMSSP_NEGOTIATE_128.
73 # If the client sends NTLMSSP_NEGOTIATE_128 to the server in the NEGOTIATE_MESSAGE, the server MUST return
74 # NTLMSSP_NEGOTIATE_128 to the client in the CHALLENGE_MESSAGE only if the client sets NTLMSSP_NEGOTIATE_SEAL or
75 # NTLMSSP_NEGOTIATE_SIGN. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are
76 # requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be
77 # returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_128 if it
78 # is supported. An alternate name for this field is NTLMSSP_NEGOTIATE_128
79 NTLMSSP_NEGOTIATE_128 = 0x20000000
81 NTLMSSP_RESERVED_1 = 0x10000000
82 NTLMSSP_RESERVED_2 = 0x08000000
83 NTLMSSP_RESERVED_3 = 0x04000000
85 # If set, requests the protocol version number. The data corresponding to this flag is provided in the Version field
86 # of the NEGOTIATE_MESSAGE, the CHALLENGE_MESSAGE, and the AUTHENTICATE_MESSAGE.<22> An alternate name for this field
87 # is NTLMSSP_NEGOTIATE_VERSION
88 NTLMSSP_NEGOTIATE_VERSION = 0x02000000
89 NTLMSSP_RESERVED_4 = 0x01000000
91 # If set, indicates that the TargetInfo fields in the CHALLENGE_MESSAGE (section 2.2.1.2) are populated.
92 # An alternate name for this field is NTLMSSP_NEGOTIATE_TARGET_INFO.
93 NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000
95 # If set, requests the usage of the LMOWF (section 3.3). An alternate name for this field is
96 # NTLMSSP_REQUEST_NON_NT_SESSION_KEY.
97 NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000
98 NTLMSSP_RESERVED_5 = 0x00200000
100 # If set, requests an identify level token. An alternate name for this field is NTLMSSP_NEGOTIATE_IDENTIFY
101 NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000
103 # If set, requests usage of the NTLM v2 session security. NTLM v2 session security is a misnomer because it is not
104 # NTLM v2. It is NTLM v1 using the extended session security that is also in NTLM v2. NTLMSSP_NEGOTIATE_LM_KEY and
105 # NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
106 # and NTLMSSP_NEGOTIATE_LM_KEY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be returned to the
107 # client. NTLM v2 authentication session key generation MUST be supported by both the client and the DC in order to be
108 # used, and extended session security signing and sealing requires support from the client and the server in order to
109 # be used.<23> An alternate name for this field is NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
110 NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000
111 NTLMSSP_NEGOTIATE_NTLM2 = 0x00080000
112 NTLMSSP_TARGET_TYPE_SHARE = 0x00040000
114 # If set, TargetName MUST be a server name. The data corresponding to this flag is provided by the server in the
115 # TargetName field of the CHALLENGE_MESSAGE. If this bit is set, then NTLMSSP_TARGET_TYPE_DOMAIN MUST NOT be set.
116 # This flag MUST be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field
117 # is NTLMSSP_TARGET_TYPE_SERVER
118 NTLMSSP_TARGET_TYPE_SERVER = 0x00020000
120 # If set, TargetName MUST be a domain name. The data corresponding to this flag is provided by the server in the
121 # TargetName field of the CHALLENGE_MESSAGE. If set, then NTLMSSP_TARGET_TYPE_SERVER MUST NOT be set. This flag MUST
122 # be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field is
123 # NTLMSSP_TARGET_TYPE_DOMAIN.
124 NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000
126 # If set, requests the presence of a signature block on all messages. NTLMSSP_NEGOTIATE_ALWAYS_SIGN MUST be set in the
127 # NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. NTLMSSP_NEGOTIATE_ALWAYS_SIGN is overridden
128 # by NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL, if they are supported. An alternate name for this field is
129 # NTLMSSP_NEGOTIATE_ALWAYS_SIGN.
130 NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000 # forces the other end to sign packets
131 NTLMSSP_RESERVED_6 = 0x00004000
133 # This flag indicates whether the Workstation field is present. If this flag is not set, the Workstation field MUST be
134 # ignored. If this flag is set, the length field of the Workstation field specifies whether the workstation name is
135 # nonempty or not.<24> An alternate name for this field is NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED.
136 NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000
138 # If set, the domain name is provided (section 2.2.1.1).<25> An alternate name for this field is
139 # NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
140 NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000
141 NTLMSSP_RESERVED_7 = 0x00000800
144 # If set, LM authentication is not allowed and only NT authentication is used.
145 NTLMSSP_NEGOTIATE_NT_ONLY = 0x00000400
147 # If set, requests usage of the NTLM v1 session security protocol. NTLMSSP_NEGOTIATE_NTLM MUST be set in the
148 # NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate name for this field is
149 # NTLMSSP_NEGOTIATE_NTLM
150 NTLMSSP_NEGOTIATE_NTLM = 0x00000200
151 NTLMSSP_RESERVED_8 = 0x00000100
153 # If set, requests LAN Manager (LM) session key computation. NTLMSSP_NEGOTIATE_LM_KEY and
154 # NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_LM_KEY and
155 # NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be
156 # returned to the client. NTLM v2 authentication session key generation MUST be supported by both the client and the
157 # DC in order to be used, and extended session security signing and sealing requires support from the client and the
158 # server to be used. An alternate name for this field is NTLMSSP_NEGOTIATE_LM_KEY.
159 NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080
161 # If set, requests connectionless authentication. If NTLMSSP_NEGOTIATE_DATAGRAM is set, then NTLMSSP_NEGOTIATE_KEY_EXCH
162 # MUST always be set in the AUTHENTICATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate
163 # name for this field is NTLMSSP_NEGOTIATE_DATAGRAM.
164 NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040
166 # If set, requests session key negotiation for message confidentiality. If the client sends NTLMSSP_NEGOTIATE_SEAL to
167 # the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SEAL to the client in the
168 # CHALLENGE_MESSAGE. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD always set NTLMSSP_NEGOTIATE_56 and
169 # NTLMSSP_NEGOTIATE_128, if they are supported. An alternate name for this field is NTLMSSP_NEGOTIATE_SEAL.
170 NTLMSSP_NEGOTIATE_SEAL = 0x00000020
172 # If set, requests session key negotiation for message signatures. If the client sends NTLMSSP_NEGOTIATE_SIGN to the
173 # server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SIGN to the client in the CHALLENGE_MESSAGE.
174 # An alternate name for this field is NTLMSSP_NEGOTIATE_SIGN.
175 NTLMSSP_NEGOTIATE_SIGN = 0x00000010 # means packet is signed, if verifier is wrong it fails
176 NTLMSSP_RESERVED_9 = 0x00000008
178 # If set, a TargetName field of the CHALLENGE_MESSAGE (section 2.2.1.2) MUST be supplied. An alternate name for this
179 # field is NTLMSSP_REQUEST_TARGET.
180 NTLMSSP_REQUEST_TARGET = 0x00000004
182 # If set, requests OEM character set encoding. An alternate name for this field is NTLM_NEGOTIATE_OEM. See bit A for
184 NTLM_NEGOTIATE_OEM = 0x00000002
186 # If set, requests Unicode character set encoding. An alternate name for this field is NTLMSSP_NEGOTIATE_UNICODE.
187 NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
190 NTLMSSP_AV_EOL = 0x00
191 NTLMSSP_AV_HOSTNAME = 0x01
192 NTLMSSP_AV_DOMAINNAME = 0x02
193 NTLMSSP_AV_DNS_HOSTNAME = 0x03
194 NTLMSSP_AV_DNS_DOMAINNAME = 0x04
195 NTLMSSP_AV_DNS_TREENAME = 0x05
196 NTLMSSP_AV_FLAGS = 0x06
197 NTLMSSP_AV_TIME = 0x07
198 NTLMSSP_AV_RESTRICTIONS = 0x08
199 NTLMSSP_AV_TARGET_NAME = 0x09
200 NTLMSSP_AV_CHANNEL_BINDINGS = 0x0a
203 def __init__(self, data = None):
206 self.fromString(data)
208 def __setitem__(self,key,value):
209 self.fields[key] = (len(value),value)
211 def __getitem__(self, key):
212 if self.fields.has_key(key):
213 return self.fields[key]
216 def __delitem__(self, key):
220 return len(self.getData())
223 return len(self.getData())
225 def fromString(self, data):
228 while fType is not NTLMSSP_AV_EOL:
229 fType = struct.unpack('<H',tInfo[:struct.calcsize('<H')])[0]
230 tInfo = tInfo[struct.calcsize('<H'):]
231 length = struct.unpack('<H',tInfo[:struct.calcsize('<H')])[0]
232 tInfo = tInfo[struct.calcsize('<H'):]
233 content = tInfo[:length]
234 self.fields[fType]=(length,content)
235 tInfo = tInfo[length:]
238 for i in self.fields.keys():
239 print "%s: {%r}" % (i,self[i])
242 if self.fields.has_key(NTLMSSP_AV_EOL):
243 del self.fields[NTLMSSP_AV_EOL]
245 for i in self.fields.keys():
246 ans+= struct.pack('<HH', i, self[i][0])
249 # end with a NTLMSSP_AV_EOL
250 ans += struct.pack('<HH', NTLMSSP_AV_EOL, 0)
255 def get_os_version(self):
256 if self['os_version'] == '':
259 mayor_v = struct.unpack('B',self['os_version'][0])[0]
260 minor_v = struct.unpack('B',self['os_version'][1])[0]
261 build_v = struct.unpack('H',self['os_version'][2:4])
262 return (mayor_v,minor_v,build_v)
264 class NTLMAuthNegotiate(Structure, NTLMAuthMixin):
268 ('message_type','<L=1'),
270 ('domain_len','<H-domain_name'),
271 ('domain_max_len','<H-domain_name'),
272 ('domain_offset','<L=0'),
273 ('host_len','<H-host_name'),
274 ('host_maxlen','<H-host_name'),
275 ('host_offset','<L=0'),
281 Structure.__init__(self)
283 NTLMSSP_NEGOTIATE_128 |
284 NTLMSSP_NEGOTIATE_KEY_EXCH|
286 NTLMSSP_NEGOTIATE_NTLM |
287 NTLMSSP_NEGOTIATE_UNICODE |
288 # NTLMSSP_ALWAYS_SIGN |
289 NTLMSSP_NEGOTIATE_SIGN |
290 NTLMSSP_NEGOTIATE_SEAL |
294 self['domain_name']=''
295 self['os_version']=''
298 if len(self.fields['host_name']) > 0:
299 self['flags'] |= NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
300 if len(self.fields['domain_name']) > 0:
301 self['flags'] |= NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
302 if len(self.fields['os_version']) > 0:
303 self['flags'] |= NTLMSSP_NEGOTIATE_VERSION
304 if (self['flags'] & NTLMSSP_NEGOTIATE_VERSION) == NTLMSSP_NEGOTIATE_VERSION:
308 if (self['flags'] & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) == NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED:
309 self['host_offset']=32 + version_len
310 if (self['flags'] & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED) == NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED:
311 self['domain_offset']=32+len(self['host_name']) + version_len
312 return Structure.getData(self)
314 def fromString(self,data):
315 Structure.fromString(self,data)
317 domain_offset = self['domain_offset']
318 domain_end = self['domain_len'] + domain_offset
319 self['domain_name'] = data[ domain_offset : domain_end ]
321 host_offset = self['host_offset']
322 host_end = self['host_len'] + host_offset
323 self['host_name'] = data[ host_offset : host_end ]
325 hasOsInfo = self['flags'] & NTLMSSP_NEGOTIATE_VERSION
326 if len(data) >= 36 and hasOsInfo:
327 self['os_version'] = data[32:40]
329 self['os_version'] = ''
331 class NTLMAuthChallenge(Structure):
335 ('message_type','<L=2'),
336 ('domain_len','<H-domain_name'),
337 ('domain_max_len','<H-domain_name'),
338 ('domain_offset','<L=40'),
341 ('reserved','8s=""'),
342 ('TargetInfoFields_len','<H-TargetInfoFields'),
343 ('TargetInfoFields_max_len','<H-TargetInfoFields'),
344 ('TargetInfoFields_offset','<L'),
345 ('VersionLen','_-Version','self.checkVersion(self["flags"])'),
348 ('TargetInfoFields',':'))
350 def checkVersion(self, flags):
351 if flags is not None:
352 if flags & NTLMSSP_NEGOTIATE_VERSION == 0:
357 if self['TargetInfoFields'] is not None and type(self['TargetInfoFields']) is not str:
358 raw_av_fields = self['TargetInfoFields'].getData()
359 self['TargetInfoFields'] = raw_av_fields
360 return Structure.getData(self)
362 def fromString(self,data):
363 Structure.fromString(self,data)
364 # Just in case there's more data after the TargetInfoFields
365 self['TargetInfoFields'] = self['TargetInfoFields'][:self['TargetInfoFields_len']]
366 # We gotta process the TargetInfoFields
367 #if self['TargetInfoFields_len'] > 0:
368 # av_pairs = AV_PAIRS(self['TargetInfoFields'][:self['TargetInfoFields_len']])
369 # self['TargetInfoFields'] = av_pairs
373 class NTLMAuthChallengeResponse(Structure, NTLMAuthMixin):
377 ('message_type','<L=3'),
378 ('lanman_len','<H-lanman'),
379 ('lanman_max_len','<H-lanman'),
380 ('lanman_offset','<L'),
381 ('ntlm_len','<H-ntlm'),
382 ('ntlm_max_len','<H-ntlm'),
383 ('ntlm_offset','<L'),
384 ('domain_len','<H-domain_name'),
385 ('domain_max_len','<H-domain_name'),
386 ('domain_offset','<L'),
387 ('user_len','<H-user_name'),
388 ('user_max_len','<H-user_name'),
389 ('user_offset','<L'),
390 ('host_len','<H-host_name'),
391 ('host_max_len','<H-host_name'),
392 ('host_offset','<L'),
393 ('session_key_len','<H-session_key'),
394 ('session_key_max_len','<H-session_key'),
395 ('session_key_offset','<L'),
397 ('VersionLen','_-Version','self.checkVersion(self["flags"])'),
399 ('MICLen','_-MIC','self.checkMIC(self["flags"])'),
408 def __init__(self, username = '', password = '', challenge = '', lmhash = '', nthash = '', flags = 0):
409 Structure.__init__(self)
410 self['session_key']=''
411 self['user_name']=username.encode('utf-16le')
412 self['domain_name']='' #"CLON".encode('utf-16le')
413 self['host_name']='' #"BETS".encode('utf-16le')
414 self['flags'] = ( #authResp['flags']
415 # we think (beto & gera) that his flags force a memory conten leakage when a windows 2000 answers using uninitializaed verifiers
416 NTLMSSP_NEGOTIATE_128 |
417 NTLMSSP_NEGOTIATE_KEY_EXCH|
419 NTLMSSP_NEGOTIATE_NTLM |
420 NTLMSSP_NEGOTIATE_UNICODE |
421 # NTLMSSP_ALWAYS_SIGN |
422 NTLMSSP_NEGOTIATE_SIGN |
423 NTLMSSP_NEGOTIATE_SEAL |
426 # Here we do the stuff
427 if username and ( lmhash != '' or nthash != ''):
428 self['lanman'] = get_ntlmv1_response(lmhash, challenge)
429 self['ntlm'] = get_ntlmv1_response(nthash, challenge)
430 elif (username and password):
431 lmhash = compute_lmhash(password)
432 nthash = compute_nthash(password)
433 self['lanman']=get_ntlmv1_response(lmhash, challenge)
434 self['ntlm']=get_ntlmv1_response(nthash, challenge) # This is not used for LM_KEY nor NTLM_KEY
438 if not self['host_name']:
439 self['host_name'] = 'NULL'.encode('utf-16le') # for NULL session there must be a hostname
441 def checkVersion(self, flags):
442 if flags is not None:
443 if flags & NTLMSSP_NEGOTIATE_VERSION == 0:
447 def checkMIC(self, flags):
448 # TODO: Find a proper way to check the MIC is in there
449 if flags is not None:
450 if flags & NTLMSSP_NEGOTIATE_VERSION == 0:
455 self['domain_offset']=64+self.checkMIC(self["flags"])+self.checkVersion(self["flags"])
456 self['user_offset']=64+self.checkMIC(self["flags"])+self.checkVersion(self["flags"])+len(self['domain_name'])
457 self['host_offset']=self['user_offset']+len(self['user_name'])
458 self['lanman_offset']=self['host_offset']+len(self['host_name'])
459 self['ntlm_offset']=self['lanman_offset']+len(self['lanman'])
460 self['session_key_offset']=self['ntlm_offset']+len(self['ntlm'])
461 return Structure.getData(self)
463 def fromString(self,data):
464 Structure.fromString(self,data)
466 # Payload data can be present in any order within the Payload field,
467 # with variable-length padding before or after the data
469 domain_offset = self['domain_offset']
470 domain_end = self['domain_len'] + domain_offset
471 self['domain_name'] = data[ domain_offset : domain_end ]
473 host_offset = self['host_offset']
474 host_end = self['host_len'] + host_offset
475 self['host_name'] = data[ host_offset: host_end ]
477 user_offset = self['user_offset']
478 user_end = self['user_len'] + user_offset
479 self['user_name'] = data[ user_offset: user_end ]
481 ntlm_offset = self['ntlm_offset']
482 ntlm_end = self['ntlm_len'] + ntlm_offset
483 self['ntlm'] = data[ ntlm_offset : ntlm_end ]
485 lanman_offset = self['lanman_offset']
486 lanman_end = self['lanman_len'] + lanman_offset
487 self['lanman'] = data[ lanman_offset : lanman_end]
490 # self['os_version'] = data[32:36]
492 # self['os_version'] = ''
494 class ImpacketStructure(Structure):
495 def set_parent(self, other):
498 def get_packet(self):
504 class ExtendedOrNotMessageSignature(Structure):
505 def __init__(self, flags = 0, **kargs):
506 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
507 self.structure = self.extendedMessageSignature
509 self.structure = self.MessageSignature
510 return Structure.__init__(self, **kargs)
512 class NTLMMessageSignature(ExtendedOrNotMessageSignature):
513 extendedMessageSignature = (
521 ('RandomPad','<i=0'),
526 KNOWN_DES_INPUT = "KGS!@#$%"
528 def __expand_DES_key( key):
529 # Expand the key from a 7-byte password key into a 8-byte DES key
531 key += '\x00'*(7-len(key))
532 s = chr(((ord(key[0]) >> 1) & 0x7f) << 1)
533 s = s + chr(((ord(key[0]) & 0x01) << 6 | ((ord(key[1]) >> 2) & 0x3f)) << 1)
534 s = s + chr(((ord(key[1]) & 0x03) << 5 | ((ord(key[2]) >> 3) & 0x1f)) << 1)
535 s = s + chr(((ord(key[2]) & 0x07) << 4 | ((ord(key[3]) >> 4) & 0x0f)) << 1)
536 s = s + chr(((ord(key[3]) & 0x0f) << 3 | ((ord(key[4]) >> 5) & 0x07)) << 1)
537 s = s + chr(((ord(key[4]) & 0x1f) << 2 | ((ord(key[5]) >> 6) & 0x03)) << 1)
538 s = s + chr(((ord(key[5]) & 0x3f) << 1 | ((ord(key[6]) >> 7) & 0x01)) << 1)
539 s = s + chr((ord(key[6]) & 0x7f) << 1)
542 def __DES_block(key, msg):
544 cipher = POW.Symmetric(POW.DES_ECB)
545 cipher.encryptInit(__expand_DES_key(key))
546 return cipher.update(msg)
548 cipher = DES.new(__expand_DES_key(key),DES.MODE_ECB)
549 return cipher.encrypt(msg)
551 def ntlmssp_DES_encrypt(key, challenge):
552 answer = __DES_block(key[:7], challenge)
553 answer += __DES_block(key[7:14], challenge)
554 answer += __DES_block(key[14:], challenge)
557 # High level functions to use NTLMSSP
559 def getNTLMSSPType1(workstation='', domain='', signingRequired = False, use_ntlmv2 = USE_NTLMv2):
560 # Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with
561 # international characters.
563 encoding = sys.getfilesystemencoding()
564 if encoding is not None:
566 workstation.encode('utf-16le')
568 workstation = workstation.decode(encoding)
570 domain.encode('utf-16le')
572 domain = domain.decode(encoding)
574 # Let's prepare a Type 1 NTLMSSP Message
575 auth = NTLMAuthNegotiate()
578 auth['flags'] = NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | NTLMSSP_NEGOTIATE_SEAL
580 auth['flags'] |= NTLMSSP_NEGOTIATE_TARGET_INFO
581 auth['flags'] |= NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | NTLMSSP_NEGOTIATE_UNICODE | NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_56
582 auth['domain_name'] = domain.encode('utf-16le')
585 def getNTLMSSPType3(type1, type2, user, password, domain, lmhash = '', nthash = '', use_ntlmv2 = USE_NTLMv2):
587 # Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with
588 # international characters.
590 encoding = sys.getfilesystemencoding()
591 if encoding is not None:
593 user.encode('utf-16le')
595 user = user.decode(encoding)
597 password.encode('utf-16le')
599 password = password.decode(encoding)
601 domain.encode('utf-16le')
603 domain = user.decode(encoding)
605 ntlmChallenge = NTLMAuthChallenge(type2)
607 # Let's start with the original flags sent in the type1 message
608 responseFlags = type1['flags']
610 # Token received and parsed. Depending on the authentication
611 # method we will create a valid ChallengeResponse
612 ntlmChallengeResponse = NTLMAuthChallengeResponse(user, password, ntlmChallenge['challenge'])
614 clientChallenge = "".join([random.choice(string.digits+string.letters) for i in xrange(8)])
616 serverName = ntlmChallenge['TargetInfoFields']
618 ntResponse, lmResponse, sessionBaseKey = computeResponse(ntlmChallenge['flags'], ntlmChallenge['challenge'], clientChallenge, serverName, domain, user, password, lmhash, nthash, use_ntlmv2 )
620 # Let's check the return flags
621 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) == 0:
622 # No extended session security, taking it out
623 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
624 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_128 ) == 0:
625 # No support for 128 key len, taking it out
626 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_128
627 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH) == 0:
628 # No key exchange supported, taking it out
629 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_KEY_EXCH
630 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_SEAL) == 0:
631 # No sign available, taking it out
632 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_SEAL
633 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_SIGN) == 0:
634 # No sign available, taking it out
635 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_SIGN
636 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) == 0:
637 # No sign available, taking it out
638 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_ALWAYS_SIGN
640 keyExchangeKey = KXKEY(ntlmChallenge['flags'],sessionBaseKey, lmResponse, ntlmChallenge['challenge'], password, lmhash, nthash,use_ntlmv2)
642 # Special case for anonymous login
643 if user == '' and password == '' and lmhash == '' and nthash == '':
644 keyExchangeKey = '\x00'*16
646 # If we set up key exchange, let's fill the right variables
647 if ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH:
648 # not exactly what I call random tho :\
649 # exportedSessionKey = this is the key we should use to sign
650 exportedSessionKey = "".join([random.choice(string.digits+string.letters) for i in xrange(16)])
651 #exportedSessionKey = "A"*16
652 #print "keyExchangeKey %r" % keyExchangeKey
653 # Let's generate the right session key based on the challenge flags
654 #if responseFlags & NTLMSSP_NTLM2_KEY:
655 # Extended session security enabled
656 # if responseFlags & NTLMSSP_KEY_128:
658 # exportedSessionKey = exportedSessionKey
659 # elif responseFlags & NTLMSSP_KEY_56:
661 # exportedSessionKey = exportedSessionKey[:7]
663 # exportedSessionKey = exportedSessionKey[:5]
664 #elif responseFlags & NTLMSSP_KEY_56:
665 # No extended session security, just 56 bits key
666 # exportedSessionKey = exportedSessionKey[:7] + '\xa0'
668 # exportedSessionKey = exportedSessionKey[:5] + '\xe5\x38\xb0'
670 encryptedRandomSessionKey = generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey)
672 encryptedRandomSessionKey = None
674 exportedSessionKey = keyExchangeKey
676 ntlmChallengeResponse['flags'] = responseFlags
677 ntlmChallengeResponse['domain_name'] = domain.encode('utf-16le')
678 ntlmChallengeResponse['lanman'] = lmResponse
679 ntlmChallengeResponse['ntlm'] = ntResponse
680 if encryptedRandomSessionKey is not None:
681 ntlmChallengeResponse['session_key'] = encryptedRandomSessionKey
683 return ntlmChallengeResponse, exportedSessionKey
688 def generateSessionKeyV1(password, lmhash, nthash):
690 hash = POW.Digest(POW.MD4_DIGEST)
693 hash.update(NTOWFv1(password, lmhash, nthash))
696 def computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='', nthash='', use_ntlmv2 = USE_NTLMv2):
697 if (user == '' and password == ''):
698 # Special case for anonymous authentication
702 lmhash = LMOWFv1(password, lmhash, nthash)
703 nthash = NTOWFv1(password, lmhash, nthash)
704 if flags & NTLMSSP_NEGOTIATE_LM_KEY:
706 lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
707 elif flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
708 md5 = hashlib.new('md5')
709 chall = (serverChallenge + clientChallenge)
711 ntResponse = ntlmssp_DES_encrypt(nthash, md5.digest()[:8])
712 lmResponse = clientChallenge + '\x00'*16
714 ntResponse = get_ntlmv1_response(nthash,serverChallenge)
715 lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
717 sessionBaseKey = generateSessionKeyV1(password, lmhash, nthash)
718 return ntResponse, lmResponse, sessionBaseKey
720 def compute_lmhash(password):
721 # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
722 password = password.upper()
723 lmhash = __DES_block(password[:7], KNOWN_DES_INPUT)
724 lmhash += __DES_block(password[7:14], KNOWN_DES_INPUT)
727 def NTOWFv1(password, lmhash = '', nthash=''):
730 return compute_nthash(password)
732 def LMOWFv1(password, lmhash = '', nthash=''):
735 return compute_lmhash(password)
737 def compute_nthash(password):
738 # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
740 password = unicode(password).encode('utf_16le')
741 except UnicodeDecodeError:
743 password = password.decode(sys.getfilesystemencoding()).encode('utf_16le')
746 hash = POW.Digest(POW.MD4_DIGEST)
749 hash.update(password)
752 def get_ntlmv1_response(key, challenge):
753 return ntlmssp_DES_encrypt(key, challenge)
755 # NTLMv2 Algorithm - as described in MS-NLMP Section 3.3.2
759 def MAC(flags, handle, signingKey, seqNum, message):
760 # [MS-NLMP] Section 3.4.4
761 # Returns the right messageSignature depending on the flags
762 messageSignature = NTLMMessageSignature(flags)
763 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
764 if flags & NTLMSSP_NEGOTIATE_KEY_EXCH:
765 messageSignature['Version'] = 1
766 messageSignature['Checksum'] = struct.unpack('<q',handle(hmac_md5(signingKey, struct.pack('<i',seqNum)+message)[:8]))[0]
767 messageSignature['SeqNum'] = seqNum
770 messageSignature['Version'] = 1
771 messageSignature['Checksum'] = struct.unpack('<q',hmac_md5(signingKey, struct.pack('<i',seqNum)+message)[:8])[0]
772 messageSignature['SeqNum'] = seqNum
775 messageSignature['Version'] = 1
776 messageSignature['Checksum'] = struct.pack('<i',binascii.crc32(message))
777 messageSignature['RandomPad'] = 0
778 messageSignature['RandomPad'] = handle(struct.pack('<i',messageSignature['RandomPad']))
779 messageSignature['Checksum'] = struct.unpack('<i',handle(messageSignature['Checksum']))[0]
780 messageSignature['SeqNum'] = handle('\x00\x00\x00\x00')
781 messageSignature['SeqNum'] = struct.unpack('<i',messageSignature['SeqNum'])[0] ^ seqNum
782 messageSignature['RandomPad'] = 0
784 return messageSignature
786 def SEAL(flags, signingKey, sealingKey, messageToSign, messageToEncrypt, seqNum, handle):
787 sealedMessage = handle(messageToEncrypt)
788 signature = MAC(flags, handle, signingKey, seqNum, messageToSign)
789 return sealedMessage, signature
791 def SIGN(flags, signingKey, message, seqNum, handle):
792 return MAC(flags, handle, signingKey, seqNum, message)
794 def SIGNKEY(flags, randomSessionKey, mode = 'Client'):
795 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
797 md5 = hashlib.new('md5')
798 md5.update(randomSessionKey + "session key to client-to-server signing key magic constant\x00")
799 signKey = md5.digest()
801 md5 = hashlib.new('md5')
802 md5.update(randomSessionKey + "session key to server-to-client signing key magic constant\x00")
803 signKey = md5.digest()
808 def SEALKEY(flags, randomSessionKey, mode = 'Client'):
809 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
810 if flags & NTLMSSP_NEGOTIATE_128:
811 sealKey = randomSessionKey
812 elif flags & NTLMSSP_NEGOTIATE_56:
813 sealKey = randomSessionKey[:7]
815 sealKey = randomSessionKey[:5]
818 md5 = hashlib.new('md5')
819 md5.update(sealKey + 'session key to client-to-server sealing key magic constant\x00')
820 sealKey = md5.digest()
822 md5 = hashlib.new('md5')
823 md5.update(sealKey + 'session key to server-to-client sealing key magic constant\x00')
824 sealKey = md5.digest()
826 elif flags & NTLMSSP_NEGOTIATE_56:
827 sealKey = randomSessionKey[:7] + '\xa0'
829 sealKey = randomSessionKey[:5] + '\xe5\x38\xb0'
834 def generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey):
836 cipher = POW.Symmetric(POW.RC4)
837 cipher.encryptInit(keyExchangeKey)
838 cipher_encrypt = cipher.update
840 cipher = ARC4.new(keyExchangeKey)
841 cipher_encrypt = cipher.encrypt
843 sessionKey = cipher_encrypt(exportedSessionKey)
846 def KXKEY(flags, sessionBaseKey, lmChallengeResponse, serverChallenge, password, lmhash, nthash, use_ntlmv2 = USE_NTLMv2):
848 return sessionBaseKey
850 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
851 if flags & NTLMSSP_NEGOTIATE_NTLM:
852 keyExchangeKey = hmac_md5(sessionBaseKey, serverChallenge + lmChallengeResponse[:8])
854 keyExchangeKey = sessionBaseKey
855 elif flags & NTLMSSP_NEGOTIATE_NTLM:
856 if flags & NTLMSSP_NEGOTIATE_LM_KEY:
857 keyExchangeKey = __DES_block(LMOWFv1(password,lmhash)[:7], lmChallengeResponse[:8]) + __DES_block(LMOWFv1(password,lmhash)[7] + '\xBD\xBD\xBD\xBD\xBD\xBD', lmChallengeResponse[:8])
858 elif flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY:
859 keyExchangeKey = LMOWFv1(password,lmhash)[:8] + '\x00'*8
861 keyExchangeKey = sessionBaseKey
863 raise "Can't create a valid KXKEY!"
865 return keyExchangeKey
867 def hmac_md5(key, data):
869 h = POW.Hmac(POW.MD5_DIGEST, key)
879 def NTOWFv2( user, password, domain, hash = ''):
883 theHash = compute_nthash(password)
884 return hmac_md5(theHash, user.upper().encode('utf-16le') + domain.encode('utf-16le'))
886 def LMOWFv2( user, password, domain, lmhash = ''):
887 return NTOWFv2( user, password, domain, lmhash)
890 def computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash = '', nthash = '', use_ntlmv2 = USE_NTLMv2):
892 responseServerVersion = '\x01'
893 hiResponseServerVersion = '\x01'
894 responseKeyNT = NTOWFv2(user, password, domain, nthash)
895 responseKeyLM = LMOWFv2(user, password, domain, lmhash)
897 # If you're running test-ntlm, comment the following lines and uncoment the ones that are commented. Don't forget to turn it back after the tests!
898 ######################
899 av_pairs = AV_PAIRS(serverName)
900 # In order to support SPN target name validation, we have to add this to the serverName av_pairs. Otherwise we will get access denied
901 # This is set at Local Security Policy -> Local Policies -> Security Options -> Server SPN target name validation level
902 av_pairs[NTLMSSP_AV_TARGET_NAME] = 'cifs/'.encode('utf-16le') + av_pairs[NTLMSSP_AV_HOSTNAME][1]
903 if av_pairs[NTLMSSP_AV_TIME] is not None:
904 aTime = av_pairs[NTLMSSP_AV_TIME][1]
906 aTime = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
908 av_pairs[NTLMSSP_AV_TIME] = aTime
909 serverName = av_pairs.getData()
911 ######################
913 ######################
914 temp = responseServerVersion + hiResponseServerVersion + '\x00' * 6 + aTime + clientChallenge + '\x00' * 4 + serverName + '\x00' * 4
916 ntProofStr = hmac_md5(responseKeyNT, serverChallenge + temp)
918 ntChallengeResponse = ntProofStr + temp
919 lmChallengeResponse = hmac_md5(responseKeyNT, serverChallenge + clientChallenge) + clientChallenge
920 sessionBaseKey = hmac_md5(responseKeyNT, ntProofStr)
922 if (user == '' and password == ''):
923 # Special case for anonymous authentication
924 ntChallengeResponse = ''
925 lmChallengeResponse = ''
927 return ntChallengeResponse, lmChallengeResponse, sessionBaseKey
929 class NTLM_HTTP(object):
930 '''Parent class for NTLM HTTP classes.'''
934 def get_instace(cls,msg_64):
938 msg = base64.b64decode(msg_64[5:]) # Remove the 'NTLM '
939 msg_type = ord(msg[8])
941 for _cls in NTLM_HTTP.__subclasses__():
942 if msg_type == _cls.MSG_TYPE:
944 instance.fromString(msg)
948 class NTLM_HTTP_AuthRequired(NTLM_HTTP):
950 # Message 0 means the first HTTP request e.g. 'GET /bla.png'
953 def fromString(self,data):
957 class NTLM_HTTP_AuthNegotiate(NTLM_HTTP, NTLMAuthNegotiate):
962 NTLMAuthNegotiate.__init__(self)
965 class NTLM_HTTP_AuthChallengeResponse(NTLM_HTTP, NTLMAuthChallengeResponse):
970 NTLMAuthChallengeResponse.__init__(self)