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# Impacket - Collection of Python classes for working with network protocols.
2#
3# SECUREAUTH LABS. Copyright (C) 2021 SecureAuth Corporation. All rights reserved.
4#
5# This software is provided under a slightly modified version
6# of the Apache Software License. See the accompanying LICENSE file
7# for more information.
8#
10from __future__ import division
11from __future__ import print_function
12import base64
13import struct
14import calendar
15import time
16import hashlib
17import random
18import string
19import binascii
20from six import b
22from impacket.structure import Structure
23from impacket import LOG
26# This is important. NTLMv2 is not negotiated by the client or server.
27# It is used if set locally on both sides. Change this item if you don't want to use
28# NTLMv2 by default and fall back to NTLMv1 (with EXTENDED_SESSION_SECURITY or not)
29# Check the following links:
30# https://davenport.sourceforge.io/ntlm.html
31# https://blogs.msdn.microsoft.com/openspecification/2010/04/19/ntlm-keys-and-sundry-stuff/
32# https://social.msdn.microsoft.com/Forums/c8f488ed-1b96-4e06-bd65-390aa41138d1/msnlmp-msntht-determining-ntlm-v1-or-v2-in-http-authentication?forum=os_specifications
33# So I'm setting a global variable to control this, this can also be set programmatically
35USE_NTLMv2 = True # if false will fall back to NTLMv1 (or NTLMv1 with ESS a.k.a NTLM2)
36TEST_CASE = False # Only set to True when running Test Cases
39def computeResponse(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='', nthash='',
40 use_ntlmv2=USE_NTLMv2):
41 if use_ntlmv2: 41 ↛ 45line 41 didn't jump to line 45, because the condition on line 41 was never false
42 return computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password,
43 lmhash, nthash, use_ntlmv2=use_ntlmv2)
44 else:
45 return computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password,
46 lmhash, nthash, use_ntlmv2=use_ntlmv2)
47try:
48 from Cryptodome.Cipher import ARC4
49 from Cryptodome.Cipher import DES
50 from Cryptodome.Hash import MD4
51except Exception:
52 LOG.critical("Warning: You don't have any crypto installed. You need pycryptodomex")
53 LOG.critical("See https://pypi.org/project/pycryptodomex/")
55NTLM_AUTH_NONE = 1
56NTLM_AUTH_CONNECT = 2
57NTLM_AUTH_CALL = 3
58NTLM_AUTH_PKT = 4
59NTLM_AUTH_PKT_INTEGRITY = 5
60NTLM_AUTH_PKT_PRIVACY = 6
62# If set, requests 56-bit encryption. If the client sends NTLMSSP_NEGOTIATE_SEAL or NTLMSSP_NEGOTIATE_SIGN
63# with NTLMSSP_NEGOTIATE_56 to the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_56 to
64# the client in the CHALLENGE_MESSAGE. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128
65# are requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be
66# returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_56 if it is
67# supported. An alternate name for this field is NTLMSSP_NEGOTIATE_56.
68NTLMSSP_NEGOTIATE_56 = 0x80000000
70# If set, requests an explicit key exchange. This capability SHOULD be used because it improves security for message
71# 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
72# this field is NTLMSSP_NEGOTIATE_KEY_EXCH.
73NTLMSSP_NEGOTIATE_KEY_EXCH = 0x40000000
75# If set, requests 128-bit session key negotiation. An alternate name for this field is NTLMSSP_NEGOTIATE_128.
76# If the client sends NTLMSSP_NEGOTIATE_128 to the server in the NEGOTIATE_MESSAGE, the server MUST return
77# NTLMSSP_NEGOTIATE_128 to the client in the CHALLENGE_MESSAGE only if the client sets NTLMSSP_NEGOTIATE_SEAL or
78# NTLMSSP_NEGOTIATE_SIGN. Otherwise it is ignored. If both NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 are
79# requested and supported by the client and server, NTLMSSP_NEGOTIATE_56 and NTLMSSP_NEGOTIATE_128 will both be
80# returned to the client. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD set NTLMSSP_NEGOTIATE_128 if it
81# is supported. An alternate name for this field is NTLMSSP_NEGOTIATE_128
82NTLMSSP_NEGOTIATE_128 = 0x20000000
84NTLMSSP_RESERVED_1 = 0x10000000
85NTLMSSP_RESERVED_2 = 0x08000000
86NTLMSSP_RESERVED_3 = 0x04000000
88# If set, requests the protocol version number. The data corresponding to this flag is provided in the Version field
89# of the NEGOTIATE_MESSAGE, the CHALLENGE_MESSAGE, and the AUTHENTICATE_MESSAGE.<22> An alternate name for this field
90# is NTLMSSP_NEGOTIATE_VERSION
91NTLMSSP_NEGOTIATE_VERSION = 0x02000000
92NTLMSSP_RESERVED_4 = 0x01000000
94# If set, indicates that the TargetInfo fields in the CHALLENGE_MESSAGE (section 2.2.1.2) are populated.
95# An alternate name for this field is NTLMSSP_NEGOTIATE_TARGET_INFO.
96NTLMSSP_NEGOTIATE_TARGET_INFO = 0x00800000
98# If set, requests the usage of the LMOWF (section 3.3). An alternate name for this field is
99# NTLMSSP_REQUEST_NON_NT_SESSION_KEY.
100NTLMSSP_REQUEST_NON_NT_SESSION_KEY = 0x00400000
101NTLMSSP_RESERVED_5 = 0x00200000
103# If set, requests an identify level token. An alternate name for this field is NTLMSSP_NEGOTIATE_IDENTIFY
104NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000
106# If set, requests usage of the NTLM v2 session security. NTLM v2 session security is a misnomer because it is not
107# NTLM v2. It is NTLM v1 using the extended session security that is also in NTLM v2. NTLMSSP_NEGOTIATE_LM_KEY and
108# NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
109# and NTLMSSP_NEGOTIATE_LM_KEY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be returned to the
110# client. NTLM v2 authentication session key generation MUST be supported by both the client and the DC in order to be
111# used, and extended session security signing and sealing requires support from the client and the server in order to
112# be used.<23> An alternate name for this field is NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
113NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY = 0x00080000
114NTLMSSP_NEGOTIATE_NTLM2 = 0x00080000
115NTLMSSP_TARGET_TYPE_SHARE = 0x00040000
117# If set, TargetName MUST be a server name. The data corresponding to this flag is provided by the server in the
118# TargetName field of the CHALLENGE_MESSAGE. If this bit is set, then NTLMSSP_TARGET_TYPE_DOMAIN MUST NOT be set.
119# This flag MUST be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field
120# is NTLMSSP_TARGET_TYPE_SERVER
121NTLMSSP_TARGET_TYPE_SERVER = 0x00020000
123# If set, TargetName MUST be a domain name. The data corresponding to this flag is provided by the server in the
124# TargetName field of the CHALLENGE_MESSAGE. If set, then NTLMSSP_TARGET_TYPE_SERVER MUST NOT be set. This flag MUST
125# be ignored in the NEGOTIATE_MESSAGE and the AUTHENTICATE_MESSAGE. An alternate name for this field is
126# NTLMSSP_TARGET_TYPE_DOMAIN.
127NTLMSSP_TARGET_TYPE_DOMAIN = 0x00010000
129# If set, requests the presence of a signature block on all messages. NTLMSSP_NEGOTIATE_ALWAYS_SIGN MUST be set in the
130# NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. NTLMSSP_NEGOTIATE_ALWAYS_SIGN is overridden
131# by NTLMSSP_NEGOTIATE_SIGN and NTLMSSP_NEGOTIATE_SEAL, if they are supported. An alternate name for this field is
132# NTLMSSP_NEGOTIATE_ALWAYS_SIGN.
133NTLMSSP_NEGOTIATE_ALWAYS_SIGN = 0x00008000 # forces the other end to sign packets
134NTLMSSP_RESERVED_6 = 0x00004000
136# This flag indicates whether the Workstation field is present. If this flag is not set, the Workstation field MUST be
137# ignored. If this flag is set, the length field of the Workstation field specifies whether the workstation name is
138# nonempty or not.<24> An alternate name for this field is NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED.
139NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED = 0x00002000
141# If set, the domain name is provided (section 2.2.1.1).<25> An alternate name for this field is
142# NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
143NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED = 0x00001000
145# If set, the connection SHOULD be anonymous
146NTLMSSP_NEGOTIATE_ANONYMOUS = 0x00000800
148# If set, LM authentication is not allowed and only NT authentication is used.
149NTLMSSP_NEGOTIATE_NT_ONLY = 0x00000400
151# If set, requests usage of the NTLM v1 session security protocol. NTLMSSP_NEGOTIATE_NTLM MUST be set in the
152# NEGOTIATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate name for this field is
153# NTLMSSP_NEGOTIATE_NTLM
154NTLMSSP_NEGOTIATE_NTLM = 0x00000200
155NTLMSSP_RESERVED_8 = 0x00000100
157# If set, requests LAN Manager (LM) session key computation. NTLMSSP_NEGOTIATE_LM_KEY and
158# NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are mutually exclusive. If both NTLMSSP_NEGOTIATE_LM_KEY and
159# NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY are requested, NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY alone MUST be
160# returned to the client. NTLM v2 authentication session key generation MUST be supported by both the client and the
161# DC in order to be used, and extended session security signing and sealing requires support from the client and the
162# server to be used. An alternate name for this field is NTLMSSP_NEGOTIATE_LM_KEY.
163NTLMSSP_NEGOTIATE_LM_KEY = 0x00000080
165# If set, requests connectionless authentication. If NTLMSSP_NEGOTIATE_DATAGRAM is set, then NTLMSSP_NEGOTIATE_KEY_EXCH
166# MUST always be set in the AUTHENTICATE_MESSAGE to the server and the CHALLENGE_MESSAGE to the client. An alternate
167# name for this field is NTLMSSP_NEGOTIATE_DATAGRAM.
168NTLMSSP_NEGOTIATE_DATAGRAM = 0x00000040
170# If set, requests session key negotiation for message confidentiality. If the client sends NTLMSSP_NEGOTIATE_SEAL to
171# the server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SEAL to the client in the
172# CHALLENGE_MESSAGE. Clients and servers that set NTLMSSP_NEGOTIATE_SEAL SHOULD always set NTLMSSP_NEGOTIATE_56 and
173# NTLMSSP_NEGOTIATE_128, if they are supported. An alternate name for this field is NTLMSSP_NEGOTIATE_SEAL.
174NTLMSSP_NEGOTIATE_SEAL = 0x00000020
176# If set, requests session key negotiation for message signatures. If the client sends NTLMSSP_NEGOTIATE_SIGN to the
177# server in the NEGOTIATE_MESSAGE, the server MUST return NTLMSSP_NEGOTIATE_SIGN to the client in the CHALLENGE_MESSAGE.
178# An alternate name for this field is NTLMSSP_NEGOTIATE_SIGN.
179NTLMSSP_NEGOTIATE_SIGN = 0x00000010 # means packet is signed, if verifier is wrong it fails
180NTLMSSP_RESERVED_9 = 0x00000008
182# If set, a TargetName field of the CHALLENGE_MESSAGE (section 2.2.1.2) MUST be supplied. An alternate name for this
183# field is NTLMSSP_REQUEST_TARGET.
184NTLMSSP_REQUEST_TARGET = 0x00000004
186# If set, requests OEM character set encoding. An alternate name for this field is NTLM_NEGOTIATE_OEM. See bit A for
187# details.
188NTLM_NEGOTIATE_OEM = 0x00000002
190# If set, requests Unicode character set encoding. An alternate name for this field is NTLMSSP_NEGOTIATE_UNICODE.
191NTLMSSP_NEGOTIATE_UNICODE = 0x00000001
193# AV_PAIR constants
194NTLMSSP_AV_EOL = 0x00
195NTLMSSP_AV_HOSTNAME = 0x01
196NTLMSSP_AV_DOMAINNAME = 0x02
197NTLMSSP_AV_DNS_HOSTNAME = 0x03
198NTLMSSP_AV_DNS_DOMAINNAME = 0x04
199NTLMSSP_AV_DNS_TREENAME = 0x05
200NTLMSSP_AV_FLAGS = 0x06
201NTLMSSP_AV_TIME = 0x07
202NTLMSSP_AV_RESTRICTIONS = 0x08
203NTLMSSP_AV_TARGET_NAME = 0x09
204NTLMSSP_AV_CHANNEL_BINDINGS = 0x0a
206class AV_PAIRS:
207 def __init__(self, data = None):
208 self.fields = {}
209 if data is not None: 209 ↛ exitline 209 didn't return from function '__init__', because the condition on line 209 was never false
210 self.fromString(data)
212 def __setitem__(self,key,value):
213 self.fields[key] = (len(value),value)
215 def __getitem__(self, key):
216 if key in self.fields: 216 ↛ 218line 216 didn't jump to line 218, because the condition on line 216 was never false
217 return self.fields[key]
218 return None
220 def __delitem__(self, key):
221 del self.fields[key]
223 def __len__(self):
224 return len(self.getData())
226 def __str__(self):
227 return len(self.getData())
229 def fromString(self, data):
230 tInfo = data
231 fType = 0xff
232 while fType is not NTLMSSP_AV_EOL:
233 fType = struct.unpack('<H',tInfo[:struct.calcsize('<H')])[0]
234 tInfo = tInfo[struct.calcsize('<H'):]
235 length = struct.unpack('<H',tInfo[:struct.calcsize('<H')])[0]
236 tInfo = tInfo[struct.calcsize('<H'):]
237 content = tInfo[:length]
238 self.fields[fType]=(length,content)
239 tInfo = tInfo[length:]
241 def dump(self):
242 for i in list(self.fields.keys()):
243 print("%s: {%r}" % (i,self[i]))
245 def getData(self):
246 if NTLMSSP_AV_EOL in self.fields: 246 ↛ 248line 246 didn't jump to line 248, because the condition on line 246 was never false
247 del self.fields[NTLMSSP_AV_EOL]
248 ans = b''
249 for i in list(self.fields.keys()):
250 ans+= struct.pack('<HH', i, self[i][0])
251 ans+= self[i][1]
253 # end with a NTLMSSP_AV_EOL
254 ans += struct.pack('<HH', NTLMSSP_AV_EOL, 0)
256 return ans
258# [MS-NLMP] 2.2.2.10 VERSION
259# https://docs.microsoft.com/en-us/openspecs/windows_protocols/ms-nlmp/b1a6ceb2-f8ad-462b-b5af-f18527c48175
260class VERSION(Structure):
261 NTLMSSP_REVISION_W2K3 = 0x0F
263 structure = (
264 ('ProductMajorVersion', '<B=0'),
265 ('ProductMinorVersion', '<B=0'),
266 ('ProductBuild', '<H=0'),
267 ('Reserved', '3s=""'),
268 ('NTLMRevisionCurrent', '<B=self.NTLMSSP_REVISION_W2K3'),
269 )
271class NTLMAuthNegotiate(Structure):
273 structure = (
274 ('','"NTLMSSP\x00'),
275 ('message_type','<L=1'),
276 ('flags','<L'),
277 ('domain_len','<H-domain_name'),
278 ('domain_max_len','<H-domain_name'),
279 ('domain_offset','<L=0'),
280 ('host_len','<H-host_name'),
281 ('host_maxlen','<H-host_name'),
282 ('host_offset','<L=0'),
283 ('os_version',':'),
284 ('host_name',':'),
285 ('domain_name',':'))
287 def __init__(self):
288 Structure.__init__(self)
289 self['flags']= (
290 NTLMSSP_NEGOTIATE_128 |
291 NTLMSSP_NEGOTIATE_KEY_EXCH|
292 # NTLMSSP_LM_KEY |
293 NTLMSSP_NEGOTIATE_NTLM |
294 NTLMSSP_NEGOTIATE_UNICODE |
295 # NTLMSSP_ALWAYS_SIGN |
296 NTLMSSP_NEGOTIATE_SIGN |
297 NTLMSSP_NEGOTIATE_SEAL |
298 # NTLMSSP_TARGET |
299 0)
300 self['host_name']=''
301 self['domain_name']=''
302 self['os_version']=''
303 self._workstation = ''
305 def setWorkstation(self, workstation):
306 self._workstation = workstation
308 def getWorkstation(self):
309 return self._workstation
311 def __hasNegotiateVersion(self):
312 return (self['flags'] & NTLMSSP_NEGOTIATE_VERSION) == NTLMSSP_NEGOTIATE_VERSION
314 def getData(self):
315 if len(self.fields['host_name']) > 0: 315 ↛ 316line 315 didn't jump to line 316, because the condition on line 315 was never true
316 self['flags'] |= NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED
317 if len(self.fields['domain_name']) > 0: 317 ↛ 318line 317 didn't jump to line 318, because the condition on line 317 was never true
318 self['flags'] |= NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED
319 version_len = len(self.fields['os_version'])
320 if version_len > 0: 320 ↛ 321line 320 didn't jump to line 321, because the condition on line 320 was never true
321 self['flags'] |= NTLMSSP_NEGOTIATE_VERSION
322 elif self.__hasNegotiateVersion(): 322 ↛ 323line 322 didn't jump to line 323, because the condition on line 322 was never true
323 raise Exception('Must provide the os_version field if the NTLMSSP_NEGOTIATE_VERSION flag is set')
324 if (self['flags'] & NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED) == NTLMSSP_NEGOTIATE_OEM_WORKSTATION_SUPPLIED: 324 ↛ 325line 324 didn't jump to line 325, because the condition on line 324 was never true
325 self['host_offset']=32 + version_len
326 if (self['flags'] & NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED) == NTLMSSP_NEGOTIATE_OEM_DOMAIN_SUPPLIED: 326 ↛ 327line 326 didn't jump to line 327, because the condition on line 326 was never true
327 self['domain_offset']=32+len(self['host_name']) + version_len
328 return Structure.getData(self)
330 def fromString(self,data):
331 Structure.fromString(self,data)
333 domain_offset = self['domain_offset']
334 domain_end = self['domain_len'] + domain_offset
335 self['domain_name'] = data[ domain_offset : domain_end ]
337 host_offset = self['host_offset']
338 host_end = self['host_len'] + host_offset
339 self['host_name'] = data[ host_offset : host_end ]
341 if len(data) >= 36 and self.__hasNegotiateVersion():
342 self['os_version'] = VERSION(data[32:])
343 else:
344 self['os_version'] = ''
346class NTLMAuthChallenge(Structure):
348 structure = (
349 ('','"NTLMSSP\x00'),
350 ('message_type','<L=2'),
351 ('domain_len','<H-domain_name'),
352 ('domain_max_len','<H-domain_name'),
353 ('domain_offset','<L=40'),
354 ('flags','<L=0'),
355 ('challenge','8s'),
356 ('reserved','8s=""'),
357 ('TargetInfoFields_len','<H-TargetInfoFields'),
358 ('TargetInfoFields_max_len','<H-TargetInfoFields'),
359 ('TargetInfoFields_offset','<L'),
360 ('VersionLen','_-Version','self.checkVersion(self["flags"])'),
361 ('Version',':'),
362 ('domain_name',':'),
363 ('TargetInfoFields',':'))
365 @staticmethod
366 def checkVersion(flags):
367 if flags is not None: 367 ↛ 370line 367 didn't jump to line 370, because the condition on line 367 was never false
368 if flags & NTLMSSP_NEGOTIATE_VERSION == 0: 368 ↛ 369line 368 didn't jump to line 369, because the condition on line 368 was never true
369 return 0
370 return 8
372 def getData(self):
373 if self['TargetInfoFields'] is not None and type(self['TargetInfoFields']) is not bytes:
374 raw_av_fields = self['TargetInfoFields'].getData()
375 self['TargetInfoFields'] = raw_av_fields
376 return Structure.getData(self)
378 def fromString(self,data):
379 Structure.fromString(self,data)
380 self['domain_name'] = data[self['domain_offset']:][:self['domain_len']]
381 self['TargetInfoFields'] = data[self['TargetInfoFields_offset']:][:self['TargetInfoFields_len']]
382 return self
384class NTLMAuthChallengeResponse(Structure):
386 structure = (
387 ('','"NTLMSSP\x00'),
388 ('message_type','<L=3'),
389 ('lanman_len','<H-lanman'),
390 ('lanman_max_len','<H-lanman'),
391 ('lanman_offset','<L'),
392 ('ntlm_len','<H-ntlm'),
393 ('ntlm_max_len','<H-ntlm'),
394 ('ntlm_offset','<L'),
395 ('domain_len','<H-domain_name'),
396 ('domain_max_len','<H-domain_name'),
397 ('domain_offset','<L'),
398 ('user_len','<H-user_name'),
399 ('user_max_len','<H-user_name'),
400 ('user_offset','<L'),
401 ('host_len','<H-host_name'),
402 ('host_max_len','<H-host_name'),
403 ('host_offset','<L'),
404 ('session_key_len','<H-session_key'),
405 ('session_key_max_len','<H-session_key'),
406 ('session_key_offset','<L'),
407 ('flags','<L'),
408 ('VersionLen','_-Version','self.checkVersion(self["flags"])'),
409 ('Version',':=""'),
410 ('MICLen','_-MIC','self.checkMIC(self["flags"])'),
411 ('MIC',':=""'),
412 ('domain_name',':'),
413 ('user_name',':'),
414 ('host_name',':'),
415 ('lanman',':'),
416 ('ntlm',':'),
417 ('session_key',':'))
419 def __init__(self, username = '', password = '', challenge = '', lmhash = '', nthash = '', flags = 0):
420 Structure.__init__(self)
421 self['session_key']=''
422 self['user_name']=username.encode('utf-16le')
423 self['domain_name']='' #"CLON".encode('utf-16le')
424 self['host_name']='' #"BETS".encode('utf-16le')
425 self['flags'] = ( #authResp['flags']
426 # we think (beto & gera) that his flags force a memory conten leakage when a windows 2000 answers using
427 # uninitializaed verifiers
428 NTLMSSP_NEGOTIATE_128 |
429 NTLMSSP_NEGOTIATE_KEY_EXCH|
430 # NTLMSSP_LM_KEY |
431 NTLMSSP_NEGOTIATE_NTLM |
432 NTLMSSP_NEGOTIATE_UNICODE |
433 # NTLMSSP_ALWAYS_SIGN |
434 NTLMSSP_NEGOTIATE_SIGN |
435 NTLMSSP_NEGOTIATE_SEAL |
436 # NTLMSSP_TARGET |
437 0)
438 # Here we do the stuff
439 if username and ( lmhash != '' or nthash != ''): 439 ↛ 440line 439 didn't jump to line 440, because the condition on line 439 was never true
440 self['lanman'] = get_ntlmv1_response(lmhash, challenge)
441 self['ntlm'] = get_ntlmv1_response(nthash, challenge)
442 elif username and password:
443 lmhash = compute_lmhash(password)
444 nthash = compute_nthash(password)
445 self['lanman']=get_ntlmv1_response(lmhash, challenge)
446 self['ntlm']=get_ntlmv1_response(nthash, challenge) # This is not used for LM_KEY nor NTLM_KEY
447 else:
448 self['lanman'] = ''
449 self['ntlm'] = ''
450 if not self['host_name']: 450 ↛ exitline 450 didn't return from function '__init__', because the condition on line 450 was never false
451 self['host_name'] = 'NULL'.encode('utf-16le') # for NULL session there must be a hostname
453 @staticmethod
454 def checkVersion(flags):
455 if flags is not None: 455 ↛ 458line 455 didn't jump to line 458, because the condition on line 455 was never false
456 if flags & NTLMSSP_NEGOTIATE_VERSION == 0: 456 ↛ 458line 456 didn't jump to line 458, because the condition on line 456 was never false
457 return 0
458 return 8
460 @staticmethod
461 def checkMIC(flags):
462 # TODO: Find a proper way to check the MIC is in there
463 if flags is not None: 463 ↛ 466line 463 didn't jump to line 466, because the condition on line 463 was never false
464 if flags & NTLMSSP_NEGOTIATE_VERSION == 0: 464 ↛ 466line 464 didn't jump to line 466, because the condition on line 464 was never false
465 return 0
466 return 16
468 def getData(self):
469 self['domain_offset']=64+self.checkMIC(self["flags"])+self.checkVersion(self["flags"])
470 self['user_offset']=64+self.checkMIC(self["flags"])+self.checkVersion(self["flags"])+len(self['domain_name'])
471 self['host_offset']=self['user_offset']+len(self['user_name'])
472 self['lanman_offset']=self['host_offset']+len(self['host_name'])
473 self['ntlm_offset']=self['lanman_offset']+len(self['lanman'])
474 self['session_key_offset']=self['ntlm_offset']+len(self['ntlm'])
475 return Structure.getData(self)
477 def fromString(self,data):
478 Structure.fromString(self,data)
479 # [MS-NLMP] page 27
480 # Payload data can be present in any order within the Payload field,
481 # with variable-length padding before or after the data
483 domain_offset = self['domain_offset']
484 domain_end = self['domain_len'] + domain_offset
485 self['domain_name'] = data[ domain_offset : domain_end ]
487 host_offset = self['host_offset']
488 host_end = self['host_len'] + host_offset
489 self['host_name'] = data[ host_offset: host_end ]
491 user_offset = self['user_offset']
492 user_end = self['user_len'] + user_offset
493 self['user_name'] = data[ user_offset: user_end ]
495 ntlm_offset = self['ntlm_offset']
496 ntlm_end = self['ntlm_len'] + ntlm_offset
497 self['ntlm'] = data[ ntlm_offset : ntlm_end ]
499 lanman_offset = self['lanman_offset']
500 lanman_end = self['lanman_len'] + lanman_offset
501 self['lanman'] = data[ lanman_offset : lanman_end]
503class ImpacketStructure(Structure):
504 def set_parent(self, other):
505 self.parent = other
507 def get_packet(self):
508 return str(self)
510 def get_size(self):
511 return len(self)
513class ExtendedOrNotMessageSignature(Structure):
514 def __init__(self, flags = 0, **kargs):
515 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 515 ↛ 518line 515 didn't jump to line 518, because the condition on line 515 was never false
516 self.structure = self.extendedMessageSignature
517 else:
518 self.structure = self.MessageSignature
519 return Structure.__init__(self, **kargs)
521class NTLMMessageSignature(ExtendedOrNotMessageSignature):
522 extendedMessageSignature = (
523 ('Version','<L=1'),
524 ('Checksum','<q'),
525 ('SeqNum','<I'),
526 )
528 MessageSignature = (
529 ('Version','<L=1'),
530 ('RandomPad','<I=0'),
531 ('Checksum','<I'),
532 ('SeqNum','<I'),
533 )
535KNOWN_DES_INPUT = b"KGS!@#$%"
537def __expand_DES_key(key):
538 # Expand the key from a 7-byte password key into a 8-byte DES key
539 if not isinstance(key, bytes): 539 ↛ 540line 539 didn't jump to line 540, because the condition on line 539 was never true
540 key = bytes(key)
541 key = bytearray(key[:7]).ljust(7, b'\x00')
542 s = bytearray()
543 s.append(((key[0] >> 1) & 0x7f) << 1)
544 s.append(((key[0] & 0x01) << 6 | ((key[1] >> 2) & 0x3f)) << 1)
545 s.append(((key[1] & 0x03) << 5 | ((key[2] >> 3) & 0x1f)) << 1)
546 s.append(((key[2] & 0x07) << 4 | ((key[3] >> 4) & 0x0f)) << 1)
547 s.append(((key[3] & 0x0f) << 3 | ((key[4] >> 5) & 0x07)) << 1)
548 s.append(((key[4] & 0x1f) << 2 | ((key[5] >> 6) & 0x03)) << 1)
549 s.append(((key[5] & 0x3f) << 1 | ((key[6] >> 7) & 0x01)) << 1)
550 s.append((key[6] & 0x7f) << 1)
551 return bytes(s)
553def __DES_block(key, msg):
554 cipher = DES.new(__expand_DES_key(key),DES.MODE_ECB)
555 return cipher.encrypt(msg)
557def ntlmssp_DES_encrypt(key, challenge):
558 answer = __DES_block(key[:7], challenge)
559 answer += __DES_block(key[7:14], challenge)
560 answer += __DES_block(key[14:], challenge)
561 return answer
563# High level functions to use NTLMSSP
565def getNTLMSSPType1(workstation='', domain='', signingRequired = False, use_ntlmv2 = USE_NTLMv2):
566 # Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with
567 # international characters.
568 import sys
569 encoding = sys.getfilesystemencoding()
570 if encoding is not None: 570 ↛ 581line 570 didn't jump to line 581, because the condition on line 570 was never false
571 try:
572 workstation.encode('utf-16le')
573 except:
574 workstation = workstation.decode(encoding)
575 try:
576 domain.encode('utf-16le')
577 except:
578 domain = domain.decode(encoding)
580 # Let's prepare a Type 1 NTLMSSP Message
581 auth = NTLMAuthNegotiate()
582 auth['flags']=0
583 if signingRequired:
584 auth['flags'] = NTLMSSP_NEGOTIATE_KEY_EXCH | NTLMSSP_NEGOTIATE_SIGN | NTLMSSP_NEGOTIATE_ALWAYS_SIGN | \
585 NTLMSSP_NEGOTIATE_SEAL
586 if use_ntlmv2: 586 ↛ 588line 586 didn't jump to line 588, because the condition on line 586 was never false
587 auth['flags'] |= NTLMSSP_NEGOTIATE_TARGET_INFO
588 auth['flags'] |= NTLMSSP_NEGOTIATE_NTLM | NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY | NTLMSSP_NEGOTIATE_UNICODE | \
589 NTLMSSP_REQUEST_TARGET | NTLMSSP_NEGOTIATE_128 | NTLMSSP_NEGOTIATE_56
591 # We're not adding workstation / domain fields this time. Normally Windows clients don't add such information but,
592 # we will save the workstation name to be used later.
593 auth.setWorkstation(workstation)
595 return auth
597def getNTLMSSPType3(type1, type2, user, password, domain, lmhash = '', nthash = '', use_ntlmv2 = USE_NTLMv2):
599 # Safety check in case somebody sent password = None.. That's not allowed. Setting it to '' and hope for the best.
600 if password is None: 600 ↛ 601line 600 didn't jump to line 601, because the condition on line 600 was never true
601 password = ''
603 # Let's do some encoding checks before moving on. Kind of dirty, but found effective when dealing with
604 # international characters.
605 import sys
606 encoding = sys.getfilesystemencoding()
607 if encoding is not None: 607 ↛ 621line 607 didn't jump to line 621, because the condition on line 607 was never false
608 try:
609 user.encode('utf-16le')
610 except:
611 user = user.decode(encoding)
612 try:
613 password.encode('utf-16le')
614 except:
615 password = password.decode(encoding)
616 try:
617 domain.encode('utf-16le')
618 except:
619 domain = user.decode(encoding)
621 ntlmChallenge = NTLMAuthChallenge(type2)
623 # Let's start with the original flags sent in the type1 message
624 responseFlags = type1['flags']
626 # Token received and parsed. Depending on the authentication
627 # method we will create a valid ChallengeResponse
628 ntlmChallengeResponse = NTLMAuthChallengeResponse(user, password, ntlmChallenge['challenge'])
630 clientChallenge = b("".join([random.choice(string.digits+string.ascii_letters) for _ in range(8)]))
632 serverName = ntlmChallenge['TargetInfoFields']
634 ntResponse, lmResponse, sessionBaseKey = computeResponse(ntlmChallenge['flags'], ntlmChallenge['challenge'],
635 clientChallenge, serverName, domain, user, password,
636 lmhash, nthash, use_ntlmv2)
638 # Let's check the return flags
639 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) == 0: 639 ↛ 641line 639 didn't jump to line 641, because the condition on line 639 was never true
640 # No extended session security, taking it out
641 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
642 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_128 ) == 0: 642 ↛ 644line 642 didn't jump to line 644, because the condition on line 642 was never true
643 # No support for 128 key len, taking it out
644 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_128
645 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH) == 0:
646 # No key exchange supported, taking it out
647 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_KEY_EXCH
648 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_SEAL) == 0:
649 # No sign available, taking it out
650 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_SEAL
651 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_SIGN) == 0:
652 # No sign available, taking it out
653 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_SIGN
654 if (ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_ALWAYS_SIGN) == 0:
655 # No sign available, taking it out
656 responseFlags &= 0xffffffff ^ NTLMSSP_NEGOTIATE_ALWAYS_SIGN
658 keyExchangeKey = KXKEY(ntlmChallenge['flags'], sessionBaseKey, lmResponse, ntlmChallenge['challenge'], password,
659 lmhash, nthash, use_ntlmv2)
661 # Special case for anonymous login
662 if user == '' and password == '' and lmhash == '' and nthash == '':
663 keyExchangeKey = b'\x00'*16
665 # If we set up key exchange, let's fill the right variables
666 if ntlmChallenge['flags'] & NTLMSSP_NEGOTIATE_KEY_EXCH:
667 # not exactly what I call random tho :\
668 # exportedSessionKey = this is the key we should use to sign
669 exportedSessionKey = b("".join([random.choice(string.digits+string.ascii_letters) for _ in range(16)]))
670 #exportedSessionKey = "A"*16
671 #print "keyExchangeKey %r" % keyExchangeKey
672 # Let's generate the right session key based on the challenge flags
673 #if responseFlags & NTLMSSP_NTLM2_KEY:
674 # Extended session security enabled
675 # if responseFlags & NTLMSSP_KEY_128:
676 # Full key
677 # exportedSessionKey = exportedSessionKey
678 # elif responseFlags & NTLMSSP_KEY_56:
679 # Only 56-bit key
680 # exportedSessionKey = exportedSessionKey[:7]
681 # else:
682 # exportedSessionKey = exportedSessionKey[:5]
683 #elif responseFlags & NTLMSSP_KEY_56:
684 # No extended session security, just 56 bits key
685 # exportedSessionKey = exportedSessionKey[:7] + '\xa0'
686 #else:
687 # exportedSessionKey = exportedSessionKey[:5] + '\xe5\x38\xb0'
689 encryptedRandomSessionKey = generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey)
690 else:
691 encryptedRandomSessionKey = None
692 # [MS-NLMP] page 46
693 exportedSessionKey = keyExchangeKey
695 ntlmChallengeResponse['flags'] = responseFlags
696 ntlmChallengeResponse['domain_name'] = domain.encode('utf-16le')
697 ntlmChallengeResponse['host_name'] = type1.getWorkstation().encode('utf-16le')
698 if lmResponse == '':
699 ntlmChallengeResponse['lanman'] = b'\x00'
700 else:
701 ntlmChallengeResponse['lanman'] = lmResponse
702 ntlmChallengeResponse['ntlm'] = ntResponse
703 if encryptedRandomSessionKey is not None:
704 ntlmChallengeResponse['session_key'] = encryptedRandomSessionKey
706 return ntlmChallengeResponse, exportedSessionKey
709# NTLMv1 Algorithm
711def generateSessionKeyV1(password, lmhash, nthash):
712 hash = MD4.new()
713 hash.update(NTOWFv1(password, lmhash, nthash))
714 return hash.digest()
717def computeResponseNTLMv1(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='',
718 nthash='', use_ntlmv2=USE_NTLMv2):
719 if user == '' and password == '':
720 # Special case for anonymous authentication
721 lmResponse = ''
722 ntResponse = ''
723 else:
724 lmhash = LMOWFv1(password, lmhash, nthash)
725 nthash = NTOWFv1(password, lmhash, nthash)
726 if flags & NTLMSSP_NEGOTIATE_LM_KEY:
727 ntResponse = ''
728 lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
729 elif flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
730 md5 = hashlib.new('md5')
731 chall = (serverChallenge + clientChallenge)
732 md5.update(chall)
733 ntResponse = ntlmssp_DES_encrypt(nthash, md5.digest()[:8])
734 lmResponse = clientChallenge + b'\x00'*16
735 else:
736 ntResponse = get_ntlmv1_response(nthash,serverChallenge)
737 lmResponse = get_ntlmv1_response(lmhash, serverChallenge)
739 sessionBaseKey = generateSessionKeyV1(password, lmhash, nthash)
740 return ntResponse, lmResponse, sessionBaseKey
742def compute_lmhash(password):
743 # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
744 password = password.upper()
745 lmhash = __DES_block(b(password[:7]), KNOWN_DES_INPUT)
746 lmhash += __DES_block(b(password[7:14]), KNOWN_DES_INPUT)
747 return lmhash
749def NTOWFv1(password, lmhash = '', nthash=''):
750 if nthash != '': 750 ↛ 751line 750 didn't jump to line 751, because the condition on line 750 was never true
751 return nthash
752 return compute_nthash(password)
754def LMOWFv1(password, lmhash = '', nthash=''):
755 if lmhash != '': 755 ↛ 756line 755 didn't jump to line 756, because the condition on line 755 was never true
756 return lmhash
757 return compute_lmhash(password)
759def compute_nthash(password):
760 # This is done according to Samba's encryption specification (docs/html/ENCRYPTION.html)
761 try:
762 password = str(password).encode('utf_16le')
763 except UnicodeDecodeError:
764 import sys
765 password = password.decode(sys.getfilesystemencoding()).encode('utf_16le')
767 hash = MD4.new()
768 hash.update(password)
769 return hash.digest()
771def get_ntlmv1_response(key, challenge):
772 return ntlmssp_DES_encrypt(key, challenge)
774# NTLMv2 Algorithm - as described in MS-NLMP Section 3.3.2
776# Crypto Stuff
778def MAC(flags, handle, signingKey, seqNum, message):
779 # [MS-NLMP] Section 3.4.4
780 # Returns the right messageSignature depending on the flags
781 messageSignature = NTLMMessageSignature(flags)
782 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 782 ↛ 795line 782 didn't jump to line 795, because the condition on line 782 was never false
783 if flags & NTLMSSP_NEGOTIATE_KEY_EXCH: 783 ↛ 790line 783 didn't jump to line 790, because the condition on line 783 was never false
784 messageSignature['Version'] = 1
785 messageSignature['Checksum'] = \
786 struct.unpack('<q', handle(hmac_md5(signingKey, struct.pack('<i', seqNum) + message)[:8]))[0]
787 messageSignature['SeqNum'] = seqNum
788 seqNum += 1
789 else:
790 messageSignature['Version'] = 1
791 messageSignature['Checksum'] = struct.unpack('<q',hmac_md5(signingKey, struct.pack('<i',seqNum)+message)[:8])[0]
792 messageSignature['SeqNum'] = seqNum
793 seqNum += 1
794 else:
795 messageSignature['Version'] = 1
796 messageSignature['Checksum'] = struct.pack('<I',binascii.crc32(message)& 0xFFFFFFFF)
797 messageSignature['RandomPad'] = 0
798 messageSignature['RandomPad'] = handle(struct.pack('<I',messageSignature['RandomPad']))
799 messageSignature['Checksum'] = struct.unpack('<I',handle(messageSignature['Checksum']))[0]
800 messageSignature['SeqNum'] = handle(b'\x00\x00\x00\x00')
801 messageSignature['SeqNum'] = struct.unpack('<I',messageSignature['SeqNum'])[0] ^ seqNum
802 messageSignature['RandomPad'] = 0
804 return messageSignature
806def SEAL(flags, signingKey, sealingKey, messageToSign, messageToEncrypt, seqNum, handle):
807 sealedMessage = handle(messageToEncrypt)
808 signature = MAC(flags, handle, signingKey, seqNum, messageToSign)
809 return sealedMessage, signature
811def SIGN(flags, signingKey, message, seqNum, handle):
812 return MAC(flags, handle, signingKey, seqNum, message)
814def SIGNKEY(flags, randomSessionKey, mode = 'Client'):
815 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 815 ↛ 825line 815 didn't jump to line 825, because the condition on line 815 was never false
816 if mode == 'Client':
817 md5 = hashlib.new('md5')
818 md5.update(randomSessionKey + b"session key to client-to-server signing key magic constant\x00")
819 signKey = md5.digest()
820 else:
821 md5 = hashlib.new('md5')
822 md5.update(randomSessionKey + b"session key to server-to-client signing key magic constant\x00")
823 signKey = md5.digest()
824 else:
825 signKey = None
826 return signKey
828def SEALKEY(flags, randomSessionKey, mode = 'Client'):
829 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 829 ↛ 846line 829 didn't jump to line 846, because the condition on line 829 was never false
830 if flags & NTLMSSP_NEGOTIATE_128: 830 ↛ 832line 830 didn't jump to line 832, because the condition on line 830 was never false
831 sealKey = randomSessionKey
832 elif flags & NTLMSSP_NEGOTIATE_56:
833 sealKey = randomSessionKey[:7]
834 else:
835 sealKey = randomSessionKey[:5]
837 if mode == 'Client':
838 md5 = hashlib.new('md5')
839 md5.update(sealKey + b'session key to client-to-server sealing key magic constant\x00')
840 sealKey = md5.digest()
841 else:
842 md5 = hashlib.new('md5')
843 md5.update(sealKey + b'session key to server-to-client sealing key magic constant\x00')
844 sealKey = md5.digest()
846 elif flags & NTLMSSP_NEGOTIATE_56:
847 sealKey = randomSessionKey[:7] + b'\xa0'
848 else:
849 sealKey = randomSessionKey[:5] + b'\xe5\x38\xb0'
851 return sealKey
854def generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey):
855 cipher = ARC4.new(keyExchangeKey)
856 cipher_encrypt = cipher.encrypt
858 sessionKey = cipher_encrypt(exportedSessionKey)
859 return sessionKey
861def KXKEY(flags, sessionBaseKey, lmChallengeResponse, serverChallenge, password, lmhash, nthash, use_ntlmv2 = USE_NTLMv2):
862 if use_ntlmv2: 862 ↛ 865line 862 didn't jump to line 865, because the condition on line 862 was never false
863 return sessionBaseKey
865 if flags & NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
866 if flags & NTLMSSP_NEGOTIATE_NTLM:
867 keyExchangeKey = hmac_md5(sessionBaseKey, serverChallenge + lmChallengeResponse[:8])
868 else:
869 keyExchangeKey = sessionBaseKey
870 elif flags & NTLMSSP_NEGOTIATE_NTLM:
871 if flags & NTLMSSP_NEGOTIATE_LM_KEY:
872 keyExchangeKey = __DES_block(LMOWFv1(password, lmhash)[:7], lmChallengeResponse[:8]) + __DES_block(
873 LMOWFv1(password, lmhash)[7] + b'\xBD\xBD\xBD\xBD\xBD\xBD', lmChallengeResponse[:8])
874 elif flags & NTLMSSP_REQUEST_NON_NT_SESSION_KEY:
875 keyExchangeKey = LMOWFv1(password,lmhash)[:8] + b'\x00'*8
876 else:
877 keyExchangeKey = sessionBaseKey
878 else:
879 raise Exception("Can't create a valid KXKEY!")
881 return keyExchangeKey
883def hmac_md5(key, data):
884 import hmac
885 h = hmac.new(key, digestmod=hashlib.md5)
886 h.update(data)
887 return h.digest()
889def NTOWFv2( user, password, domain, hash = ''):
890 if hash != '':
891 theHash = hash
892 else:
893 theHash = compute_nthash(password)
894 return hmac_md5(theHash, user.upper().encode('utf-16le') + domain.encode('utf-16le'))
896def LMOWFv2( user, password, domain, lmhash = ''):
897 return NTOWFv2( user, password, domain, lmhash)
900def computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='',
901 nthash='', use_ntlmv2=USE_NTLMv2):
903 responseServerVersion = b'\x01'
904 hiResponseServerVersion = b'\x01'
905 responseKeyNT = NTOWFv2(user, password, domain, nthash)
907 av_pairs = AV_PAIRS(serverName)
908 # In order to support SPN target name validation, we have to add this to the serverName av_pairs. Otherwise we will
909 # get access denied
910 # This is set at Local Security Policy -> Local Policies -> Security Options -> Server SPN target name validation
911 # level
912 if TEST_CASE is False: 912 ↛ 921line 912 didn't jump to line 921, because the condition on line 912 was never false
913 av_pairs[NTLMSSP_AV_TARGET_NAME] = 'cifs/'.encode('utf-16le') + av_pairs[NTLMSSP_AV_HOSTNAME][1]
914 if av_pairs[NTLMSSP_AV_TIME] is not None: 914 ↛ 917line 914 didn't jump to line 917, because the condition on line 914 was never false
915 aTime = av_pairs[NTLMSSP_AV_TIME][1]
916 else:
917 aTime = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
918 av_pairs[NTLMSSP_AV_TIME] = aTime
919 serverName = av_pairs.getData()
920 else:
921 aTime = b'\x00'*8
923 temp = responseServerVersion + hiResponseServerVersion + b'\x00' * 6 + aTime + clientChallenge + b'\x00' * 4 + \
924 serverName + b'\x00' * 4
926 ntProofStr = hmac_md5(responseKeyNT, serverChallenge + temp)
928 ntChallengeResponse = ntProofStr + temp
929 lmChallengeResponse = hmac_md5(responseKeyNT, serverChallenge + clientChallenge) + clientChallenge
930 sessionBaseKey = hmac_md5(responseKeyNT, ntProofStr)
932 if user == '' and password == '':
933 # Special case for anonymous authentication
934 ntChallengeResponse = ''
935 lmChallengeResponse = ''
937 return ntChallengeResponse, lmChallengeResponse, sessionBaseKey
939class NTLM_HTTP(object):
940 # Parent class for NTLM HTTP classes.
941 MSG_TYPE = None
943 @classmethod
944 def get_instace(cls,msg_64):
945 msg = None
946 msg_type = 0
947 if msg_64 != '':
948 msg = base64.b64decode(msg_64[5:]) # Remove the 'NTLM '
949 msg_type = ord(msg[8])
951 for _cls in NTLM_HTTP.__subclasses__():
952 if msg_type == _cls.MSG_TYPE:
953 instance = _cls()
954 instance.fromString(msg)
955 return instance
958class NTLM_HTTP_AuthRequired(NTLM_HTTP):
959 commonHdr = ()
960 # Message 0 means the first HTTP request e.g. 'GET /bla.png'
961 MSG_TYPE = 0
963 def fromString(self,data):
964 pass
967class NTLM_HTTP_AuthNegotiate(NTLM_HTTP, NTLMAuthNegotiate):
968 commonHdr = ()
969 MSG_TYPE = 1
971 def __init__(self):
972 NTLMAuthNegotiate.__init__(self)
975class NTLM_HTTP_AuthChallengeResponse(NTLM_HTTP, NTLMAuthChallengeResponse):
976 commonHdr = ()
977 MSG_TYPE = 3
979 def __init__(self):
980 NTLMAuthChallengeResponse.__init__(self)