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# 

7# Author: Alberto Solino (@agsolino) 

8# 

9# TODO: 

10# [-] Functions should return NT error codes 

11# [-] Handling errors in all situations, right now it's just raising exceptions.  

12# [*] Standard authentication support 

13# [ ] Organize the connectionData stuff 

14# [*] Add capability to send a bad user ID if the user is not authenticated, 

15# right now you can ask for any command without actually being authenticated 

16# [ ] PATH TRAVERSALS EVERYWHERE.. BE WARNED! 

17# [ ] Check error situation (now many places assume the right data is coming) 

18# [ ] Implement IPC to the main process so the connectionData is on a single place 

19# [ ] Hence.. implement locking 

20# estamos en la B 

21 

22 

23import calendar 

24import socket 

25import time 

26import datetime 

27import struct 

28import threading 

29import logging 

30import logging.config 

31import ntpath 

32import os 

33import fnmatch 

34import errno 

35import sys 

36import random 

37import shutil 

38import string 

39import hashlib 

40import hmac 

41 

42from binascii import unhexlify, hexlify, a2b_hex 

43from six import PY2, b, text_type 

44from six.moves import configparser, socketserver 

45 

46# For signing 

47from impacket import smb, nmb, ntlm, uuid 

48from impacket import smb3structs as smb2 

49from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, \ 

50 ASN1_SUPPORTED_MECH 

51from impacket.nt_errors import STATUS_NO_MORE_FILES, STATUS_NETWORK_NAME_DELETED, STATUS_INVALID_PARAMETER, \ 

52 STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \ 

53 STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \ 

54 STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \ 

55 STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS, \ 

56 STATUS_LOGON_FAILURE, STATUS_OBJECT_PATH_SYNTAX_BAD 

57 

58# Setting LOG to current's module name 

59LOG = logging.getLogger(__name__) 

60 

61# These ones not defined in nt_errors 

62STATUS_SMB_BAD_UID = 0x005B0002 

63STATUS_SMB_BAD_TID = 0x00050002 

64 

65 

66# Utility functions 

67# and general functions. 

68# There are some common functions that can be accessed from more than one SMB 

69# command (or either TRANSACTION). That's why I'm putting them here 

70# TODO: Return NT ERROR Codes 

71 

72def computeNTLMv2(identity, lmhash, nthash, serverChallenge, authenticateMessage, ntlmChallenge, type1): 

73 # Let's calculate the NTLMv2 Response 

74 

75 responseKeyNT = ntlm.NTOWFv2(identity, '', authenticateMessage['domain_name'].decode('utf-16le'), nthash) 

76 responseKeyLM = ntlm.LMOWFv2(identity, '', authenticateMessage['domain_name'].decode('utf-16le'), lmhash) 

77 

78 ntProofStr = authenticateMessage['ntlm'][:16] 

79 temp = authenticateMessage['ntlm'][16:] 

80 ntProofStr2 = ntlm.hmac_md5(responseKeyNT, serverChallenge + temp) 

81 lmChallengeResponse = authenticateMessage['lanman'] 

82 sessionBaseKey = ntlm.hmac_md5(responseKeyNT, ntProofStr) 

83 

84 responseFlags = type1['flags'] 

85 

86 # Let's check the return flags 

87 if (ntlmChallenge['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY) == 0: 

88 # No extended session security, taking it out 

89 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 

90 if (ntlmChallenge['flags'] & ntlm.NTLMSSP_NEGOTIATE_128) == 0: 

91 # No support for 128 key len, taking it out 

92 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_128 

93 if (ntlmChallenge['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH) == 0: 

94 # No key exchange supported, taking it out 

95 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH 

96 if (ntlmChallenge['flags'] & ntlm.NTLMSSP_NEGOTIATE_SEAL) == 0: 

97 # No sign available, taking it out 

98 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_SEAL 

99 if (ntlmChallenge['flags'] & ntlm.NTLMSSP_NEGOTIATE_SIGN) == 0: 

100 # No sign available, taking it out 

101 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_SIGN 

102 if (ntlmChallenge['flags'] & ntlm.NTLMSSP_NEGOTIATE_ALWAYS_SIGN) == 0: 

103 # No sign available, taking it out 

104 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_ALWAYS_SIGN 

105 

106 keyExchangeKey = ntlm.KXKEY(ntlmChallenge['flags'], sessionBaseKey, lmChallengeResponse, 

107 ntlmChallenge['challenge'], '', 

108 lmhash, nthash, True) 

109 

110 # If we set up key exchange, let's fill the right variables 

111 if ntlmChallenge['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH: 

112 exportedSessionKey = authenticateMessage['session_key'] 

113 exportedSessionKey = ntlm.generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey) 

114 else: 

115 encryptedRandomSessionKey = None 

116 # [MS-NLMP] page 46 

117 exportedSessionKey = keyExchangeKey 

118 

119 # Do they match? 

120 if ntProofStr == ntProofStr2: 

121 # Yes!, process login 

122 return STATUS_SUCCESS, exportedSessionKey 

123 else: 

124 return STATUS_LOGON_FAILURE, exportedSessionKey 

125 

126 

127def outputToJohnFormat(challenge, username, domain, lmresponse, ntresponse): 

128 # We don't want to add a possible failure here, since this is an 

129 # extra bonus. We try, if it fails, returns nothing 

130 # ToDo: Document the parameter's types (bytes / string) and check all the places where it's called 

131 ret_value = '' 

132 if type(challenge) is not bytes: 

133 challenge = challenge.decode('latin-1') 

134 

135 try: 

136 if len(ntresponse) > 24: 

137 # Extended Security - NTLMv2 

138 ret_value = {'hash_string': '%s::%s:%s:%s:%s' % ( 

139 username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(challenge).decode('latin-1'), 

140 hexlify(ntresponse).decode('latin-1')[:32], 

141 hexlify(ntresponse).decode()[32:]), 'hash_version': 'ntlmv2'} 

142 else: 

143 # NTLMv1 

144 ret_value = {'hash_string': '%s::%s:%s:%s:%s' % ( 

145 username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(lmresponse).decode('latin-1'), 

146 hexlify(ntresponse).decode('latin-1'), 

147 hexlify(challenge).decode()), 'hash_version': 'ntlm'} 

148 except: 

149 # Let's try w/o decoding Unicode 

150 try: 

151 if len(ntresponse) > 24: 

152 # Extended Security - NTLMv2 

153 ret_value = {'hash_string': '%s::%s:%s:%s:%s' % ( 

154 username.decode('latin-1'), domain.decode('latin-1'), hexlify(challenge).decode('latin-1'), 

155 hexlify(ntresponse)[:32].decode('latin-1'), hexlify(ntresponse)[32:].decode('latin-1')), 

156 'hash_version': 'ntlmv2'} 

157 else: 

158 # NTLMv1 

159 ret_value = {'hash_string': '%s::%s:%s:%s:%s' % ( 

160 username, domain, hexlify(lmresponse).decode('latin-1'), hexlify(ntresponse).decode('latin-1'), 

161 hexlify(challenge).decode('latin-1')), 'hash_version': 'ntlm'} 

162 except Exception as e: 

163 import traceback 

164 traceback.print_exc() 

165 LOG.error("outputToJohnFormat: %s" % e) 

166 pass 

167 

168 return ret_value 

169 

170 

171def writeJohnOutputToFile(hash_string, hash_version, file_name): 

172 fn_data = os.path.splitext(file_name) 

173 if hash_version == "ntlmv2": 

174 output_filename = fn_data[0] + "_ntlmv2" + fn_data[1] 

175 else: 

176 output_filename = fn_data[0] + "_ntlm" + fn_data[1] 

177 

178 with open(output_filename, "a") as f: 

179 f.write(hash_string) 

180 f.write('\n') 

181 

182 

183def decodeSMBString(flags, text): 

184 if flags & smb.SMB.FLAGS2_UNICODE: 

185 return text.decode('utf-16le') 

186 else: 

187 return text 

188 

189 

190def encodeSMBString(flags, text): 

191 if flags & smb.SMB.FLAGS2_UNICODE: 

192 return (text).encode('utf-16le') 

193 else: 

194 return text.encode('ascii') 

195 

196 

197def getFileTime(t): 

198 t *= 10000000 

199 t += 116444736000000000 

200 return t 

201 

202 

203def getUnixTime(t): 

204 t -= 116444736000000000 

205 t //= 10000000 

206 return t 

207 

208 

209def getSMBDate(t): 

210 # TODO: Fix this :P 

211 d = datetime.date.fromtimestamp(t) 

212 year = d.year - 1980 

213 ret = (year << 8) + (d.month << 4) + d.day 

214 return ret 

215 

216 

217def getSMBTime(t): 

218 # TODO: Fix this :P 

219 d = datetime.datetime.fromtimestamp(t) 

220 return (d.hour << 8) + (d.minute << 4) + d.second 

221 

222 

223def getShares(connId, smbServer): 

224 config = smbServer.getServerConfig() 

225 sections = config.sections() 

226 # Remove the global one 

227 del (sections[sections.index('global')]) 

228 shares = {} 

229 for i in sections: 

230 shares[i] = dict(config.items(i)) 

231 return shares 

232 

233 

234def searchShare(connId, share, smbServer): 

235 config = smbServer.getServerConfig() 

236 if config.has_section(share): 

237 return dict(config.items(share)) 

238 else: 

239 return None 

240 

241 

242def openFile(path, fileName, accessMode, fileAttributes, openMode): 

243 fileName = os.path.normpath(fileName.replace('\\', '/')) 

244 errorCode = 0 

245 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'): 

246 # strip leading '/' 

247 fileName = fileName[1:] 

248 pathName = os.path.join(path, fileName) 

249 mode = 0 

250 # Check the Open Mode 

251 if openMode & 0x10: 

252 # If the file does not exist, create it. 

253 mode = os.O_CREAT 

254 else: 

255 # If file does not exist, return an error 

256 if os.path.exists(pathName) is not True: 

257 errorCode = STATUS_NO_SUCH_FILE 

258 return 0, mode, pathName, errorCode 

259 

260 if os.path.isdir(pathName) and (fileAttributes & smb.ATTR_DIRECTORY) == 0: 

261 # Request to open a normal file and this is actually a directory 

262 errorCode = STATUS_FILE_IS_A_DIRECTORY 

263 return 0, mode, pathName, errorCode 

264 # Check the Access Mode 

265 if accessMode & 0x7 == 1: 

266 mode |= os.O_WRONLY 

267 elif accessMode & 0x7 == 2: 

268 mode |= os.O_RDWR 

269 else: 

270 mode = os.O_RDONLY 

271 

272 try: 

273 if sys.platform == 'win32': 

274 mode |= os.O_BINARY 

275 fid = os.open(pathName, mode) 

276 except Exception as e: 

277 LOG.error("openFile: %s,%s" % (pathName, mode), e) 

278 fid = 0 

279 errorCode = STATUS_ACCESS_DENIED 

280 

281 return fid, mode, pathName, errorCode 

282 

283 

284def queryFsInformation(path, filename, level=0, pktFlags=smb.SMB.FLAGS2_UNICODE): 

285 if pktFlags & smb.SMB.FLAGS2_UNICODE: 

286 encoding = 'utf-16le' 

287 else: 

288 encoding = 'ascii' 

289 

290 fileName = os.path.normpath(filename.replace('\\', '/')) 

291 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'): 

292 # strip leading '/' 

293 fileName = fileName[1:] 

294 pathName = os.path.join(path, fileName) 

295 fileSize = os.path.getsize(pathName) 

296 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName) 

297 if level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO: 

298 data = smb.SMBQueryFsAttributeInfo() 

299 data['FileSystemAttributes'] = smb.FILE_CASE_SENSITIVE_SEARCH | smb.FILE_CASE_PRESERVED_NAMES 

300 data['MaxFilenNameLengthInBytes'] = 255 

301 data['LengthOfFileSystemName'] = len('XTFS') * 2 

302 data['FileSystemName'] = 'XTFS'.encode('utf-16le') 

303 return data.getData() 

304 elif level == smb.SMB_INFO_VOLUME: 

305 data = smb.SMBQueryFsInfoVolume(flags=pktFlags) 

306 data['VolumeLabel'] = 'SHARE'.encode(encoding) 

307 return data.getData() 

308 elif level == smb.SMB_QUERY_FS_VOLUME_INFO or level == smb2.SMB2_FILESYSTEM_VOLUME_INFO: 

309 data = smb.SMBQueryFsVolumeInfo() 

310 data['VolumeLabel'] = '' 

311 data['VolumeCreationTime'] = getFileTime(ctime) 

312 return data.getData() 

313 elif level == smb.SMB_QUERY_FS_SIZE_INFO: 

314 data = smb.SMBQueryFsSizeInfo() 

315 return data.getData() 

316 elif level == smb.FILE_FS_FULL_SIZE_INFORMATION: 

317 data = smb.SMBFileFsFullSizeInformation() 

318 return data.getData() 

319 elif level == smb.FILE_FS_SIZE_INFORMATION: 

320 data = smb.FileFsSizeInformation() 

321 return data.getData() 

322 else: 

323 lastWriteTime = mtime 

324 attribs = 0 

325 if os.path.isdir(pathName): 

326 attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

327 if os.path.isfile(pathName): 

328 attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL 

329 fileAttributes = attribs 

330 return fileSize, lastWriteTime, fileAttributes 

331 

332 

333def findFirst2(path, fileName, level, searchAttributes, pktFlags=smb.SMB.FLAGS2_UNICODE, isSMB2=False): 

334 # TODO: Depending on the level, this could be done much simpler 

335 

336 # print "FindFirs2 path:%s, filename:%s" % (path, fileName) 

337 fileName = os.path.normpath(fileName.replace('\\', '/')) 

338 # Let's choose the right encoding depending on the request 

339 if pktFlags & smb.SMB.FLAGS2_UNICODE: 

340 encoding = 'utf-16le' 

341 else: 

342 encoding = 'ascii' 

343 

344 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'): 

345 # strip leading '/' 

346 fileName = fileName[1:] 

347 

348 if not isInFileJail(path, fileName): 

349 LOG.error("Path not in current working directory") 

350 return [], 0, STATUS_OBJECT_PATH_SYNTAX_BAD 

351 

352 pathName = os.path.join(path, fileName) 

353 files = [] 

354 

355 if pathName.find('*') == -1 and pathName.find('?') == -1: 

356 # No search patterns 

357 pattern = '' 

358 else: 

359 pattern = os.path.basename(pathName) 

360 dirName = os.path.dirname(pathName) 

361 

362 # Always add . and .. Not that important for Windows, but Samba whines if 

363 # not present (for * search only) 

364 if pattern == '*': 

365 files.append(os.path.join(dirName, '.')) 

366 files.append(os.path.join(dirName, '..')) 

367 

368 if pattern != '': 

369 for file in os.listdir(dirName): 

370 if fnmatch.fnmatch(file.lower(), pattern.lower()): 

371 entry = os.path.join(dirName, file) 

372 if os.path.isdir(entry): 

373 if searchAttributes & smb.ATTR_DIRECTORY: 

374 files.append(entry) 

375 else: 

376 files.append(entry) 

377 else: 

378 if os.path.exists(pathName): 

379 files.append(pathName) 

380 

381 searchResult = [] 

382 searchCount = len(files) 

383 errorCode = STATUS_SUCCESS 

384 

385 for i in files: 

386 if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO: 

387 item = smb.SMBFindFileBothDirectoryInfo(flags=pktFlags) 

388 elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO or level == smb2.SMB2_FILE_DIRECTORY_INFO: 

389 item = smb.SMBFindFileDirectoryInfo(flags=pktFlags) 

390 elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO: 

391 item = smb.SMBFindFileFullDirectoryInfo(flags=pktFlags) 

392 elif level == smb.SMB_FIND_INFO_STANDARD: 

393 item = smb.SMBFindInfoStandard(flags=pktFlags) 

394 elif level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO: 

395 item = smb.SMBFindFileIdFullDirectoryInfo(flags=pktFlags) 

396 elif level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO: 

397 item = smb.SMBFindFileIdBothDirectoryInfo(flags=pktFlags) 

398 elif level == smb.SMB_FIND_FILE_NAMES_INFO or level == smb2.SMB2_FILE_NAMES_INFO: 

399 item = smb.SMBFindFileNamesInfo(flags=pktFlags) 

400 else: 

401 LOG.error("Wrong level %d!" % level) 

402 return searchResult, searchCount, STATUS_NOT_SUPPORTED 

403 

404 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(i) 

405 if os.path.isdir(i): 

406 item['ExtFileAttributes'] = smb.ATTR_DIRECTORY 

407 else: 

408 item['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE 

409 

410 item['FileName'] = os.path.basename(i).encode(encoding) 

411 

412 if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO: 

413 item['EaSize'] = 0 

414 item['EndOfFile'] = size 

415 item['AllocationSize'] = size 

416 item['CreationTime'] = getFileTime(ctime) 

417 item['LastAccessTime'] = getFileTime(atime) 

418 item['LastWriteTime'] = getFileTime(mtime) 

419 item['LastChangeTime'] = getFileTime(mtime) 

420 item['ShortName'] = '\x00' * 24 

421 item['FileName'] = os.path.basename(i).encode(encoding) 

422 padLen = (8 - (len(item) % 8)) % 8 

423 item['NextEntryOffset'] = len(item) + padLen 

424 elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO: 

425 item['EndOfFile'] = size 

426 item['AllocationSize'] = size 

427 item['CreationTime'] = getFileTime(ctime) 

428 item['LastAccessTime'] = getFileTime(atime) 

429 item['LastWriteTime'] = getFileTime(mtime) 

430 item['LastChangeTime'] = getFileTime(mtime) 

431 item['FileName'] = os.path.basename(i).encode(encoding) 

432 padLen = (8 - (len(item) % 8)) % 8 

433 item['NextEntryOffset'] = len(item) + padLen 

434 elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO: 

435 item['EaSize'] = 0 

436 item['EndOfFile'] = size 

437 item['AllocationSize'] = size 

438 item['CreationTime'] = getFileTime(ctime) 

439 item['LastAccessTime'] = getFileTime(atime) 

440 item['LastWriteTime'] = getFileTime(mtime) 

441 item['LastChangeTime'] = getFileTime(mtime) 

442 padLen = (8 - (len(item) % 8)) % 8 

443 item['NextEntryOffset'] = len(item) + padLen 

444 elif level == smb.SMB_FIND_INFO_STANDARD: 

445 item['EaSize'] = size 

446 item['CreationDate'] = getSMBDate(ctime) 

447 item['CreationTime'] = getSMBTime(ctime) 

448 item['LastAccessDate'] = getSMBDate(atime) 

449 item['LastAccessTime'] = getSMBTime(atime) 

450 item['LastWriteDate'] = getSMBDate(mtime) 

451 item['LastWriteTime'] = getSMBTime(mtime) 

452 searchResult.append(item) 

453 

454 # No more files 

455 if (level >= smb.SMB_FIND_FILE_DIRECTORY_INFO or isSMB2 is True) and searchCount > 0: 

456 searchResult[-1]['NextEntryOffset'] = 0 

457 

458 return searchResult, searchCount, errorCode 

459 

460 

461def queryFileInformation(path, filename, level): 

462 # print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level) 

463 return queryPathInformation(path, filename, level) 

464 

465 

466def queryPathInformation(path, filename, level): 

467 # TODO: Depending on the level, this could be done much simpler 

468 # print("queryPathInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)) 

469 try: 

470 errorCode = 0 

471 fileName = os.path.normpath(filename.replace('\\', '/')) 

472 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '': 

473 # strip leading '/' 

474 fileName = fileName[1:] 

475 pathName = os.path.join(path, fileName) 

476 if os.path.exists(pathName): 

477 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName) 

478 if level == smb.SMB_QUERY_FILE_BASIC_INFO: 

479 infoRecord = smb.SMBQueryFileBasicInfo() 

480 infoRecord['CreationTime'] = getFileTime(ctime) 

481 infoRecord['LastAccessTime'] = getFileTime(atime) 

482 infoRecord['LastWriteTime'] = getFileTime(mtime) 

483 infoRecord['LastChangeTime'] = getFileTime(mtime) 

484 if os.path.isdir(pathName): 

485 infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY 

486 else: 

487 infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE 

488 elif level == smb.SMB_QUERY_FILE_STANDARD_INFO: 

489 infoRecord = smb.SMBQueryFileStandardInfo() 

490 infoRecord['AllocationSize'] = size 

491 infoRecord['EndOfFile'] = size 

492 if os.path.isdir(pathName): 

493 infoRecord['Directory'] = 1 

494 else: 

495 infoRecord['Directory'] = 0 

496 elif level == smb.SMB_QUERY_FILE_ALL_INFO or level == smb2.SMB2_FILE_ALL_INFO: 

497 infoRecord = smb.SMBQueryFileAllInfo() 

498 infoRecord['CreationTime'] = getFileTime(ctime) 

499 infoRecord['LastAccessTime'] = getFileTime(atime) 

500 infoRecord['LastWriteTime'] = getFileTime(mtime) 

501 infoRecord['LastChangeTime'] = getFileTime(mtime) 

502 if os.path.isdir(pathName): 

503 infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY 

504 else: 

505 infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE 

506 infoRecord['AllocationSize'] = size 

507 infoRecord['EndOfFile'] = size 

508 if os.path.isdir(pathName): 

509 infoRecord['Directory'] = 1 

510 else: 

511 infoRecord['Directory'] = 0 

512 infoRecord['FileName'] = filename.encode('utf-16le') 

513 elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO: 

514 infoRecord = smb.SMBFileNetworkOpenInfo() 

515 infoRecord['CreationTime'] = getFileTime(ctime) 

516 infoRecord['LastAccessTime'] = getFileTime(atime) 

517 infoRecord['LastWriteTime'] = getFileTime(mtime) 

518 infoRecord['ChangeTime'] = getFileTime(mtime) 

519 infoRecord['AllocationSize'] = size 

520 infoRecord['EndOfFile'] = size 

521 if os.path.isdir(pathName): 

522 infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY 

523 else: 

524 infoRecord['FileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE 

525 elif level == smb.SMB_QUERY_FILE_EA_INFO or level == smb2.SMB2_FILE_EA_INFO: 

526 infoRecord = smb.SMBQueryFileEaInfo() 

527 elif level == smb2.SMB2_FILE_STREAM_INFO: 

528 infoRecord = smb.SMBFileStreamInformation() 

529 else: 

530 LOG.error('Unknown level for query path info! 0x%x' % level) 

531 # UNSUPPORTED 

532 return None, STATUS_NOT_SUPPORTED 

533 

534 return infoRecord, errorCode 

535 else: 

536 # NOT FOUND 

537 return None, STATUS_OBJECT_NAME_NOT_FOUND 

538 except Exception as e: 

539 LOG.error('queryPathInfo: %s' % e) 

540 raise 

541 

542 

543def queryDiskInformation(path): 

544 # TODO: Do something useful here :) 

545 # For now we just return fake values 

546 totalUnits = 65535 

547 freeUnits = 65535 

548 return totalUnits, freeUnits 

549 

550 

551def isInFileJail(path, fileName): 

552 pathName = os.path.join(path, fileName) 

553 share_real_path = os.path.realpath(path) 

554 return os.path.commonprefix((os.path.realpath(pathName), share_real_path)) == share_real_path 

555 

556 

557# Here we implement the NT transaction handlers 

558class NTTRANSCommands: 

559 def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount=0): 

560 pass 

561 

562 

563# Here we implement the NT transaction handlers 

564class TRANSCommands: 

565 @staticmethod 

566 def lanMan(connId, smbServer, recvPacket, parameters, data, maxDataCount=0): 

567 # Minimal [MS-RAP] implementation, just to return the shares 

568 connData = smbServer.getConnectionData(connId) 

569 

570 respSetup = b'' 

571 respParameters = b'' 

572 respData = b'' 

573 errorCode = STATUS_SUCCESS 

574 if struct.unpack('<H', parameters[:2])[0] == 0: 

575 # NetShareEnum Request 

576 netShareEnum = smb.SMBNetShareEnum(parameters) 

577 if netShareEnum['InfoLevel'] == 1: 

578 shares = getShares(connId, smbServer) 

579 respParameters = smb.SMBNetShareEnumResponse() 

580 respParameters['EntriesReturned'] = len(shares) 

581 respParameters['EntriesAvailable'] = len(shares) 

582 tailData = '' 

583 for i in shares: 

584 # NetShareInfo1 len == 20 

585 entry = smb.NetShareInfo1() 

586 entry['NetworkName'] = i + '\x00' * (13 - len(i)) 

587 entry['Type'] = int(shares[i]['share type']) 

588 # (beto) If offset == 0 it crashes explorer.exe on windows 7 

589 entry['RemarkOffsetLow'] = 20 * len(shares) + len(tailData) 

590 respData += entry.getData() 

591 if 'comment' in shares[i]: 

592 tailData += shares[i]['comment'] + '\x00' 

593 else: 

594 tailData += '\x00' 

595 respData += tailData 

596 else: 

597 # We don't support other info levels 

598 errorCode = STATUS_NOT_SUPPORTED 

599 elif struct.unpack('<H', parameters[:2])[0] == 13: 

600 # NetrServerGetInfo Request 

601 respParameters = smb.SMBNetServerGetInfoResponse() 

602 netServerInfo = smb.SMBNetServerInfo1() 

603 netServerInfo['ServerName'] = smbServer.getServerName() 

604 respData = netServerInfo.getData() 

605 respParameters['TotalBytesAvailable'] = len(respData) 

606 elif struct.unpack('<H', parameters[:2])[0] == 1: 

607 # NetrShareGetInfo Request 

608 request = smb.SMBNetShareGetInfo(parameters) 

609 respParameters = smb.SMBNetShareGetInfoResponse() 

610 shares = getShares(connId, smbServer) 

611 share = shares[request['ShareName'].upper()] 

612 shareInfo = smb.NetShareInfo1() 

613 shareInfo['NetworkName'] = request['ShareName'].upper() + '\x00' 

614 shareInfo['Type'] = int(share['share type']) 

615 respData = shareInfo.getData() 

616 if 'comment' in share: 

617 shareInfo['RemarkOffsetLow'] = len(respData) 

618 respData += share['comment'] + '\x00' 

619 respParameters['TotalBytesAvailable'] = len(respData) 

620 

621 else: 

622 # We don't know how to handle anything else 

623 errorCode = STATUS_NOT_SUPPORTED 

624 

625 smbServer.setConnectionData(connId, connData) 

626 

627 return respSetup, respParameters, respData, errorCode 

628 

629 @staticmethod 

630 def transactNamedPipe(connId, smbServer, recvPacket, parameters, data, maxDataCount=0): 

631 connData = smbServer.getConnectionData(connId) 

632 

633 respSetup = b'' 

634 respParameters = b'' 

635 respData = b'' 

636 errorCode = STATUS_SUCCESS 

637 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) 

638 transParameters = smb.SMBTransaction_Parameters(SMBCommand['Parameters']) 

639 

640 # Extract the FID 

641 fid = struct.unpack('<H', transParameters['Setup'][2:])[0] 

642 

643 if fid in connData['OpenedFiles']: 

644 fileHandle = connData['OpenedFiles'][fid]['FileHandle'] 

645 if fileHandle != PIPE_FILE_DESCRIPTOR: 

646 os.write(fileHandle, data) 

647 respData = os.read(fileHandle, data) 

648 else: 

649 sock = connData['OpenedFiles'][fid]['Socket'] 

650 sock.send(data) 

651 respData = sock.recv(maxDataCount) 

652 else: 

653 errorCode = STATUS_INVALID_HANDLE 

654 

655 smbServer.setConnectionData(connId, connData) 

656 

657 return respSetup, respParameters, respData, errorCode 

658 

659 

660# Here we implement the transaction2 handlers 

661class TRANS2Commands: 

662 # All these commands return setup, parameters, data, errorCode 

663 @staticmethod 

664 def setPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount=0): 

665 connData = smbServer.getConnectionData(connId) 

666 

667 respSetup = b'' 

668 respParameters = b'' 

669 respData = b'' 

670 errorCode = STATUS_SUCCESS 

671 setPathInfoParameters = smb.SMBSetPathInformation_Parameters(flags=recvPacket['Flags2'], data=parameters) 

672 if recvPacket['Tid'] in connData['ConnectedShares']: 

673 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

674 fileName = decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName']) 

675 fileName = os.path.normpath(fileName.replace('\\', '/')) 

676 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '': 

677 # strip leading '/' 

678 fileName = fileName[1:] 

679 pathName = os.path.join(path, fileName) 

680 if os.path.exists(pathName): 

681 informationLevel = setPathInfoParameters['InformationLevel'] 

682 if informationLevel == smb.SMB_SET_FILE_BASIC_INFO: 

683 infoRecord = smb.SMBSetFileBasicInfo(data) 

684 # Creation time won't be set, the other ones we play with. 

685 atime = infoRecord['LastAccessTime'] 

686 if atime == 0: 

687 atime = -1 

688 else: 

689 atime = getUnixTime(atime) 

690 mtime = infoRecord['LastWriteTime'] 

691 if mtime == 0: 

692 mtime = -1 

693 else: 

694 mtime = getUnixTime(mtime) 

695 if mtime != -1 or atime != -1: 

696 os.utime(pathName, (atime, mtime)) 

697 else: 

698 smbServer.log('Unknown level for set path info! 0x%x' % setPathInfoParameters['InformationLevel'], 

699 logging.ERROR) 

700 # UNSUPPORTED 

701 errorCode = STATUS_NOT_SUPPORTED 

702 else: 

703 errorCode = STATUS_OBJECT_NAME_NOT_FOUND 

704 

705 if errorCode == STATUS_SUCCESS: 

706 respParameters = smb.SMBSetPathInformationResponse_Parameters() 

707 

708 else: 

709 errorCode = STATUS_SMB_BAD_TID 

710 

711 smbServer.setConnectionData(connId, connData) 

712 

713 return respSetup, respParameters, respData, errorCode 

714 

715 @staticmethod 

716 def setFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount=0): 

717 connData = smbServer.getConnectionData(connId) 

718 

719 respSetup = b'' 

720 respParameters = b'' 

721 respData = b'' 

722 errorCode = STATUS_SUCCESS 

723 setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters) 

724 

725 if recvPacket['Tid'] in connData['ConnectedShares']: 

726 if setFileInfoParameters['FID'] in connData['OpenedFiles']: 

727 fileName = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileName'] 

728 informationLevel = setFileInfoParameters['InformationLevel'] 

729 if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO: 

730 infoRecord = smb.SMBSetFileDispositionInfo(parameters) 

731 if infoRecord['DeletePending'] > 0: 

732 # Mark this file for removal after closed 

733 connData['OpenedFiles'][setFileInfoParameters['FID']]['DeleteOnClose'] = True 

734 respParameters = smb.SMBSetFileInformationResponse_Parameters() 

735 elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO: 

736 infoRecord = smb.SMBSetFileBasicInfo(data) 

737 # Creation time won't be set, the other ones we play with. 

738 atime = infoRecord['LastAccessTime'] 

739 if atime == 0: 

740 atime = -1 

741 else: 

742 atime = getUnixTime(atime) 

743 mtime = infoRecord['LastWriteTime'] 

744 if mtime == 0: 

745 mtime = -1 

746 else: 

747 mtime = getUnixTime(mtime) 

748 os.utime(fileName, (atime, mtime)) 

749 elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO: 

750 fileHandle = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileHandle'] 

751 infoRecord = smb.SMBSetFileEndOfFileInfo(data) 

752 if infoRecord['EndOfFile'] > 0: 

753 os.lseek(fileHandle, infoRecord['EndOfFile'] - 1, 0) 

754 os.write(fileHandle, b'\x00') 

755 else: 

756 smbServer.log('Unknown level for set file info! 0x%x' % setFileInfoParameters['InformationLevel'], 

757 logging.ERROR) 

758 # UNSUPPORTED 

759 errorCode = STATUS_NOT_SUPPORTED 

760 else: 

761 errorCode = STATUS_NO_SUCH_FILE 

762 

763 if errorCode == STATUS_SUCCESS: 

764 respParameters = smb.SMBSetFileInformationResponse_Parameters() 

765 else: 

766 errorCode = STATUS_SMB_BAD_TID 

767 

768 smbServer.setConnectionData(connId, connData) 

769 

770 return respSetup, respParameters, respData, errorCode 

771 

772 @staticmethod 

773 def queryFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount=0): 

774 connData = smbServer.getConnectionData(connId) 

775 

776 respSetup = b'' 

777 respParameters = b'' 

778 respData = b'' 

779 

780 queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters) 

781 

782 if recvPacket['Tid'] in connData['ConnectedShares']: 

783 if queryFileInfoParameters['FID'] in connData['OpenedFiles']: 

784 fileName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName'] 

785 

786 infoRecord, errorCode = queryFileInformation('', fileName, queryFileInfoParameters['InformationLevel']) 

787 

788 if infoRecord is not None: 

789 respParameters = smb.SMBQueryFileInformationResponse_Parameters() 

790 respData = infoRecord 

791 else: 

792 errorCode = STATUS_INVALID_HANDLE 

793 else: 

794 errorCode = STATUS_SMB_BAD_TID 

795 

796 smbServer.setConnectionData(connId, connData) 

797 

798 return respSetup, respParameters, respData, errorCode 

799 

800 @staticmethod 

801 def queryPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount=0): 

802 connData = smbServer.getConnectionData(connId) 

803 

804 respSetup = b'' 

805 respParameters = b'' 

806 respData = b'' 

807 errorCode = 0 

808 

809 queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags=recvPacket['Flags2'], data=parameters) 

810 

811 if recvPacket['Tid'] in connData['ConnectedShares']: 

812 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

813 try: 

814 infoRecord, errorCode = queryPathInformation(path, decodeSMBString(recvPacket['Flags2'], 

815 queryPathInfoParameters['FileName']), 

816 queryPathInfoParameters['InformationLevel']) 

817 except Exception as e: 

818 smbServer.log("queryPathInformation: %s" % e, logging.ERROR) 

819 

820 if infoRecord is not None: 

821 respParameters = smb.SMBQueryPathInformationResponse_Parameters() 

822 respData = infoRecord 

823 else: 

824 errorCode = STATUS_SMB_BAD_TID 

825 

826 smbServer.setConnectionData(connId, connData) 

827 

828 return respSetup, respParameters, respData, errorCode 

829 

830 @staticmethod 

831 def queryFsInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount=0): 

832 connData = smbServer.getConnectionData(connId) 

833 errorCode = 0 

834 # Get the Tid associated 

835 if recvPacket['Tid'] in connData['ConnectedShares']: 

836 data = queryFsInformation(connData['ConnectedShares'][recvPacket['Tid']]['path'], '', 

837 struct.unpack('<H', parameters)[0], pktFlags=recvPacket['Flags2']) 

838 

839 smbServer.setConnectionData(connId, connData) 

840 

841 return b'', b'', data, errorCode 

842 

843 @staticmethod 

844 def findNext2(connId, smbServer, recvPacket, parameters, data, maxDataCount): 

845 connData = smbServer.getConnectionData(connId) 

846 

847 respSetup = b'' 

848 respParameters = b'' 

849 respData = b'' 

850 errorCode = STATUS_SUCCESS 

851 findNext2Parameters = smb.SMBFindNext2_Parameters(flags=recvPacket['Flags2'], data=parameters) 

852 

853 sid = findNext2Parameters['SID'] 

854 if recvPacket['Tid'] in connData['ConnectedShares']: 

855 if sid in connData['SIDs']: 

856 searchResult = connData['SIDs'][sid] 

857 respParameters = smb.SMBFindNext2Response_Parameters() 

858 endOfSearch = 1 

859 searchCount = 1 

860 totalData = 0 

861 for i in enumerate(searchResult): 

862 data = i[1].getData() 

863 lenData = len(data) 

864 if (totalData + lenData) >= maxDataCount or (i[0] + 1) >= findNext2Parameters['SearchCount']: 

865 # We gotta stop here and continue on a find_next2 

866 endOfSearch = 0 

867 connData['SIDs'][sid] = searchResult[i[0]:] 

868 respParameters['LastNameOffset'] = totalData 

869 break 

870 else: 

871 searchCount += 1 

872 respData += data 

873 totalData += lenData 

874 

875 # Have we reached the end of the search or still stuff to send? 

876 if endOfSearch > 0: 

877 # Let's remove the SID from our ConnData 

878 del (connData['SIDs'][sid]) 

879 

880 respParameters['EndOfSearch'] = endOfSearch 

881 respParameters['SearchCount'] = searchCount 

882 else: 

883 errorCode = STATUS_INVALID_HANDLE 

884 else: 

885 errorCode = STATUS_SMB_BAD_TID 

886 

887 smbServer.setConnectionData(connId, connData) 

888 

889 return respSetup, respParameters, respData, errorCode 

890 

891 @staticmethod 

892 def findFirst2(connId, smbServer, recvPacket, parameters, data, maxDataCount): 

893 connData = smbServer.getConnectionData(connId) 

894 

895 respSetup = b'' 

896 respParameters = b'' 

897 respData = b'' 

898 findFirst2Parameters = smb.SMBFindFirst2_Parameters(recvPacket['Flags2'], data=parameters) 

899 

900 if recvPacket['Tid'] in connData['ConnectedShares']: 

901 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

902 

903 searchResult, searchCount, errorCode = findFirst2(path, 

904 decodeSMBString(recvPacket['Flags2'], 

905 findFirst2Parameters['FileName']), 

906 findFirst2Parameters['InformationLevel'], 

907 findFirst2Parameters['SearchAttributes'], 

908 pktFlags=recvPacket['Flags2']) 

909 

910 respParameters = smb.SMBFindFirst2Response_Parameters() 

911 endOfSearch = 1 

912 sid = 0x80 # default SID 

913 searchCount = 0 

914 totalData = 0 

915 for i in enumerate(searchResult): 

916 # i[1].dump() 

917 data = i[1].getData() 

918 lenData = len(data) 

919 if (totalData + lenData) >= maxDataCount or (i[0] + 1) > findFirst2Parameters['SearchCount']: 

920 # We gotta stop here and continue on a find_next2 

921 endOfSearch = 0 

922 # Simple way to generate a fid 

923 if len(connData['SIDs']) == 0: 

924 sid = 1 

925 else: 

926 sid = list(connData['SIDs'].keys())[-1] + 1 

927 # Store the remaining search results in the ConnData SID 

928 connData['SIDs'][sid] = searchResult[i[0]:] 

929 respParameters['LastNameOffset'] = totalData 

930 break 

931 else: 

932 searchCount += 1 

933 respData += data 

934 

935 padLen = (8 - (lenData % 8)) % 8 

936 respData += b'\xaa' * padLen 

937 totalData += lenData + padLen 

938 

939 respParameters['SID'] = sid 

940 respParameters['EndOfSearch'] = endOfSearch 

941 respParameters['SearchCount'] = searchCount 

942 else: 

943 errorCode = STATUS_SMB_BAD_TID 

944 

945 smbServer.setConnectionData(connId, connData) 

946 

947 return respSetup, respParameters, respData, errorCode 

948 

949 

950# Here we implement the commands handlers 

951class SMBCommands: 

952 

953 @staticmethod 

954 def smbTransaction(connId, smbServer, SMBCommand, recvPacket, transCommands): 

955 connData = smbServer.getConnectionData(connId) 

956 

957 respSMBCommand = smb.SMBCommand(recvPacket['Command']) 

958 

959 transParameters = smb.SMBTransaction_Parameters(SMBCommand['Parameters']) 

960 

961 # Do the stuff 

962 if transParameters['ParameterCount'] != transParameters['TotalParameterCount']: 

963 # TODO: Handle partial parameters 

964 raise Exception("Unsupported partial parameters in TRANSACT2!") 

965 else: 

966 transData = smb.SMBTransaction_SData(flags=recvPacket['Flags2']) 

967 # Standard says servers shouldn't trust Parameters and Data comes 

968 # in order, so we have to parse the offsets, ugly 

969 

970 paramCount = transParameters['ParameterCount'] 

971 transData['Trans_ParametersLength'] = paramCount 

972 dataCount = transParameters['DataCount'] 

973 transData['Trans_DataLength'] = dataCount 

974 transData.fromString(SMBCommand['Data']) 

975 if transParameters['ParameterOffset'] > 0: 

976 paramOffset = transParameters['ParameterOffset'] - 63 - transParameters['SetupLength'] 

977 transData['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset + paramCount] 

978 else: 

979 transData['Trans_Parameters'] = b'' 

980 

981 if transParameters['DataOffset'] > 0: 

982 dataOffset = transParameters['DataOffset'] - 63 - transParameters['SetupLength'] 

983 transData['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount] 

984 else: 

985 transData['Trans_Data'] = b'' 

986 

987 # Call the handler for this TRANSACTION 

988 if transParameters['SetupCount'] == 0: 

989 # No subcommand, let's play with the Name 

990 command = decodeSMBString(recvPacket['Flags2'], transData['Name']) 

991 else: 

992 command = struct.unpack('<H', transParameters['Setup'][:2])[0] 

993 

994 if command in transCommands: 

995 # Call the TRANS subcommand 

996 setup = b'' 

997 parameters = b'' 

998 data = b'' 

999 try: 

1000 setup, parameters, data, errorCode = transCommands[command](connId, 

1001 smbServer, 

1002 recvPacket, 

1003 transData['Trans_Parameters'], 

1004 transData['Trans_Data'], 

1005 transParameters['MaxDataCount']) 

1006 except Exception as e: 

1007 # print 'Transaction: %s' % e,e 

1008 smbServer.log('Transaction: (%r,%s)' % (command, e), logging.ERROR) 

1009 errorCode = STATUS_ACCESS_DENIED 

1010 # raise 

1011 

1012 if setup == b'' and parameters == b'' and data == b'': 

1013 # Something wen't wrong 

1014 respParameters = b'' 

1015 respData = b'' 

1016 else: 

1017 # Build the answer 

1018 if hasattr(data, 'getData'): 

1019 data = data.getData() 

1020 remainingData = len(data) 

1021 if hasattr(parameters, 'getData'): 

1022 parameters = parameters.getData() 

1023 remainingParameters = len(parameters) 

1024 commands = [] 

1025 dataDisplacement = 0 

1026 while remainingData > 0 or remainingParameters > 0: 

1027 respSMBCommand = smb.SMBCommand(recvPacket['Command']) 

1028 respParameters = smb.SMBTransactionResponse_Parameters() 

1029 respData = smb.SMBTransaction2Response_Data() 

1030 

1031 respParameters['TotalParameterCount'] = len(parameters) 

1032 respParameters['ParameterCount'] = len(parameters) 

1033 respData['Trans_ParametersLength'] = len(parameters) 

1034 respParameters['TotalDataCount'] = len(data) 

1035 respParameters['DataDisplacement'] = dataDisplacement 

1036 

1037 # TODO: Do the same for parameters 

1038 if len(data) > transParameters['MaxDataCount']: 

1039 # Answer doesn't fit in this packet 

1040 LOG.debug("Lowering answer from %d to %d" % (len(data), transParameters['MaxDataCount'])) 

1041 respParameters['DataCount'] = transParameters['MaxDataCount'] 

1042 else: 

1043 respParameters['DataCount'] = len(data) 

1044 

1045 respData['Trans_DataLength'] = respParameters['DataCount'] 

1046 respParameters['SetupCount'] = len(setup) 

1047 respParameters['Setup'] = setup 

1048 # TODO: Make sure we're calculating the pad right 

1049 if len(parameters) > 0: 

1050 # padLen = 4 - (55 + len(setup)) % 4 

1051 padLen = (4 - (55 + len(setup)) % 4) % 4 

1052 padBytes = b'\xFF' * padLen 

1053 respData['Pad1'] = padBytes 

1054 respParameters['ParameterOffset'] = 55 + len(setup) + padLen 

1055 else: 

1056 padLen = 0 

1057 respParameters['ParameterOffset'] = 0 

1058 respData['Pad1'] = b'' 

1059 

1060 if len(data) > 0: 

1061 # pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4 

1062 pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4 

1063 respData['Pad2'] = b'\xFF' * pad2Len 

1064 respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len 

1065 else: 

1066 respParameters['DataOffset'] = 0 

1067 respData['Pad2'] = b'' 

1068 

1069 respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']] 

1070 respData['Trans_Data'] = data[:respParameters['DataCount']] 

1071 respSMBCommand['Parameters'] = respParameters 

1072 respSMBCommand['Data'] = respData 

1073 

1074 data = data[respParameters['DataCount']:] 

1075 remainingData -= respParameters['DataCount'] 

1076 dataDisplacement += respParameters['DataCount'] + 1 

1077 

1078 parameters = parameters[respParameters['ParameterCount']:] 

1079 remainingParameters -= respParameters['ParameterCount'] 

1080 commands.append(respSMBCommand) 

1081 

1082 smbServer.setConnectionData(connId, connData) 

1083 return commands, None, errorCode 

1084 

1085 else: 

1086 smbServer.log("Unsupported Transact command %r" % command, logging.ERROR) 

1087 respParameters = b'' 

1088 respData = b'' 

1089 errorCode = STATUS_NOT_IMPLEMENTED 

1090 

1091 respSMBCommand['Parameters'] = respParameters 

1092 respSMBCommand['Data'] = respData 

1093 smbServer.setConnectionData(connId, connData) 

1094 

1095 return [respSMBCommand], None, errorCode 

1096 

1097 @staticmethod 

1098 def smbNTTransact(connId, smbServer, SMBCommand, recvPacket, transCommands): 

1099 connData = smbServer.getConnectionData(connId) 

1100 

1101 respSMBCommand = smb.SMBCommand(recvPacket['Command']) 

1102 

1103 NTTransParameters = smb.SMBNTTransaction_Parameters(SMBCommand['Parameters']) 

1104 # Do the stuff 

1105 if NTTransParameters['ParameterCount'] != NTTransParameters['TotalParameterCount']: 

1106 # TODO: Handle partial parameters 

1107 raise Exception("Unsupported partial parameters in NTTrans!") 

1108 else: 

1109 NTTransData = smb.SMBNTTransaction_Data() 

1110 # Standard says servers shouldn't trust Parameters and Data comes 

1111 # in order, so we have to parse the offsets, ugly 

1112 

1113 paramCount = NTTransParameters['ParameterCount'] 

1114 NTTransData['NT_Trans_ParametersLength'] = paramCount 

1115 dataCount = NTTransParameters['DataCount'] 

1116 NTTransData['NT_Trans_DataLength'] = dataCount 

1117 

1118 if NTTransParameters['ParameterOffset'] > 0: 

1119 paramOffset = NTTransParameters['ParameterOffset'] - 73 - NTTransParameters['SetupLength'] 

1120 NTTransData['NT_Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset + paramCount] 

1121 else: 

1122 NTTransData['NT_Trans_Parameters'] = b'' 

1123 

1124 if NTTransParameters['DataOffset'] > 0: 

1125 dataOffset = NTTransParameters['DataOffset'] - 73 - NTTransParameters['SetupLength'] 

1126 NTTransData['NT_Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount] 

1127 else: 

1128 NTTransData['NT_Trans_Data'] = b'' 

1129 

1130 # Call the handler for this TRANSACTION 

1131 command = NTTransParameters['Function'] 

1132 if command in transCommands: 

1133 # Call the NT TRANS subcommand 

1134 setup = b'' 

1135 parameters = b'' 

1136 data = b'' 

1137 try: 

1138 setup, parameters, data, errorCode = transCommands[command](connId, 

1139 smbServer, 

1140 recvPacket, 

1141 NTTransData['NT_Trans_Parameters'], 

1142 NTTransData['NT_Trans_Data'], 

1143 NTTransParameters['MaxDataCount']) 

1144 except Exception as e: 

1145 smbServer.log('NTTransaction: (0x%x,%s)' % (command, e), logging.ERROR) 

1146 errorCode = STATUS_ACCESS_DENIED 

1147 # raise 

1148 

1149 if setup == b'' and parameters == b'' and data == b'': 

1150 # Something wen't wrong 

1151 respParameters = b'' 

1152 respData = b'' 

1153 if errorCode == STATUS_SUCCESS: 

1154 errorCode = STATUS_ACCESS_DENIED 

1155 else: 

1156 # Build the answer 

1157 if hasattr(data, 'getData'): 

1158 data = data.getData() 

1159 remainingData = len(data) 

1160 if hasattr(parameters, 'getData'): 

1161 parameters = parameters.getData() 

1162 remainingParameters = len(parameters) 

1163 commands = [] 

1164 dataDisplacement = 0 

1165 while remainingData > 0 or remainingParameters > 0: 

1166 respSMBCommand = smb.SMBCommand(recvPacket['Command']) 

1167 respParameters = smb.SMBNTTransactionResponse_Parameters() 

1168 respData = smb.SMBNTTransactionResponse_Data() 

1169 

1170 respParameters['TotalParameterCount'] = len(parameters) 

1171 respParameters['ParameterCount'] = len(parameters) 

1172 respData['Trans_ParametersLength'] = len(parameters) 

1173 respParameters['TotalDataCount'] = len(data) 

1174 respParameters['DataDisplacement'] = dataDisplacement 

1175 # TODO: Do the same for parameters 

1176 if len(data) > NTTransParameters['MaxDataCount']: 

1177 # Answer doesn't fit in this packet 

1178 LOG.debug("Lowering answer from %d to %d" % (len(data), NTTransParameters['MaxDataCount'])) 

1179 respParameters['DataCount'] = NTTransParameters['MaxDataCount'] 

1180 else: 

1181 respParameters['DataCount'] = len(data) 

1182 

1183 respData['NT_Trans_DataLength'] = respParameters['DataCount'] 

1184 respParameters['SetupCount'] = len(setup) 

1185 respParameters['Setup'] = setup 

1186 # TODO: Make sure we're calculating the pad right 

1187 if len(parameters) > 0: 

1188 # padLen = 4 - (71 + len(setup)) % 4 

1189 padLen = (4 - (73 + len(setup)) % 4) % 4 

1190 padBytes = b'\xFF' * padLen 

1191 respData['Pad1'] = padBytes 

1192 respParameters['ParameterOffset'] = 73 + len(setup) + padLen 

1193 else: 

1194 padLen = 0 

1195 respParameters['ParameterOffset'] = 0 

1196 respData['Pad1'] = b'' 

1197 

1198 if len(data) > 0: 

1199 # pad2Len = 4 - (71 + len(setup) + padLen + len(parameters)) % 4 

1200 pad2Len = (4 - (73 + len(setup) + padLen + len(parameters)) % 4) % 4 

1201 respData['Pad2'] = b'\xFF' * pad2Len 

1202 respParameters['DataOffset'] = 73 + len(setup) + padLen + len(parameters) + pad2Len 

1203 else: 

1204 respParameters['DataOffset'] = 0 

1205 respData['Pad2'] = b'' 

1206 

1207 respData['NT_Trans_Parameters'] = parameters[:respParameters['ParameterCount']] 

1208 respData['NT_Trans_Data'] = data[:respParameters['DataCount']] 

1209 respSMBCommand['Parameters'] = respParameters 

1210 respSMBCommand['Data'] = respData 

1211 

1212 data = data[respParameters['DataCount']:] 

1213 remainingData -= respParameters['DataCount'] 

1214 dataDisplacement += respParameters['DataCount'] + 1 

1215 

1216 parameters = parameters[respParameters['ParameterCount']:] 

1217 remainingParameters -= respParameters['ParameterCount'] 

1218 commands.append(respSMBCommand) 

1219 

1220 smbServer.setConnectionData(connId, connData) 

1221 return commands, None, errorCode 

1222 

1223 else: 

1224 # smbServer.log("Unsupported NTTransact command 0x%x" % command, logging.ERROR) 

1225 respParameters = b'' 

1226 respData = b'' 

1227 errorCode = STATUS_NOT_IMPLEMENTED 

1228 

1229 respSMBCommand['Parameters'] = respParameters 

1230 respSMBCommand['Data'] = respData 

1231 

1232 smbServer.setConnectionData(connId, connData) 

1233 return [respSMBCommand], None, errorCode 

1234 

1235 @staticmethod 

1236 def smbTransaction2(connId, smbServer, SMBCommand, recvPacket, transCommands): 

1237 connData = smbServer.getConnectionData(connId) 

1238 

1239 respSMBCommand = smb.SMBCommand(recvPacket['Command']) 

1240 

1241 trans2Parameters = smb.SMBTransaction2_Parameters(SMBCommand['Parameters']) 

1242 

1243 # Do the stuff 

1244 if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']: 

1245 # TODO: Handle partial parameters 

1246 # print "Unsupported partial parameters in TRANSACT2!" 

1247 raise Exception("Unsupported partial parameters in TRANSACT2!") 

1248 else: 

1249 trans2Data = smb.SMBTransaction2_Data() 

1250 # Standard says servers shouldn't trust Parameters and Data comes 

1251 # in order, so we have to parse the offsets, ugly 

1252 

1253 paramCount = trans2Parameters['ParameterCount'] 

1254 trans2Data['Trans_ParametersLength'] = paramCount 

1255 dataCount = trans2Parameters['DataCount'] 

1256 trans2Data['Trans_DataLength'] = dataCount 

1257 

1258 if trans2Parameters['ParameterOffset'] > 0: 

1259 paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength'] 

1260 trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset + paramCount] 

1261 else: 

1262 trans2Data['Trans_Parameters'] = b'' 

1263 

1264 if trans2Parameters['DataOffset'] > 0: 

1265 dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength'] 

1266 trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount] 

1267 else: 

1268 trans2Data['Trans_Data'] = b'' 

1269 

1270 # Call the handler for this TRANSACTION 

1271 command = struct.unpack('<H', trans2Parameters['Setup'])[0] 

1272 if command in transCommands: 

1273 # Call the TRANS2 subcommand 

1274 try: 

1275 setup, parameters, data, errorCode = transCommands[command](connId, 

1276 smbServer, 

1277 recvPacket, 

1278 trans2Data['Trans_Parameters'], 

1279 trans2Data['Trans_Data'], 

1280 trans2Parameters['MaxDataCount']) 

1281 except Exception as e: 

1282 smbServer.log('Transaction2: (0x%x,%s)' % (command, e), logging.ERROR) 

1283 # import traceback 

1284 # traceback.print_exc() 

1285 raise 

1286 

1287 if setup == b'' and parameters == b'' and data == b'': 

1288 # Something wen't wrong 

1289 respParameters = b'' 

1290 respData = b'' 

1291 else: 

1292 # Build the answer 

1293 if hasattr(data, 'getData'): 

1294 data = data.getData() 

1295 remainingData = len(data) 

1296 if hasattr(parameters, 'getData'): 

1297 parameters = parameters.getData() 

1298 remainingParameters = len(parameters) 

1299 commands = [] 

1300 dataDisplacement = 0 

1301 while remainingData > 0 or remainingParameters > 0: 

1302 respSMBCommand = smb.SMBCommand(recvPacket['Command']) 

1303 respParameters = smb.SMBTransaction2Response_Parameters() 

1304 respData = smb.SMBTransaction2Response_Data() 

1305 

1306 respParameters['TotalParameterCount'] = len(parameters) 

1307 respParameters['ParameterCount'] = len(parameters) 

1308 respData['Trans_ParametersLength'] = len(parameters) 

1309 respParameters['TotalDataCount'] = len(data) 

1310 respParameters['DataDisplacement'] = dataDisplacement 

1311 # TODO: Do the same for parameters 

1312 if len(data) > trans2Parameters['MaxDataCount']: 

1313 # Answer doesn't fit in this packet 

1314 LOG.debug("Lowering answer from %d to %d" % (len(data), trans2Parameters['MaxDataCount'])) 

1315 respParameters['DataCount'] = trans2Parameters['MaxDataCount'] 

1316 else: 

1317 respParameters['DataCount'] = len(data) 

1318 

1319 respData['Trans_DataLength'] = respParameters['DataCount'] 

1320 respParameters['SetupCount'] = len(setup) 

1321 respParameters['Setup'] = setup 

1322 # TODO: Make sure we're calculating the pad right 

1323 if len(parameters) > 0: 

1324 # padLen = 4 - (55 + len(setup)) % 4 

1325 padLen = (4 - (55 + len(setup)) % 4) % 4 

1326 padBytes = b'\xFF' * padLen 

1327 respData['Pad1'] = padBytes 

1328 respParameters['ParameterOffset'] = 55 + len(setup) + padLen 

1329 else: 

1330 padLen = 0 

1331 respParameters['ParameterOffset'] = 0 

1332 respData['Pad1'] = b'' 

1333 

1334 if len(data) > 0: 

1335 # pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4 

1336 pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4 

1337 respData['Pad2'] = b'\xFF' * pad2Len 

1338 respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len 

1339 else: 

1340 respParameters['DataOffset'] = 0 

1341 respData['Pad2'] = b'' 

1342 

1343 respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']] 

1344 respData['Trans_Data'] = data[:respParameters['DataCount']] 

1345 respSMBCommand['Parameters'] = respParameters 

1346 respSMBCommand['Data'] = respData 

1347 

1348 data = data[respParameters['DataCount']:] 

1349 remainingData -= respParameters['DataCount'] 

1350 dataDisplacement += respParameters['DataCount'] + 1 

1351 

1352 parameters = parameters[respParameters['ParameterCount']:] 

1353 remainingParameters -= respParameters['ParameterCount'] 

1354 commands.append(respSMBCommand) 

1355 

1356 smbServer.setConnectionData(connId, connData) 

1357 return commands, None, errorCode 

1358 

1359 else: 

1360 smbServer.log("Unsupported Transact/2 command 0x%x" % command, logging.ERROR) 

1361 respParameters = b'' 

1362 respData = b'' 

1363 errorCode = STATUS_NOT_IMPLEMENTED 

1364 

1365 respSMBCommand['Parameters'] = respParameters 

1366 respSMBCommand['Data'] = respData 

1367 

1368 smbServer.setConnectionData(connId, connData) 

1369 return [respSMBCommand], None, errorCode 

1370 

1371 @staticmethod 

1372 def smbComLockingAndX(connId, smbServer, SMBCommand, recvPacket): 

1373 connData = smbServer.getConnectionData(connId) 

1374 

1375 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOCKING_ANDX) 

1376 respParameters = b'' 

1377 respData = b'' 

1378 

1379 # I'm actually doing nothing.. just make MacOS happy ;) 

1380 errorCode = STATUS_SUCCESS 

1381 

1382 respSMBCommand['Parameters'] = respParameters 

1383 respSMBCommand['Data'] = respData 

1384 smbServer.setConnectionData(connId, connData) 

1385 

1386 return [respSMBCommand], None, errorCode 

1387 

1388 @staticmethod 

1389 def smbComClose(connId, smbServer, SMBCommand, recvPacket): 

1390 connData = smbServer.getConnectionData(connId) 

1391 

1392 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CLOSE) 

1393 respParameters = b'' 

1394 respData = b'' 

1395 

1396 comClose = smb.SMBClose_Parameters(SMBCommand['Parameters']) 

1397 

1398 if comClose['FID'] in connData['OpenedFiles']: 

1399 errorCode = STATUS_SUCCESS 

1400 fileHandle = connData['OpenedFiles'][comClose['FID']]['FileHandle'] 

1401 try: 

1402 if fileHandle == PIPE_FILE_DESCRIPTOR: 

1403 connData['OpenedFiles'][comClose['FID']]['Socket'].close() 

1404 elif fileHandle != VOID_FILE_DESCRIPTOR: 

1405 os.close(fileHandle) 

1406 except Exception as e: 

1407 smbServer.log("comClose %s" % e, logging.ERROR) 

1408 errorCode = STATUS_ACCESS_DENIED 

1409 else: 

1410 # Check if the file was marked for removal 

1411 if connData['OpenedFiles'][comClose['FID']]['DeleteOnClose'] is True: 

1412 try: 

1413 os.remove(connData['OpenedFiles'][comClose['FID']]['FileName']) 

1414 except Exception as e: 

1415 smbServer.log("comClose %s" % e, logging.ERROR) 

1416 errorCode = STATUS_ACCESS_DENIED 

1417 del (connData['OpenedFiles'][comClose['FID']]) 

1418 else: 

1419 errorCode = STATUS_INVALID_HANDLE 

1420 

1421 if errorCode > 0: 

1422 respParameters = b'' 

1423 respData = b'' 

1424 

1425 respSMBCommand['Parameters'] = respParameters 

1426 respSMBCommand['Data'] = respData 

1427 smbServer.setConnectionData(connId, connData) 

1428 

1429 return [respSMBCommand], None, errorCode 

1430 

1431 @staticmethod 

1432 def smbComWrite(connId, smbServer, SMBCommand, recvPacket): 

1433 connData = smbServer.getConnectionData(connId) 

1434 

1435 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE) 

1436 respParameters = smb.SMBWriteResponse_Parameters() 

1437 respData = b'' 

1438 

1439 comWriteParameters = smb.SMBWrite_Parameters(SMBCommand['Parameters']) 

1440 comWriteData = smb.SMBWrite_Data(SMBCommand['Data']) 

1441 

1442 if comWriteParameters['Fid'] in connData['OpenedFiles']: 

1443 fileHandle = connData['OpenedFiles'][comWriteParameters['Fid']]['FileHandle'] 

1444 errorCode = STATUS_SUCCESS 

1445 try: 

1446 if fileHandle != PIPE_FILE_DESCRIPTOR: 

1447 # TODO: Handle big size files 

1448 # If we're trying to write past the file end we just skip the write call (Vista does this) 

1449 if os.lseek(fileHandle, 0, 2) >= comWriteParameters['Offset']: 

1450 os.lseek(fileHandle, comWriteParameters['Offset'], 0) 

1451 os.write(fileHandle, comWriteData['Data']) 

1452 else: 

1453 sock = connData['OpenedFiles'][comWriteParameters['Fid']]['Socket'] 

1454 sock.send(comWriteData['Data']) 

1455 respParameters['Count'] = comWriteParameters['Count'] 

1456 except Exception as e: 

1457 smbServer.log('smbComWrite: %s' % e, logging.ERROR) 

1458 errorCode = STATUS_ACCESS_DENIED 

1459 else: 

1460 errorCode = STATUS_INVALID_HANDLE 

1461 

1462 if errorCode > 0: 

1463 respParameters = b'' 

1464 respData = b'' 

1465 

1466 respSMBCommand['Parameters'] = respParameters 

1467 respSMBCommand['Data'] = respData 

1468 smbServer.setConnectionData(connId, connData) 

1469 

1470 return [respSMBCommand], None, errorCode 

1471 

1472 @staticmethod 

1473 def smbComFlush(connId, smbServer, SMBCommand, recvPacket): 

1474 connData = smbServer.getConnectionData(connId) 

1475 

1476 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_FLUSH) 

1477 respParameters = b'' 

1478 respData = b'' 

1479 

1480 comFlush = smb.SMBFlush_Parameters(SMBCommand['Parameters']) 

1481 

1482 if comFlush['FID'] in connData['OpenedFiles']: 

1483 errorCode = STATUS_SUCCESS 

1484 fileHandle = connData['OpenedFiles'][comFlush['FID']]['FileHandle'] 

1485 try: 

1486 os.fsync(fileHandle) 

1487 except Exception as e: 

1488 smbServer.log("comFlush %s" % e, logging.ERROR) 

1489 errorCode = STATUS_ACCESS_DENIED 

1490 else: 

1491 errorCode = STATUS_INVALID_HANDLE 

1492 

1493 if errorCode > 0: 

1494 respParameters = b'' 

1495 respData = b'' 

1496 

1497 respSMBCommand['Parameters'] = respParameters 

1498 respSMBCommand['Data'] = respData 

1499 smbServer.setConnectionData(connId, connData) 

1500 

1501 return [respSMBCommand], None, errorCode 

1502 

1503 @staticmethod 

1504 def smbComCreateDirectory(connId, smbServer, SMBCommand, recvPacket): 

1505 connData = smbServer.getConnectionData(connId) 

1506 

1507 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY) 

1508 respParameters = b'' 

1509 respData = b'' 

1510 

1511 comCreateDirectoryData = smb.SMBCreateDirectory_Data(flags=recvPacket['Flags2'], data=SMBCommand['Data']) 

1512 

1513 # Get the Tid associated 

1514 if recvPacket['Tid'] in connData['ConnectedShares']: 

1515 errorCode = STATUS_SUCCESS 

1516 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

1517 fileName = os.path.normpath( 

1518 decodeSMBString(recvPacket['Flags2'], comCreateDirectoryData['DirectoryName']).replace('\\', '/')) 

1519 if len(fileName) > 0: 

1520 if fileName[0] == '/' or fileName[0] == '\\': 

1521 # strip leading '/' 

1522 fileName = fileName[1:] 

1523 pathName = os.path.join(path, fileName) 

1524 if os.path.exists(pathName): 

1525 errorCode = STATUS_OBJECT_NAME_COLLISION 

1526 

1527 # TODO: More checks here in the future.. Specially when we support 

1528 # user access 

1529 else: 

1530 try: 

1531 os.mkdir(pathName) 

1532 except Exception as e: 

1533 smbServer.log("smbComCreateDirectory: %s" % e, logging.ERROR) 

1534 errorCode = STATUS_ACCESS_DENIED 

1535 else: 

1536 errorCode = STATUS_SMB_BAD_TID 

1537 

1538 if errorCode > 0: 

1539 respParameters = b'' 

1540 respData = b'' 

1541 

1542 respSMBCommand['Parameters'] = respParameters 

1543 respSMBCommand['Data'] = respData 

1544 smbServer.setConnectionData(connId, connData) 

1545 

1546 return [respSMBCommand], None, errorCode 

1547 

1548 @staticmethod 

1549 def smbComRename(connId, smbServer, SMBCommand, recvPacket): 

1550 connData = smbServer.getConnectionData(connId) 

1551 

1552 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_RENAME) 

1553 respParameters = b'' 

1554 respData = b'' 

1555 

1556 comRenameData = smb.SMBRename_Data(flags=recvPacket['Flags2'], data=SMBCommand['Data']) 

1557 # Get the Tid associated 

1558 if recvPacket['Tid'] in connData['ConnectedShares']: 

1559 errorCode = STATUS_SUCCESS 

1560 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

1561 oldFileName = os.path.normpath( 

1562 decodeSMBString(recvPacket['Flags2'], comRenameData['OldFileName']).replace('\\', '/')) 

1563 newFileName = os.path.normpath( 

1564 decodeSMBString(recvPacket['Flags2'], comRenameData['NewFileName']).replace('\\', '/')) 

1565 if len(oldFileName) > 0 and (oldFileName[0] == '/' or oldFileName[0] == '\\'): 

1566 # strip leading '/' 

1567 oldFileName = oldFileName[1:] 

1568 oldPathName = os.path.join(path, oldFileName) 

1569 if len(newFileName) > 0 and (newFileName[0] == '/' or newFileName[0] == '\\'): 

1570 # strip leading '/' 

1571 newFileName = newFileName[1:] 

1572 newPathName = os.path.join(path, newFileName) 

1573 

1574 if os.path.exists(oldPathName) is not True: 

1575 errorCode = STATUS_NO_SUCH_FILE 

1576 

1577 # TODO: More checks here in the future.. Specially when we support 

1578 # user access 

1579 else: 

1580 try: 

1581 os.rename(oldPathName, newPathName) 

1582 except OSError as e: 

1583 smbServer.log("smbComRename: %s" % e, logging.ERROR) 

1584 errorCode = STATUS_ACCESS_DENIED 

1585 else: 

1586 errorCode = STATUS_SMB_BAD_TID 

1587 

1588 if errorCode > 0: 

1589 respParameters = b'' 

1590 respData = b'' 

1591 

1592 respSMBCommand['Parameters'] = respParameters 

1593 respSMBCommand['Data'] = respData 

1594 smbServer.setConnectionData(connId, connData) 

1595 

1596 return [respSMBCommand], None, errorCode 

1597 

1598 @staticmethod 

1599 def smbComDelete(connId, smbServer, SMBCommand, recvPacket): 

1600 connData = smbServer.getConnectionData(connId) 

1601 

1602 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE) 

1603 respParameters = b'' 

1604 respData = b'' 

1605 

1606 comDeleteData = smb.SMBDelete_Data(flags=recvPacket['Flags2'], data=SMBCommand['Data']) 

1607 

1608 # Get the Tid associated 

1609 if recvPacket['Tid'] in connData['ConnectedShares']: 

1610 errorCode = STATUS_SUCCESS 

1611 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

1612 fileName = os.path.normpath( 

1613 decodeSMBString(recvPacket['Flags2'], comDeleteData['FileName']).replace('\\', '/')) 

1614 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'): 

1615 # strip leading '/' 

1616 fileName = fileName[1:] 

1617 pathName = os.path.join(path, fileName) 

1618 if os.path.exists(pathName) is not True: 

1619 errorCode = STATUS_NO_SUCH_FILE 

1620 

1621 # TODO: More checks here in the future.. Specially when we support 

1622 # user access 

1623 else: 

1624 try: 

1625 os.remove(pathName) 

1626 except OSError as e: 

1627 smbServer.log("smbComDelete: %s" % e, logging.ERROR) 

1628 errorCode = STATUS_ACCESS_DENIED 

1629 else: 

1630 errorCode = STATUS_SMB_BAD_TID 

1631 

1632 if errorCode > 0: 

1633 respParameters = b'' 

1634 respData = b'' 

1635 

1636 respSMBCommand['Parameters'] = respParameters 

1637 respSMBCommand['Data'] = respData 

1638 smbServer.setConnectionData(connId, connData) 

1639 

1640 return [respSMBCommand], None, errorCode 

1641 

1642 @staticmethod 

1643 def smbComDeleteDirectory(connId, smbServer, SMBCommand, recvPacket): 

1644 connData = smbServer.getConnectionData(connId) 

1645 

1646 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY) 

1647 respParameters = b'' 

1648 respData = b'' 

1649 

1650 comDeleteDirectoryData = smb.SMBDeleteDirectory_Data(flags=recvPacket['Flags2'], data=SMBCommand['Data']) 

1651 

1652 # Get the Tid associated 

1653 if recvPacket['Tid'] in connData['ConnectedShares']: 

1654 errorCode = STATUS_SUCCESS 

1655 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

1656 fileName = os.path.normpath( 

1657 decodeSMBString(recvPacket['Flags2'], comDeleteDirectoryData['DirectoryName']).replace('\\', '/')) 

1658 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'): 

1659 # strip leading '/' 

1660 fileName = fileName[1:] 

1661 pathName = os.path.join(path, fileName) 

1662 if os.path.exists(pathName) is not True: 

1663 errorCode = STATUS_NO_SUCH_FILE 

1664 

1665 # TODO: More checks here in the future.. Specially when we support 

1666 # user access 

1667 else: 

1668 try: 

1669 os.rmdir(pathName) 

1670 except OSError as e: 

1671 smbServer.log("smbComDeleteDirectory: %s" % e, logging.ERROR) 

1672 if e.errno == errno.ENOTEMPTY: 

1673 errorCode = STATUS_DIRECTORY_NOT_EMPTY 

1674 else: 

1675 errorCode = STATUS_ACCESS_DENIED 

1676 else: 

1677 errorCode = STATUS_SMB_BAD_TID 

1678 

1679 if errorCode > 0: 

1680 respParameters = b'' 

1681 respData = b'' 

1682 

1683 respSMBCommand['Parameters'] = respParameters 

1684 respSMBCommand['Data'] = respData 

1685 smbServer.setConnectionData(connId, connData) 

1686 

1687 return [respSMBCommand], None, errorCode 

1688 

1689 @staticmethod 

1690 def smbComWriteAndX(connId, smbServer, SMBCommand, recvPacket): 

1691 connData = smbServer.getConnectionData(connId) 

1692 

1693 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX) 

1694 respParameters = smb.SMBWriteAndXResponse_Parameters() 

1695 respData = b'' 

1696 

1697 if SMBCommand['WordCount'] == 0x0C: 

1698 writeAndX = smb.SMBWriteAndX_Parameters_Short(SMBCommand['Parameters']) 

1699 writeAndXData = smb.SMBWriteAndX_Data_Short() 

1700 else: 

1701 writeAndX = smb.SMBWriteAndX_Parameters(SMBCommand['Parameters']) 

1702 writeAndXData = smb.SMBWriteAndX_Data() 

1703 writeAndXData['DataLength'] = writeAndX['DataLength'] 

1704 writeAndXData['DataOffset'] = writeAndX['DataOffset'] 

1705 writeAndXData.fromString(SMBCommand['Data']) 

1706 

1707 if writeAndX['Fid'] in connData['OpenedFiles']: 

1708 fileHandle = connData['OpenedFiles'][writeAndX['Fid']]['FileHandle'] 

1709 errorCode = STATUS_SUCCESS 

1710 try: 

1711 if fileHandle != PIPE_FILE_DESCRIPTOR: 

1712 offset = writeAndX['Offset'] 

1713 if 'HighOffset' in writeAndX.fields: 

1714 offset += (writeAndX['HighOffset'] << 32) 

1715 # If we're trying to write past the file end we just skip the write call (Vista does this) 

1716 if os.lseek(fileHandle, 0, 2) >= offset: 

1717 os.lseek(fileHandle, offset, 0) 

1718 os.write(fileHandle, writeAndXData['Data']) 

1719 else: 

1720 sock = connData['OpenedFiles'][writeAndX['Fid']]['Socket'] 

1721 sock.send(writeAndXData['Data']) 

1722 

1723 respParameters['Count'] = writeAndX['DataLength'] 

1724 respParameters['Available'] = 0xff 

1725 except Exception as e: 

1726 smbServer.log('smbComWriteAndx: %s' % e, logging.ERROR) 

1727 errorCode = STATUS_ACCESS_DENIED 

1728 else: 

1729 errorCode = STATUS_INVALID_HANDLE 

1730 

1731 if errorCode > 0: 

1732 respParameters = b'' 

1733 respData = b'' 

1734 

1735 respSMBCommand['Parameters'] = respParameters 

1736 respSMBCommand['Data'] = respData 

1737 smbServer.setConnectionData(connId, connData) 

1738 

1739 return [respSMBCommand], None, errorCode 

1740 

1741 @staticmethod 

1742 def smbComRead(connId, smbServer, SMBCommand, recvPacket): 

1743 connData = smbServer.getConnectionData(connId) 

1744 

1745 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ) 

1746 respParameters = smb.SMBReadResponse_Parameters() 

1747 respData = smb.SMBReadResponse_Data() 

1748 

1749 comReadParameters = smb.SMBRead_Parameters(SMBCommand['Parameters']) 

1750 

1751 if comReadParameters['Fid'] in connData['OpenedFiles']: 

1752 fileHandle = connData['OpenedFiles'][comReadParameters['Fid']]['FileHandle'] 

1753 errorCode = STATUS_SUCCESS 

1754 try: 

1755 if fileHandle != PIPE_FILE_DESCRIPTOR: 

1756 # TODO: Handle big size files 

1757 os.lseek(fileHandle, comReadParameters['Offset'], 0) 

1758 content = os.read(fileHandle, comReadParameters['Count']) 

1759 else: 

1760 sock = connData['OpenedFiles'][comReadParameters['Fid']]['Socket'] 

1761 content = sock.recv(comReadParameters['Count']) 

1762 respParameters['Count'] = len(content) 

1763 respData['DataLength'] = len(content) 

1764 respData['Data'] = content 

1765 except Exception as e: 

1766 smbServer.log('smbComRead: %s ' % e, logging.ERROR) 

1767 errorCode = STATUS_ACCESS_DENIED 

1768 else: 

1769 errorCode = STATUS_INVALID_HANDLE 

1770 

1771 if errorCode > 0: 

1772 respParameters = b'' 

1773 respData = b'' 

1774 

1775 respSMBCommand['Parameters'] = respParameters 

1776 respSMBCommand['Data'] = respData 

1777 smbServer.setConnectionData(connId, connData) 

1778 

1779 return [respSMBCommand], None, errorCode 

1780 

1781 @staticmethod 

1782 def smbComReadAndX(connId, smbServer, SMBCommand, recvPacket): 

1783 connData = smbServer.getConnectionData(connId) 

1784 

1785 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ_ANDX) 

1786 respParameters = smb.SMBReadAndXResponse_Parameters() 

1787 respData = b'' 

1788 

1789 if SMBCommand['WordCount'] == 0x0A: 

1790 readAndX = smb.SMBReadAndX_Parameters2(SMBCommand['Parameters']) 

1791 else: 

1792 readAndX = smb.SMBReadAndX_Parameters(SMBCommand['Parameters']) 

1793 

1794 if readAndX['Fid'] in connData['OpenedFiles']: 

1795 fileHandle = connData['OpenedFiles'][readAndX['Fid']]['FileHandle'] 

1796 errorCode = 0 

1797 try: 

1798 if fileHandle != PIPE_FILE_DESCRIPTOR: 

1799 offset = readAndX['Offset'] 

1800 if 'HighOffset' in readAndX.fields: 

1801 offset += (readAndX['HighOffset'] << 32) 

1802 os.lseek(fileHandle, offset, 0) 

1803 content = os.read(fileHandle, readAndX['MaxCount']) 

1804 else: 

1805 sock = connData['OpenedFiles'][readAndX['Fid']]['Socket'] 

1806 content = sock.recv(readAndX['MaxCount']) 

1807 respParameters['Remaining'] = 0xffff 

1808 respParameters['DataCount'] = len(content) 

1809 respParameters['DataOffset'] = 59 

1810 respParameters['DataCount_Hi'] = 0 

1811 respData = content 

1812 except Exception as e: 

1813 smbServer.log('smbComReadAndX: %s ' % e, logging.ERROR) 

1814 errorCode = STATUS_ACCESS_DENIED 

1815 else: 

1816 errorCode = STATUS_INVALID_HANDLE 

1817 

1818 if errorCode > 0: 

1819 respParameters = b'' 

1820 respData = b'' 

1821 

1822 respSMBCommand['Parameters'] = respParameters 

1823 respSMBCommand['Data'] = respData 

1824 smbServer.setConnectionData(connId, connData) 

1825 

1826 return [respSMBCommand], None, errorCode 

1827 

1828 @staticmethod 

1829 def smbQueryInformation(connId, smbServer, SMBCommand, recvPacket): 

1830 connData = smbServer.getConnectionData(connId) 

1831 

1832 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION) 

1833 respParameters = smb.SMBQueryInformationResponse_Parameters() 

1834 respData = b'' 

1835 

1836 queryInformation = smb.SMBQueryInformation_Data(flags=recvPacket['Flags2'], data=SMBCommand['Data']) 

1837 

1838 # Get the Tid associated 

1839 if recvPacket['Tid'] in connData['ConnectedShares']: 

1840 fileSize, lastWriteTime, fileAttributes = queryFsInformation( 

1841 connData['ConnectedShares'][recvPacket['Tid']]['path'], 

1842 decodeSMBString(recvPacket['Flags2'], queryInformation['FileName']), pktFlags=recvPacket['Flags2']) 

1843 

1844 respParameters['FileSize'] = fileSize 

1845 respParameters['LastWriteTime'] = lastWriteTime 

1846 respParameters['FileAttributes'] = fileAttributes 

1847 errorCode = STATUS_SUCCESS 

1848 else: 

1849 # STATUS_SMB_BAD_TID 

1850 errorCode = STATUS_SMB_BAD_TID 

1851 respParameters = b'' 

1852 respData = b'' 

1853 

1854 respSMBCommand['Parameters'] = respParameters 

1855 respSMBCommand['Data'] = respData 

1856 

1857 smbServer.setConnectionData(connId, connData) 

1858 return [respSMBCommand], None, errorCode 

1859 

1860 @staticmethod 

1861 def smbQueryInformationDisk(connId, smbServer, SMBCommand, recvPacket): 

1862 connData = smbServer.getConnectionData(connId) 

1863 

1864 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION_DISK) 

1865 respParameters = smb.SMBQueryInformationDiskResponse_Parameters() 

1866 respData = b'' 

1867 

1868 # Get the Tid associated 

1869 if recvPacket['Tid'] in connData['ConnectedShares']: 

1870 totalUnits, freeUnits = queryDiskInformation( 

1871 connData['ConnectedShares'][recvPacket['Tid']]['path']) 

1872 

1873 respParameters['TotalUnits'] = totalUnits 

1874 respParameters['BlocksPerUnit'] = 1 

1875 respParameters['BlockSize'] = 1 

1876 respParameters['FreeUnits'] = freeUnits 

1877 errorCode = STATUS_SUCCESS 

1878 else: 

1879 # STATUS_SMB_BAD_TID 

1880 respData = b'' 

1881 respParameters = b'' 

1882 errorCode = STATUS_SMB_BAD_TID 

1883 

1884 respSMBCommand['Parameters'] = respParameters 

1885 respSMBCommand['Data'] = respData 

1886 

1887 smbServer.setConnectionData(connId, connData) 

1888 return [respSMBCommand], None, errorCode 

1889 

1890 @staticmethod 

1891 def smbComEcho(connId, smbServer, SMBCommand, recvPacket): 

1892 connData = smbServer.getConnectionData(connId) 

1893 

1894 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO) 

1895 respParameters = smb.SMBEchoResponse_Parameters() 

1896 respData = smb.SMBEchoResponse_Data() 

1897 

1898 echoData = smb.SMBEcho_Data(SMBCommand['Data']) 

1899 

1900 respParameters['SequenceNumber'] = 1 

1901 respData['Data'] = echoData['Data'] 

1902 

1903 respSMBCommand['Parameters'] = respParameters 

1904 respSMBCommand['Data'] = respData 

1905 

1906 errorCode = STATUS_SUCCESS 

1907 smbServer.setConnectionData(connId, connData) 

1908 return [respSMBCommand], None, errorCode 

1909 

1910 @staticmethod 

1911 def smbComTreeDisconnect(connId, smbServer, SMBCommand, recvPacket): 

1912 connData = smbServer.getConnectionData(connId) 

1913 

1914 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_DISCONNECT) 

1915 

1916 # Check if the Tid matches the Tid trying to disconnect 

1917 respParameters = b'' 

1918 respData = b'' 

1919 

1920 if recvPacket['Tid'] in connData['ConnectedShares']: 

1921 smbServer.log("Disconnecting Share(%d:%s)" % ( 

1922 recvPacket['Tid'], connData['ConnectedShares'][recvPacket['Tid']]['shareName'])) 

1923 del (connData['ConnectedShares'][recvPacket['Tid']]) 

1924 errorCode = STATUS_SUCCESS 

1925 else: 

1926 # STATUS_SMB_BAD_TID 

1927 errorCode = STATUS_SMB_BAD_TID 

1928 

1929 respSMBCommand['Parameters'] = respParameters 

1930 respSMBCommand['Data'] = respData 

1931 

1932 smbServer.setConnectionData(connId, connData) 

1933 return [respSMBCommand], None, errorCode 

1934 

1935 @staticmethod 

1936 def smbComLogOffAndX(connId, smbServer, SMBCommand, recvPacket): 

1937 connData = smbServer.getConnectionData(connId) 

1938 

1939 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOGOFF_ANDX) 

1940 

1941 # Check if the Uid matches the user trying to logoff 

1942 respParameters = b'' 

1943 respData = b'' 

1944 if recvPacket['Uid'] != connData['Uid']: 

1945 # STATUS_SMB_BAD_UID 

1946 errorCode = STATUS_SMB_BAD_UID 

1947 else: 

1948 errorCode = STATUS_SUCCESS 

1949 

1950 respSMBCommand['Parameters'] = respParameters 

1951 respSMBCommand['Data'] = respData 

1952 connData['Uid'] = 0 

1953 connData['Authenticated'] = False 

1954 

1955 smbServer.setConnectionData(connId, connData) 

1956 

1957 return [respSMBCommand], None, errorCode 

1958 

1959 @staticmethod 

1960 def smbComQueryInformation2(connId, smbServer, SMBCommand, recvPacket): 

1961 connData = smbServer.getConnectionData(connId) 

1962 

1963 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION2) 

1964 respParameters = smb.SMBQueryInformation2Response_Parameters() 

1965 respData = b'' 

1966 

1967 queryInformation2 = smb.SMBQueryInformation2_Parameters(SMBCommand['Parameters']) 

1968 errorCode = 0xFF 

1969 if queryInformation2['Fid'] in connData['OpenedFiles']: 

1970 errorCode = STATUS_SUCCESS 

1971 pathName = connData['OpenedFiles'][queryInformation2['Fid']]['FileName'] 

1972 try: 

1973 (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName) 

1974 respParameters['CreateDate'] = getSMBDate(ctime) 

1975 respParameters['CreationTime'] = getSMBTime(ctime) 

1976 respParameters['LastAccessDate'] = getSMBDate(atime) 

1977 respParameters['LastAccessTime'] = getSMBTime(atime) 

1978 respParameters['LastWriteDate'] = getSMBDate(mtime) 

1979 respParameters['LastWriteTime'] = getSMBTime(mtime) 

1980 respParameters['FileDataSize'] = size 

1981 respParameters['FileAllocationSize'] = size 

1982 attribs = 0 

1983 if os.path.isdir(pathName): 

1984 attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

1985 if os.path.isfile(pathName): 

1986 attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL 

1987 respParameters['FileAttributes'] = attribs 

1988 except Exception as e: 

1989 smbServer.log('smbComQueryInformation2 %s' % e, logging.ERROR) 

1990 errorCode = STATUS_ACCESS_DENIED 

1991 

1992 if errorCode > 0: 

1993 respParameters = b'' 

1994 respData = b'' 

1995 

1996 respSMBCommand['Parameters'] = respParameters 

1997 respSMBCommand['Data'] = respData 

1998 smbServer.setConnectionData(connId, connData) 

1999 

2000 return [respSMBCommand], None, errorCode 

2001 

2002 @staticmethod 

2003 def smbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket): 

2004 # TODO: Fully implement this 

2005 connData = smbServer.getConnectionData(connId) 

2006 

2007 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX) 

2008 respParameters = smb.SMBNtCreateAndXResponse_Parameters() 

2009 respData = b'' 

2010 

2011 ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters']) 

2012 ntCreateAndXData = smb.SMBNtCreateAndX_Data(flags=recvPacket['Flags2'], data=SMBCommand['Data']) 

2013 

2014 # if ntCreateAndXParameters['CreateFlags'] & 0x10: # NT_CREATE_REQUEST_EXTENDED_RESPONSE 

2015 # respParameters = smb.SMBNtCreateAndXExtendedResponse_Parameters() 

2016 # respParameters['VolumeGUID'] = '\x00' 

2017 

2018 # Get the Tid associated 

2019 if recvPacket['Tid'] in connData['ConnectedShares']: 

2020 # If we have a rootFid, the path is relative to that fid 

2021 errorCode = STATUS_SUCCESS 

2022 if ntCreateAndXParameters['RootFid'] > 0: 

2023 path = connData['OpenedFiles'][ntCreateAndXParameters['RootFid']]['FileName'] 

2024 LOG.debug("RootFid present %s!" % path) 

2025 else: 

2026 if 'path' in connData['ConnectedShares'][recvPacket['Tid']]: 

2027 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

2028 else: 

2029 path = 'NONE' 

2030 errorCode = STATUS_ACCESS_DENIED 

2031 

2032 deleteOnClose = False 

2033 

2034 fileName = os.path.normpath( 

2035 decodeSMBString(recvPacket['Flags2'], ntCreateAndXData['FileName']).replace('\\', '/')) 

2036 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'): 

2037 # strip leading '/' 

2038 fileName = fileName[1:] 

2039 

2040 if not isInFileJail(path, fileName): 

2041 LOG.error("Path not in current working directory") 

2042 respSMBCommand['Parameters'] = b'' 

2043 respSMBCommand['Data'] = b'' 

2044 return [respSMBCommand], None, STATUS_OBJECT_PATH_SYNTAX_BAD 

2045 

2046 pathName = os.path.join(path, fileName) 

2047 createDisposition = ntCreateAndXParameters['Disposition'] 

2048 mode = 0 

2049 

2050 if createDisposition == smb.FILE_SUPERSEDE: 

2051 mode |= os.O_TRUNC | os.O_CREAT 

2052 elif createDisposition & smb.FILE_OVERWRITE_IF == smb.FILE_OVERWRITE_IF: 

2053 mode |= os.O_TRUNC | os.O_CREAT 

2054 elif createDisposition & smb.FILE_OVERWRITE == smb.FILE_OVERWRITE: 

2055 if os.path.exists(pathName) is True: 

2056 mode |= os.O_TRUNC 

2057 else: 

2058 errorCode = STATUS_NO_SUCH_FILE 

2059 elif createDisposition & smb.FILE_OPEN_IF == smb.FILE_OPEN_IF: 

2060 if os.path.exists(pathName) is True: 

2061 mode |= os.O_TRUNC 

2062 else: 

2063 mode |= os.O_TRUNC | os.O_CREAT 

2064 elif createDisposition & smb.FILE_CREATE == smb.FILE_CREATE: 

2065 if os.path.exists(pathName) is True: 

2066 errorCode = STATUS_OBJECT_NAME_COLLISION 

2067 else: 

2068 mode |= os.O_CREAT 

2069 elif createDisposition & smb.FILE_OPEN == smb.FILE_OPEN: 

2070 if os.path.exists(pathName) is not True and ( 

2071 str(pathName) in smbServer.getRegisteredNamedPipes()) is not True: 

2072 errorCode = STATUS_NO_SUCH_FILE 

2073 

2074 if errorCode == STATUS_SUCCESS: 

2075 desiredAccess = ntCreateAndXParameters['AccessMask'] 

2076 if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ): 

2077 mode |= os.O_RDONLY 

2078 if (desiredAccess & smb.FILE_WRITE_DATA) or (desiredAccess & smb.GENERIC_WRITE): 

2079 if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ): 

2080 mode |= os.O_RDWR # | os.O_APPEND 

2081 else: 

2082 mode |= os.O_WRONLY # | os.O_APPEND 

2083 if desiredAccess & smb.GENERIC_ALL: 

2084 mode |= os.O_RDWR # | os.O_APPEND 

2085 

2086 createOptions = ntCreateAndXParameters['CreateOptions'] 

2087 if mode & os.O_CREAT == os.O_CREAT: 

2088 if createOptions & smb.FILE_DIRECTORY_FILE == smb.FILE_DIRECTORY_FILE: 

2089 try: 

2090 # Let's create the directory 

2091 os.mkdir(pathName) 

2092 mode = os.O_RDONLY 

2093 except Exception as e: 

2094 smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName, mode, e), logging.ERROR) 

2095 errorCode = STATUS_ACCESS_DENIED 

2096 if createOptions & smb.FILE_NON_DIRECTORY_FILE == smb.FILE_NON_DIRECTORY_FILE: 

2097 # If the file being opened is a directory, the server MUST fail the request with 

2098 # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server 

2099 # response. 

2100 if os.path.isdir(pathName) is True: 

2101 errorCode = STATUS_FILE_IS_A_DIRECTORY 

2102 

2103 if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE: 

2104 deleteOnClose = True 

2105 

2106 if errorCode == STATUS_SUCCESS: 

2107 try: 

2108 if os.path.isdir(pathName) and sys.platform == 'win32': 

2109 fid = VOID_FILE_DESCRIPTOR 

2110 else: 

2111 if sys.platform == 'win32': 

2112 mode |= os.O_BINARY 

2113 if str(pathName) in smbServer.getRegisteredNamedPipes(): 

2114 fid = PIPE_FILE_DESCRIPTOR 

2115 sock = socket.socket() 

2116 sock.connect(smbServer.getRegisteredNamedPipes()[str(pathName)]) 

2117 else: 

2118 fid = os.open(pathName, mode) 

2119 except Exception as e: 

2120 smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName, mode, e), logging.ERROR) 

2121 # print e 

2122 fid = 0 

2123 errorCode = STATUS_ACCESS_DENIED 

2124 else: 

2125 errorCode = STATUS_SMB_BAD_TID 

2126 

2127 if errorCode == STATUS_SUCCESS: 

2128 # Simple way to generate a fid 

2129 if len(connData['OpenedFiles']) == 0: 

2130 fakefid = 1 

2131 else: 

2132 fakefid = list(connData['OpenedFiles'].keys())[-1] + 1 

2133 respParameters['Fid'] = fakefid 

2134 respParameters['CreateAction'] = createDisposition 

2135 if fid == PIPE_FILE_DESCRIPTOR: 

2136 respParameters['FileAttributes'] = 0x80 

2137 respParameters['IsDirectory'] = 0 

2138 respParameters['CreateTime'] = 0 

2139 respParameters['LastAccessTime'] = 0 

2140 respParameters['LastWriteTime'] = 0 

2141 respParameters['LastChangeTime'] = 0 

2142 respParameters['AllocationSize'] = 4096 

2143 respParameters['EndOfFile'] = 0 

2144 respParameters['FileType'] = 2 

2145 respParameters['IPCState'] = 0x5ff 

2146 else: 

2147 if os.path.isdir(pathName): 

2148 respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

2149 respParameters['IsDirectory'] = 1 

2150 else: 

2151 respParameters['IsDirectory'] = 0 

2152 respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes'] 

2153 # Let's get this file's information 

2154 respInfo, errorCode = queryPathInformation('', pathName, level=smb.SMB_QUERY_FILE_ALL_INFO) 

2155 if errorCode == STATUS_SUCCESS: 

2156 respParameters['CreateTime'] = respInfo['CreationTime'] 

2157 respParameters['LastAccessTime'] = respInfo['LastAccessTime'] 

2158 respParameters['LastWriteTime'] = respInfo['LastWriteTime'] 

2159 respParameters['LastChangeTime'] = respInfo['LastChangeTime'] 

2160 respParameters['FileAttributes'] = respInfo['ExtFileAttributes'] 

2161 respParameters['AllocationSize'] = respInfo['AllocationSize'] 

2162 respParameters['EndOfFile'] = respInfo['EndOfFile'] 

2163 else: 

2164 respParameters = b'' 

2165 respData = b'' 

2166 

2167 if errorCode == STATUS_SUCCESS: 

2168 # Let's store the fid for the connection 

2169 # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode)) 

2170 connData['OpenedFiles'][fakefid] = {} 

2171 connData['OpenedFiles'][fakefid]['FileHandle'] = fid 

2172 connData['OpenedFiles'][fakefid]['FileName'] = pathName 

2173 connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose 

2174 if fid == PIPE_FILE_DESCRIPTOR: 

2175 connData['OpenedFiles'][fakefid]['Socket'] = sock 

2176 else: 

2177 respParameters = b'' 

2178 respData = b'' 

2179 

2180 respSMBCommand['Parameters'] = respParameters 

2181 respSMBCommand['Data'] = respData 

2182 smbServer.setConnectionData(connId, connData) 

2183 

2184 return [respSMBCommand], None, errorCode 

2185 

2186 @staticmethod 

2187 def smbComOpenAndX(connId, smbServer, SMBCommand, recvPacket): 

2188 connData = smbServer.getConnectionData(connId) 

2189 

2190 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_OPEN_ANDX) 

2191 respParameters = smb.SMBOpenAndXResponse_Parameters() 

2192 respData = b'' 

2193 

2194 openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters']) 

2195 openAndXData = smb.SMBOpenAndX_Data(flags=recvPacket['Flags2'], data=SMBCommand['Data']) 

2196 

2197 # Get the Tid associated 

2198 if recvPacket['Tid'] in connData['ConnectedShares']: 

2199 path = connData['ConnectedShares'][recvPacket['Tid']]['path'] 

2200 openedFile, mode, pathName, errorCode = openFile(path, 

2201 decodeSMBString(recvPacket['Flags2'], 

2202 openAndXData['FileName']), 

2203 openAndXParameters['DesiredAccess'], 

2204 openAndXParameters['FileAttributes'], 

2205 openAndXParameters['OpenMode']) 

2206 else: 

2207 errorCode = STATUS_SMB_BAD_TID 

2208 

2209 if errorCode == STATUS_SUCCESS: 

2210 # Simple way to generate a fid 

2211 fid = len(connData['OpenedFiles']) + 1 

2212 if len(connData['OpenedFiles']) == 0: 

2213 fid = 1 

2214 else: 

2215 fid = list(connData['OpenedFiles'].keys())[-1] + 1 

2216 respParameters['Fid'] = fid 

2217 if mode & os.O_CREAT: 

2218 # File did not exist and was created 

2219 respParameters['Action'] = 0x2 

2220 elif mode & os.O_RDONLY: 

2221 # File existed and was opened 

2222 respParameters['Action'] = 0x1 

2223 elif mode & os.O_APPEND: 

2224 # File existed and was opened 

2225 respParameters['Action'] = 0x1 

2226 else: 

2227 # File existed and was truncated 

2228 respParameters['Action'] = 0x3 

2229 

2230 # Let's store the fid for the connection 

2231 # smbServer.log('Opening file %s' % pathName) 

2232 connData['OpenedFiles'][fid] = {} 

2233 connData['OpenedFiles'][fid]['FileHandle'] = openedFile 

2234 connData['OpenedFiles'][fid]['FileName'] = pathName 

2235 connData['OpenedFiles'][fid]['DeleteOnClose'] = False 

2236 else: 

2237 respParameters = b'' 

2238 respData = b'' 

2239 

2240 respSMBCommand['Parameters'] = respParameters 

2241 respSMBCommand['Data'] = respData 

2242 smbServer.setConnectionData(connId, connData) 

2243 

2244 return [respSMBCommand], None, errorCode 

2245 

2246 @staticmethod 

2247 def smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket): 

2248 connData = smbServer.getConnectionData(connId) 

2249 

2250 resp = smb.NewSMBPacket() 

2251 resp['Flags1'] = smb.SMB.FLAGS1_REPLY 

2252 resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | \ 

2253 recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE 

2254 

2255 resp['Tid'] = recvPacket['Tid'] 

2256 resp['Mid'] = recvPacket['Mid'] 

2257 resp['Pid'] = connData['Pid'] 

2258 

2259 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX) 

2260 respParameters = smb.SMBTreeConnectAndXResponse_Parameters() 

2261 respData = smb.SMBTreeConnectAndXResponse_Data() 

2262 

2263 treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters']) 

2264 

2265 if treeConnectAndXParameters['Flags'] & 0x8: 

2266 respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters() 

2267 

2268 treeConnectAndXData = smb.SMBTreeConnectAndX_Data(flags=recvPacket['Flags2']) 

2269 treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength'] 

2270 treeConnectAndXData.fromString(SMBCommand['Data']) 

2271 

2272 errorCode = STATUS_SUCCESS 

2273 

2274 ## Process here the request, does the share exist? 

2275 UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path']) 

2276 

2277 # Is this a UNC? 

2278 if ntpath.ismount(UNCOrShare): 

2279 path = UNCOrShare.split('\\')[3] 

2280 else: 

2281 path = ntpath.basename(UNCOrShare) 

2282 

2283 share = searchShare(connId, path, smbServer) 

2284 if share is not None: 

2285 # Simple way to generate a Tid 

2286 if len(connData['ConnectedShares']) == 0: 

2287 tid = 1 

2288 else: 

2289 tid = list(connData['ConnectedShares'].keys())[-1] + 1 

2290 connData['ConnectedShares'][tid] = share 

2291 connData['ConnectedShares'][tid]['shareName'] = path 

2292 resp['Tid'] = tid 

2293 # smbServer.log("Connecting Share(%d:%s)" % (tid,path)) 

2294 else: 

2295 smbServer.log("TreeConnectAndX not found %s" % path, logging.ERROR) 

2296 errorCode = STATUS_OBJECT_PATH_NOT_FOUND 

2297 resp['ErrorCode'] = errorCode >> 16 

2298 resp['ErrorClass'] = errorCode & 0xff 

2299 ## 

2300 respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS 

2301 

2302 if path == 'IPC$': 

2303 respData['Service'] = 'IPC' 

2304 else: 

2305 respData['Service'] = path 

2306 respData['PadLen'] = 0 

2307 respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS').decode() 

2308 

2309 respSMBCommand['Parameters'] = respParameters 

2310 respSMBCommand['Data'] = respData 

2311 

2312 resp['Uid'] = connData['Uid'] 

2313 resp.addCommand(respSMBCommand) 

2314 

2315 # Sign the packet if needed 

2316 if connData['SignatureEnabled']: 

2317 smbServer.signSMBv1(connData, resp, connData['SigningSessionKey'], connData['SigningChallengeResponse']) 

2318 smbServer.setConnectionData(connId, connData) 

2319 

2320 return None, [resp], errorCode 

2321 

2322 @staticmethod 

2323 def smbComSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket): 

2324 connData = smbServer.getConnectionData(connId, checkStatus=False) 

2325 

2326 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX) 

2327 

2328 # From [MS-SMB] 

2329 # When extended security is being used (see section 3.2.4.2.4), the 

2330 # request MUST take the following form 

2331 # [..] 

2332 # WordCount (1 byte): The value of this field MUST be 0x0C. 

2333 if SMBCommand['WordCount'] == 12: 

2334 # Extended security. Here we deal with all SPNEGO stuff 

2335 respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters() 

2336 respData = smb.SMBSessionSetupAndX_Extended_Response_Data(flags=recvPacket['Flags2']) 

2337 sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters']) 

2338 sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data() 

2339 sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength'] 

2340 sessionSetupData.fromString(SMBCommand['Data']) 

2341 connData['Capabilities'] = sessionSetupParameters['Capabilities'] 

2342 

2343 rawNTLM = False 

2344 if struct.unpack('B', sessionSetupData['SecurityBlob'][0:1])[0] == ASN1_AID: 

2345 # NEGOTIATE packet 

2346 blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob']) 

2347 token = blob['MechToken'] 

2348 if len(blob['MechTypes'][0]) > 0: 

2349 # Is this GSSAPI NTLM or something else we don't support? 

2350 mechType = blob['MechTypes'][0] 

2351 if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']: 

2352 # Nope, do we know it? 

2353 if mechType in MechTypes: 

2354 mechStr = MechTypes[mechType] 

2355 else: 

2356 mechStr = hexlify(mechType) 

2357 smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL) 

2358 # We don't know the token, we answer back again saying 

2359 # we just support NTLM. 

2360 # ToDo: Build this into a SPNEGO_NegTokenResp() 

2361 respToken = b'\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' 

2362 respParameters['SecurityBlobLength'] = len(respToken) 

2363 respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] 

2364 respData['SecurityBlob'] = respToken 

2365 respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS()) 

2366 respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS()) 

2367 respSMBCommand['Parameters'] = respParameters 

2368 respSMBCommand['Data'] = respData 

2369 return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED 

2370 

2371 elif struct.unpack('B', sessionSetupData['SecurityBlob'][0:1])[0] == ASN1_SUPPORTED_MECH: 

2372 # AUTH packet 

2373 blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob']) 

2374 token = blob['ResponseToken'] 

2375 else: 

2376 # No GSSAPI stuff, raw NTLMSSP 

2377 rawNTLM = True 

2378 token = sessionSetupData['SecurityBlob'] 

2379 

2380 # Here we only handle NTLMSSP, depending on what stage of the 

2381 # authentication we are, we act on it 

2382 messageType = struct.unpack('<L', token[len('NTLMSSP\x00'):len('NTLMSSP\x00') + 4])[0] 

2383 

2384 if messageType == 0x01: 

2385 # NEGOTIATE_MESSAGE 

2386 negotiateMessage = ntlm.NTLMAuthNegotiate() 

2387 negotiateMessage.fromString(token) 

2388 # Let's store it in the connection data 

2389 connData['NEGOTIATE_MESSAGE'] = negotiateMessage 

2390 # Let's build the answer flags 

2391 # TODO: Parse all the flags. With this we're leaving some clients out 

2392 

2393 ansFlags = 0 

2394 

2395 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56: 

2396 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56 

2397 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128: 

2398 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128 

2399 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH: 

2400 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH 

2401 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 

2402 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 

2403 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE: 

2404 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE 

2405 if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM: 

2406 ansFlags |= ntlm.NTLM_NEGOTIATE_OEM 

2407 

2408 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET 

2409 

2410 # Generate the AV_PAIRS 

2411 av_pairs = ntlm.AV_PAIRS() 

2412 # TODO: Put the proper data from SMBSERVER config 

2413 av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ 

2414 ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le') 

2415 av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ 

2416 ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le') 

2417 av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', ( 

2418 116444736000000000 + calendar.timegm(time.gmtime()) * 10000000)) 

2419 

2420 challengeMessage = ntlm.NTLMAuthChallenge() 

2421 challengeMessage['flags'] = ansFlags 

2422 challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le')) 

2423 challengeMessage['domain_max_len'] = challengeMessage['domain_len'] 

2424 challengeMessage['domain_offset'] = 40 + 16 

2425 challengeMessage['challenge'] = smbServer.getSMBChallenge() 

2426 challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le') 

2427 challengeMessage['TargetInfoFields_len'] = len(av_pairs) 

2428 challengeMessage['TargetInfoFields_max_len'] = len(av_pairs) 

2429 challengeMessage['TargetInfoFields'] = av_pairs 

2430 challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name']) 

2431 challengeMessage['Version'] = b'\xff' * 8 

2432 challengeMessage['VersionLen'] = 8 

2433 

2434 if rawNTLM is False: 

2435 respToken = SPNEGO_NegTokenResp() 

2436 # accept-incomplete. We want more data 

2437 respToken['NegState'] = b'\x01' 

2438 respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] 

2439 

2440 respToken['ResponseToken'] = challengeMessage.getData() 

2441 else: 

2442 respToken = challengeMessage 

2443 

2444 # Setting the packet to STATUS_MORE_PROCESSING 

2445 errorCode = STATUS_MORE_PROCESSING_REQUIRED 

2446 # Let's set up an UID for this connection and store it 

2447 # in the connection's data 

2448 # Picking a fixed value 

2449 # TODO: Manage more UIDs for the same session 

2450 connData['Uid'] = 10 

2451 # Let's store it in the connection data 

2452 connData['CHALLENGE_MESSAGE'] = challengeMessage 

2453 

2454 elif messageType == 0x02: 

2455 # CHALLENGE_MESSAGE 

2456 raise Exception('Challenge Message raise, not implemented!') 

2457 elif messageType == 0x03: 

2458 # AUTHENTICATE_MESSAGE, here we deal with authentication 

2459 authenticateMessage = ntlm.NTLMAuthChallengeResponse() 

2460 authenticateMessage.fromString(token) 

2461 smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % ( 

2462 authenticateMessage['domain_name'].decode('utf-16le'), 

2463 authenticateMessage['user_name'].decode('utf-16le'), 

2464 authenticateMessage['host_name'].decode('utf-16le'))) 

2465 # Do we have credentials to check? 

2466 if len(smbServer.getCredentials()) > 0: 

2467 identity = authenticateMessage['user_name'].decode('utf-16le').lower() 

2468 # Do we have this user's credentials? 

2469 if identity in smbServer.getCredentials(): 

2470 # Process data: 

2471 # Let's parse some data and keep it to ourselves in case it is asked 

2472 uid, lmhash, nthash = smbServer.getCredentials()[identity] 

2473 

2474 errorCode, sessionKey = computeNTLMv2(identity, lmhash, nthash, smbServer.getSMBChallenge(), 

2475 authenticateMessage, connData['CHALLENGE_MESSAGE'], 

2476 connData['NEGOTIATE_MESSAGE']) 

2477 

2478 if sessionKey is not None: 

2479 connData['SignatureEnabled'] = False 

2480 connData['SigningSessionKey'] = sessionKey 

2481 connData['SignSequenceNumber'] = 1 

2482 else: 

2483 errorCode = STATUS_LOGON_FAILURE 

2484 else: 

2485 # No credentials provided, let's grant access 

2486 errorCode = STATUS_SUCCESS 

2487 

2488 if errorCode == STATUS_SUCCESS: 

2489 connData['Authenticated'] = True 

2490 respToken = SPNEGO_NegTokenResp() 

2491 # accept-completed 

2492 respToken['NegState'] = b'\x00' 

2493 

2494 smbServer.log( 

2495 'User %s\\%s authenticated successfully' % (authenticateMessage['host_name'].decode('utf-16le'), 

2496 authenticateMessage['user_name'].decode( 

2497 'utf-16le'))) 

2498 # Let's store it in the connection data 

2499 connData['AUTHENTICATE_MESSAGE'] = authenticateMessage 

2500 try: 

2501 jtr_dump_path = smbServer.getJTRdumpPath() 

2502 ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], 

2503 authenticateMessage['user_name'], 

2504 authenticateMessage['domain_name'], 

2505 authenticateMessage['lanman'], authenticateMessage['ntlm']) 

2506 smbServer.log(ntlm_hash_data['hash_string']) 

2507 if jtr_dump_path != '': 

2508 writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], 

2509 jtr_dump_path) 

2510 except: 

2511 smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path) 

2512 else: 

2513 respToken = SPNEGO_NegTokenResp() 

2514 respToken['NegState'] = b'\x02' 

2515 smbServer.log("Could not authenticate user!") 

2516 else: 

2517 raise Exception("Unknown NTLMSSP MessageType %d" % messageType) 

2518 

2519 respParameters['SecurityBlobLength'] = len(respToken) 

2520 respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] 

2521 respData['SecurityBlob'] = respToken.getData() 

2522 

2523 else: 

2524 # Process Standard Security 

2525 respParameters = smb.SMBSessionSetupAndXResponse_Parameters() 

2526 respData = smb.SMBSessionSetupAndXResponse_Data() 

2527 sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters']) 

2528 sessionSetupData = smb.SMBSessionSetupAndX_Data() 

2529 sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength'] 

2530 sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength'] 

2531 sessionSetupData.fromString(SMBCommand['Data']) 

2532 connData['Capabilities'] = sessionSetupParameters['Capabilities'] 

2533 # Do the verification here, for just now we grant access 

2534 # TODO: Manage more UIDs for the same session 

2535 errorCode = STATUS_SUCCESS 

2536 connData['Uid'] = 10 

2537 connData['Authenticated'] = True 

2538 respParameters['Action'] = 0 

2539 smbServer.log('User %s\\%s authenticated successfully (basic)' % ( 

2540 sessionSetupData['PrimaryDomain'], sessionSetupData['Account'])) 

2541 try: 

2542 jtr_dump_path = smbServer.getJTRdumpPath() 

2543 ntlm_hash_data = outputToJohnFormat(b'', b(sessionSetupData['Account']), 

2544 b(sessionSetupData['PrimaryDomain']), sessionSetupData['AnsiPwd'], 

2545 sessionSetupData['UnicodePwd']) 

2546 smbServer.log(ntlm_hash_data['hash_string']) 

2547 if jtr_dump_path != '': 

2548 writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path) 

2549 except: 

2550 smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path) 

2551 

2552 respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS()) 

2553 respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS()) 

2554 respSMBCommand['Parameters'] = respParameters 

2555 respSMBCommand['Data'] = respData 

2556 

2557 # From now on, the client can ask for other commands 

2558 connData['Authenticated'] = True 

2559 # For now, just switching to nobody 

2560 # os.setregid(65534,65534) 

2561 # os.setreuid(65534,65534) 

2562 smbServer.setConnectionData(connId, connData) 

2563 

2564 return [respSMBCommand], None, errorCode 

2565 

2566 @staticmethod 

2567 def smbComNegotiate(connId, smbServer, SMBCommand, recvPacket): 

2568 connData = smbServer.getConnectionData(connId, checkStatus=False) 

2569 connData['Pid'] = recvPacket['Pid'] 

2570 

2571 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) 

2572 respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE) 

2573 

2574 resp = smb.NewSMBPacket() 

2575 resp['Flags1'] = smb.SMB.FLAGS1_REPLY 

2576 resp['Pid'] = connData['Pid'] 

2577 resp['Tid'] = recvPacket['Tid'] 

2578 resp['Mid'] = recvPacket['Mid'] 

2579 

2580 # TODO: We support more dialects, and parse them accordingly 

2581 dialects = SMBCommand['Data'].split(b'\x02') 

2582 try: 

2583 index = dialects.index(b'NT LM 0.12\x00') - 1 

2584 # Let's fill the data for NTLM 

2585 if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY: 

2586 resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE 

2587 # resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS 

2588 _dialects_data = smb.SMBExtended_Security_Data() 

2589 _dialects_data['ServerGUID'] = b'A' * 16 

2590 blob = SPNEGO_NegTokenInit() 

2591 blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']] 

2592 _dialects_data['SecurityBlob'] = blob.getData() 

2593 

2594 _dialects_parameters = smb.SMBExtended_Security_Parameters() 

2595 _dialects_parameters[ 

2596 'Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS | smb.SMB.CAP_UNICODE 

2597 _dialects_parameters['ChallengeLength'] = 0 

2598 

2599 else: 

2600 resp['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE 

2601 _dialects_parameters = smb.SMBNTLMDialect_Parameters() 

2602 _dialects_data = smb.SMBNTLMDialect_Data() 

2603 _dialects_data['Payload'] = '' 

2604 if 'EncryptionKey' in connData: 

2605 _dialects_data['Challenge'] = connData['EncryptionKey'] 

2606 _dialects_parameters['ChallengeLength'] = len(_dialects_data.getData()) 

2607 else: 

2608 # TODO: Handle random challenges, now one that can be used with rainbow tables 

2609 _dialects_data['Challenge'] = b'\x11\x22\x33\x44\x55\x66\x77\x88' 

2610 _dialects_parameters['ChallengeLength'] = 8 

2611 _dialects_parameters['Capabilities'] = smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS 

2612 

2613 # Let's see if we need to support RPC_REMOTE_APIS 

2614 config = smbServer.getServerConfig() 

2615 if config.has_option('global', 'rpc_apis'): 

2616 if config.getboolean('global', 'rpc_apis') is True: 

2617 _dialects_parameters['Capabilities'] |= smb.SMB.CAP_RPC_REMOTE_APIS 

2618 

2619 _dialects_parameters['DialectIndex'] = index 

2620 # _dialects_parameters['SecurityMode'] = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER | smb.SMB.SECURITY_SIGNATURES_REQUIRED 

2621 _dialects_parameters['SecurityMode'] = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER 

2622 _dialects_parameters['MaxMpxCount'] = 1 

2623 _dialects_parameters['MaxNumberVcs'] = 1 

2624 _dialects_parameters['MaxBufferSize'] = 64000 

2625 _dialects_parameters['MaxRawSize'] = 65536 

2626 _dialects_parameters['SessionKey'] = 0 

2627 _dialects_parameters['LowDateTime'] = 0 

2628 _dialects_parameters['HighDateTime'] = 0 

2629 _dialects_parameters['ServerTimeZone'] = 0 

2630 

2631 respSMBCommand['Data'] = _dialects_data 

2632 respSMBCommand['Parameters'] = _dialects_parameters 

2633 connData['_dialects_data'] = _dialects_data 

2634 connData['_dialects_parameters'] = _dialects_parameters 

2635 

2636 except Exception as e: 

2637 # No NTLM throw an error 

2638 smbServer.log('smbComNegotiate: %s' % e, logging.ERROR) 

2639 respSMBCommand['Data'] = struct.pack('<H', 0xffff) 

2640 

2641 smbServer.setConnectionData(connId, connData) 

2642 

2643 resp.addCommand(respSMBCommand) 

2644 

2645 return None, [resp], STATUS_SUCCESS 

2646 

2647 @staticmethod 

2648 def default(connId, smbServer, SMBCommand, recvPacket): 

2649 # By default we return an SMB Packet with error not implemented 

2650 smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'], logging.DEBUG) 

2651 packet = smb.NewSMBPacket() 

2652 packet['Flags1'] = smb.SMB.FLAGS1_REPLY 

2653 packet['Flags2'] = smb.SMB.FLAGS2_NT_STATUS 

2654 packet['Command'] = recvPacket['Command'] 

2655 packet['Pid'] = recvPacket['Pid'] 

2656 packet['Tid'] = recvPacket['Tid'] 

2657 packet['Mid'] = recvPacket['Mid'] 

2658 packet['Uid'] = recvPacket['Uid'] 

2659 packet['Data'] = b'\x00\x00\x00' 

2660 errorCode = STATUS_NOT_IMPLEMENTED 

2661 packet['ErrorCode'] = errorCode >> 16 

2662 packet['ErrorClass'] = errorCode & 0xff 

2663 

2664 return None, [packet], errorCode 

2665 

2666 

2667class SMB2Commands: 

2668 @staticmethod 

2669 def smb2Negotiate(connId, smbServer, recvPacket, isSMB1=False): 

2670 connData = smbServer.getConnectionData(connId, checkStatus=False) 

2671 

2672 respPacket = smb2.SMB2Packet() 

2673 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR 

2674 respPacket['Status'] = STATUS_SUCCESS 

2675 respPacket['CreditRequestResponse'] = 1 

2676 respPacket['Command'] = smb2.SMB2_NEGOTIATE 

2677 respPacket['SessionID'] = 0 

2678 if isSMB1 is False: 

2679 respPacket['MessageID'] = recvPacket['MessageID'] 

2680 else: 

2681 respPacket['MessageID'] = 0 

2682 respPacket['TreeID'] = 0 

2683 

2684 respSMBCommand = smb2.SMB2Negotiate_Response() 

2685 

2686 respSMBCommand['SecurityMode'] = 1 

2687 if isSMB1 is True: 

2688 # Let's first parse the packet to see if the client supports SMB2 

2689 SMBCommand = smb.SMBCommand(recvPacket['Data'][0]) 

2690 

2691 dialects = SMBCommand['Data'].split(b'\x02') 

2692 if b'SMB 2.002\x00' in dialects or b'SMB 2.???\x00' in dialects: 

2693 respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002 

2694 else: 

2695 # Client does not support SMB2 fallbacking 

2696 raise Exception('SMB2 not supported, fallbacking') 

2697 else: 

2698 respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002 

2699 respSMBCommand['ServerGuid'] = b'A' * 16 

2700 respSMBCommand['Capabilities'] = 0 

2701 respSMBCommand['MaxTransactSize'] = 65536 

2702 respSMBCommand['MaxReadSize'] = 65536 

2703 respSMBCommand['MaxWriteSize'] = 65536 

2704 respSMBCommand['SystemTime'] = getFileTime(calendar.timegm(time.gmtime())) 

2705 respSMBCommand['ServerStartTime'] = getFileTime(calendar.timegm(time.gmtime())) 

2706 respSMBCommand['SecurityBufferOffset'] = 0x80 

2707 

2708 blob = SPNEGO_NegTokenInit() 

2709 blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']] 

2710 

2711 respSMBCommand['Buffer'] = blob.getData() 

2712 respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer']) 

2713 

2714 respPacket['Data'] = respSMBCommand 

2715 

2716 smbServer.setConnectionData(connId, connData) 

2717 

2718 return None, [respPacket], STATUS_SUCCESS 

2719 

2720 @staticmethod 

2721 def smb2SessionSetup(connId, smbServer, recvPacket): 

2722 connData = smbServer.getConnectionData(connId, checkStatus=False) 

2723 

2724 respSMBCommand = smb2.SMB2SessionSetup_Response() 

2725 

2726 sessionSetupData = smb2.SMB2SessionSetup(recvPacket['Data']) 

2727 

2728 connData['Capabilities'] = sessionSetupData['Capabilities'] 

2729 

2730 securityBlob = sessionSetupData['Buffer'] 

2731 

2732 rawNTLM = False 

2733 if struct.unpack('B', securityBlob[0:1])[0] == ASN1_AID: 

2734 # NEGOTIATE packet 

2735 blob = SPNEGO_NegTokenInit(securityBlob) 

2736 token = blob['MechToken'] 

2737 if len(blob['MechTypes'][0]) > 0: 

2738 # Is this GSSAPI NTLM or something else we don't support? 

2739 mechType = blob['MechTypes'][0] 

2740 if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']: 

2741 # Nope, do we know it? 

2742 if mechType in MechTypes: 

2743 mechStr = MechTypes[mechType] 

2744 else: 

2745 mechStr = hexlify(mechType) 

2746 smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL) 

2747 # We don't know the token, we answer back again saying 

2748 # we just support NTLM. 

2749 # ToDo: Build this into a SPNEGO_NegTokenResp() 

2750 respToken = b'\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a' 

2751 respSMBCommand['SecurityBufferOffset'] = 0x48 

2752 respSMBCommand['SecurityBufferLength'] = len(respToken) 

2753 respSMBCommand['Buffer'] = respToken 

2754 

2755 return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED 

2756 elif struct.unpack('B', securityBlob[0:1])[0] == ASN1_SUPPORTED_MECH: 

2757 # AUTH packet 

2758 blob = SPNEGO_NegTokenResp(securityBlob) 

2759 token = blob['ResponseToken'] 

2760 else: 

2761 # No GSSAPI stuff, raw NTLMSSP 

2762 rawNTLM = True 

2763 token = securityBlob 

2764 

2765 # Here we only handle NTLMSSP, depending on what stage of the 

2766 # authentication we are, we act on it 

2767 messageType = struct.unpack('<L', token[len('NTLMSSP\x00'):len('NTLMSSP\x00') + 4])[0] 

2768 

2769 if messageType == 0x01: 

2770 # NEGOTIATE_MESSAGE 

2771 negotiateMessage = ntlm.NTLMAuthNegotiate() 

2772 negotiateMessage.fromString(token) 

2773 # Let's store it in the connection data 

2774 connData['NEGOTIATE_MESSAGE'] = negotiateMessage 

2775 # Let's build the answer flags 

2776 # TODO: Parse all the flags. With this we're leaving some clients out 

2777 

2778 ansFlags = 0 

2779 

2780 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56: 

2781 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56 

2782 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128: 

2783 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128 

2784 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH: 

2785 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH 

2786 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY: 

2787 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 

2788 if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE: 

2789 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE 

2790 if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM: 

2791 ansFlags |= ntlm.NTLM_NEGOTIATE_OEM 

2792 

2793 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET 

2794 

2795 # Generate the AV_PAIRS 

2796 av_pairs = ntlm.AV_PAIRS() 

2797 # TODO: Put the proper data from SMBSERVER config 

2798 av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ 

2799 ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le') 

2800 av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ 

2801 ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le') 

2802 av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', ( 

2803 116444736000000000 + calendar.timegm(time.gmtime()) * 10000000)) 

2804 

2805 challengeMessage = ntlm.NTLMAuthChallenge() 

2806 challengeMessage['flags'] = ansFlags 

2807 challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le')) 

2808 challengeMessage['domain_max_len'] = challengeMessage['domain_len'] 

2809 challengeMessage['domain_offset'] = 40 + 16 

2810 challengeMessage['challenge'] = smbServer.getSMBChallenge() 

2811 challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le') 

2812 challengeMessage['TargetInfoFields_len'] = len(av_pairs) 

2813 challengeMessage['TargetInfoFields_max_len'] = len(av_pairs) 

2814 challengeMessage['TargetInfoFields'] = av_pairs 

2815 challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name']) 

2816 challengeMessage['Version'] = b'\xff' * 8 

2817 challengeMessage['VersionLen'] = 8 

2818 

2819 if rawNTLM is False: 

2820 respToken = SPNEGO_NegTokenResp() 

2821 # accept-incomplete. We want more data 

2822 respToken['NegState'] = b'\x01' 

2823 respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider'] 

2824 

2825 respToken['ResponseToken'] = challengeMessage.getData() 

2826 else: 

2827 respToken = challengeMessage 

2828 

2829 # Setting the packet to STATUS_MORE_PROCESSING 

2830 errorCode = STATUS_MORE_PROCESSING_REQUIRED 

2831 # Let's set up an UID for this connection and store it 

2832 # in the connection's data 

2833 # Picking a fixed value 

2834 # TODO: Manage more UIDs for the same session 

2835 connData['Uid'] = random.randint(1, 0xffffffff) 

2836 # Let's store it in the connection data 

2837 connData['CHALLENGE_MESSAGE'] = challengeMessage 

2838 

2839 elif messageType == 0x02: 

2840 # CHALLENGE_MESSAGE 

2841 raise Exception('Challenge Message raise, not implemented!') 

2842 elif messageType == 0x03: 

2843 # AUTHENTICATE_MESSAGE, here we deal with authentication 

2844 authenticateMessage = ntlm.NTLMAuthChallengeResponse() 

2845 authenticateMessage.fromString(token) 

2846 smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % ( 

2847 authenticateMessage['domain_name'].decode('utf-16le'), 

2848 authenticateMessage['user_name'].decode('utf-16le'), 

2849 authenticateMessage['host_name'].decode('utf-16le'))) 

2850 # TODO: Check the credentials! Now granting permissions 

2851 # Do we have credentials to check? 

2852 if len(smbServer.getCredentials()) > 0: 

2853 isGuest = False 

2854 identity = authenticateMessage['user_name'].decode('utf-16le').lower() 

2855 # Do we have this user's credentials? 

2856 if identity in smbServer.getCredentials(): 

2857 # Process data: 

2858 # Let's parse some data and keep it to ourselves in case it is asked 

2859 uid, lmhash, nthash = smbServer.getCredentials()[identity] 

2860 

2861 errorCode, sessionKey = computeNTLMv2(identity, lmhash, nthash, smbServer.getSMBChallenge(), 

2862 authenticateMessage, connData['CHALLENGE_MESSAGE'], 

2863 connData['NEGOTIATE_MESSAGE']) 

2864 

2865 if sessionKey is not None: 

2866 connData['SignatureEnabled'] = True 

2867 connData['SigningSessionKey'] = sessionKey 

2868 connData['SignSequenceNumber'] = 1 

2869 else: 

2870 errorCode = STATUS_LOGON_FAILURE 

2871 else: 

2872 # No credentials provided, let's grant access 

2873 isGuest = True 

2874 errorCode = STATUS_SUCCESS 

2875 

2876 if errorCode == STATUS_SUCCESS: 

2877 connData['Authenticated'] = True 

2878 respToken = SPNEGO_NegTokenResp() 

2879 # accept-completed 

2880 respToken['NegState'] = b'\x00' 

2881 smbServer.log('User %s\\%s authenticated successfully' % ( 

2882 authenticateMessage['host_name'].decode('utf-16le'), 

2883 authenticateMessage['user_name'].decode('utf-16le'))) 

2884 # Let's store it in the connection data 

2885 connData['AUTHENTICATE_MESSAGE'] = authenticateMessage 

2886 try: 

2887 jtr_dump_path = smbServer.getJTRdumpPath() 

2888 ntlm_hash_data = outputToJohnFormat(connData['CHALLENGE_MESSAGE']['challenge'], 

2889 authenticateMessage['user_name'], 

2890 authenticateMessage['domain_name'], 

2891 authenticateMessage['lanman'], authenticateMessage['ntlm']) 

2892 smbServer.log(ntlm_hash_data['hash_string']) 

2893 if jtr_dump_path != '': 

2894 writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], 

2895 jtr_dump_path) 

2896 except: 

2897 smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path) 

2898 

2899 if isGuest: 

2900 respSMBCommand['SessionFlags'] = 1 

2901 

2902 else: 

2903 respToken = SPNEGO_NegTokenResp() 

2904 respToken['NegState'] = b'\x02' 

2905 smbServer.log("Could not authenticate user!") 

2906 else: 

2907 raise Exception("Unknown NTLMSSP MessageType %d" % messageType) 

2908 

2909 respSMBCommand['SecurityBufferOffset'] = 0x48 

2910 respSMBCommand['SecurityBufferLength'] = len(respToken) 

2911 respSMBCommand['Buffer'] = respToken.getData() 

2912 

2913 # From now on, the client can ask for other commands 

2914 connData['Authenticated'] = True 

2915 # For now, just switching to nobody 

2916 # os.setregid(65534,65534) 

2917 # os.setreuid(65534,65534) 

2918 smbServer.setConnectionData(connId, connData) 

2919 

2920 return [respSMBCommand], None, errorCode 

2921 

2922 @staticmethod 

2923 def smb2TreeConnect(connId, smbServer, recvPacket): 

2924 connData = smbServer.getConnectionData(connId) 

2925 

2926 respPacket = smb2.SMB2Packet() 

2927 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR 

2928 respPacket['Status'] = STATUS_SUCCESS 

2929 respPacket['CreditRequestResponse'] = 1 

2930 respPacket['Command'] = recvPacket['Command'] 

2931 respPacket['SessionID'] = connData['Uid'] 

2932 respPacket['Reserved'] = recvPacket['Reserved'] 

2933 respPacket['MessageID'] = recvPacket['MessageID'] 

2934 respPacket['TreeID'] = recvPacket['TreeID'] 

2935 

2936 respSMBCommand = smb2.SMB2TreeConnect_Response() 

2937 

2938 treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data']) 

2939 

2940 errorCode = STATUS_SUCCESS 

2941 

2942 ## Process here the request, does the share exist? 

2943 path = recvPacket.getData()[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']] 

2944 UNCOrShare = path.decode('utf-16le') 

2945 

2946 # Is this a UNC? 

2947 if ntpath.ismount(UNCOrShare): 

2948 path = UNCOrShare.split('\\')[3] 

2949 else: 

2950 path = ntpath.basename(UNCOrShare) 

2951 

2952 share = searchShare(connId, path.upper(), smbServer) 

2953 if share is not None: 

2954 # Simple way to generate a Tid 

2955 if len(connData['ConnectedShares']) == 0: 

2956 tid = 1 

2957 else: 

2958 tid = list(connData['ConnectedShares'].keys())[-1] + 1 

2959 connData['ConnectedShares'][tid] = share 

2960 connData['ConnectedShares'][tid]['shareName'] = path 

2961 respPacket['TreeID'] = tid 

2962 smbServer.log("Connecting Share(%d:%s)" % (tid, path)) 

2963 else: 

2964 smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR) 

2965 errorCode = STATUS_OBJECT_PATH_NOT_FOUND 

2966 respPacket['Status'] = errorCode 

2967 ## 

2968 

2969 if path.upper() == 'IPC$': 

2970 respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE 

2971 respSMBCommand['ShareFlags'] = 0x30 

2972 else: 

2973 respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK 

2974 respSMBCommand['ShareFlags'] = 0x0 

2975 

2976 respSMBCommand['Capabilities'] = 0 

2977 respSMBCommand['MaximalAccess'] = 0x000f01ff 

2978 

2979 respPacket['Data'] = respSMBCommand 

2980 

2981 # Sign the packet if needed 

2982 if connData['SignatureEnabled']: 

2983 smbServer.signSMBv2(respPacket, connData['SigningSessionKey']) 

2984 smbServer.setConnectionData(connId, connData) 

2985 

2986 return None, [respPacket], errorCode 

2987 

2988 @staticmethod 

2989 def smb2Create(connId, smbServer, recvPacket): 

2990 connData = smbServer.getConnectionData(connId) 

2991 

2992 respSMBCommand = smb2.SMB2Create_Response() 

2993 

2994 ntCreateRequest = smb2.SMB2Create(recvPacket['Data']) 

2995 

2996 respSMBCommand['Buffer'] = b'\x00' 

2997 # Get the Tid associated 

2998 if recvPacket['TreeID'] in connData['ConnectedShares']: 

2999 # If we have a rootFid, the path is relative to that fid 

3000 errorCode = STATUS_SUCCESS 

3001 if 'path' in connData['ConnectedShares'][recvPacket['TreeID']]: 

3002 path = connData['ConnectedShares'][recvPacket['TreeID']]['path'] 

3003 else: 

3004 path = 'NONE' 

3005 errorCode = STATUS_ACCESS_DENIED 

3006 

3007 deleteOnClose = False 

3008 

3009 fileName = os.path.normpath( 

3010 ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\', '/')) 

3011 if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'): 

3012 # strip leading '/' 

3013 fileName = fileName[1:] 

3014 

3015 if not isInFileJail(path, fileName): 

3016 LOG.error("Path not in current working directory") 

3017 return [smb2.SMB2Error()], None, STATUS_OBJECT_PATH_SYNTAX_BAD 

3018 

3019 pathName = os.path.join(path, fileName) 

3020 createDisposition = ntCreateRequest['CreateDisposition'] 

3021 mode = 0 

3022 

3023 if createDisposition == smb2.FILE_SUPERSEDE: 

3024 mode |= os.O_TRUNC | os.O_CREAT 

3025 elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF: 

3026 mode |= os.O_TRUNC | os.O_CREAT 

3027 elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE: 

3028 if os.path.exists(pathName) is True: 

3029 mode |= os.O_TRUNC 

3030 else: 

3031 errorCode = STATUS_NO_SUCH_FILE 

3032 elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF: 

3033 if os.path.exists(pathName) is True: 

3034 mode |= os.O_TRUNC 

3035 else: 

3036 mode |= os.O_TRUNC | os.O_CREAT 

3037 elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE: 

3038 if os.path.exists(pathName) is True: 

3039 errorCode = STATUS_OBJECT_NAME_COLLISION 

3040 else: 

3041 mode |= os.O_CREAT 

3042 elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN: 

3043 if os.path.exists(pathName) is not True and ( 

3044 str(pathName) in smbServer.getRegisteredNamedPipes()) is not True: 

3045 errorCode = STATUS_NO_SUCH_FILE 

3046 

3047 if errorCode == STATUS_SUCCESS: 

3048 desiredAccess = ntCreateRequest['DesiredAccess'] 

3049 if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ): 

3050 mode |= os.O_RDONLY 

3051 if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE): 

3052 if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ): 

3053 mode |= os.O_RDWR # | os.O_APPEND 

3054 else: 

3055 mode |= os.O_WRONLY # | os.O_APPEND 

3056 if desiredAccess & smb2.GENERIC_ALL: 

3057 mode |= os.O_RDWR # | os.O_APPEND 

3058 

3059 createOptions = ntCreateRequest['CreateOptions'] 

3060 if mode & os.O_CREAT == os.O_CREAT: 

3061 if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE: 

3062 try: 

3063 # Let's create the directory 

3064 os.mkdir(pathName) 

3065 mode = os.O_RDONLY 

3066 except Exception as e: 

3067 smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName, mode, e), logging.ERROR) 

3068 errorCode = STATUS_ACCESS_DENIED 

3069 if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE: 

3070 # If the file being opened is a directory, the server MUST fail the request with 

3071 # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server 

3072 # response. 

3073 if os.path.isdir(pathName) is True: 

3074 errorCode = STATUS_FILE_IS_A_DIRECTORY 

3075 

3076 if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE: 

3077 deleteOnClose = True 

3078 

3079 if errorCode == STATUS_SUCCESS: 

3080 try: 

3081 if os.path.isdir(pathName) and sys.platform == 'win32': 

3082 fid = VOID_FILE_DESCRIPTOR 

3083 else: 

3084 if sys.platform == 'win32': 

3085 mode |= os.O_BINARY 

3086 if str(pathName) in smbServer.getRegisteredNamedPipes(): 

3087 fid = PIPE_FILE_DESCRIPTOR 

3088 sock = socket.socket() 

3089 sock.connect(smbServer.getRegisteredNamedPipes()[str(pathName)]) 

3090 else: 

3091 fid = os.open(pathName, mode) 

3092 except Exception as e: 

3093 smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName, mode, e), logging.ERROR) 

3094 # print e 

3095 fid = 0 

3096 errorCode = STATUS_ACCESS_DENIED 

3097 else: 

3098 errorCode = STATUS_SMB_BAD_TID 

3099 

3100 if errorCode == STATUS_SUCCESS: 

3101 # Simple way to generate a fid 

3102 fakefid = uuid.generate() 

3103 

3104 respSMBCommand['FileID'] = fakefid 

3105 respSMBCommand['CreateAction'] = createDisposition 

3106 

3107 if fid == PIPE_FILE_DESCRIPTOR: 

3108 respSMBCommand['CreationTime'] = 0 

3109 respSMBCommand['LastAccessTime'] = 0 

3110 respSMBCommand['LastWriteTime'] = 0 

3111 respSMBCommand['ChangeTime'] = 0 

3112 respSMBCommand['AllocationSize'] = 4096 

3113 respSMBCommand['EndOfFile'] = 0 

3114 respSMBCommand['FileAttributes'] = 0x80 

3115 

3116 else: 

3117 if os.path.isdir(pathName): 

3118 respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

3119 else: 

3120 respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes'] 

3121 # Let's get this file's information 

3122 respInfo, errorCode = queryPathInformation('', pathName, level=smb.SMB_QUERY_FILE_ALL_INFO) 

3123 if errorCode == STATUS_SUCCESS: 

3124 respSMBCommand['CreationTime'] = respInfo['CreationTime'] 

3125 respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime'] 

3126 respSMBCommand['LastWriteTime'] = respInfo['LastWriteTime'] 

3127 respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime'] 

3128 respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes'] 

3129 respSMBCommand['AllocationSize'] = respInfo['AllocationSize'] 

3130 respSMBCommand['EndOfFile'] = respInfo['EndOfFile'] 

3131 

3132 if errorCode == STATUS_SUCCESS: 

3133 # Let's store the fid for the connection 

3134 # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode)) 

3135 connData['OpenedFiles'][fakefid] = {} 

3136 connData['OpenedFiles'][fakefid]['FileHandle'] = fid 

3137 connData['OpenedFiles'][fakefid]['FileName'] = pathName 

3138 connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose 

3139 connData['OpenedFiles'][fakefid]['Open'] = {} 

3140 connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0 

3141 connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = '' 

3142 if fid == PIPE_FILE_DESCRIPTOR: 

3143 connData['OpenedFiles'][fakefid]['Socket'] = sock 

3144 else: 

3145 respSMBCommand = smb2.SMB2Error() 

3146 

3147 if errorCode == STATUS_SUCCESS: 

3148 connData['LastRequest']['SMB2_CREATE'] = respSMBCommand 

3149 smbServer.setConnectionData(connId, connData) 

3150 

3151 return [respSMBCommand], None, errorCode 

3152 

3153 @staticmethod 

3154 def smb2Close(connId, smbServer, recvPacket): 

3155 connData = smbServer.getConnectionData(connId) 

3156 

3157 respSMBCommand = smb2.SMB2Close_Response() 

3158 

3159 closeRequest = smb2.SMB2Close(recvPacket['Data']) 

3160 

3161 if closeRequest['FileID'].getData() == b'\xff' * 16: 

3162 # Let's take the data from the lastRequest 

3163 if 'SMB2_CREATE' in connData['LastRequest']: 

3164 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3165 else: 

3166 fileID = closeRequest['FileID'].getData() 

3167 else: 

3168 fileID = closeRequest['FileID'].getData() 

3169 

3170 if fileID in connData['OpenedFiles']: 

3171 errorCode = STATUS_SUCCESS 

3172 fileHandle = connData['OpenedFiles'][fileID]['FileHandle'] 

3173 pathName = connData['OpenedFiles'][fileID]['FileName'] 

3174 infoRecord = None 

3175 try: 

3176 if fileHandle == PIPE_FILE_DESCRIPTOR: 

3177 connData['OpenedFiles'][fileID]['Socket'].close() 

3178 elif fileHandle != VOID_FILE_DESCRIPTOR: 

3179 os.close(fileHandle) 

3180 infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), 

3181 smb2.SMB2_FILE_NETWORK_OPEN_INFO) 

3182 except Exception as e: 

3183 smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR) 

3184 errorCode = STATUS_INVALID_HANDLE 

3185 else: 

3186 # Check if the file was marked for removal 

3187 if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True: 

3188 try: 

3189 if os.path.isdir(pathName): 

3190 shutil.rmtree(connData['OpenedFiles'][fileID]['FileName']) 

3191 else: 

3192 os.remove(connData['OpenedFiles'][fileID]['FileName']) 

3193 except Exception as e: 

3194 smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR) 

3195 errorCode = STATUS_ACCESS_DENIED 

3196 

3197 # Now fill out the response 

3198 if infoRecord is not None: 

3199 respSMBCommand['CreationTime'] = infoRecord['CreationTime'] 

3200 respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime'] 

3201 respSMBCommand['LastWriteTime'] = infoRecord['LastWriteTime'] 

3202 respSMBCommand['ChangeTime'] = infoRecord['ChangeTime'] 

3203 respSMBCommand['AllocationSize'] = infoRecord['AllocationSize'] 

3204 respSMBCommand['EndofFile'] = infoRecord['EndOfFile'] 

3205 respSMBCommand['FileAttributes'] = infoRecord['FileAttributes'] 

3206 if errorCode == STATUS_SUCCESS: 

3207 del (connData['OpenedFiles'][fileID]) 

3208 else: 

3209 errorCode = STATUS_INVALID_HANDLE 

3210 

3211 smbServer.setConnectionData(connId, connData) 

3212 return [respSMBCommand], None, errorCode 

3213 

3214 @staticmethod 

3215 def smb2QueryInfo(connId, smbServer, recvPacket): 

3216 connData = smbServer.getConnectionData(connId) 

3217 

3218 respSMBCommand = smb2.SMB2QueryInfo_Response() 

3219 

3220 queryInfo = smb2.SMB2QueryInfo(recvPacket['Data']) 

3221 

3222 errorCode = STATUS_SUCCESS 

3223 

3224 respSMBCommand['OutputBufferOffset'] = 0x48 

3225 respSMBCommand['Buffer'] = b'\x00' 

3226 

3227 if queryInfo['FileID'].getData() == b'\xff' * 16: 

3228 # Let's take the data from the lastRequest 

3229 if 'SMB2_CREATE' in connData['LastRequest']: 

3230 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3231 else: 

3232 fileID = queryInfo['FileID'].getData() 

3233 else: 

3234 fileID = queryInfo['FileID'].getData() 

3235 

3236 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3237 if fileID in connData['OpenedFiles']: 

3238 fileName = connData['OpenedFiles'][fileID]['FileName'] 

3239 

3240 if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE: 

3241 if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO: 

3242 # No need to call queryFileInformation, we have the data here 

3243 infoRecord = smb2.FileInternalInformation() 

3244 infoRecord['IndexNumber'] = fileID 

3245 else: 

3246 infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), 

3247 os.path.basename(fileName), 

3248 queryInfo['FileInfoClass']) 

3249 elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM: 

3250 if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_EA_INFO: 

3251 infoRecord = b'\x00' * 4 

3252 else: 

3253 infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), 

3254 queryInfo['FileInfoClass']) 

3255 elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY: 

3256 # Failing for now, until we support it 

3257 infoRecord = None 

3258 errorCode = STATUS_ACCESS_DENIED 

3259 else: 

3260 smbServer.log("queryInfo not supported (%x)" % queryInfo['InfoType'], logging.ERROR) 

3261 

3262 if infoRecord is not None: 

3263 respSMBCommand['OutputBufferLength'] = len(infoRecord) 

3264 respSMBCommand['Buffer'] = infoRecord 

3265 else: 

3266 errorCode = STATUS_INVALID_HANDLE 

3267 else: 

3268 errorCode = STATUS_SMB_BAD_TID 

3269 

3270 smbServer.setConnectionData(connId, connData) 

3271 return [respSMBCommand], None, errorCode 

3272 

3273 @staticmethod 

3274 def smb2SetInfo(connId, smbServer, recvPacket): 

3275 connData = smbServer.getConnectionData(connId) 

3276 

3277 respSMBCommand = smb2.SMB2SetInfo_Response() 

3278 

3279 setInfo = smb2.SMB2SetInfo(recvPacket['Data']) 

3280 

3281 errorCode = STATUS_SUCCESS 

3282 

3283 if setInfo['FileID'].getData() == b'\xff' * 16: 

3284 # Let's take the data from the lastRequest 

3285 if 'SMB2_CREATE' in connData['LastRequest']: 

3286 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3287 else: 

3288 fileID = setInfo['FileID'].getData() 

3289 else: 

3290 fileID = setInfo['FileID'].getData() 

3291 

3292 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3293 path = connData['ConnectedShares'][recvPacket['TreeID']]['path'] 

3294 if fileID in connData['OpenedFiles']: 

3295 pathName = connData['OpenedFiles'][fileID]['FileName'] 

3296 

3297 if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE: 

3298 # The file information is being set 

3299 informationLevel = setInfo['FileInfoClass'] 

3300 if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO: 

3301 infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer']) 

3302 if infoRecord['DeletePending'] > 0: 

3303 # Mark this file for removal after closed 

3304 connData['OpenedFiles'][fileID]['DeleteOnClose'] = True 

3305 elif informationLevel == smb2.SMB2_FILE_BASIC_INFO: 

3306 infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer']) 

3307 # Creation time won't be set, the other ones we play with. 

3308 atime = infoRecord['LastWriteTime'] 

3309 if atime == 0: 

3310 atime = -1 

3311 else: 

3312 atime = getUnixTime(atime) 

3313 mtime = infoRecord['ChangeTime'] 

3314 if mtime == 0: 

3315 mtime = -1 

3316 else: 

3317 mtime = getUnixTime(mtime) 

3318 if atime > 0 and mtime > 0: 

3319 os.utime(pathName, (atime, mtime)) 

3320 elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO: 

3321 fileHandle = connData['OpenedFiles'][fileID]['FileHandle'] 

3322 infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer']) 

3323 if infoRecord['EndOfFile'] > 0: 

3324 os.lseek(fileHandle, infoRecord['EndOfFile'] - 1, 0) 

3325 os.write(fileHandle, b'\x00') 

3326 elif informationLevel == smb2.SMB2_FILE_RENAME_INFO: 

3327 renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer']) 

3328 newPathName = os.path.join(path, renameInfo['FileName'].decode('utf-16le').replace('\\', '/')) 

3329 if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName): 

3330 return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION 

3331 try: 

3332 os.rename(pathName, newPathName) 

3333 connData['OpenedFiles'][fileID]['FileName'] = newPathName 

3334 except Exception as e: 

3335 smbServer.log("smb2SetInfo: %s" % e, logging.ERROR) 

3336 errorCode = STATUS_ACCESS_DENIED 

3337 else: 

3338 smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR) 

3339 # UNSUPPORTED 

3340 errorCode = STATUS_NOT_SUPPORTED 

3341 # elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM: 

3342 # # The underlying object store information is being set. 

3343 # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass']) 

3344 # elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY: 

3345 # # The security information is being set. 

3346 # # Failing for now, until we support it 

3347 # infoRecord = None 

3348 # errorCode = STATUS_ACCESS_DENIED 

3349 # elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA: 

3350 # # The underlying object store quota information is being set. 

3351 # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass']) 

3352 else: 

3353 smbServer.log("setInfo not supported (%x)" % setInfo['InfoType'], logging.ERROR) 

3354 

3355 else: 

3356 errorCode = STATUS_INVALID_HANDLE 

3357 else: 

3358 errorCode = STATUS_SMB_BAD_TID 

3359 

3360 smbServer.setConnectionData(connId, connData) 

3361 return [respSMBCommand], None, errorCode 

3362 

3363 @staticmethod 

3364 def smb2Write(connId, smbServer, recvPacket): 

3365 connData = smbServer.getConnectionData(connId) 

3366 

3367 respSMBCommand = smb2.SMB2Write_Response() 

3368 writeRequest = smb2.SMB2Write(recvPacket['Data']) 

3369 

3370 respSMBCommand['Buffer'] = b'\x00' 

3371 

3372 if writeRequest['FileID'].getData() == b'\xff' * 16: 

3373 # Let's take the data from the lastRequest 

3374 if 'SMB2_CREATE' in connData['LastRequest']: 

3375 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3376 else: 

3377 fileID = writeRequest['FileID'].getData() 

3378 else: 

3379 fileID = writeRequest['FileID'].getData() 

3380 

3381 if fileID in connData['OpenedFiles']: 

3382 fileHandle = connData['OpenedFiles'][fileID]['FileHandle'] 

3383 errorCode = STATUS_SUCCESS 

3384 try: 

3385 if fileHandle != PIPE_FILE_DESCRIPTOR: 

3386 offset = writeRequest['Offset'] 

3387 # If we're trying to write past the file end we just skip the write call (Vista does this) 

3388 if os.lseek(fileHandle, 0, 2) >= offset: 

3389 os.lseek(fileHandle, offset, 0) 

3390 os.write(fileHandle, writeRequest['Buffer']) 

3391 else: 

3392 sock = connData['OpenedFiles'][fileID]['Socket'] 

3393 sock.send(writeRequest['Buffer']) 

3394 

3395 respSMBCommand['Count'] = writeRequest['Length'] 

3396 respSMBCommand['Remaining'] = 0xff 

3397 except Exception as e: 

3398 smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR) 

3399 errorCode = STATUS_ACCESS_DENIED 

3400 else: 

3401 errorCode = STATUS_INVALID_HANDLE 

3402 

3403 smbServer.setConnectionData(connId, connData) 

3404 return [respSMBCommand], None, errorCode 

3405 

3406 @staticmethod 

3407 def smb2Read(connId, smbServer, recvPacket): 

3408 connData = smbServer.getConnectionData(connId) 

3409 

3410 respSMBCommand = smb2.SMB2Read_Response() 

3411 readRequest = smb2.SMB2Read(recvPacket['Data']) 

3412 

3413 respSMBCommand['Buffer'] = b'\x00' 

3414 

3415 if readRequest['FileID'].getData() == b'\xff' * 16: 

3416 # Let's take the data from the lastRequest 

3417 if 'SMB2_CREATE' in connData['LastRequest']: 

3418 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3419 else: 

3420 fileID = readRequest['FileID'].getData() 

3421 else: 

3422 fileID = readRequest['FileID'].getData() 

3423 

3424 if fileID in connData['OpenedFiles']: 

3425 fileHandle = connData['OpenedFiles'][fileID]['FileHandle'] 

3426 errorCode = 0 

3427 try: 

3428 if fileHandle != PIPE_FILE_DESCRIPTOR: 

3429 offset = readRequest['Offset'] 

3430 os.lseek(fileHandle, offset, 0) 

3431 content = os.read(fileHandle, readRequest['Length']) 

3432 else: 

3433 sock = connData['OpenedFiles'][fileID]['Socket'] 

3434 content = sock.recv(readRequest['Length']) 

3435 

3436 respSMBCommand['DataOffset'] = 0x50 

3437 respSMBCommand['DataLength'] = len(content) 

3438 respSMBCommand['DataRemaining'] = 0 

3439 respSMBCommand['Buffer'] = content 

3440 except Exception as e: 

3441 smbServer.log('SMB2_READ: %s ' % e, logging.ERROR) 

3442 errorCode = STATUS_ACCESS_DENIED 

3443 else: 

3444 errorCode = STATUS_INVALID_HANDLE 

3445 

3446 smbServer.setConnectionData(connId, connData) 

3447 return [respSMBCommand], None, errorCode 

3448 

3449 @staticmethod 

3450 def smb2Flush(connId, smbServer, recvPacket): 

3451 connData = smbServer.getConnectionData(connId) 

3452 

3453 respSMBCommand = smb2.SMB2Flush_Response() 

3454 flushRequest = smb2.SMB2Flush(recvPacket['Data']) 

3455 

3456 if flushRequest['FileID'].getData() in connData['OpenedFiles']: 

3457 fileHandle = connData['OpenedFiles'][flushRequest['FileID'].getData()]['FileHandle'] 

3458 errorCode = STATUS_SUCCESS 

3459 try: 

3460 os.fsync(fileHandle) 

3461 except Exception as e: 

3462 smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR) 

3463 errorCode = STATUS_ACCESS_DENIED 

3464 else: 

3465 errorCode = STATUS_INVALID_HANDLE 

3466 

3467 smbServer.setConnectionData(connId, connData) 

3468 return [respSMBCommand], None, errorCode 

3469 

3470 @staticmethod 

3471 def smb2QueryDirectory(connId, smbServer, recvPacket): 

3472 connData = smbServer.getConnectionData(connId) 

3473 respSMBCommand = smb2.SMB2QueryDirectory_Response() 

3474 queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data']) 

3475 

3476 respSMBCommand['Buffer'] = b'\x00' 

3477 

3478 # The server MUST locate the tree connection, as specified in section 3.3.5.2.11. 

3479 if (recvPacket['TreeID'] in connData['ConnectedShares']) is False: 

3480 return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED 

3481 

3482 # Next, the server MUST locate the open for the directory to be queried 

3483 # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED 

3484 if queryDirectoryRequest['FileID'].getData() == b'\xff' * 16: 

3485 # Let's take the data from the lastRequest 

3486 if 'SMB2_CREATE' in connData['LastRequest']: 

3487 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3488 else: 

3489 fileID = queryDirectoryRequest['FileID'].getData() 

3490 else: 

3491 fileID = queryDirectoryRequest['FileID'].getData() 

3492 

3493 if (fileID in connData['OpenedFiles']) is False: 

3494 return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED 

3495 

3496 # If the open is not an open to a directory, the request MUST be failed 

3497 # with STATUS_INVALID_PARAMETER. 

3498 if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False: 

3499 return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER 

3500 

3501 # If any other information class is specified in the FileInformationClass 

3502 # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the 

3503 # operation with STATUS_INVALID_INFO_CLASS. 

3504 if queryDirectoryRequest['FileInformationClass'] not in ( 

3505 smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, 

3506 smb2.FILEID_FULL_DIRECTORY_INFORMATION, 

3507 smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, 

3508 smb2.FILENAMES_INFORMATION): 

3509 return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS 

3510 

3511 # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY 

3512 # Request, the server SHOULD<326> set Open.EnumerationLocation to 0 

3513 # and Open.EnumerationSearchPattern to an empty string. 

3514 if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN: 

3515 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0 

3516 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = '' 

3517 

3518 # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2 

3519 # QUERY_DIRECTORY Request, the server MUST set 

3520 # Open.EnumerationLocation to 0. 

3521 if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS: 

3522 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0 

3523 

3524 # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern 

3525 # is an empty string, then Open.EnumerationSearchPattern MUST be set 

3526 # to the search pattern specified in the SMB2 QUERY_DIRECTORY by 

3527 # FileNameOffset and FileNameLength. If FileNameLength is 0, the server 

3528 # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries. 

3529 

3530 pattern = queryDirectoryRequest['Buffer'].decode('utf-16le') 

3531 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \ 

3532 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '': 

3533 if pattern == '': 

3534 pattern = '*' 

3535 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern 

3536 

3537 # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero, 

3538 # the server MUST set Open.EnumerationSearchPattern to the search pattern 

3539 # specified in the request by FileNameOffset and FileNameLength. 

3540 if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \ 

3541 queryDirectoryRequest['FileNameLength'] > 0: 

3542 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern 

3543 

3544 pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']), pattern) 

3545 searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName), 

3546 os.path.basename(pathName), 

3547 queryDirectoryRequest['FileInformationClass'], 

3548 smb.ATTR_DIRECTORY, isSMB2=True) 

3549 

3550 if errorCode != STATUS_SUCCESS: 

3551 return [smb2.SMB2Error()], None, errorCode 

3552 

3553 if searchCount > 2 and pattern == '*': 

3554 # strip . and .. 

3555 searchCount -= 2 

3556 searchResult = searchResult[2:] 

3557 

3558 if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0: 

3559 return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE 

3560 

3561 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0: 

3562 return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES 

3563 

3564 totalData = 0 

3565 respData = b'' 

3566 for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount): 

3567 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1 

3568 if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY: 

3569 # If single entry is requested we must clear the NextEntryOffset 

3570 searchResult[nItem]['NextEntryOffset'] = 0 

3571 data = searchResult[nItem].getData() 

3572 lenData = len(data) 

3573 padLen = (8 - (lenData % 8)) % 8 

3574 

3575 if (totalData + lenData) >= queryDirectoryRequest['OutputBufferLength']: 

3576 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1 

3577 break 

3578 else: 

3579 respData += data + b'\x00' * padLen 

3580 totalData += lenData + padLen 

3581 

3582 if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY: 

3583 break 

3584 

3585 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount: 

3586 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1 

3587 

3588 respSMBCommand['OutputBufferOffset'] = 0x48 

3589 respSMBCommand['OutputBufferLength'] = totalData 

3590 respSMBCommand['Buffer'] = respData 

3591 

3592 smbServer.setConnectionData(connId, connData) 

3593 return [respSMBCommand], None, errorCode 

3594 

3595 @staticmethod 

3596 def smb2ChangeNotify(connId, smbServer, recvPacket): 

3597 

3598 return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED 

3599 

3600 @staticmethod 

3601 def smb2Echo(connId, smbServer, recvPacket): 

3602 

3603 respSMBCommand = smb2.SMB2Echo_Response() 

3604 

3605 return [respSMBCommand], None, STATUS_SUCCESS 

3606 

3607 @staticmethod 

3608 def smb2TreeDisconnect(connId, smbServer, recvPacket): 

3609 connData = smbServer.getConnectionData(connId) 

3610 

3611 respSMBCommand = smb2.SMB2TreeDisconnect_Response() 

3612 

3613 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3614 smbServer.log("Disconnecting Share(%d:%s)" % ( 

3615 recvPacket['TreeID'], connData['ConnectedShares'][recvPacket['TreeID']]['shareName'])) 

3616 del (connData['ConnectedShares'][recvPacket['TreeID']]) 

3617 errorCode = STATUS_SUCCESS 

3618 else: 

3619 # STATUS_SMB_BAD_TID 

3620 errorCode = STATUS_SMB_BAD_TID 

3621 

3622 smbServer.setConnectionData(connId, connData) 

3623 return [respSMBCommand], None, errorCode 

3624 

3625 @staticmethod 

3626 def smb2Logoff(connId, smbServer, recvPacket): 

3627 connData = smbServer.getConnectionData(connId) 

3628 

3629 respSMBCommand = smb2.SMB2Logoff_Response() 

3630 

3631 if recvPacket['SessionID'] != connData['Uid']: 

3632 # STATUS_SMB_BAD_UID 

3633 errorCode = STATUS_SMB_BAD_UID 

3634 else: 

3635 errorCode = STATUS_SUCCESS 

3636 

3637 connData['Uid'] = 0 

3638 connData['Authenticated'] = False 

3639 

3640 smbServer.setConnectionData(connId, connData) 

3641 return [respSMBCommand], None, errorCode 

3642 

3643 @staticmethod 

3644 def smb2Ioctl(connId, smbServer, recvPacket): 

3645 connData = smbServer.getConnectionData(connId) 

3646 

3647 respSMBCommand = smb2.SMB2Ioctl_Response() 

3648 ioctlRequest = smb2.SMB2Ioctl(recvPacket['Data']) 

3649 

3650 ioctls = smbServer.getIoctls() 

3651 if ioctlRequest['CtlCode'] in ioctls: 

3652 outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest) 

3653 if errorCode == STATUS_SUCCESS: 

3654 respSMBCommand['CtlCode'] = ioctlRequest['CtlCode'] 

3655 respSMBCommand['FileID'] = ioctlRequest['FileID'] 

3656 respSMBCommand['InputOffset'] = 0 

3657 respSMBCommand['InputCount'] = 0 

3658 respSMBCommand['OutputOffset'] = 0x70 

3659 respSMBCommand['OutputCount'] = len(outputData) 

3660 respSMBCommand['Flags'] = 0 

3661 respSMBCommand['Buffer'] = outputData 

3662 else: 

3663 respSMBCommand = outputData 

3664 else: 

3665 smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'], logging.DEBUG) 

3666 errorCode = STATUS_INVALID_DEVICE_REQUEST 

3667 respSMBCommand = smb2.SMB2Error() 

3668 

3669 smbServer.setConnectionData(connId, connData) 

3670 return [respSMBCommand], None, errorCode 

3671 

3672 @staticmethod 

3673 def smb2Lock(connId, smbServer, recvPacket): 

3674 connData = smbServer.getConnectionData(connId) 

3675 

3676 respSMBCommand = smb2.SMB2Lock_Response() 

3677 

3678 # I'm actually doing nothing.. just make MacOS happy ;) 

3679 errorCode = STATUS_SUCCESS 

3680 

3681 smbServer.setConnectionData(connId, connData) 

3682 return [respSMBCommand], None, errorCode 

3683 

3684 @staticmethod 

3685 def smb2Cancel(connId, smbServer, recvPacket): 

3686 # I'm actually doing nothing 

3687 return [smb2.SMB2Error()], None, STATUS_CANCELLED 

3688 

3689 @staticmethod 

3690 def default(connId, smbServer, recvPacket): 

3691 # By default we return an SMB Packet with error not implemented 

3692 smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'], logging.DEBUG) 

3693 return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED 

3694 

3695 

3696class Ioctls: 

3697 @staticmethod 

3698 def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest): 

3699 return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED 

3700 

3701 @staticmethod 

3702 def fsctlPipeTransceive(connId, smbServer, ioctlRequest): 

3703 connData = smbServer.getConnectionData(connId) 

3704 

3705 ioctlResponse = '' 

3706 

3707 if ioctlRequest['FileID'].getData() in connData['OpenedFiles']: 

3708 fileHandle = connData['OpenedFiles'][ioctlRequest['FileID'].getData()]['FileHandle'] 

3709 errorCode = STATUS_SUCCESS 

3710 try: 

3711 if fileHandle != PIPE_FILE_DESCRIPTOR: 

3712 errorCode = STATUS_INVALID_DEVICE_REQUEST 

3713 else: 

3714 sock = connData['OpenedFiles'][ioctlRequest['FileID'].getData()]['Socket'] 

3715 sock.sendall(ioctlRequest['Buffer']) 

3716 ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse']) 

3717 except Exception as e: 

3718 smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR) 

3719 errorCode = STATUS_ACCESS_DENIED 

3720 else: 

3721 errorCode = STATUS_INVALID_DEVICE_REQUEST 

3722 

3723 smbServer.setConnectionData(connId, connData) 

3724 return ioctlResponse, errorCode 

3725 

3726 @staticmethod 

3727 def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest): 

3728 connData = smbServer.getConnectionData(connId) 

3729 

3730 errorCode = STATUS_SUCCESS 

3731 

3732 validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer']) 

3733 validateNegotiateInfoResponse = smb2.VALIDATE_NEGOTIATE_INFO_RESPONSE() 

3734 validateNegotiateInfoResponse['Capabilities'] = 0 

3735 validateNegotiateInfoResponse['Guid'] = b'A' * 16 

3736 validateNegotiateInfoResponse['SecurityMode'] = 1 

3737 validateNegotiateInfoResponse['Dialect'] = smb2.SMB2_DIALECT_002 

3738 

3739 smbServer.setConnectionData(connId, connData) 

3740 return validateNegotiateInfoResponse.getData(), errorCode 

3741 

3742 

3743class SMBSERVERHandler(socketserver.BaseRequestHandler): 

3744 def __init__(self, request, client_address, server, select_poll=False): 

3745 self.__SMB = server 

3746 # In case of AF_INET6 the client_address contains 4 items, ignore the last 2 

3747 self.__ip, self.__port = client_address[:2] 

3748 self.__request = request 

3749 self.__connId = threading.currentThread().getName() 

3750 self.__timeOut = 60 * 5 

3751 self.__select_poll = select_poll 

3752 # self.__connId = os.getpid() 

3753 socketserver.BaseRequestHandler.__init__(self, request, client_address, server) 

3754 

3755 def handle(self): 

3756 self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port)) 

3757 self.__SMB.addConnection(self.__connId, self.__ip, self.__port) 

3758 while True: 

3759 try: 

3760 # First of all let's get the NETBIOS packet 

3761 session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(), 'HOST', self.__ip, sess_port=self.__port, 

3762 sock=self.__request, select_poll=self.__select_poll) 

3763 try: 

3764 p = session.recv_packet(self.__timeOut) 

3765 except nmb.NetBIOSTimeout: 

3766 raise 

3767 except nmb.NetBIOSError: 

3768 break 

3769 

3770 if p.get_type() == nmb.NETBIOS_SESSION_REQUEST: 

3771 # Someone is requesting a session, we're gonna accept them all :) 

3772 _, rn, my = p.get_trailer().split(b' ') 

3773 remote_name = nmb.decode_name(b'\x20' + rn) 

3774 myname = nmb.decode_name(b'\x20' + my) 

3775 self.__SMB.log( 

3776 "NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1])) 

3777 r = nmb.NetBIOSSessionPacket() 

3778 r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE) 

3779 r.set_trailer(p.get_trailer()) 

3780 self.__request.send(r.rawData()) 

3781 else: 

3782 resp = self.__SMB.processRequest(self.__connId, p.get_trailer()) 

3783 # Send all the packets received. Except for big transactions this should be 

3784 # a single packet 

3785 for i in resp: 

3786 if hasattr(i, 'getData'): 

3787 session.send_packet(i.getData()) 

3788 else: 

3789 session.send_packet(i) 

3790 except Exception as e: 

3791 self.__SMB.log("Handle: %s" % e) 

3792 # import traceback 

3793 # traceback.print_exc() 

3794 break 

3795 

3796 def finish(self): 

3797 # Thread/process is dying, we should tell the main SMB thread to remove all this thread data 

3798 self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port)) 

3799 self.__SMB.removeConnection(self.__connId) 

3800 return socketserver.BaseRequestHandler.finish(self) 

3801 

3802 

3803class SMBSERVER(socketserver.ThreadingMixIn, socketserver.TCPServer): 

3804 # class SMBSERVER(socketserver.ForkingMixIn, socketserver.TCPServer): 

3805 def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser=None): 

3806 socketserver.TCPServer.allow_reuse_address = True 

3807 socketserver.TCPServer.__init__(self, server_address, handler_class) 

3808 

3809 # Server name and OS to be presented whenever is necessary 

3810 self.__serverName = '' 

3811 self.__serverOS = '' 

3812 self.__serverDomain = '' 

3813 self.__challenge = '' 

3814 self.__log = None 

3815 

3816 # Our ConfigParser data 

3817 self.__serverConfig = config_parser 

3818 

3819 # Our credentials to be used during the server's lifetime 

3820 self.__credentials = {} 

3821 

3822 # Our log file 

3823 self.__logFile = '' 

3824 

3825 # Registered Named Pipes, format is PipeName,Socket 

3826 self.__registeredNamedPipes = {} 

3827 

3828 # JTR dump path 

3829 self.__jtr_dump_path = '' 

3830 

3831 # SMB2 Support flag = default not active 

3832 self.__SMB2Support = False 

3833 

3834 # Our list of commands we will answer, by default the NOT IMPLEMENTED one 

3835 self.__smbCommandsHandler = SMBCommands() 

3836 self.__smbTrans2Handler = TRANS2Commands() 

3837 self.__smbTransHandler = TRANSCommands() 

3838 self.__smbNTTransHandler = NTTRANSCommands() 

3839 self.__smb2CommandsHandler = SMB2Commands() 

3840 self.__IoctlHandler = Ioctls() 

3841 

3842 self.__smbNTTransCommands = { 

3843 # NT IOCTL, can't find doc for this 

3844 0xff: self.__smbNTTransHandler.default 

3845 } 

3846 

3847 self.__smbTransCommands = { 

3848 '\\PIPE\\LANMAN': self.__smbTransHandler.lanMan, 

3849 smb.SMB.TRANS_TRANSACT_NMPIPE: self.__smbTransHandler.transactNamedPipe, 

3850 } 

3851 self.__smbTrans2Commands = { 

3852 smb.SMB.TRANS2_FIND_FIRST2: self.__smbTrans2Handler.findFirst2, 

3853 smb.SMB.TRANS2_FIND_NEXT2: self.__smbTrans2Handler.findNext2, 

3854 smb.SMB.TRANS2_QUERY_FS_INFORMATION: self.__smbTrans2Handler.queryFsInformation, 

3855 smb.SMB.TRANS2_QUERY_PATH_INFORMATION: self.__smbTrans2Handler.queryPathInformation, 

3856 smb.SMB.TRANS2_QUERY_FILE_INFORMATION: self.__smbTrans2Handler.queryFileInformation, 

3857 smb.SMB.TRANS2_SET_FILE_INFORMATION: self.__smbTrans2Handler.setFileInformation, 

3858 smb.SMB.TRANS2_SET_PATH_INFORMATION: self.__smbTrans2Handler.setPathInformation 

3859 } 

3860 

3861 self.__smbCommands = { 

3862 # smb.SMB.SMB_COM_FLUSH: self.__smbCommandsHandler.smbComFlush, 

3863 smb.SMB.SMB_COM_CREATE_DIRECTORY: self.__smbCommandsHandler.smbComCreateDirectory, 

3864 smb.SMB.SMB_COM_DELETE_DIRECTORY: self.__smbCommandsHandler.smbComDeleteDirectory, 

3865 smb.SMB.SMB_COM_RENAME: self.__smbCommandsHandler.smbComRename, 

3866 smb.SMB.SMB_COM_DELETE: self.__smbCommandsHandler.smbComDelete, 

3867 smb.SMB.SMB_COM_NEGOTIATE: self.__smbCommandsHandler.smbComNegotiate, 

3868 smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX, 

3869 smb.SMB.SMB_COM_LOGOFF_ANDX: self.__smbCommandsHandler.smbComLogOffAndX, 

3870 smb.SMB.SMB_COM_TREE_CONNECT_ANDX: self.__smbCommandsHandler.smbComTreeConnectAndX, 

3871 smb.SMB.SMB_COM_TREE_DISCONNECT: self.__smbCommandsHandler.smbComTreeDisconnect, 

3872 smb.SMB.SMB_COM_ECHO: self.__smbCommandsHandler.smbComEcho, 

3873 smb.SMB.SMB_COM_QUERY_INFORMATION: self.__smbCommandsHandler.smbQueryInformation, 

3874 smb.SMB.SMB_COM_TRANSACTION2: self.__smbCommandsHandler.smbTransaction2, 

3875 smb.SMB.SMB_COM_TRANSACTION: self.__smbCommandsHandler.smbTransaction, 

3876 # Not needed for now 

3877 smb.SMB.SMB_COM_NT_TRANSACT: self.__smbCommandsHandler.smbNTTransact, 

3878 smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk, 

3879 smb.SMB.SMB_COM_OPEN_ANDX: self.__smbCommandsHandler.smbComOpenAndX, 

3880 smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2, 

3881 smb.SMB.SMB_COM_READ_ANDX: self.__smbCommandsHandler.smbComReadAndX, 

3882 smb.SMB.SMB_COM_READ: self.__smbCommandsHandler.smbComRead, 

3883 smb.SMB.SMB_COM_WRITE_ANDX: self.__smbCommandsHandler.smbComWriteAndX, 

3884 smb.SMB.SMB_COM_WRITE: self.__smbCommandsHandler.smbComWrite, 

3885 smb.SMB.SMB_COM_CLOSE: self.__smbCommandsHandler.smbComClose, 

3886 smb.SMB.SMB_COM_LOCKING_ANDX: self.__smbCommandsHandler.smbComLockingAndX, 

3887 smb.SMB.SMB_COM_NT_CREATE_ANDX: self.__smbCommandsHandler.smbComNtCreateAndX, 

3888 0xFF: self.__smbCommandsHandler.default 

3889 } 

3890 

3891 self.__smb2Ioctls = { 

3892 smb2.FSCTL_DFS_GET_REFERRALS: self.__IoctlHandler.fsctlDfsGetReferrals, 

3893 # smb2.FSCTL_PIPE_PEEK: self.__IoctlHandler.fsctlPipePeek, 

3894 # smb2.FSCTL_PIPE_WAIT: self.__IoctlHandler.fsctlPipeWait, 

3895 smb2.FSCTL_PIPE_TRANSCEIVE: self.__IoctlHandler.fsctlPipeTransceive, 

3896 # smb2.FSCTL_SRV_COPYCHUNK: self.__IoctlHandler.fsctlSrvCopyChunk, 

3897 # smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS: self.__IoctlHandler.fsctlSrvEnumerateSnapshots, 

3898 # smb2.FSCTL_SRV_REQUEST_RESUME_KEY: self.__IoctlHandler.fsctlSrvRequestResumeKey, 

3899 # smb2.FSCTL_SRV_READ_HASH: self.__IoctlHandler.fsctlSrvReadHash, 

3900 # smb2.FSCTL_SRV_COPYCHUNK_WRITE: self.__IoctlHandler.fsctlSrvCopyChunkWrite, 

3901 # smb2.FSCTL_LMR_REQUEST_RESILIENCY: self.__IoctlHandler.fsctlLmrRequestResiliency, 

3902 # smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo, 

3903 # smb2.FSCTL_SET_REPARSE_POINT: self.__IoctlHandler.fsctlSetReparsePoint, 

3904 # smb2.FSCTL_DFS_GET_REFERRALS_EX: self.__IoctlHandler.fsctlDfsGetReferralsEx, 

3905 # smb2.FSCTL_FILE_LEVEL_TRIM: self.__IoctlHandler.fsctlFileLevelTrim, 

3906 smb2.FSCTL_VALIDATE_NEGOTIATE_INFO: self.__IoctlHandler.fsctlValidateNegotiateInfo, 

3907 } 

3908 

3909 self.__smb2Commands = { 

3910 smb2.SMB2_NEGOTIATE: self.__smb2CommandsHandler.smb2Negotiate, 

3911 smb2.SMB2_SESSION_SETUP: self.__smb2CommandsHandler.smb2SessionSetup, 

3912 smb2.SMB2_LOGOFF: self.__smb2CommandsHandler.smb2Logoff, 

3913 smb2.SMB2_TREE_CONNECT: self.__smb2CommandsHandler.smb2TreeConnect, 

3914 smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect, 

3915 smb2.SMB2_CREATE: self.__smb2CommandsHandler.smb2Create, 

3916 smb2.SMB2_CLOSE: self.__smb2CommandsHandler.smb2Close, 

3917 smb2.SMB2_FLUSH: self.__smb2CommandsHandler.smb2Flush, 

3918 smb2.SMB2_READ: self.__smb2CommandsHandler.smb2Read, 

3919 smb2.SMB2_WRITE: self.__smb2CommandsHandler.smb2Write, 

3920 smb2.SMB2_LOCK: self.__smb2CommandsHandler.smb2Lock, 

3921 smb2.SMB2_IOCTL: self.__smb2CommandsHandler.smb2Ioctl, 

3922 smb2.SMB2_CANCEL: self.__smb2CommandsHandler.smb2Cancel, 

3923 smb2.SMB2_ECHO: self.__smb2CommandsHandler.smb2Echo, 

3924 smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory, 

3925 smb2.SMB2_CHANGE_NOTIFY: self.__smb2CommandsHandler.smb2ChangeNotify, 

3926 smb2.SMB2_QUERY_INFO: self.__smb2CommandsHandler.smb2QueryInfo, 

3927 smb2.SMB2_SET_INFO: self.__smb2CommandsHandler.smb2SetInfo, 

3928 # smb2.SMB2_OPLOCK_BREAK: self.__smb2CommandsHandler.smb2SessionSetup, 

3929 0xFF: self.__smb2CommandsHandler.default 

3930 } 

3931 

3932 # List of active connections 

3933 self.__activeConnections = {} 

3934 

3935 def getIoctls(self): 

3936 return self.__smb2Ioctls 

3937 

3938 def getCredentials(self): 

3939 return self.__credentials 

3940 

3941 def removeConnection(self, name): 

3942 try: 

3943 del (self.__activeConnections[name]) 

3944 except: 

3945 pass 

3946 self.log("Remaining connections %s" % list(self.__activeConnections.keys())) 

3947 

3948 def addConnection(self, name, ip, port): 

3949 self.__activeConnections[name] = {} 

3950 # Let's init with some know stuff we will need to have 

3951 # TODO: Document what's in there 

3952 # print "Current Connections", self.__activeConnections.keys() 

3953 self.__activeConnections[name]['PacketNum'] = 0 

3954 self.__activeConnections[name]['ClientIP'] = ip 

3955 self.__activeConnections[name]['ClientPort'] = port 

3956 self.__activeConnections[name]['Uid'] = 0 

3957 self.__activeConnections[name]['ConnectedShares'] = {} 

3958 self.__activeConnections[name]['OpenedFiles'] = {} 

3959 # SID results for findfirst2 

3960 self.__activeConnections[name]['SIDs'] = {} 

3961 self.__activeConnections[name]['LastRequest'] = {} 

3962 self.__activeConnections[name]['SignatureEnabled'] = False 

3963 self.__activeConnections[name]['SigningChallengeResponse'] = '' 

3964 self.__activeConnections[name]['SigningSessionKey'] = b'' 

3965 self.__activeConnections[name]['Authenticated'] = False 

3966 

3967 def getActiveConnections(self): 

3968 return self.__activeConnections 

3969 

3970 def setConnectionData(self, connId, data): 

3971 self.__activeConnections[connId] = data 

3972 # print "setConnectionData" 

3973 # print self.__activeConnections 

3974 

3975 def getConnectionData(self, connId, checkStatus=True): 

3976 conn = self.__activeConnections[connId] 

3977 if checkStatus is True: 

3978 if ('Authenticated' in conn) is not True: 

3979 # Can't keep going further 

3980 raise Exception("User not Authenticated!") 

3981 return conn 

3982 

3983 def getRegisteredNamedPipes(self): 

3984 return self.__registeredNamedPipes 

3985 

3986 def registerNamedPipe(self, pipeName, address): 

3987 self.__registeredNamedPipes[str(pipeName)] = address 

3988 return True 

3989 

3990 def unregisterNamedPipe(self, pipeName): 

3991 if pipeName in self.__registeredNamedPipes: 

3992 del (self.__registeredNamedPipes[str(pipeName)]) 

3993 return True 

3994 return False 

3995 

3996 def unregisterTransaction(self, transCommand): 

3997 if transCommand in self.__smbTransCommands: 

3998 del (self.__smbTransCommands[transCommand]) 

3999 

4000 def hookTransaction(self, transCommand, callback): 

4001 # If you call this function, callback will replace 

4002 # the current Transaction sub command. 

4003 # (don't get confused with the Transaction smbCommand) 

4004 # If the transaction sub command doesn't not exist, it is added 

4005 # If the transaction sub command exists, it returns the original function # replaced 

4006 # 

4007 # callback MUST be declared as: 

4008 # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0) 

4009 # 

4010 # WHERE: 

4011 # 

4012 # connId : the connection Id, used to grab/update information about 

4013 # the current connection 

4014 # smbServer : the SMBServer instance available for you to ask 

4015 # configuration data 

4016 # recvPacket : the full SMBPacket that triggered this command 

4017 # parameters : the transaction parameters 

4018 # data : the transaction data 

4019 # maxDataCount: the max amount of data that can be transferred agreed 

4020 # with the client 

4021 # 

4022 # and MUST return: 

4023 # respSetup, respParameters, respData, errorCode 

4024 # 

4025 # WHERE: 

4026 # 

4027 # respSetup: the setup response of the transaction 

4028 # respParameters: the parameters response of the transaction 

4029 # respData: the data response of the transaction 

4030 # errorCode: the NT error code 

4031 

4032 if transCommand in self.__smbTransCommands: 

4033 originalCommand = self.__smbTransCommands[transCommand] 

4034 else: 

4035 originalCommand = None 

4036 

4037 self.__smbTransCommands[transCommand] = callback 

4038 return originalCommand 

4039 

4040 def unregisterTransaction2(self, transCommand): 

4041 if transCommand in self.__smbTrans2Commands: 

4042 del (self.__smbTrans2Commands[transCommand]) 

4043 

4044 def hookTransaction2(self, transCommand, callback): 

4045 # Here we should add to __smbTrans2Commands 

4046 # Same description as Transaction 

4047 if transCommand in self.__smbTrans2Commands: 

4048 originalCommand = self.__smbTrans2Commands[transCommand] 

4049 else: 

4050 originalCommand = None 

4051 

4052 self.__smbTrans2Commands[transCommand] = callback 

4053 return originalCommand 

4054 

4055 def unregisterNTTransaction(self, transCommand): 

4056 if transCommand in self.__smbNTTransCommands: 

4057 del (self.__smbNTTransCommands[transCommand]) 

4058 

4059 def hookNTTransaction(self, transCommand, callback): 

4060 # Here we should add to __smbNTTransCommands 

4061 # Same description as Transaction 

4062 if transCommand in self.__smbNTTransCommands: 

4063 originalCommand = self.__smbNTTransCommands[transCommand] 

4064 else: 

4065 originalCommand = None 

4066 

4067 self.__smbNTTransCommands[transCommand] = callback 

4068 return originalCommand 

4069 

4070 def unregisterSmbCommand(self, smbCommand): 

4071 if smbCommand in self.__smbCommands: 

4072 del (self.__smbCommands[smbCommand]) 

4073 

4074 def hookSmbCommand(self, smbCommand, callback): 

4075 # Here we should add to self.__smbCommands 

4076 # If you call this function, callback will replace 

4077 # the current smbCommand. 

4078 # If smbCommand doesn't not exist, it is added 

4079 # If SMB command exists, it returns the original function replaced 

4080 # 

4081 # callback MUST be declared as: 

4082 # callback(connId, smbServer, SMBCommand, recvPacket) 

4083 # 

4084 # WHERE: 

4085 # 

4086 # connId : the connection Id, used to grab/update information about 

4087 # the current connection 

4088 # smbServer : the SMBServer instance available for you to ask 

4089 # configuration data 

4090 # SMBCommand: the SMBCommand itself, with its data and parameters. 

4091 # Check smb.py:SMBCommand() for a reference 

4092 # recvPacket: the full SMBPacket that triggered this command 

4093 # 

4094 # and MUST return: 

4095 # <list of respSMBCommands>, <list of packets>, errorCode 

4096 # <list of packets> has higher preference over commands, in case you 

4097 # want to change the whole packet 

4098 # errorCode: the NT error code 

4099 # 

4100 # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT 

4101 # the callback function is slightly different: 

4102 # 

4103 # callback(connId, smbServer, SMBCommand, recvPacket, transCommands) 

4104 # 

4105 # WHERE: 

4106 # 

4107 # transCommands: a list of transaction subcommands already registered 

4108 # 

4109 

4110 if smbCommand in self.__smbCommands: 

4111 originalCommand = self.__smbCommands[smbCommand] 

4112 else: 

4113 originalCommand = None 

4114 

4115 self.__smbCommands[smbCommand] = callback 

4116 return originalCommand 

4117 

4118 def unregisterSmb2Command(self, smb2Command): 

4119 if smb2Command in self.__smb2Commands: 

4120 del (self.__smb2Commands[smb2Command]) 

4121 

4122 def hookSmb2Command(self, smb2Command, callback): 

4123 if smb2Command in self.__smb2Commands: 

4124 originalCommand = self.__smb2Commands[smb2Command] 

4125 else: 

4126 originalCommand = None 

4127 

4128 self.__smb2Commands[smb2Command] = callback 

4129 return originalCommand 

4130 

4131 def log(self, msg, level=logging.INFO): 

4132 self.__log.log(level, msg) 

4133 

4134 def getServerName(self): 

4135 return self.__serverName 

4136 

4137 def getServerOS(self): 

4138 return self.__serverOS 

4139 

4140 def getServerDomain(self): 

4141 return self.__serverDomain 

4142 

4143 def getSMBChallenge(self): 

4144 return self.__challenge 

4145 

4146 def getServerConfig(self): 

4147 return self.__serverConfig 

4148 

4149 def setServerConfig(self, config): 

4150 self.__serverConfig = config 

4151 

4152 def getJTRdumpPath(self): 

4153 return self.__jtr_dump_path 

4154 

4155 def verify_request(self, request, client_address): 

4156 # TODO: Control here the max amount of processes we want to launch 

4157 # returning False, closes the connection 

4158 return True 

4159 

4160 def signSMBv1(self, connData, packet, signingSessionKey, signingChallengeResponse): 

4161 # This logic MUST be applied for messages sent in response to any of the higher-layer actions and in 

4162 # compliance with the message sequencing rules. 

4163 # * The client or server that sends the message MUST provide the 32-bit sequence number for this 

4164 # message, as specified in sections 3.2.4.1 and 3.3.4.1. 

4165 # * The SMB_FLAGS2_SMB_SECURITY_SIGNATURE flag in the header MUST be set. 

4166 # * To generate the signature, a 32-bit sequence number is copied into the 

4167 # least significant 32 bits of the SecuritySignature field and the remaining 

4168 # 4 bytes are set to 0x00. 

4169 # * The MD5 algorithm, as specified in [RFC1321], MUST be used to generate a hash of the SMB 

4170 # message from the start of the SMB Header, which is defined as follows. 

4171 # CALL MD5Init( md5context ) 

4172 # CALL MD5Update( md5context, Connection.SigningSessionKey ) 

4173 # CALL MD5Update( md5context, Connection.SigningChallengeResponse ) 

4174 # CALL MD5Update( md5context, SMB message ) 

4175 # CALL MD5Final( digest, md5context ) 

4176 # SET signature TO the first 8 bytes of the digest 

4177 # The resulting 8-byte signature MUST be copied into the SecuritySignature field of the SMB Header, 

4178 # after which the message can be transmitted. 

4179 

4180 # print "seq(%d) signingSessionKey %r, signingChallengeResponse %r" % (connData['SignSequenceNumber'], signingSessionKey, signingChallengeResponse) 

4181 packet['SecurityFeatures'] = struct.pack('<q', connData['SignSequenceNumber']) 

4182 # Sign with the sequence 

4183 m = hashlib.md5() 

4184 m.update(signingSessionKey) 

4185 m.update(signingChallengeResponse) 

4186 if hasattr(packet, 'getData'): 

4187 m.update(packet.getData()) 

4188 else: 

4189 m.update(packet) 

4190 # Replace sequence with acual hash 

4191 packet['SecurityFeatures'] = m.digest()[:8] 

4192 connData['SignSequenceNumber'] += 2 

4193 

4194 def signSMBv2(self, packet, signingSessionKey): 

4195 packet['Signature'] = b'\x00' * 16 

4196 packet['Flags'] |= smb2.SMB2_FLAGS_SIGNED 

4197 signature = hmac.new(signingSessionKey, packet.getData(), hashlib.sha256).digest() 

4198 packet['Signature'] = signature[:16] 

4199 # print "%s" % packet['Signature'].encode('hex') 

4200 

4201 def processRequest(self, connId, data): 

4202 

4203 # TODO: Process batched commands. 

4204 isSMB2 = False 

4205 SMBCommand = None 

4206 try: 

4207 packet = smb.NewSMBPacket(data=data) 

4208 SMBCommand = smb.SMBCommand(packet['Data'][0]) 

4209 except: 

4210 # Maybe a SMB2 packet? 

4211 packet = smb2.SMB2Packet(data=data) 

4212 connData = self.getConnectionData(connId, False) 

4213 self.signSMBv2(packet, connData['SigningSessionKey']) 

4214 isSMB2 = True 

4215 

4216 connData = self.getConnectionData(connId, False) 

4217 

4218 # We might have compound requests 

4219 compoundedPacketsResponse = [] 

4220 compoundedPackets = [] 

4221 try: 

4222 # Search out list of implemented commands 

4223 # We provide them with: 

4224 # connId : representing the data for this specific connection 

4225 # self : the SMBSERVER if they want to ask data to it 

4226 # SMBCommand : the SMBCommand they are expecting to process 

4227 # packet : the received packet itself, in case they need more data than the actual command 

4228 # Only for Transactions 

4229 # transCommand: a list of transaction subcommands 

4230 # We expect to get: 

4231 # respCommands: a list of answers for the commands processed 

4232 # respPacket : if the commands chose to directly craft packet/s, we use this and not the previous 

4233 # this MUST be a list 

4234 # errorCode : self explanatory 

4235 if isSMB2 is False: 

4236 # Is the client authenticated already? 

4237 if connData['Authenticated'] is False and packet['Command'] not in ( 

4238 smb.SMB.SMB_COM_NEGOTIATE, smb.SMB.SMB_COM_SESSION_SETUP_ANDX): 

4239 # Nope.. in that case he should only ask for a few commands, if not throw him out. 

4240 errorCode = STATUS_ACCESS_DENIED 

4241 respPackets = None 

4242 respCommands = [smb.SMBCommand(packet['Command'])] 

4243 else: 

4244 if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2: 

4245 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4246 connId, 

4247 self, 

4248 SMBCommand, 

4249 packet, 

4250 self.__smbTrans2Commands) 

4251 elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT: 

4252 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4253 connId, 

4254 self, 

4255 SMBCommand, 

4256 packet, 

4257 self.__smbNTTransCommands) 

4258 elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION: 

4259 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4260 connId, 

4261 self, 

4262 SMBCommand, 

4263 packet, 

4264 self.__smbTransCommands) 

4265 else: 

4266 if packet['Command'] in self.__smbCommands: 

4267 if self.__SMB2Support is True: 

4268 if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE: 

4269 try: 

4270 respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE]( 

4271 connId, self, packet, True) 

4272 isSMB2 = True 

4273 except Exception as e: 

4274 import traceback 

4275 traceback.print_exc() 

4276 self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR) 

4277 # If something went wrong, let's fallback to SMB1 

4278 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4279 connId, 

4280 self, 

4281 SMBCommand, 

4282 packet) 

4283 # self.__SMB2Support = False 

4284 pass 

4285 else: 

4286 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4287 connId, 

4288 self, 

4289 SMBCommand, 

4290 packet) 

4291 else: 

4292 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4293 connId, 

4294 self, 

4295 SMBCommand, 

4296 packet) 

4297 else: 

4298 respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, 

4299 packet) 

4300 

4301 compoundedPacketsResponse.append((respCommands, respPackets, errorCode)) 

4302 compoundedPackets.append(packet) 

4303 

4304 else: 

4305 # Is the client authenticated already? 

4306 if connData['Authenticated'] is False and packet['Command'] not in ( 

4307 smb2.SMB2_NEGOTIATE, smb2.SMB2_SESSION_SETUP): 

4308 # Nope.. in that case he should only ask for a few commands, if not throw him out. 

4309 errorCode = STATUS_ACCESS_DENIED 

4310 respPackets = None 

4311 respCommands = [''] 

4312 compoundedPacketsResponse.append((respCommands, respPackets, errorCode)) 

4313 compoundedPackets.append(packet) 

4314 else: 

4315 done = False 

4316 while not done: 

4317 if packet['Command'] in self.__smb2Commands: 

4318 if self.__SMB2Support is True: 

4319 respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']]( 

4320 connId, 

4321 self, 

4322 packet) 

4323 else: 

4324 respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet) 

4325 else: 

4326 respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet) 

4327 # Let's store the result for this compounded packet 

4328 compoundedPacketsResponse.append((respCommands, respPackets, errorCode)) 

4329 compoundedPackets.append(packet) 

4330 if packet['NextCommand'] != 0: 

4331 data = data[packet['NextCommand']:] 

4332 packet = smb2.SMB2Packet(data=data) 

4333 else: 

4334 done = True 

4335 

4336 except Exception as e: 

4337 # import traceback 

4338 # traceback.print_exc() 

4339 # Something wen't wrong, defaulting to Bad user ID 

4340 self.log('processRequest (0x%x,%s)' % (packet['Command'], e), logging.ERROR) 

4341 raise 

4342 

4343 # We prepare the response packet to commands don't need to bother about that. 

4344 connData = self.getConnectionData(connId, False) 

4345 

4346 # Force reconnection loop.. This is just a test.. client will send me back credentials :) 

4347 # connData['PacketNum'] += 1 

4348 # if connData['PacketNum'] == 15: 

4349 # connData['PacketNum'] = 0 

4350 # # Something wen't wrong, defaulting to Bad user ID 

4351 # self.log('Sending BAD USER ID!', logging.ERROR) 

4352 # #raise 

4353 # packet['Flags1'] |= smb.SMB.FLAGS1_REPLY 

4354 # packet['Flags2'] = 0 

4355 # errorCode = STATUS_SMB_BAD_UID 

4356 # packet['ErrorCode'] = errorCode >> 16 

4357 # packet['ErrorClass'] = errorCode & 0xff 

4358 # return [packet] 

4359 

4360 self.setConnectionData(connId, connData) 

4361 

4362 packetsToSend = [] 

4363 for packetNum in range(len(compoundedPacketsResponse)): 

4364 respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum] 

4365 packet = compoundedPackets[packetNum] 

4366 if respPackets is None: 

4367 for respCommand in respCommands: 

4368 if isSMB2 is False: 

4369 respPacket = smb.NewSMBPacket() 

4370 respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY 

4371 

4372 # TODO this should come from a per session configuration 

4373 respPacket[ 

4374 'Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | \ 

4375 packet['Flags2'] & smb.SMB.FLAGS2_UNICODE 

4376 # respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES 

4377 # respPacket['Flags1'] = 0x98 

4378 # respPacket['Flags2'] = 0xc807 

4379 

4380 respPacket['Tid'] = packet['Tid'] 

4381 respPacket['Mid'] = packet['Mid'] 

4382 respPacket['Pid'] = packet['Pid'] 

4383 respPacket['Uid'] = connData['Uid'] 

4384 

4385 respPacket['ErrorCode'] = errorCode >> 16 

4386 respPacket['_reserved'] = errorCode >> 8 & 0xff 

4387 respPacket['ErrorClass'] = errorCode & 0xff 

4388 respPacket.addCommand(respCommand) 

4389 

4390 if connData['SignatureEnabled']: 

4391 respPacket['Flags2'] |= smb.SMB.FLAGS2_SMB_SECURITY_SIGNATURE 

4392 self.signSMBv1(connData, respPacket, connData['SigningSessionKey'], 

4393 connData['SigningChallengeResponse']) 

4394 

4395 packetsToSend.append(respPacket) 

4396 else: 

4397 respPacket = smb2.SMB2Packet() 

4398 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR 

4399 if packetNum > 0: 

4400 respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS 

4401 respPacket['Status'] = errorCode 

4402 respPacket['CreditRequestResponse'] = packet['CreditRequestResponse'] 

4403 respPacket['Command'] = packet['Command'] 

4404 respPacket['CreditCharge'] = packet['CreditCharge'] 

4405 # respPacket['CreditCharge'] = 0 

4406 respPacket['Reserved'] = packet['Reserved'] 

4407 respPacket['SessionID'] = connData['Uid'] 

4408 respPacket['MessageID'] = packet['MessageID'] 

4409 respPacket['TreeID'] = packet['TreeID'] 

4410 if hasattr(respCommand, 'getData'): 

4411 respPacket['Data'] = respCommand.getData() 

4412 else: 

4413 respPacket['Data'] = str(respCommand) 

4414 

4415 if connData['SignatureEnabled']: 

4416 self.signSMBv2(respPacket, connData['SigningSessionKey']) 

4417 

4418 packetsToSend.append(respPacket) 

4419 else: 

4420 # The SMBCommand took care of building the packet 

4421 packetsToSend = respPackets 

4422 

4423 if isSMB2 is True: 

4424 # Let's build a compound answer 

4425 finalData = b'' 

4426 i = 0 

4427 for i in range(len(packetsToSend) - 1): 

4428 packet = packetsToSend[i] 

4429 # Align to 8-bytes 

4430 padLen = (8 - (len(packet) % 8)) % 8 

4431 packet['NextCommand'] = len(packet) + padLen 

4432 if hasattr(packet, 'getData'): 

4433 finalData += packet.getData() + padLen * b'\x00' 

4434 else: 

4435 finalData += packet + padLen * b'\x00' 

4436 

4437 # Last one 

4438 if hasattr(packetsToSend[len(packetsToSend) - 1], 'getData'): 

4439 finalData += packetsToSend[len(packetsToSend) - 1].getData() 

4440 else: 

4441 finalData += packetsToSend[len(packetsToSend) - 1] 

4442 packetsToSend = [finalData] 

4443 

4444 # We clear the compound requests 

4445 connData['LastRequest'] = {} 

4446 

4447 return packetsToSend 

4448 

4449 def processConfigFile(self, configFile=None): 

4450 # TODO: Do a real config parser 

4451 if self.__serverConfig is None: 

4452 if configFile is None: 

4453 configFile = 'smb.conf' 

4454 self.__serverConfig = configparser.ConfigParser() 

4455 self.__serverConfig.read(configFile) 

4456 

4457 self.__serverName = self.__serverConfig.get('global', 'server_name') 

4458 self.__serverOS = self.__serverConfig.get('global', 'server_os') 

4459 self.__serverDomain = self.__serverConfig.get('global', 'server_domain') 

4460 self.__logFile = self.__serverConfig.get('global', 'log_file') 

4461 if self.__serverConfig.has_option('global', 'challenge'): 

4462 self.__challenge = unhexlify(self.__serverConfig.get('global', 'challenge')) 

4463 else: 

4464 self.__challenge = b'A' * 16 

4465 

4466 if self.__serverConfig.has_option("global", "jtr_dump_path"): 

4467 self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path") 

4468 

4469 if self.__serverConfig.has_option("global", "SMB2Support"): 

4470 self.__SMB2Support = self.__serverConfig.getboolean("global", "SMB2Support") 

4471 else: 

4472 self.__SMB2Support = False 

4473 

4474 if self.__logFile != 'None': 

4475 logging.basicConfig(filename=self.__logFile, 

4476 level=logging.DEBUG, 

4477 format="%(asctime)s: %(levelname)s: %(message)s", 

4478 datefmt='%m/%d/%Y %I:%M:%S %p') 

4479 self.__log = LOG 

4480 

4481 # Process the credentials 

4482 credentials_fname = self.__serverConfig.get('global', 'credentials_file') 

4483 if credentials_fname != "": 

4484 cred = open(credentials_fname) 

4485 line = cred.readline() 

4486 while line: 

4487 name, uid, lmhash, nthash = line.split(':') 

4488 self.__credentials[name.lower()] = (uid, lmhash, nthash.strip('\r\n')) 

4489 line = cred.readline() 

4490 cred.close() 

4491 self.log('Config file parsed') 

4492 

4493 def addCredential(self, name, uid, lmhash, nthash): 

4494 # If we have hashes, normalize them 

4495 if lmhash != '' or nthash != '': 

4496 if len(lmhash) % 2: 

4497 lmhash = '0%s' % lmhash 

4498 if len(nthash) % 2: 

4499 nthash = '0%s' % nthash 

4500 try: # just in case they were converted already 

4501 lmhash = a2b_hex(lmhash) 

4502 nthash = a2b_hex(nthash) 

4503 except: 

4504 pass 

4505 self.__credentials[name.lower()] = (uid, lmhash, nthash) 

4506 

4507 

4508# For windows platforms, opening a directory is not an option, so we set a void FD 

4509VOID_FILE_DESCRIPTOR = -1 

4510PIPE_FILE_DESCRIPTOR = -2 

4511 

4512###################################################################### 

4513# HELPER CLASSES 

4514###################################################################### 

4515 

4516from impacket.dcerpc.v5.rpcrt import DCERPCServer 

4517from impacket.dcerpc.v5.dtypes import NULL 

4518from impacket.dcerpc.v5.srvs import NetrShareEnum, NetrShareEnumResponse, SHARE_INFO_1, NetrServerGetInfo, \ 

4519 NetrServerGetInfoResponse, NetrShareGetInfo, NetrShareGetInfoResponse 

4520from impacket.dcerpc.v5.wkst import NetrWkstaGetInfo, NetrWkstaGetInfoResponse 

4521from impacket.system_errors import ERROR_INVALID_LEVEL 

4522 

4523 

4524class WKSTServer(DCERPCServer): 

4525 def __init__(self): 

4526 DCERPCServer.__init__(self) 

4527 self.wkssvcCallBacks = { 

4528 0: self.NetrWkstaGetInfo, 

4529 } 

4530 self.addCallbacks(('6BFFD098-A112-3610-9833-46C3F87E345A', '1.0'), '\\PIPE\\wkssvc', self.wkssvcCallBacks) 

4531 

4532 def NetrWkstaGetInfo(self, data): 

4533 request = NetrWkstaGetInfo(data) 

4534 self.log("NetrWkstaGetInfo Level: %d" % request['Level']) 

4535 

4536 answer = NetrWkstaGetInfoResponse() 

4537 

4538 if request['Level'] not in (100, 101): 

4539 answer['ErrorCode'] = ERROR_INVALID_LEVEL 

4540 return answer 

4541 

4542 answer['WkstaInfo']['tag'] = request['Level'] 

4543 

4544 if request['Level'] == 100: 

4545 # Windows. Decimal value 500. 

4546 answer['WkstaInfo']['WkstaInfo100']['wki100_platform_id'] = 0x000001F4 

4547 answer['WkstaInfo']['WkstaInfo100']['wki100_computername'] = NULL 

4548 answer['WkstaInfo']['WkstaInfo100']['wki100_langroup'] = NULL 

4549 answer['WkstaInfo']['WkstaInfo100']['wki100_ver_major'] = 5 

4550 answer['WkstaInfo']['WkstaInfo100']['wki100_ver_minor'] = 0 

4551 else: 

4552 # Windows. Decimal value 500. 

4553 answer['WkstaInfo']['WkstaInfo101']['wki101_platform_id'] = 0x000001F4 

4554 answer['WkstaInfo']['WkstaInfo101']['wki101_computername'] = NULL 

4555 answer['WkstaInfo']['WkstaInfo101']['wki101_langroup'] = NULL 

4556 answer['WkstaInfo']['WkstaInfo101']['wki101_ver_major'] = 5 

4557 answer['WkstaInfo']['WkstaInfo101']['wki101_ver_minor'] = 0 

4558 answer['WkstaInfo']['WkstaInfo101']['wki101_lanroot'] = NULL 

4559 

4560 return answer 

4561 

4562 

4563class SRVSServer(DCERPCServer): 

4564 def __init__(self): 

4565 DCERPCServer.__init__(self) 

4566 

4567 self._shares = {} 

4568 self.__serverConfig = None 

4569 self.__logFile = None 

4570 

4571 self.srvsvcCallBacks = { 

4572 15: self.NetrShareEnum, 

4573 16: self.NetrShareGetInfo, 

4574 21: self.NetrServerGetInfo, 

4575 } 

4576 

4577 self.addCallbacks(('4B324FC8-1670-01D3-1278-5A47BF6EE188', '3.0'), '\\PIPE\\srvsvc', self.srvsvcCallBacks) 

4578 

4579 def setServerConfig(self, config): 

4580 self.__serverConfig = config 

4581 

4582 def processConfigFile(self, configFile=None): 

4583 if configFile is not None: 

4584 self.__serverConfig = configparser.ConfigParser() 

4585 self.__serverConfig.read(configFile) 

4586 sections = self.__serverConfig.sections() 

4587 # Let's check the log file 

4588 self.__logFile = self.__serverConfig.get('global', 'log_file') 

4589 if self.__logFile != 'None': 

4590 logging.basicConfig(filename=self.__logFile, 

4591 level=logging.DEBUG, 

4592 format="%(asctime)s: %(levelname)s: %(message)s", 

4593 datefmt='%m/%d/%Y %I:%M:%S %p') 

4594 

4595 # Remove the global one 

4596 del (sections[sections.index('global')]) 

4597 self._shares = {} 

4598 for i in sections: 

4599 self._shares[i] = dict(self.__serverConfig.items(i)) 

4600 

4601 def NetrShareGetInfo(self, data): 

4602 request = NetrShareGetInfo(data) 

4603 self.log("NetrGetShareInfo Level: %d" % request['Level']) 

4604 

4605 s = request['NetName'][:-1].upper() 

4606 answer = NetrShareGetInfoResponse() 

4607 if s in self._shares: 

4608 share = self._shares[s] 

4609 

4610 answer['InfoStruct']['tag'] = 1 

4611 answer['InfoStruct']['ShareInfo1']['shi1_netname'] = s + '\x00' 

4612 answer['InfoStruct']['ShareInfo1']['shi1_type'] = share['share type'] 

4613 answer['InfoStruct']['ShareInfo1']['shi1_remark'] = share['comment'] + '\x00' 

4614 answer['ErrorCode'] = 0 

4615 else: 

4616 answer['InfoStruct']['tag'] = 1 

4617 answer['InfoStruct']['ShareInfo1'] = NULL 

4618 answer['ErrorCode'] = 0x0906 # WERR_NET_NAME_NOT_FOUND 

4619 

4620 return answer 

4621 

4622 def NetrServerGetInfo(self, data): 

4623 request = NetrServerGetInfo(data) 

4624 self.log("NetrServerGetInfo Level: %d" % request['Level']) 

4625 answer = NetrServerGetInfoResponse() 

4626 answer['InfoStruct']['tag'] = 101 

4627 # PLATFORM_ID_NT = 500 

4628 answer['InfoStruct']['ServerInfo101']['sv101_platform_id'] = 500 

4629 answer['InfoStruct']['ServerInfo101']['sv101_name'] = request['ServerName'] 

4630 # Windows 7 = 6.1 

4631 answer['InfoStruct']['ServerInfo101']['sv101_version_major'] = 6 

4632 answer['InfoStruct']['ServerInfo101']['sv101_version_minor'] = 1 

4633 # Workstation = 1 

4634 answer['InfoStruct']['ServerInfo101']['sv101_type'] = 1 

4635 answer['InfoStruct']['ServerInfo101']['sv101_comment'] = NULL 

4636 answer['ErrorCode'] = 0 

4637 return answer 

4638 

4639 def NetrShareEnum(self, data): 

4640 request = NetrShareEnum(data) 

4641 self.log("NetrShareEnum Level: %d" % request['InfoStruct']['Level']) 

4642 shareEnum = NetrShareEnumResponse() 

4643 shareEnum['InfoStruct']['Level'] = 1 

4644 shareEnum['InfoStruct']['ShareInfo']['tag'] = 1 

4645 shareEnum['TotalEntries'] = len(self._shares) 

4646 shareEnum['InfoStruct']['ShareInfo']['Level1']['EntriesRead'] = len(self._shares) 

4647 shareEnum['ErrorCode'] = 0 

4648 

4649 for i in self._shares: 

4650 shareInfo = SHARE_INFO_1() 

4651 shareInfo['shi1_netname'] = i + '\x00' 

4652 shareInfo['shi1_type'] = self._shares[i]['share type'] 

4653 shareInfo['shi1_remark'] = self._shares[i]['comment'] + '\x00' 

4654 shareEnum['InfoStruct']['ShareInfo']['Level1']['Buffer'].append(shareInfo) 

4655 

4656 return shareEnum 

4657 

4658 

4659class SimpleSMBServer: 

4660 """ 

4661 SimpleSMBServer class - Implements a simple, customizable SMB Server 

4662 

4663 :param string listenAddress: the address you want the server to listen on 

4664 :param integer listenPort: the port number you want the server to listen on 

4665 :param string configFile: a file with all the servers' configuration. If no file specified, this class will create the basic parameters needed to run. You will need to add your shares manually tho. See addShare() method 

4666 """ 

4667 

4668 def __init__(self, listenAddress='0.0.0.0', listenPort=445, configFile=''): 

4669 if configFile != '': 

4670 self.__server = SMBSERVER((listenAddress, listenPort)) 

4671 self.__server.processConfigFile(configFile) 

4672 self.__smbConfig = None 

4673 else: 

4674 # Here we write a mini config for the server 

4675 self.__smbConfig = configparser.ConfigParser() 

4676 self.__smbConfig.add_section('global') 

4677 self.__smbConfig.set('global', 'server_name', 

4678 ''.join([random.choice(string.ascii_letters) for _ in range(8)])) 

4679 self.__smbConfig.set('global', 'server_os', ''.join([random.choice(string.ascii_letters) for _ in range(8)]) 

4680 ) 

4681 self.__smbConfig.set('global', 'server_domain', 

4682 ''.join([random.choice(string.ascii_letters) for _ in range(8)]) 

4683 ) 

4684 self.__smbConfig.set('global', 'log_file', 'None') 

4685 self.__smbConfig.set('global', 'rpc_apis', 'yes') 

4686 self.__smbConfig.set('global', 'credentials_file', '') 

4687 self.__smbConfig.set('global', 'challenge', "A" * 16) 

4688 

4689 # IPC always needed 

4690 self.__smbConfig.add_section('IPC$') 

4691 self.__smbConfig.set('IPC$', 'comment', '') 

4692 self.__smbConfig.set('IPC$', 'read only', 'yes') 

4693 self.__smbConfig.set('IPC$', 'share type', '3') 

4694 self.__smbConfig.set('IPC$', 'path', '') 

4695 self.__server = SMBSERVER((listenAddress, listenPort), config_parser=self.__smbConfig) 

4696 self.__server.processConfigFile() 

4697 

4698 # Now we have to register the MS-SRVS server. This specially important for 

4699 # Windows 7+ and Mavericks clients since they WON'T (specially OSX) 

4700 # ask for shares using MS-RAP. 

4701 

4702 self.__srvsServer = SRVSServer() 

4703 self.__srvsServer.daemon = True 

4704 self.__wkstServer = WKSTServer() 

4705 self.__wkstServer.daemon = True 

4706 self.__server.registerNamedPipe('srvsvc', ('127.0.0.1', self.__srvsServer.getListenPort())) 

4707 self.__server.registerNamedPipe('wkssvc', ('127.0.0.1', self.__wkstServer.getListenPort())) 

4708 

4709 def start(self): 

4710 self.__srvsServer.start() 

4711 self.__wkstServer.start() 

4712 self.__server.serve_forever() 

4713 

4714 def registerNamedPipe(self, pipeName, address): 

4715 return self.__server.registerNamedPipe(pipeName, address) 

4716 

4717 def unregisterNamedPipe(self, pipeName): 

4718 return self.__server.unregisterNamedPipe(pipeName) 

4719 

4720 def getRegisteredNamedPipes(self): 

4721 return self.__server.getRegisteredNamedPipes() 

4722 

4723 def addShare(self, shareName, sharePath, shareComment='', shareType='0', readOnly='no'): 

4724 share = shareName.upper() 

4725 self.__smbConfig.add_section(share) 

4726 self.__smbConfig.set(share, 'comment', shareComment) 

4727 self.__smbConfig.set(share, 'read only', readOnly) 

4728 self.__smbConfig.set(share, 'share type', shareType) 

4729 self.__smbConfig.set(share, 'path', sharePath) 

4730 self.__server.setServerConfig(self.__smbConfig) 

4731 self.__srvsServer.setServerConfig(self.__smbConfig) 

4732 self.__server.processConfigFile() 

4733 self.__srvsServer.processConfigFile() 

4734 

4735 def removeShare(self, shareName): 

4736 self.__smbConfig.remove_section(shareName.upper()) 

4737 self.__server.setServerConfig(self.__smbConfig) 

4738 self.__srvsServer.setServerConfig(self.__smbConfig) 

4739 self.__server.processConfigFile() 

4740 self.__srvsServer.processConfigFile() 

4741 

4742 def setSMBChallenge(self, challenge): 

4743 if challenge != '': 

4744 self.__smbConfig.set('global', 'challenge', challenge) 

4745 self.__server.setServerConfig(self.__smbConfig) 

4746 self.__server.processConfigFile() 

4747 

4748 def setLogFile(self, logFile): 

4749 self.__smbConfig.set('global', 'log_file', logFile) 

4750 self.__server.setServerConfig(self.__smbConfig) 

4751 self.__server.processConfigFile() 

4752 

4753 def setCredentialsFile(self, logFile): 

4754 self.__smbConfig.set('global', 'credentials_file', logFile) 

4755 self.__server.setServerConfig(self.__smbConfig) 

4756 self.__server.processConfigFile() 

4757 

4758 def addCredential(self, name, uid, lmhash, nthash): 

4759 self.__server.addCredential(name, uid, lmhash, nthash) 

4760 

4761 def setSMB2Support(self, value): 

4762 if value is True: 

4763 self.__smbConfig.set("global", "SMB2Support", "True") 

4764 else: 

4765 self.__smbConfig.set("global", "SMB2Support", "False") 

4766 self.__server.setServerConfig(self.__smbConfig) 

4767 self.__server.processConfigFile()