Coverage for /root/GitHubProjects/impacket/impacket/ntlm.py : 69%

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
1# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
2#
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.
6#
7from __future__ import division
8from __future__ import print_function
9import base64
10import struct
11import calendar
12import time
13import hashlib
14import random
15import string
16import binascii
17from six import b
19from impacket.structure import Structure
20from impacket import LOG
23# This is important. NTLMv2 is not negotiated by the client or server.
24# It is used if set locally on both sides. Change this item if you don't want to use
25# NTLMv2 by default and fall back to NTLMv1 (with EXTENDED_SESSION_SECURITY or not)
26# Check the following links:
27# https://davenport.sourceforge.io/ntlm.html
28# https://blogs.msdn.microsoft.com/openspecification/2010/04/19/ntlm-keys-and-sundry-stuff/
29# https://social.msdn.microsoft.com/Forums/c8f488ed-1b96-4e06-bd65-390aa41138d1/msnlmp-msntht-determining-ntlm-v1-or-v2-in-http-authentication?forum=os_specifications
30# So I'm setting a global variable to control this, this can also be set programmatically
32USE_NTLMv2 = True # if false will fall back to NTLMv1 (or NTLMv1 with ESS a.k.a NTLM2)
33TEST_CASE = False # Only set to True when running Test Cases
36def computeResponse(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='', nthash='',
37 use_ntlmv2=USE_NTLMv2):
38 if use_ntlmv2: 38 ↛ 42line 38 didn't jump to line 42, because the condition on line 38 was never false
39 return computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password,
40 lmhash, nthash, use_ntlmv2=use_ntlmv2)
41 else:
42 return computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password,
43 lmhash, nthash, use_ntlmv2=use_ntlmv2)
44try:
45 from Cryptodome.Cipher import ARC4
46 from Cryptodome.Cipher import DES
47 from Cryptodome.Hash import MD4
48except Exception:
49 LOG.critical("Warning: You don't have any crypto installed. You need pycryptodomex")
50 LOG.critical("See https://pypi.org/project/pycryptodomex/")
52NTLM_AUTH_NONE = 1
53NTLM_AUTH_CONNECT = 2
54NTLM_AUTH_CALL = 3
55NTLM_AUTH_PKT = 4
56NTLM_AUTH_PKT_INTEGRITY = 5
57NTLM_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.
65NTLMSSP_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.
70NTLMSSP_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
79NTLMSSP_NEGOTIATE_128 = 0x20000000
81NTLMSSP_RESERVED_1 = 0x10000000
82NTLMSSP_RESERVED_2 = 0x08000000
83NTLMSSP_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
88NTLMSSP_NEGOTIATE_VERSION = 0x02000000
89NTLMSSP_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.
93NTLMSSP_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.
97NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000
98NTLMSSP_RESERVED_5 = 0x00200000
100# If set, requests an identify level token. An alternate name for this field is NTLMSSP_NEGOTIATE_IDENTIFY
101NTLMSSP_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
110NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000
111NTLMSSP_NEGOTIATE_NTLM2 = 0x00080000
112NTLMSSP_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
118NTLMSSP_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.
124NTLMSSP_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.
130NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000 # forces the other end to sign packets
131NTLMSSP_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.
136NTLMSSP_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
140NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000
141NTLMSSP_RESERVED_7 = 0x00000800
144# If set, LM authentication is not allowed and only NT authentication is used.
145NTLMSSP_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
150NTLMSSP_NEGOTIATE_NTLM = 0x00000200
151NTLMSSP_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.
159NTLMSSP_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.
164NTLMSSP_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.
170NTLMSSP_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.
175NTLMSSP_NEGOTIATE_SIGN = 0x00000010 # means packet is signed, if verifier is wrong it fails
176NTLMSSP_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.
180NTLMSSP_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
183# details.
184NTLM_NEGOTIATE_OEM = 0x00000002
186# If set, requests Unicode character set encoding. An alternate name for this field is NTLMSSP_NEGOTIATE_UNICODE.
187NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
189# AV_PAIR constants
190NTLMSSP_AV_EOL = 0x00
191NTLMSSP_AV_HOSTNAME = 0x01
192NTLMSSP_AV_DOMAINNAME = 0x02
193NTLMSSP_AV_DNS_HOSTNAME = 0x03
194NTLMSSP_AV_DNS_DOMAINNAME = 0x04
195NTLMSSP_AV_DNS_TREENAME = 0x05
196NTLMSSP_AV_FLAGS = 0x06
197NTLMSSP_AV_TIME = 0x07
198NTLMSSP_AV_RESTRICTIONS = 0x08
199NTLMSSP_AV_TARGET_NAME = 0x09
200NTLMSSP_AV_CHANNEL_BINDINGS = 0x0a
202class AV_PAIRS:
203 def __init__(self, data = None):
204 self.fields = {}
205 if data is not None: 205 ↛ exitline 205 didn't return from function '__init__', because the condition on line 205 was never false
206 self.fromString(data)
208 def __setitem__(self,key,value):
209 self.fields[key] = (len(value),value)
211 def __getitem__(self, key):
212 if key in self.fields: 212 ↛ 214line 212 didn't jump to line 214, because the condition on line 212 was never false
213 return self.fields[key]
214 return None
216 def __delitem__(self, key):
217 del self.fields[key]
219 def __len__(self):
220 return len(self.getData())
222 def __str__(self):
223 return len(self.getData())
225 def fromString(self, data):
226 tInfo = data
227 fType = 0xff
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:]
237 def dump(self):
238 for i in list(self.fields.keys()):
239 print("%s: {%r}" % (i,self[i]))
241 def getData(self):
242 if NTLMSSP_AV_EOL in self.fields: 242 ↛ 244line 242 didn't jump to line 244, because the condition on line 242 was never false
243 del self.fields[NTLMSSP_AV_EOL]
244 ans = b''
245 for i in list(self.fields.keys()):
246 ans+= struct.pack('<HH', i, self[i][0])
247 ans+= self[i][1]
249 # end with a NTLMSSP_AV_EOL
250 ans += struct.pack('<HH', NTLMSSP_AV_EOL, 0)
252 return ans
254# [MS-NLMP] 2.2.2.10 VERSION
255# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/b1a6ceb2-f8ad-462b-b5af-f18527c48175
256class VERSION(Structure):
257 NTLMSSP_REVISION_W2K3 = 0x0F
259 structure = (
260 ('ProductMajorVersion', '<B=0'),
261 ('ProductMinorVersion', '<B=0'),
262 ('ProductBuild', '<H=0'),
263 ('Reserved', '3s=""'),
264 ('NTLMRevisionCurrent', '<B=self.NTLMSSP_REVISION_W2K3'),
265 )
267class NTLMAuthNegotiate(Structure):
269 structure = (
270 ('','"NTLMSSP\x00'),
271 ('message_type','<L=1'),
272 ('flags','<L'),
273 ('domain_len','<H-domain_name'),
274 ('domain_max_len','<H-domain_name'),
275 ('domain_offset','<L=0'),
276 ('host_len','<H-host_name'),
277 ('host_maxlen','<H-host_name'),
278 ('host_offset','<L=0'),
279 ('os_version',':'),
280 ('host_name',':'),
281 ('domain_name',':'))
283 def __init__(self):
284 Structure.__init__(self)
285 self['flags']= (
286 NTLMSSP_NEGOTIATE_128 |
287 NTLMSSP_NEGOTIATE_KEY_EXCH|
288 # NTLMSSP_LM_KEY |
289 NTLMSSP_NEGOTIATE_NTLM |
290 NTLMSSP_NEGOTIATE_UNICODE |
291 # NTLMSSP_ALWAYS_SIGN |
292 NTLMSSP_NEGOTIATE_SIGN |
293 NTLMSSP_NEGOTIATE_SEAL |
294 # NTLMSSP_TARGET |
295 0)
296 self['host_name']=''
297 self['domain_name']=''
298 self['os_version']=''
299 self._workstation = ''
301 def setWorkstation(self, workstation):
302 self._workstation = workstation
304 def getWorkstation(self):
305 return self._workstation
307 def __hasNegotiateVersion(self):
308 return (self['flags'] & NTLMSSP_NEGOTIATE_VERSION) == NTLMSSP_NEGOTIATE_VERSION
310 def getData(self):
311 if len(self.fields['host_name']) > 0: 311 ↛ 312line 311 didn't jump to line 312, because the condition on line 311 was never true
312 self['flags'] |= NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
313 if len(self.fields['domain_name']) > 0: 313 ↛ 314line 313 didn't jump to line 314, because the condition on line 313 was never true
314 self['flags'] |= NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
315 version_len = len(self.fields['os_version'])
316 if version_len > 0: 316 ↛ 317line 316 didn't jump to line 317, because the condition on line 316 was never true
317 self['flags'] |= NTLMSSP_NEGOTIATE_VERSION
318 elif self.__hasNegotiateVersion(): 318 ↛ 319line 318 didn't jump to line 319, because the condition on line 318 was never true
319 raise Exception('Must provide the os_version field if the NTLMSSP_NEGOTIATE_VERSION flag is set')
320 if (self['flags'] & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) == NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED: 320 ↛ 321line 320 didn't jump to line 321, because the condition on line 320 was never true
321 self['host_offset']=32 + version_len
322 if (self['flags'] & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED) == NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED: 322 ↛ 323line 322 didn't jump to line 323, because the condition on line 322 was never true
323 self['domain_offset']=32+len(self['host_name']) + version_len
324 return Structure.getData(self)
326 def fromString(self,data):
327 Structure.fromString(self,data)
329 domain_offset = self['domain_offset']
330 domain_end = self['domain_len'] + domain_offset
331 self['domain_name'] = data[ domain_offset : domain_end ]
333 host_offset = self['host_offset']
334 host_end = self['host_len'] + host_offset
335 self['host_name'] = data[ host_offset : host_end ]
337 if len(data) >= 36 and self.__hasNegotiateVersion():
338 self['os_version'] = VERSION(data[32:])
339 else:
340 self['os_version'] = ''
342class NTLMAuthChallenge(Structure):
344 structure = (
345 ('','"NTLMSSP\x00'),
346 ('message_type','<L=2'),
347 ('domain_len','<H-domain_name'),
348 ('domain_max_len','<H-domain_name'),
349 ('domain_offset','<L=40'),
350 ('flags','<L=0'),
351 ('challenge','8s'),
352 ('reserved','8s=""'),
353 ('TargetInfoFields_len','<H-TargetInfoFields'),
354 ('TargetInfoFields_max_len','<H-TargetInfoFields'),
355 ('TargetInfoFields_offset','<L'),
356 ('VersionLen','_-Version','self.checkVersion(self["flags"])'),
357 ('Version',':'),
358 ('domain_name',':'),
359 ('TargetInfoFields',':'))
361 @staticmethod
362 def checkVersion(flags):
363 if flags is not None: 363 ↛ 366line 363 didn't jump to line 366, because the condition on line 363 was never false
364 if flags & NTLMSSP_NEGOTIATE_VERSION == 0: 364 ↛ 365line 364 didn't jump to line 365, because the condition on line 364 was never true
365 return 0
366 return 8
368 def getData(self):
369 if self['TargetInfoFields'] is not None and type(self['TargetInfoFields']) is not bytes:
370 raw_av_fields = self['TargetInfoFields'].getData()
371 self['TargetInfoFields'] = raw_av_fields
372 return Structure.getData(self)
374 def fromString(self,data):
375 Structure.fromString(self,data)
376 self['domain_name'] = data[self['domain_offset']:][:self['domain_len']]
377 self['TargetInfoFields'] = data[self['TargetInfoFields_offset']:][:self['TargetInfoFields_len']]
378 return self
380class NTLMAuthChallengeResponse(Structure):
382 structure = (
383 ('','"NTLMSSP\x00'),
384 ('message_type','<L=3'),
385 ('lanman_len','<H-lanman'),
386 ('lanman_max_len','<H-lanman'),
387 ('lanman_offset','<L'),
388 ('ntlm_len','<H-ntlm'),
389 ('ntlm_max_len','<H-ntlm'),
390 ('ntlm_offset','<L'),
391 ('domain_len','<H-domain_name'),
392 ('domain_max_len','<H-domain_name'),
393 ('domain_offset','<L'),
394 ('user_len','<H-user_name'),
395 ('user_max_len','<H-user_name'),
396 ('user_offset','<L'),
397 ('host_len','<H-host_name'),
398 ('host_max_len','<H-host_name'),
399 ('host_offset','<L'),
400 ('session_key_len','<H-session_key'),
401 ('session_key_max_len','<H-session_key'),
402 ('session_key_offset','<L'),
403 ('flags','<L'),
404 ('VersionLen','_-Version','self.checkVersion(self["flags"])'),
405 ('Version',':=""'),
406 ('MICLen','_-MIC','self.checkMIC(self["flags"])'),
407 ('MIC',':=""'),
408 ('domain_name',':'),
409 ('user_name',':'),
410 ('host_name',':'),
411 ('lanman',':'),
412 ('ntlm',':'),
413 ('session_key',':'))
415 def __init__(self, username = '', password = '', challenge = '', lmhash = '', nthash = '', flags = 0):
416 Structure.__init__(self)
417 self['session_key']=''
418 self['user_name']=username.encode('utf-16le')
419 self['domain_name']='' #"CLON".encode('utf-16le')
420 self['host_name']='' #"BETS".encode('utf-16le')
421 self['flags'] = ( #authResp['flags']
422 # we think (beto & gera) that his flags force a memory conten leakage when a windows 2000 answers using
423 # uninitializaed verifiers
424 NTLMSSP_NEGOTIATE_128 |
425 NTLMSSP_NEGOTIATE_KEY_EXCH|
426 # NTLMSSP_LM_KEY |
427 NTLMSSP_NEGOTIATE_NTLM |
428 NTLMSSP_NEGOTIATE_UNICODE |
429 # NTLMSSP_ALWAYS_SIGN |
430 NTLMSSP_NEGOTIATE_SIGN |
431 NTLMSSP_NEGOTIATE_SEAL |
432 # NTLMSSP_TARGET |
433 0)
434 # Here we do the stuff
435 if username and ( lmhash != '' or nthash != ''): 435 ↛ 436line 435 didn't jump to line 436, because the condition on line 435 was never true
436 self['lanman'] = get_ntlmv1_response(lmhash, challenge)
437 self['ntlm'] = get_ntlmv1_response(nthash, challenge)
438 elif username and password:
439 lmhash = compute_lmhash(password)
440 nthash = compute_nthash(password)
441 self['lanman']=get_ntlmv1_response(lmhash, challenge)
442 self['ntlm']=get_ntlmv1_response(nthash, challenge) # This is not used for LM_KEY nor NTLM_KEY
443 else:
444 self['lanman'] = ''
445 self['ntlm'] = ''
446 if not self['host_name']: 446 ↛ exitline 446 didn't return from function '__init__', because the condition on line 446 was never false
447 self['host_name'] = 'NULL'.encode('utf-16le') # for NULL session there must be a hostname
449 @staticmethod
450 def checkVersion(flags):
451 if flags is not None: 451 ↛ 454line 451 didn't jump to line 454, because the condition on line 451 was never false
452 if flags & NTLMSSP_NEGOTIATE_VERSION == 0: 452 ↛ 454line 452 didn't jump to line 454, because the condition on line 452 was never false
453 return 0
454 return 8
456 @staticmethod
457 def checkMIC(flags):
458 # TODO: Find a proper way to check the MIC is in there
459 if flags is not None: 459 ↛ 462line 459 didn't jump to line 462, because the condition on line 459 was never false
460 if flags & NTLMSSP_NEGOTIATE_VERSION == 0: 460 ↛ 462line 460 didn't jump to line 462, because the condition on line 460 was never false
461 return 0
462 return 16
464 def getData(self):
465 self['domain_offset']=64+self.checkMIC(self["flags"])+self.checkVersion(self["flags"])
466 self['user_offset']=64+self.checkMIC(self["flags"])+self.checkVersion(self["flags"])+len(self['domain_name'])
467 self['host_offset']=self['user_offset']+len(self['user_name'])
468 self['lanman_offset']=self['host_offset']+len(self['host_name'])
469 self['ntlm_offset']=self['lanman_offset']+len(self['lanman'])
470 self['session_key_offset']=self['ntlm_offset']+len(self['ntlm'])
471 return Structure.getData(self)
473 def fromString(self,data):
474 Structure.fromString(self,data)
475 # [MS-NLMP] page 27
476 # Payload data can be present in any order within the Payload field,
477 # with variable-length padding before or after the data
479 domain_offset = self['domain_offset']
480 domain_end = self['domain_len'] + domain_offset
481 self['domain_name'] = data[ domain_offset : domain_end ]
483 host_offset = self['host_offset']
484 host_end = self['host_len'] + host_offset
485 self['host_name'] = data[ host_offset: host_end ]
487 user_offset = self['user_offset']
488 user_end = self['user_len'] + user_offset
489 self['user_name'] = data[ user_offset: user_end ]
491 ntlm_offset = self['ntlm_offset']
492 ntlm_end = self['ntlm_len'] + ntlm_offset
493 self['ntlm'] = data[ ntlm_offset : ntlm_end ]
495 lanman_offset = self['lanman_offset']
496 lanman_end = self['lanman_len'] + lanman_offset
497 self['lanman'] = data[ lanman_offset : lanman_end]
499class ImpacketStructure(Structure):
500 def set_parent(self, other):
501 self.parent = other
503 def get_packet(self):
504 return str(self)
506 def get_size(self):
507 return len(self)
509class ExtendedOrNotMessageSignature(Structure):
510 def __init__(self, flags = 0, **kargs):
511 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 511 ↛ 514line 511 didn't jump to line 514, because the condition on line 511 was never false
512 self.structure = self.extendedMessageSignature
513 else:
514 self.structure = self.MessageSignature
515 return Structure.__init__(self, **kargs)
517class NTLMMessageSignature(ExtendedOrNotMessageSignature):
518 extendedMessageSignature = (
519 ('Version','<L=1'),
520 ('Checksum','<q'),
521 ('SeqNum','<I'),
522 )
524 MessageSignature = (
525 ('Version','<L=1'),
526 ('RandomPad','<I=0'),
527 ('Checksum','<I'),
528 ('SeqNum','<I'),
529 )
531KNOWN_DES_INPUT = b"KGS!@#$%"
533def __expand_DES_key(key):
534 # Expand the key from a 7-byte password key into a 8-byte DES key
535 if not isinstance(key, bytes): 535 ↛ 536line 535 didn't jump to line 536, because the condition on line 535 was never true
536 key = bytes(key)
537 key = bytearray(key[:7]).ljust(7, b'\x00')
538 s = bytearray()
539 s.append(((key[0] >> 1) & 0x7f) << 1)
540 s.append(((key[0] & 0x01) << 6 | ((key[1] >> 2) & 0x3f)) << 1)
541 s.append(((key[1] & 0x03) << 5 | ((key[2] >> 3) & 0x1f)) << 1)
542 s.append(((key[2] & 0x07) << 4 | ((key[3] >> 4) & 0x0f)) << 1)
543 s.append(((key[3] & 0x0f) << 3 | ((key[4] >> 5) & 0x07)) << 1)
544 s.append(((key[4] & 0x1f) << 2 | ((key[5] >> 6) & 0x03)) << 1)
545 s.append(((key[5] & 0x3f) << 1 | ((key[6] >> 7) & 0x01)) << 1)
546 s.append((key[6] & 0x7f) << 1)
547 return bytes(s)
549def __DES_block(key, msg):
550 cipher = DES.new(__expand_DES_key(key),DES.MODE_ECB)
551 return cipher.encrypt(msg)
553def ntlmssp_DES_encrypt(key, challenge):
554 answer = __DES_block(key[:7], challenge)
555 answer += __DES_block(key[7:14], challenge)
556 answer += __DES_block(key[14:], challenge)
557 return answer
559# High level functions to use NTLMSSP
561def getNTLMSSPType1(workstation='', domain='', signingRequired = False, use_ntlmv2 = USE_NTLMv2):
562 # Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with
563 # international characters.
564 import sys
565 encoding = sys.getfilesystemencoding()
566 if encoding is not None: 566 ↛ 577line 566 didn't jump to line 577, because the condition on line 566 was never false
567 try:
568 workstation.encode('utf-16le')
569 except:
570 workstation = workstation.decode(encoding)
571 try:
572 domain.encode('utf-16le')
573 except:
574 domain = domain.decode(encoding)
576 # Let's prepare a Type 1 NTLMSSP Message
577 auth = NTLMAuthNegotiate()
578 auth['flags']=0
579 if signingRequired:
580 auth['flags'] = NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
581 NTLMSSP_NEGOTIATE_SEAL
582 if use_ntlmv2: 582 ↛ 584line 582 didn't jump to line 584, because the condition on line 582 was never false
583 auth['flags'] |= NTLMSSP_NEGOTIATE_TARGET_INFO
584 auth['flags'] |= NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | NTLMSSP_NEGOTIATE_UNICODE | \
585 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_56
587 # We're not adding workstation / domain fields this time. Normally Windows clients don't add such information but,
588 # we will save the workstation name to be used later.
589 auth.setWorkstation(workstation)
591 return auth
593def getNTLMSSPType3(type1, type2, user, password, domain, lmhash = '', nthash = '', use_ntlmv2 = USE_NTLMv2):
595 # Safety check in case somebody sent password = None.. That's not allowed. Setting it to '' and hope for the best.
596 if password is None: 596 ↛ 597line 596 didn't jump to line 597, because the condition on line 596 was never true
597 password = ''
599 # Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with
600 # international characters.
601 import sys
602 encoding = sys.getfilesystemencoding()
603 if encoding is not None: 603 ↛ 617line 603 didn't jump to line 617, because the condition on line 603 was never false
604 try:
605 user.encode('utf-16le')
606 except:
607 user = user.decode(encoding)
608 try:
609 password.encode('utf-16le')
610 except:
611 password = password.decode(encoding)
612 try:
613 domain.encode('utf-16le')
614 except:
615 domain = user.decode(encoding)
617 ntlmChallenge = NTLMAuthChallenge(type2)
619 # Let's start with the original flags sent in the type1 message
620 responseFlags = type1['flags']
622 # Token received and parsed. Depending on the authentication
623 # method we will create a valid ChallengeResponse
624 ntlmChallengeResponse = NTLMAuthChallengeResponse(user, password, ntlmChallenge['challenge'])
626 clientChallenge = b("".join([random.choice(string.digits+string.ascii_letters) for _ in range(8)]))
628 serverName = ntlmChallenge['TargetInfoFields']
630 ntResponse, lmResponse, sessionBaseKey = computeResponse(ntlmChallenge['flags'], ntlmChallenge['challenge'],
631 clientChallenge, serverName, domain, user, password,
632 lmhash, nthash, use_ntlmv2)
634 # Let's check the return flags
635 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) == 0: 635 ↛ 637line 635 didn't jump to line 637, because the condition on line 635 was never true
636 # No extended session security, taking it out
637 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
638 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_128 ) == 0: 638 ↛ 640line 638 didn't jump to line 640, because the condition on line 638 was never true
639 # No support for 128 key len, taking it out
640 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_128
641 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH) == 0:
642 # No key exchange supported, taking it out
643 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_KEY_EXCH
644 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_SEAL) == 0:
645 # No sign available, taking it out
646 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_SEAL
647 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_SIGN) == 0:
648 # No sign available, taking it out
649 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_SIGN
650 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) == 0:
651 # No sign available, taking it out
652 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_ALWAYS_SIGN
654 keyExchangeKey = KXKEY(ntlmChallenge['flags'], sessionBaseKey, lmResponse, ntlmChallenge['challenge'], password,
655 lmhash, nthash, use_ntlmv2)
657 # Special case for anonymous login
658 if user == '' and password == '' and lmhash == '' and nthash == '':
659 keyExchangeKey = b'\x00'*16
661 # If we set up key exchange, let's fill the right variables
662 if ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH:
663 # not exactly what I call random tho :\
664 # exportedSessionKey = this is the key we should use to sign
665 exportedSessionKey = b("".join([random.choice(string.digits+string.ascii_letters) for _ in range(16)]))
666 #exportedSessionKey = "A"*16
667 #print "keyExchangeKey %r" % keyExchangeKey
668 # Let's generate the right session key based on the challenge flags
669 #if responseFlags & NTLMSSP_NTLM2_KEY:
670 # Extended session security enabled
671 # if responseFlags & NTLMSSP_KEY_128:
672 # Full key
673 # exportedSessionKey = exportedSessionKey
674 # elif responseFlags & NTLMSSP_KEY_56:
675 # Only 56-bit key
676 # exportedSessionKey = exportedSessionKey[:7]
677 # else:
678 # exportedSessionKey = exportedSessionKey[:5]
679 #elif responseFlags & NTLMSSP_KEY_56:
680 # No extended session security, just 56 bits key
681 # exportedSessionKey = exportedSessionKey[:7] + '\xa0'
682 #else:
683 # exportedSessionKey = exportedSessionKey[:5] + '\xe5\x38\xb0'
685 encryptedRandomSessionKey = generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey)
686 else:
687 encryptedRandomSessionKey = None
688 # [MS-NLMP] page 46
689 exportedSessionKey = keyExchangeKey
691 ntlmChallengeResponse['flags'] = responseFlags
692 ntlmChallengeResponse['domain_name'] = domain.encode('utf-16le')
693 ntlmChallengeResponse['host_name'] = type1.getWorkstation().encode('utf-16le')
694 if lmResponse == '':
695 ntlmChallengeResponse['lanman'] = b'\x00'
696 else:
697 ntlmChallengeResponse['lanman'] = lmResponse
698 ntlmChallengeResponse['ntlm'] = ntResponse
699 if encryptedRandomSessionKey is not None:
700 ntlmChallengeResponse['session_key'] = encryptedRandomSessionKey
702 return ntlmChallengeResponse, exportedSessionKey
705# NTLMv1 Algorithm
707def generateSessionKeyV1(password, lmhash, nthash):
708 hash = MD4.new()
709 hash.update(NTOWFv1(password, lmhash, nthash))
710 return hash.digest()
713def computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='',
714 nthash='', use_ntlmv2=USE_NTLMv2):
715 if user == '' and password == '':
716 # Special case for anonymous authentication
717 lmResponse = ''
718 ntResponse = ''
719 else:
720 lmhash = LMOWFv1(password, lmhash, nthash)
721 nthash = NTOWFv1(password, lmhash, nthash)
722 if flags & NTLMSSP_NEGOTIATE_LM_KEY:
723 ntResponse = ''
724 lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
725 elif flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
726 md5 = hashlib.new('md5')
727 chall = (serverChallenge + clientChallenge)
728 md5.update(chall)
729 ntResponse = ntlmssp_DES_encrypt(nthash, md5.digest()[:8])
730 lmResponse = clientChallenge + b'\x00'*16
731 else:
732 ntResponse = get_ntlmv1_response(nthash,serverChallenge)
733 lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
735 sessionBaseKey = generateSessionKeyV1(password, lmhash, nthash)
736 return ntResponse, lmResponse, sessionBaseKey
738def compute_lmhash(password):
739 # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
740 password = password.upper()
741 lmhash = __DES_block(b(password[:7]), KNOWN_DES_INPUT)
742 lmhash += __DES_block(b(password[7:14]), KNOWN_DES_INPUT)
743 return lmhash
745def NTOWFv1(password, lmhash = '', nthash=''):
746 if nthash != '': 746 ↛ 747line 746 didn't jump to line 747, because the condition on line 746 was never true
747 return nthash
748 return compute_nthash(password)
750def LMOWFv1(password, lmhash = '', nthash=''):
751 if lmhash != '': 751 ↛ 752line 751 didn't jump to line 752, because the condition on line 751 was never true
752 return lmhash
753 return compute_lmhash(password)
755def compute_nthash(password):
756 # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
757 try:
758 password = str(password).encode('utf_16le')
759 except UnicodeDecodeError:
760 import sys
761 password = password.decode(sys.getfilesystemencoding()).encode('utf_16le')
763 hash = MD4.new()
764 hash.update(password)
765 return hash.digest()
767def get_ntlmv1_response(key, challenge):
768 return ntlmssp_DES_encrypt(key, challenge)
770# NTLMv2 Algorithm - as described in MS-NLMP Section 3.3.2
772# Crypto Stuff
774def MAC(flags, handle, signingKey, seqNum, message):
775 # [MS-NLMP] Section 3.4.4
776 # Returns the right messageSignature depending on the flags
777 messageSignature = NTLMMessageSignature(flags)
778 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 778 ↛ 791line 778 didn't jump to line 791, because the condition on line 778 was never false
779 if flags & NTLMSSP_NEGOTIATE_KEY_EXCH: 779 ↛ 786line 779 didn't jump to line 786, because the condition on line 779 was never false
780 messageSignature['Version'] = 1
781 messageSignature['Checksum'] = \
782 struct.unpack('<q', handle(hmac_md5(signingKey, struct.pack('<i', seqNum) + message)[:8]))[0]
783 messageSignature['SeqNum'] = seqNum
784 seqNum += 1
785 else:
786 messageSignature['Version'] = 1
787 messageSignature['Checksum'] = struct.unpack('<q',hmac_md5(signingKey, struct.pack('<i',seqNum)+message)[:8])[0]
788 messageSignature['SeqNum'] = seqNum
789 seqNum += 1
790 else:
791 messageSignature['Version'] = 1
792 messageSignature['Checksum'] = struct.pack('<I',binascii.crc32(message)& 0xFFFFFFFF)
793 messageSignature['RandomPad'] = 0
794 messageSignature['RandomPad'] = handle(struct.pack('<I',messageSignature['RandomPad']))
795 messageSignature['Checksum'] = struct.unpack('<I',handle(messageSignature['Checksum']))[0]
796 messageSignature['SeqNum'] = handle(b'\x00\x00\x00\x00')
797 messageSignature['SeqNum'] = struct.unpack('<I',messageSignature['SeqNum'])[0] ^ seqNum
798 messageSignature['RandomPad'] = 0
800 return messageSignature
802def SEAL(flags, signingKey, sealingKey, messageToSign, messageToEncrypt, seqNum, handle):
803 sealedMessage = handle(messageToEncrypt)
804 signature = MAC(flags, handle, signingKey, seqNum, messageToSign)
805 return sealedMessage, signature
807def SIGN(flags, signingKey, message, seqNum, handle):
808 return MAC(flags, handle, signingKey, seqNum, message)
810def SIGNKEY(flags, randomSessionKey, mode = 'Client'):
811 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 811 ↛ 821line 811 didn't jump to line 821, because the condition on line 811 was never false
812 if mode == 'Client':
813 md5 = hashlib.new('md5')
814 md5.update(randomSessionKey + b"session key to client-to-server signing key magic constant\x00")
815 signKey = md5.digest()
816 else:
817 md5 = hashlib.new('md5')
818 md5.update(randomSessionKey + b"session key to server-to-client signing key magic constant\x00")
819 signKey = md5.digest()
820 else:
821 signKey = None
822 return signKey
824def SEALKEY(flags, randomSessionKey, mode = 'Client'):
825 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 825 ↛ 842line 825 didn't jump to line 842, because the condition on line 825 was never false
826 if flags & NTLMSSP_NEGOTIATE_128: 826 ↛ 828line 826 didn't jump to line 828, because the condition on line 826 was never false
827 sealKey = randomSessionKey
828 elif flags & NTLMSSP_NEGOTIATE_56:
829 sealKey = randomSessionKey[:7]
830 else:
831 sealKey = randomSessionKey[:5]
833 if mode == 'Client':
834 md5 = hashlib.new('md5')
835 md5.update(sealKey + b'session key to client-to-server sealing key magic constant\x00')
836 sealKey = md5.digest()
837 else:
838 md5 = hashlib.new('md5')
839 md5.update(sealKey + b'session key to server-to-client sealing key magic constant\x00')
840 sealKey = md5.digest()
842 elif flags & NTLMSSP_NEGOTIATE_56:
843 sealKey = randomSessionKey[:7] + b'\xa0'
844 else:
845 sealKey = randomSessionKey[:5] + b'\xe5\x38\xb0'
847 return sealKey
850def generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey):
851 cipher = ARC4.new(keyExchangeKey)
852 cipher_encrypt = cipher.encrypt
854 sessionKey = cipher_encrypt(exportedSessionKey)
855 return sessionKey
857def KXKEY(flags, sessionBaseKey, lmChallengeResponse, serverChallenge, password, lmhash, nthash, use_ntlmv2 = USE_NTLMv2):
858 if use_ntlmv2: 858 ↛ 861line 858 didn't jump to line 861, because the condition on line 858 was never false
859 return sessionBaseKey
861 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
862 if flags & NTLMSSP_NEGOTIATE_NTLM:
863 keyExchangeKey = hmac_md5(sessionBaseKey, serverChallenge + lmChallengeResponse[:8])
864 else:
865 keyExchangeKey = sessionBaseKey
866 elif flags & NTLMSSP_NEGOTIATE_NTLM:
867 if flags & NTLMSSP_NEGOTIATE_LM_KEY:
868 keyExchangeKey = __DES_block(LMOWFv1(password, lmhash)[:7], lmChallengeResponse[:8]) + __DES_block(
869 LMOWFv1(password, lmhash)[7] + b'\xBD\xBD\xBD\xBD\xBD\xBD', lmChallengeResponse[:8])
870 elif flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY:
871 keyExchangeKey = LMOWFv1(password,lmhash)[:8] + b'\x00'*8
872 else:
873 keyExchangeKey = sessionBaseKey
874 else:
875 raise Exception("Can't create a valid KXKEY!")
877 return keyExchangeKey
879def hmac_md5(key, data):
880 import hmac
881 h = hmac.new(key, digestmod=hashlib.md5)
882 h.update(data)
883 return h.digest()
885def NTOWFv2( user, password, domain, hash = ''):
886 if hash != '':
887 theHash = hash
888 else:
889 theHash = compute_nthash(password)
890 return hmac_md5(theHash, user.upper().encode('utf-16le') + domain.encode('utf-16le'))
892def LMOWFv2( user, password, domain, lmhash = ''):
893 return NTOWFv2( user, password, domain, lmhash)
896def computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='',
897 nthash='', use_ntlmv2=USE_NTLMv2):
899 responseServerVersion = b'\x01'
900 hiResponseServerVersion = b'\x01'
901 responseKeyNT = NTOWFv2(user, password, domain, nthash)
903 av_pairs = AV_PAIRS(serverName)
904 # In order to support SPN target name validation, we have to add this to the serverName av_pairs. Otherwise we will
905 # get access denied
906 # This is set at Local Security Policy -> Local Policies -> Security Options -> Server SPN target name validation
907 # level
908 if TEST_CASE is False: 908 ↛ 917line 908 didn't jump to line 917, because the condition on line 908 was never false
909 av_pairs[NTLMSSP_AV_TARGET_NAME] = 'cifs/'.encode('utf-16le') + av_pairs[NTLMSSP_AV_HOSTNAME][1]
910 if av_pairs[NTLMSSP_AV_TIME] is not None: 910 ↛ 913line 910 didn't jump to line 913, because the condition on line 910 was never false
911 aTime = av_pairs[NTLMSSP_AV_TIME][1]
912 else:
913 aTime = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
914 av_pairs[NTLMSSP_AV_TIME] = aTime
915 serverName = av_pairs.getData()
916 else:
917 aTime = b'\x00'*8
919 temp = responseServerVersion + hiResponseServerVersion + b'\x00' * 6 + aTime + clientChallenge + b'\x00' * 4 + \
920 serverName + b'\x00' * 4
922 ntProofStr = hmac_md5(responseKeyNT, serverChallenge + temp)
924 ntChallengeResponse = ntProofStr + temp
925 lmChallengeResponse = hmac_md5(responseKeyNT, serverChallenge + clientChallenge) + clientChallenge
926 sessionBaseKey = hmac_md5(responseKeyNT, ntProofStr)
928 if user == '' and password == '':
929 # Special case for anonymous authentication
930 ntChallengeResponse = ''
931 lmChallengeResponse = ''
933 return ntChallengeResponse, lmChallengeResponse, sessionBaseKey
935class NTLM_HTTP(object):
936 # Parent class for NTLM HTTP classes.
937 MSG_TYPE = None
939 @classmethod
940 def get_instace(cls,msg_64):
941 msg = None
942 msg_type = 0
943 if msg_64 != '':
944 msg = base64.b64decode(msg_64[5:]) # Remove the 'NTLM '
945 msg_type = ord(msg[8])
947 for _cls in NTLM_HTTP.__subclasses__():
948 if msg_type == _cls.MSG_TYPE:
949 instance = _cls()
950 instance.fromString(msg)
951 return instance
954class NTLM_HTTP_AuthRequired(NTLM_HTTP):
955 commonHdr = ()
956 # Message 0 means the first HTTP request e.g. 'GET /bla.png'
957 MSG_TYPE = 0
959 def fromString(self,data):
960 pass
963class NTLM_HTTP_AuthNegotiate(NTLM_HTTP, NTLMAuthNegotiate):
964 commonHdr = ()
965 MSG_TYPE = 1
967 def __init__(self):
968 NTLMAuthNegotiate.__init__(self)
971class NTLM_HTTP_AuthChallengeResponse(NTLM_HTTP, NTLMAuthChallengeResponse):
972 commonHdr = ()
973 MSG_TYPE = 3
975 def __init__(self):
976 NTLMAuthChallengeResponse.__init__(self)