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# 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 

18 

19from impacket.structure import Structure 

20from impacket import LOG 

21 

22 

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 

31 

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 

34 

35 

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

51 

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 

58 

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 

66 

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 

71 

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 

80 

81NTLMSSP_RESERVED_1 = 0x10000000 

82NTLMSSP_RESERVED_2 = 0x08000000 

83NTLMSSP_RESERVED_3 = 0x04000000 

84 

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 

90 

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 

94 

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 

99 

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

101NTLMSSP_NEGOTIATE_IDENTIFY = 0x00100000 

102 

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 

113 

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 

119 

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 

125 

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 

132 

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 

137 

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 

142 

143 

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

145NTLMSSP_NEGOTIATE_NT_ONLY = 0x00000400 

146 

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 

152 

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 

160 

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 

165 

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 

171 

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 

177 

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 

181 

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 

185 

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

187NTLMSSP_NEGOTIATE_UNICODE = 0x00000001 

188 

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 

201 

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) 

207 

208 def __setitem__(self,key,value): 

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

210 

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 

215 

216 def __delitem__(self, key): 

217 del self.fields[key] 

218 

219 def __len__(self): 

220 return len(self.getData()) 

221 

222 def __str__(self): 

223 return len(self.getData()) 

224 

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

236 

237 def dump(self): 

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

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

240 

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] 

248 

249 # end with a NTLMSSP_AV_EOL 

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

251 

252 return ans 

253 

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 

258 

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 ) 

266 

267class NTLMAuthNegotiate(Structure): 

268 

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

282 

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

300 

301 def setWorkstation(self, workstation): 

302 self._workstation = workstation 

303 

304 def getWorkstation(self): 

305 return self._workstation 

306 

307 def __hasNegotiateVersion(self): 

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

309 

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) 

325 

326 def fromString(self,data): 

327 Structure.fromString(self,data) 

328 

329 domain_offset = self['domain_offset'] 

330 domain_end = self['domain_len'] + domain_offset 

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

332 

333 host_offset = self['host_offset'] 

334 host_end = self['host_len'] + host_offset 

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

336 

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

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

339 else: 

340 self['os_version'] = '' 

341 

342class NTLMAuthChallenge(Structure): 

343 

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

360 

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 

367 

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) 

373 

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 

379 

380class NTLMAuthChallengeResponse(Structure): 

381 

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

414 

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 

448 

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 

455 

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 

463 

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) 

472 

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 

478 

479 domain_offset = self['domain_offset'] 

480 domain_end = self['domain_len'] + domain_offset 

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

482 

483 host_offset = self['host_offset'] 

484 host_end = self['host_len'] + host_offset 

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

486 

487 user_offset = self['user_offset'] 

488 user_end = self['user_len'] + user_offset 

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

490 

491 ntlm_offset = self['ntlm_offset'] 

492 ntlm_end = self['ntlm_len'] + ntlm_offset 

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

494 

495 lanman_offset = self['lanman_offset'] 

496 lanman_end = self['lanman_len'] + lanman_offset 

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

498 

499class ImpacketStructure(Structure): 

500 def set_parent(self, other): 

501 self.parent = other 

502 

503 def get_packet(self): 

504 return str(self) 

505 

506 def get_size(self): 

507 return len(self) 

508 

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) 

516 

517class NTLMMessageSignature(ExtendedOrNotMessageSignature): 

518 extendedMessageSignature = ( 

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

520 ('Checksum','<q'), 

521 ('SeqNum','<I'), 

522 ) 

523 

524 MessageSignature = ( 

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

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

527 ('Checksum','<I'), 

528 ('SeqNum','<I'), 

529 ) 

530 

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

532 

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) 

548 

549def __DES_block(key, msg): 

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

551 return cipher.encrypt(msg) 

552 

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 

558 

559# High level functions to use NTLMSSP 

560 

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) 

575 

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 

586 

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) 

590 

591 return auth 

592 

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

594 

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

598 

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) 

616 

617 ntlmChallenge = NTLMAuthChallenge(type2) 

618 

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

620 responseFlags = type1['flags'] 

621 

622 # Token received and parsed. Depending on the authentication  

623 # method we will create a valid ChallengeResponse 

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

625 

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

627 

628 serverName = ntlmChallenge['TargetInfoFields'] 

629 

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

631 clientChallenge, serverName, domain, user, password, 

632 lmhash, nthash, use_ntlmv2) 

633 

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 

653 

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

655 lmhash, nthash, use_ntlmv2) 

656 

657 # Special case for anonymous login 

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

659 keyExchangeKey = b'\x00'*16 

660 

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' 

684 

685 encryptedRandomSessionKey = generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey) 

686 else: 

687 encryptedRandomSessionKey = None 

688 # [MS-NLMP] page 46 

689 exportedSessionKey = keyExchangeKey 

690 

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 

701 

702 return ntlmChallengeResponse, exportedSessionKey 

703 

704 

705# NTLMv1 Algorithm 

706 

707def generateSessionKeyV1(password, lmhash, nthash): 

708 hash = MD4.new() 

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

710 return hash.digest() 

711 

712 

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) 

734 

735 sessionBaseKey = generateSessionKeyV1(password, lmhash, nthash) 

736 return ntResponse, lmResponse, sessionBaseKey 

737 

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 

744 

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) 

749 

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) 

754 

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

762 

763 hash = MD4.new() 

764 hash.update(password) 

765 return hash.digest() 

766 

767def get_ntlmv1_response(key, challenge): 

768 return ntlmssp_DES_encrypt(key, challenge) 

769 

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

771 

772# Crypto Stuff 

773 

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 

799 

800 return messageSignature 

801 

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 

806 

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

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

809 

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 

823 

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] 

832 

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

841 

842 elif flags & NTLMSSP_NEGOTIATE_56: 

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

844 else: 

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

846 

847 return sealKey 

848 

849 

850def generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey): 

851 cipher = ARC4.new(keyExchangeKey) 

852 cipher_encrypt = cipher.encrypt 

853 

854 sessionKey = cipher_encrypt(exportedSessionKey) 

855 return sessionKey 

856 

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 

860 

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

876 

877 return keyExchangeKey 

878 

879def hmac_md5(key, data): 

880 import hmac 

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

882 h.update(data) 

883 return h.digest() 

884 

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

891 

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

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

894 

895 

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

897 nthash='', use_ntlmv2=USE_NTLMv2): 

898 

899 responseServerVersion = b'\x01' 

900 hiResponseServerVersion = b'\x01' 

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

902 

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 

918 

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

920 serverName + b'\x00' * 4 

921 

922 ntProofStr = hmac_md5(responseKeyNT, serverChallenge + temp) 

923 

924 ntChallengeResponse = ntProofStr + temp 

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

926 sessionBaseKey = hmac_md5(responseKeyNT, ntProofStr) 

927 

928 if user == '' and password == '': 

929 # Special case for anonymous authentication 

930 ntChallengeResponse = '' 

931 lmChallengeResponse = '' 

932 

933 return ntChallengeResponse, lmChallengeResponse, sessionBaseKey 

934 

935class NTLM_HTTP(object): 

936 # Parent class for NTLM HTTP classes. 

937 MSG_TYPE = None 

938 

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

946 

947 for _cls in NTLM_HTTP.__subclasses__(): 

948 if msg_type == _cls.MSG_TYPE: 

949 instance = _cls() 

950 instance.fromString(msg) 

951 return instance 

952 

953 

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 

958 

959 def fromString(self,data): 

960 pass 

961 

962 

963class NTLM_HTTP_AuthNegotiate(NTLM_HTTP, NTLMAuthNegotiate): 

964 commonHdr = () 

965 MSG_TYPE = 1 

966 

967 def __init__(self): 

968 NTLMAuthNegotiate.__init__(self) 

969 

970 

971class NTLM_HTTP_AuthChallengeResponse(NTLM_HTTP, NTLMAuthChallengeResponse): 

972 commonHdr = () 

973 MSG_TYPE = 3 

974 

975 def __init__(self): 

976 NTLMAuthChallengeResponse.__init__(self)