Hide keyboard shortcuts

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# 

9 

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 

21 

22from impacket.structure import Structure 

23from impacket import LOG 

24 

25 

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 

34 

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 

37 

38 

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/") 

54 

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 

61 

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 

69 

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 

74 

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 

83 

84NTLMSSP_RESERVED_1 = 0x10000000 

85NTLMSSP_RESERVED_2 = 0x08000000 

86NTLMSSP_RESERVED_3 = 0x04000000 

87 

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 

93 

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 

97 

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 

102 

103# If set, requests an identify level token. An alternate name for this field is NTLMSSP_NEGOTIATE_IDENTIFY 

104NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000 

105 

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 

116 

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 

122 

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 

128 

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 

135 

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 

140 

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 

144 

145# If set, the connection SHOULD be anonymous 

146NTLMSSP_NEGOTIATE_ANONYMOUS = 0x00000800 

147 

148# If set, LM authentication is not allowed and only NT authentication is used. 

149NTLMSSP_NEGOTIATE_NT_ONLY = 0x00000400 

150 

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 

156 

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 

164 

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 

169 

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 

175 

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 

181 

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 

185 

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 

189 

190# If set, requests Unicode character set encoding. An alternate name for this field is NTLMSSP_NEGOTIATE_UNICODE. 

191NTLMSSP_NEGOTIATE_UNICODE = 0x00000001 

192 

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 

205 

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) 

211 

212 def __setitem__(self,key,value): 

213 self.fields[key] = (len(value),value) 

214 

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 

219 

220 def __delitem__(self, key): 

221 del self.fields[key] 

222 

223 def __len__(self): 

224 return len(self.getData()) 

225 

226 def __str__(self): 

227 return len(self.getData()) 

228 

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:] 

240 

241 def dump(self): 

242 for i in list(self.fields.keys()): 

243 print("%s: {%r}" % (i,self[i])) 

244 

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] 

252 

253 # end with a NTLMSSP_AV_EOL 

254 ans += struct.pack('<HH', NTLMSSP_AV_EOL, 0) 

255 

256 return ans 

257 

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 

262 

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 ) 

270 

271class NTLMAuthNegotiate(Structure): 

272 

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',':')) 

286 

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 = '' 

304 

305 def setWorkstation(self, workstation): 

306 self._workstation = workstation 

307 

308 def getWorkstation(self): 

309 return self._workstation 

310 

311 def __hasNegotiateVersion(self): 

312 return (self['flags'] & NTLMSSP_NEGOTIATE_VERSION) == NTLMSSP_NEGOTIATE_VERSION 

313 

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) 

329 

330 def fromString(self,data): 

331 Structure.fromString(self,data) 

332 

333 domain_offset = self['domain_offset'] 

334 domain_end = self['domain_len'] + domain_offset 

335 self['domain_name'] = data[ domain_offset : domain_end ] 

336 

337 host_offset = self['host_offset'] 

338 host_end = self['host_len'] + host_offset 

339 self['host_name'] = data[ host_offset : host_end ] 

340 

341 if len(data) >= 36 and self.__hasNegotiateVersion(): 

342 self['os_version'] = VERSION(data[32:]) 

343 else: 

344 self['os_version'] = '' 

345 

346class NTLMAuthChallenge(Structure): 

347 

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',':')) 

364 

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 

371 

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) 

377 

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 

383 

384class NTLMAuthChallengeResponse(Structure): 

385 

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',':')) 

418 

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 

452 

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 

459 

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 

467 

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) 

476 

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 

482 

483 domain_offset = self['domain_offset'] 

484 domain_end = self['domain_len'] + domain_offset 

485 self['domain_name'] = data[ domain_offset : domain_end ] 

486 

487 host_offset = self['host_offset'] 

488 host_end = self['host_len'] + host_offset 

489 self['host_name'] = data[ host_offset: host_end ] 

490 

491 user_offset = self['user_offset'] 

492 user_end = self['user_len'] + user_offset 

493 self['user_name'] = data[ user_offset: user_end ] 

494 

495 ntlm_offset = self['ntlm_offset'] 

496 ntlm_end = self['ntlm_len'] + ntlm_offset 

497 self['ntlm'] = data[ ntlm_offset : ntlm_end ] 

498 

499 lanman_offset = self['lanman_offset'] 

500 lanman_end = self['lanman_len'] + lanman_offset 

501 self['lanman'] = data[ lanman_offset : lanman_end] 

502 

503class ImpacketStructure(Structure): 

504 def set_parent(self, other): 

505 self.parent = other 

506 

507 def get_packet(self): 

508 return str(self) 

509 

510 def get_size(self): 

511 return len(self) 

512 

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) 

520 

521class NTLMMessageSignature(ExtendedOrNotMessageSignature): 

522 extendedMessageSignature = ( 

523 ('Version','<L=1'), 

524 ('Checksum','<q'), 

525 ('SeqNum','<I'), 

526 ) 

527 

528 MessageSignature = ( 

529 ('Version','<L=1'), 

530 ('RandomPad','<I=0'), 

531 ('Checksum','<I'), 

532 ('SeqNum','<I'), 

533 ) 

534 

535KNOWN_DES_INPUT = b"KGS!@#$%" 

536 

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) 

552 

553def __DES_block(key, msg): 

554 cipher = DES.new(__expand_DES_key(key),DES.MODE_ECB) 

555 return cipher.encrypt(msg) 

556 

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 

562 

563# High level functions to use NTLMSSP 

564 

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) 

579 

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 

590 

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) 

594 

595 return auth 

596 

597def getNTLMSSPType3(type1, type2, user, password, domain, lmhash = '', nthash = '', use_ntlmv2 = USE_NTLMv2): 

598 

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 = '' 

602 

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) 

620 

621 ntlmChallenge = NTLMAuthChallenge(type2) 

622 

623 # Let's start with the original flags sent in the type1 message 

624 responseFlags = type1['flags'] 

625 

626 # Token received and parsed. Depending on the authentication  

627 # method we will create a valid ChallengeResponse 

628 ntlmChallengeResponse = NTLMAuthChallengeResponse(user, password, ntlmChallenge['challenge']) 

629 

630 clientChallenge = b("".join([random.choice(string.digits+string.ascii_letters) for _ in range(8)])) 

631 

632 serverName = ntlmChallenge['TargetInfoFields'] 

633 

634 ntResponse, lmResponse, sessionBaseKey = computeResponse(ntlmChallenge['flags'], ntlmChallenge['challenge'], 

635 clientChallenge, serverName, domain, user, password, 

636 lmhash, nthash, use_ntlmv2) 

637 

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 

657 

658 keyExchangeKey = KXKEY(ntlmChallenge['flags'], sessionBaseKey, lmResponse, ntlmChallenge['challenge'], password, 

659 lmhash, nthash, use_ntlmv2) 

660 

661 # Special case for anonymous login 

662 if user == '' and password == '' and lmhash == '' and nthash == '': 

663 keyExchangeKey = b'\x00'*16 

664 

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' 

688 

689 encryptedRandomSessionKey = generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey) 

690 else: 

691 encryptedRandomSessionKey = None 

692 # [MS-NLMP] page 46 

693 exportedSessionKey = keyExchangeKey 

694 

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 

705 

706 return ntlmChallengeResponse, exportedSessionKey 

707 

708 

709# NTLMv1 Algorithm 

710 

711def generateSessionKeyV1(password, lmhash, nthash): 

712 hash = MD4.new() 

713 hash.update(NTOWFv1(password, lmhash, nthash)) 

714 return hash.digest() 

715 

716 

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) 

738 

739 sessionBaseKey = generateSessionKeyV1(password, lmhash, nthash) 

740 return ntResponse, lmResponse, sessionBaseKey 

741 

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 

748 

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) 

753 

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) 

758 

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') 

766 

767 hash = MD4.new() 

768 hash.update(password) 

769 return hash.digest() 

770 

771def get_ntlmv1_response(key, challenge): 

772 return ntlmssp_DES_encrypt(key, challenge) 

773 

774# NTLMv2 Algorithm - as described in MS-NLMP Section 3.3.2 

775 

776# Crypto Stuff 

777 

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 

803 

804 return messageSignature 

805 

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 

810 

811def SIGN(flags, signingKey, message, seqNum, handle): 

812 return MAC(flags, handle, signingKey, seqNum, message) 

813 

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 

827 

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] 

836 

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() 

845 

846 elif flags & NTLMSSP_NEGOTIATE_56: 

847 sealKey = randomSessionKey[:7] + b'\xa0' 

848 else: 

849 sealKey = randomSessionKey[:5] + b'\xe5\x38\xb0' 

850 

851 return sealKey 

852 

853 

854def generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey): 

855 cipher = ARC4.new(keyExchangeKey) 

856 cipher_encrypt = cipher.encrypt 

857 

858 sessionKey = cipher_encrypt(exportedSessionKey) 

859 return sessionKey 

860 

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 

864 

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!") 

880 

881 return keyExchangeKey 

882 

883def hmac_md5(key, data): 

884 import hmac 

885 h = hmac.new(key, digestmod=hashlib.md5) 

886 h.update(data) 

887 return h.digest() 

888 

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')) 

895 

896def LMOWFv2( user, password, domain, lmhash = ''): 

897 return NTOWFv2( user, password, domain, lmhash) 

898 

899 

900def computeResponseNTLMv2(flags, serverChallenge, clientChallenge, serverName, domain, user, password, lmhash='', 

901 nthash='', use_ntlmv2=USE_NTLMv2): 

902 

903 responseServerVersion = b'\x01' 

904 hiResponseServerVersion = b'\x01' 

905 responseKeyNT = NTOWFv2(user, password, domain, nthash) 

906 

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 

922 

923 temp = responseServerVersion + hiResponseServerVersion + b'\x00' * 6 + aTime + clientChallenge + b'\x00' * 4 + \ 

924 serverName + b'\x00' * 4 

925 

926 ntProofStr = hmac_md5(responseKeyNT, serverChallenge + temp) 

927 

928 ntChallengeResponse = ntProofStr + temp 

929 lmChallengeResponse = hmac_md5(responseKeyNT, serverChallenge + clientChallenge) + clientChallenge 

930 sessionBaseKey = hmac_md5(responseKeyNT, ntProofStr) 

931 

932 if user == '' and password == '': 

933 # Special case for anonymous authentication 

934 ntChallengeResponse = '' 

935 lmChallengeResponse = '' 

936 

937 return ntChallengeResponse, lmChallengeResponse, sessionBaseKey 

938 

939class NTLM_HTTP(object): 

940 # Parent class for NTLM HTTP classes. 

941 MSG_TYPE = None 

942 

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]) 

950 

951 for _cls in NTLM_HTTP.__subclasses__(): 

952 if msg_type == _cls.MSG_TYPE: 

953 instance = _cls() 

954 instance.fromString(msg) 

955 return instance 

956 

957 

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 

962 

963 def fromString(self,data): 

964 pass 

965 

966 

967class NTLM_HTTP_AuthNegotiate(NTLM_HTTP, NTLMAuthNegotiate): 

968 commonHdr = () 

969 MSG_TYPE = 1 

970 

971 def __init__(self): 

972 NTLMAuthNegotiate.__init__(self) 

973 

974 

975class NTLM_HTTP_AuthChallengeResponse(NTLM_HTTP, NTLMAuthChallengeResponse): 

976 commonHdr = () 

977 MSG_TYPE = 3 

978 

979 def __init__(self): 

980 NTLMAuthChallengeResponse.__init__(self)