Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# Impacket - Collection of Python classes for working with network protocols. 

2# 

3# SECUREAUTH LABS. Copyright (C) 2021 SecureAuth Corporation. All rights reserved. 

4# 

5# This software is provided under a slightly modified version 

6# of the Apache Software License. See the accompanying LICENSE file 

7# for more information. 

8# 

9# Author: 

10# Alberto Solino (@agsolino) 

11# 

12# TODO: 

13# [-] Functions should return NT error codes 

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

15# [*] Standard authentication support 

16# [ ] Organize the connectionData stuff 

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

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

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

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

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

22# [ ] Hence.. implement locking 

23# estamos en la B 

24 

25import calendar 

26import socket 

27import time 

28import datetime 

29import struct 

30import threading 

31import logging 

32import logging.config 

33import ntpath 

34import os 

35import fnmatch 

36import errno 

37import sys 

38import random 

39import shutil 

40import string 

41import hashlib 

42import hmac 

43 

44from binascii import unhexlify, hexlify, a2b_hex 

45from six import PY2, b, text_type 

46from six.moves import configparser, socketserver 

47 

48# For signing 

49from impacket import smb, nmb, ntlm, uuid 

50from impacket import smb3structs as smb2 

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

52 ASN1_SUPPORTED_MECH 

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

54 STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \ 

55 STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \ 

56 STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \ 

57 STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS, \ 

58 STATUS_LOGON_FAILURE, STATUS_OBJECT_PATH_SYNTAX_BAD 

59 

60# Setting LOG to current's module name 

61LOG = logging.getLogger(__name__) 

62 

63# These ones not defined in nt_errors 

64STATUS_SMB_BAD_UID = 0x005B0002 

65STATUS_SMB_BAD_TID = 0x00050002 

66 

67 

68# Utility functions 

69# and general functions. 

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

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

72# TODO: Return NT ERROR Codes 

73 

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

75 # Let's calculate the NTLMv2 Response 

76 

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

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

79 

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

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

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

83 lmChallengeResponse = authenticateMessage['lanman'] 

84 sessionBaseKey = ntlm.hmac_md5(responseKeyNT, ntProofStr) 

85 

86 responseFlags = type1['flags'] 

87 

88 # Let's check the return flags 

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

90 # No extended session security, taking it out 

91 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 

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

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

94 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_128 

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

96 # No key exchange supported, taking it out 

97 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH 

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

99 # No sign available, taking it out 

100 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_SEAL 

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

102 # No sign available, taking it out 

103 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_SIGN 

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

105 # No sign available, taking it out 

106 responseFlags &= 0xffffffff ^ ntlm.NTLMSSP_NEGOTIATE_ALWAYS_SIGN 

107 

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

109 ntlmChallenge['challenge'], '', 

110 lmhash, nthash, True) 

111 

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

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

114 exportedSessionKey = authenticateMessage['session_key'] 

115 exportedSessionKey = ntlm.generateEncryptedSessionKey(keyExchangeKey, exportedSessionKey) 

116 else: 

117 encryptedRandomSessionKey = None 

118 # [MS-NLMP] page 46 

119 exportedSessionKey = keyExchangeKey 

120 

121 # Do they match? 

122 if ntProofStr == ntProofStr2: 

123 # Yes!, process login 

124 return STATUS_SUCCESS, exportedSessionKey 

125 else: 

126 return STATUS_LOGON_FAILURE, exportedSessionKey 

127 

128 

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

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

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

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

133 ret_value = '' 

134 if type(challenge) is not bytes: 

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

136 

137 try: 

138 if len(ntresponse) > 24: 

139 # Extended Security - NTLMv2 

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

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

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

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

144 else: 

145 # NTLMv1 

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

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

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

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

150 except: 

151 # Let's try w/o decoding Unicode 

152 try: 

153 if len(ntresponse) > 24: 

154 # Extended Security - NTLMv2 

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

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

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

158 'hash_version': 'ntlmv2'} 

159 else: 

160 # NTLMv1 

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

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

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

164 except Exception as e: 

165 import traceback 

166 traceback.print_exc() 

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

168 pass 

169 

170 return ret_value 

171 

172 

173def writeJohnOutputToFile(hash_string, hash_version, file_name): 

174 fn_data = os.path.splitext(file_name) 

175 if hash_version == "ntlmv2": 

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

177 else: 

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

179 

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

181 f.write(hash_string) 

182 f.write('\n') 

183 

184 

185def decodeSMBString(flags, text): 

186 if flags & smb.SMB.FLAGS2_UNICODE: 

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

188 else: 

189 return text 

190 

191 

192def encodeSMBString(flags, text): 

193 if flags & smb.SMB.FLAGS2_UNICODE: 

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

195 else: 

196 return text.encode('ascii') 

197 

198 

199def getFileTime(t): 

200 t *= 10000000 

201 t += 116444736000000000 

202 return t 

203 

204 

205def getUnixTime(t): 

206 t -= 116444736000000000 

207 t //= 10000000 

208 return t 

209 

210 

211def getSMBDate(t): 

212 # TODO: Fix this :P 

213 d = datetime.date.fromtimestamp(t) 

214 year = d.year - 1980 

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

216 return ret 

217 

218 

219def getSMBTime(t): 

220 # TODO: Fix this :P 

221 d = datetime.datetime.fromtimestamp(t) 

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

223 

224 

225def getShares(connId, smbServer): 

226 config = smbServer.getServerConfig() 

227 sections = config.sections() 

228 # Remove the global one 

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

230 shares = {} 

231 for i in sections: 

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

233 return shares 

234 

235 

236def searchShare(connId, share, smbServer): 

237 config = smbServer.getServerConfig() 

238 if config.has_section(share): 

239 return dict(config.items(share)) 

240 else: 

241 return None 

242 

243 

244def normalize_path(file_name, path=None): 

245 """Normalizes a path by replacing "\" with "/" and stripping potential 

246 leading "/" chars. If a path is provided, only strip leading '/' when 

247 the path is empty. 

248 

249 :param file_name: file name to normalize 

250 :type file_name: string 

251 

252 :param path: path to normalize 

253 :type path: string 

254 

255 :return normalized file name 

256 :rtype string 

257 """ 

258 file_name = os.path.normpath(file_name.replace('\\', '/')) 

259 if len(file_name) > 0 and (file_name[0] == '/' or file_name[0] == '\\'): 

260 if path is None or path != '': 

261 # Strip leading "/" 

262 file_name = file_name[1:] 

263 return file_name 

264 

265 

266def isInFileJail(path, file_name): 

267 """Validates if a provided file name path is inside a path. This function is used 

268 to check for path traversals. 

269 

270 :param path: base path to check 

271 :type path: string 

272 :param file_name: file name to validate 

273 :type file_name: string 

274 

275 :return whether the file name is inside the base path or not 

276 :rtype bool 

277 """ 

278 path_name = os.path.join(path, file_name) 

279 share_real_path = os.path.realpath(path) 

280 return os.path.commonprefix((os.path.realpath(path_name), share_real_path)) == share_real_path 

281 

282 

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

284 fileName = normalize_path(fileName) 

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

286 errorCode = 0 

287 mode = 0 

288 

289 if not isInFileJail(path, fileName): 

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

291 errorCode = STATUS_OBJECT_PATH_SYNTAX_BAD 

292 return 0, mode, pathName, errorCode 

293 

294 # Check the Open Mode 

295 if openMode & 0x10: 

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

297 mode = os.O_CREAT 

298 else: 

299 # If file does not exist, return an error 

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

301 errorCode = STATUS_NO_SUCH_FILE 

302 return 0, mode, pathName, errorCode 

303 

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

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

306 errorCode = STATUS_FILE_IS_A_DIRECTORY 

307 return 0, mode, pathName, errorCode 

308 # Check the Access Mode 

309 if accessMode & 0x7 == 1: 

310 mode |= os.O_WRONLY 

311 elif accessMode & 0x7 == 2: 

312 mode |= os.O_RDWR 

313 else: 

314 mode = os.O_RDONLY 

315 

316 try: 

317 if sys.platform == 'win32': 

318 mode |= os.O_BINARY 

319 fid = os.open(pathName, mode) 

320 except Exception as e: 

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

322 fid = 0 

323 errorCode = STATUS_ACCESS_DENIED 

324 

325 return fid, mode, pathName, errorCode 

326 

327 

328def queryFsInformation(path, filename, level=None, pktFlags=smb.SMB.FLAGS2_UNICODE): 

329 if pktFlags & smb.SMB.FLAGS2_UNICODE: 

330 encoding = 'utf-16le' 

331 else: 

332 encoding = 'ascii' 

333 

334 fileName = normalize_path(filename) 

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

336 fileSize = os.path.getsize(pathName) 

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

338 

339 if level is None: 

340 lastWriteTime = mtime 

341 attribs = 0 

342 if os.path.isdir(pathName): 

343 attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

344 if os.path.isfile(pathName): 

345 attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL 

346 fileAttributes = attribs 

347 return fileSize, lastWriteTime, fileAttributes 

348 

349 elif level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO: 

350 data = smb.SMBQueryFsAttributeInfo() 

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

352 data['MaxFilenNameLengthInBytes'] = 255 

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

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

355 return data.getData() 

356 elif level == smb.SMB_INFO_VOLUME: 

357 data = smb.SMBQueryFsInfoVolume(flags=pktFlags) 

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

359 return data.getData() 

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

361 data = smb.SMBQueryFsVolumeInfo() 

362 data['VolumeLabel'] = '' 

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

364 return data.getData() 

365 elif level == smb.SMB_QUERY_FS_SIZE_INFO: 

366 data = smb.SMBQueryFsSizeInfo() 

367 return data.getData() 

368 elif level == smb.SMB_QUERY_FS_DEVICE_INFO or level == smb2.SMB2_FILESYSTEM_DEVICE_INFO: 

369 data = smb.SMBQueryFsDeviceInfo() 

370 data['DeviceType'] = smb.FILE_DEVICE_DISK 

371 return data.getData() 

372 elif level == smb.FILE_FS_FULL_SIZE_INFORMATION: 

373 data = smb.SMBFileFsFullSizeInformation() 

374 return data.getData() 

375 elif level == smb.FILE_FS_SIZE_INFORMATION: 

376 data = smb.FileFsSizeInformation() 

377 return data.getData() 

378 else: 

379 return None 

380 

381 

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

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

384 

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

386 if pktFlags & smb.SMB.FLAGS2_UNICODE: 

387 encoding = 'utf-16le' 

388 else: 

389 encoding = 'ascii' 

390 

391 fileName = normalize_path(fileName) 

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

393 

394 if not isInFileJail(path, fileName): 

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

396 return [], 0, STATUS_OBJECT_PATH_SYNTAX_BAD 

397 

398 files = [] 

399 

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

401 # No search patterns 

402 pattern = '' 

403 else: 

404 pattern = os.path.basename(pathName) 

405 dirName = os.path.dirname(pathName) 

406 

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

408 # not present (for * search only) 

409 if pattern == '*': 

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

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

412 

413 if pattern != '': 

414 for file in os.listdir(dirName): 

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

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

417 if os.path.isdir(entry): 

418 if searchAttributes & smb.ATTR_DIRECTORY: 

419 files.append(entry) 

420 else: 

421 files.append(entry) 

422 else: 

423 if os.path.exists(pathName): 

424 files.append(pathName) 

425 

426 searchResult = [] 

427 searchCount = len(files) 

428 errorCode = STATUS_SUCCESS 

429 

430 for i in files: 

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

432 item = smb.SMBFindFileBothDirectoryInfo(flags=pktFlags) 

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

434 item = smb.SMBFindFileDirectoryInfo(flags=pktFlags) 

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

436 item = smb.SMBFindFileFullDirectoryInfo(flags=pktFlags) 

437 elif level == smb.SMB_FIND_INFO_STANDARD: 

438 item = smb.SMBFindInfoStandard(flags=pktFlags) 

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

440 item = smb.SMBFindFileIdFullDirectoryInfo(flags=pktFlags) 

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

442 item = smb.SMBFindFileIdBothDirectoryInfo(flags=pktFlags) 

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

444 item = smb.SMBFindFileNamesInfo(flags=pktFlags) 

445 else: 

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

447 return searchResult, searchCount, STATUS_NOT_SUPPORTED 

448 

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

450 if os.path.isdir(i): 

451 item['ExtFileAttributes'] = smb.ATTR_DIRECTORY 

452 else: 

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

454 

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

456 

457 if level in [smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO, smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO, 

458 smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO]: 

459 item['EaSize'] = 0 

460 item['EndOfFile'] = size 

461 item['AllocationSize'] = size 

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

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

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

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

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

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

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

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

470 elif level in [smb.SMB_FIND_FILE_DIRECTORY_INFO, smb2.SMB2_FILE_DIRECTORY_INFO]: 

471 item['EndOfFile'] = size 

472 item['AllocationSize'] = size 

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

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

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

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

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

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

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

480 elif level in [smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO, smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO, 

481 smb2.SMB2_FULL_DIRECTORY_INFO, smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO]: 

482 item['EaSize'] = 0 

483 item['EndOfFile'] = size 

484 item['AllocationSize'] = size 

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

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

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

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

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

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

491 elif level == smb.SMB_FIND_INFO_STANDARD: 

492 item['EaSize'] = size 

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

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

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

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

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

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

499 searchResult.append(item) 

500 

501 # No more files 

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

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

504 

505 return searchResult, searchCount, errorCode 

506 

507 

508def queryFileInformation(path, filename, level): 

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

510 return queryPathInformation(path, filename, level) 

511 

512 

513def queryPathInformation(path, filename, level): 

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

515 try: 

516 errorCode = 0 

517 fileName = normalize_path(filename, path) 

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

519 

520 if not isInFileJail(path, fileName): 

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

522 return None, STATUS_OBJECT_PATH_SYNTAX_BAD 

523 

524 if os.path.exists(pathName): 

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

526 if level == smb.SMB_QUERY_FILE_BASIC_INFO: 

527 infoRecord = smb.SMBQueryFileBasicInfo() 

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

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

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

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

532 if os.path.isdir(pathName): 

533 infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY 

534 else: 

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

536 elif level == smb.SMB_QUERY_FILE_STANDARD_INFO or level == smb2.SMB2_FILE_STANDARD_INFO: 

537 infoRecord = smb.SMBQueryFileStandardInfo() 

538 infoRecord['AllocationSize'] = size 

539 infoRecord['EndOfFile'] = size 

540 if os.path.isdir(pathName): 

541 infoRecord['Directory'] = 1 

542 else: 

543 infoRecord['Directory'] = 0 

544 elif level == smb.SMB_QUERY_FILE_ALL_INFO: 

545 infoRecord = smb.SMBQueryFileAllInfo() 

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

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

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

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

550 if os.path.isdir(pathName): 

551 infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY 

552 else: 

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

554 infoRecord['AllocationSize'] = size 

555 infoRecord['EndOfFile'] = size 

556 if os.path.isdir(pathName): 

557 infoRecord['Directory'] = 1 

558 else: 

559 infoRecord['Directory'] = 0 

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

561 elif level == smb2.SMB2_FILE_ALL_INFO: 

562 infoRecord = smb2.FILE_ALL_INFORMATION() 

563 infoRecord['BasicInformation'] = smb2.FILE_BASIC_INFORMATION() 

564 infoRecord['StandardInformation'] = smb2.FILE_STANDARD_INFORMATION() 

565 infoRecord['InternalInformation'] = smb2.FILE_INTERNAL_INFORMATION() 

566 infoRecord['EaInformation'] = smb2.FILE_EA_INFORMATION() 

567 infoRecord['AccessInformation'] = smb2.FILE_ACCESS_INFORMATION() 

568 infoRecord['PositionInformation'] = smb2.FILE_POSITION_INFORMATION() 

569 infoRecord['ModeInformation'] = smb2.FILE_MODE_INFORMATION() 

570 infoRecord['AlignmentInformation'] = smb2.FILE_ALIGNMENT_INFORMATION() 

571 infoRecord['NameInformation'] = smb2.FILE_NAME_INFORMATION() 

572 infoRecord['BasicInformation']['CreationTime'] = getFileTime(ctime) 

573 infoRecord['BasicInformation']['LastAccessTime'] = getFileTime(atime) 

574 infoRecord['BasicInformation']['LastWriteTime'] = getFileTime(mtime) 

575 infoRecord['BasicInformation']['ChangeTime'] = getFileTime(mtime) 

576 if os.path.isdir(pathName): 

577 infoRecord['BasicInformation']['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

578 infoRecord['StandardInformation']['Directory'] = 1 

579 infoRecord['EaInformation']['EaSize'] = smb.ATTR_DIRECTORY 

580 else: 

581 infoRecord['BasicInformation']['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_NORMAL | smb.SMB_FILE_ATTRIBUTE_ARCHIVE 

582 infoRecord['StandardInformation']['Directory'] = 0 

583 infoRecord['EaInformation']['EaSize'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE 

584 infoRecord['StandardInformation']['AllocationSize'] = size 

585 infoRecord['StandardInformation']['EndOfFile'] = size 

586 infoRecord['StandardInformation']['NumberOfLinks'] = nlink 

587 infoRecord['StandardInformation']['DeletePending'] = 0 

588 infoRecord['InternalInformation']['IndexNumber'] = ino 

589 infoRecord['AccessInformation']['AccessFlags'] = 0 # 

590 infoRecord['PositionInformation']['CurrentByteOffset'] = 0 # 

591 infoRecord['ModeInformation']['mode'] = mode 

592 infoRecord['AlignmentInformation']['AlignmentRequirement'] = 0 # 

593 infoRecord['NameInformation']['FileName'] = fileName 

594 infoRecord['NameInformation']['FileNameLength'] = len(fileName) 

595 elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO: 

596 infoRecord = smb.SMBFileNetworkOpenInfo() 

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

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

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

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

601 infoRecord['AllocationSize'] = size 

602 infoRecord['EndOfFile'] = size 

603 if os.path.isdir(pathName): 

604 infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY 

605 else: 

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

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

608 infoRecord = smb.SMBQueryFileEaInfo() 

609 elif level == smb2.SMB2_FILE_STREAM_INFO: 

610 infoRecord = smb.SMBFileStreamInformation() 

611 else: 

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

613 # UNSUPPORTED 

614 return None, STATUS_NOT_SUPPORTED 

615 

616 return infoRecord, errorCode 

617 else: 

618 # NOT FOUND 

619 return None, STATUS_OBJECT_NAME_NOT_FOUND 

620 except Exception as e: 

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

622 raise 

623 

624 

625def queryDiskInformation(path): 

626 # TODO: Do something useful here :) 

627 # For now we just return fake values 

628 totalUnits = 65535 

629 freeUnits = 65535 

630 return totalUnits, freeUnits 

631 

632 

633# Here we implement the NT transaction handlers 

634class NTTRANSCommands: 

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

636 pass 

637 

638 

639# Here we implement the NT transaction handlers 

640class TRANSCommands: 

641 @staticmethod 

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

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

644 connData = smbServer.getConnectionData(connId) 

645 

646 respSetup = b'' 

647 respParameters = b'' 

648 respData = b'' 

649 errorCode = STATUS_SUCCESS 

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

651 # NetShareEnum Request 

652 netShareEnum = smb.SMBNetShareEnum(parameters) 

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

654 shares = getShares(connId, smbServer) 

655 respParameters = smb.SMBNetShareEnumResponse() 

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

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

658 tailData = '' 

659 for i in shares: 

660 # NetShareInfo1 len == 20 

661 entry = smb.NetShareInfo1() 

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

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

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

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

666 respData += entry.getData() 

667 if 'comment' in shares[i]: 

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

669 else: 

670 tailData += '\x00' 

671 respData += tailData 

672 else: 

673 # We don't support other info levels 

674 errorCode = STATUS_NOT_SUPPORTED 

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

676 # NetrServerGetInfo Request 

677 respParameters = smb.SMBNetServerGetInfoResponse() 

678 netServerInfo = smb.SMBNetServerInfo1() 

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

680 respData = netServerInfo.getData() 

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

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

683 # NetrShareGetInfo Request 

684 request = smb.SMBNetShareGetInfo(parameters) 

685 respParameters = smb.SMBNetShareGetInfoResponse() 

686 shares = getShares(connId, smbServer) 

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

688 shareInfo = smb.NetShareInfo1() 

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

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

691 respData = shareInfo.getData() 

692 if 'comment' in share: 

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

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

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

696 

697 else: 

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

699 errorCode = STATUS_NOT_SUPPORTED 

700 

701 smbServer.setConnectionData(connId, connData) 

702 

703 return respSetup, respParameters, respData, errorCode 

704 

705 @staticmethod 

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

707 connData = smbServer.getConnectionData(connId) 

708 

709 respSetup = b'' 

710 respParameters = b'' 

711 respData = b'' 

712 errorCode = STATUS_SUCCESS 

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

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

715 

716 # Extract the FID 

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

718 

719 if fid in connData['OpenedFiles']: 

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

721 if fileHandle != PIPE_FILE_DESCRIPTOR: 

722 os.write(fileHandle, data) 

723 respData = os.read(fileHandle, data) 

724 else: 

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

726 sock.send(data) 

727 respData = sock.recv(maxDataCount) 

728 else: 

729 errorCode = STATUS_INVALID_HANDLE 

730 

731 smbServer.setConnectionData(connId, connData) 

732 

733 return respSetup, respParameters, respData, errorCode 

734 

735 

736# Here we implement the transaction2 handlers 

737class TRANS2Commands: 

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

739 @staticmethod 

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

741 connData = smbServer.getConnectionData(connId) 

742 

743 respSetup = b'' 

744 respParameters = b'' 

745 respData = b'' 

746 errorCode = STATUS_SUCCESS 

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

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

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

750 fileName = normalize_path(decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName']), path) 

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

752 

753 if isInFileJail(path, fileName): 

754 smbServer.log("Path not in current working directory") 

755 errorCode = STATUS_OBJECT_PATH_SYNTAX_BAD 

756 

757 elif os.path.exists(pathName): 

758 informationLevel = setPathInfoParameters['InformationLevel'] 

759 if informationLevel == smb.SMB_SET_FILE_BASIC_INFO: 

760 infoRecord = smb.SMBSetFileBasicInfo(data) 

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

762 atime = infoRecord['LastAccessTime'] 

763 if atime == 0: 

764 atime = -1 

765 else: 

766 atime = getUnixTime(atime) 

767 mtime = infoRecord['LastWriteTime'] 

768 if mtime == 0: 

769 mtime = -1 

770 else: 

771 mtime = getUnixTime(mtime) 

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

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

774 else: 

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

776 logging.ERROR) 

777 # UNSUPPORTED 

778 errorCode = STATUS_NOT_SUPPORTED 

779 else: 

780 errorCode = STATUS_OBJECT_NAME_NOT_FOUND 

781 

782 if errorCode == STATUS_SUCCESS: 

783 respParameters = smb.SMBSetPathInformationResponse_Parameters() 

784 

785 else: 

786 errorCode = STATUS_SMB_BAD_TID 

787 

788 smbServer.setConnectionData(connId, connData) 

789 

790 return respSetup, respParameters, respData, errorCode 

791 

792 @staticmethod 

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

794 connData = smbServer.getConnectionData(connId) 

795 

796 respSetup = b'' 

797 respParameters = b'' 

798 respData = b'' 

799 errorCode = STATUS_SUCCESS 

800 setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters) 

801 

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

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

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

805 informationLevel = setFileInfoParameters['InformationLevel'] 

806 if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO: 

807 infoRecord = smb.SMBSetFileDispositionInfo(parameters) 

808 if infoRecord['DeletePending'] > 0: 

809 # Mark this file for removal after closed 

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

811 respParameters = smb.SMBSetFileInformationResponse_Parameters() 

812 elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO: 

813 infoRecord = smb.SMBSetFileBasicInfo(data) 

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

815 atime = infoRecord['LastAccessTime'] 

816 if atime == 0: 

817 atime = -1 

818 else: 

819 atime = getUnixTime(atime) 

820 mtime = infoRecord['LastWriteTime'] 

821 if mtime == 0: 

822 mtime = -1 

823 else: 

824 mtime = getUnixTime(mtime) 

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

826 elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO: 

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

828 infoRecord = smb.SMBSetFileEndOfFileInfo(data) 

829 if infoRecord['EndOfFile'] > 0: 

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

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

832 else: 

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

834 logging.ERROR) 

835 # UNSUPPORTED 

836 errorCode = STATUS_NOT_SUPPORTED 

837 else: 

838 errorCode = STATUS_NO_SUCH_FILE 

839 

840 if errorCode == STATUS_SUCCESS: 

841 respParameters = smb.SMBSetFileInformationResponse_Parameters() 

842 else: 

843 errorCode = STATUS_SMB_BAD_TID 

844 

845 smbServer.setConnectionData(connId, connData) 

846 

847 return respSetup, respParameters, respData, errorCode 

848 

849 @staticmethod 

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

851 connData = smbServer.getConnectionData(connId) 

852 

853 respSetup = b'' 

854 respParameters = b'' 

855 respData = b'' 

856 

857 queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters) 

858 

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

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

861 pathName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName'] 

862 

863 infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), 

864 queryFileInfoParameters['InformationLevel']) 

865 

866 if infoRecord is not None: 

867 respParameters = smb.SMBQueryFileInformationResponse_Parameters() 

868 respData = infoRecord 

869 else: 

870 errorCode = STATUS_INVALID_HANDLE 

871 else: 

872 errorCode = STATUS_SMB_BAD_TID 

873 

874 smbServer.setConnectionData(connId, connData) 

875 

876 return respSetup, respParameters, respData, errorCode 

877 

878 @staticmethod 

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

880 connData = smbServer.getConnectionData(connId) 

881 

882 respSetup = b'' 

883 respParameters = b'' 

884 respData = b'' 

885 errorCode = 0 

886 

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

888 

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

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

891 try: 

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

893 queryPathInfoParameters['FileName']), 

894 queryPathInfoParameters['InformationLevel']) 

895 except Exception as e: 

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

897 

898 if infoRecord is not None: 

899 respParameters = smb.SMBQueryPathInformationResponse_Parameters() 

900 respData = infoRecord 

901 else: 

902 errorCode = STATUS_SMB_BAD_TID 

903 

904 smbServer.setConnectionData(connId, connData) 

905 

906 return respSetup, respParameters, respData, errorCode 

907 

908 @staticmethod 

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

910 connData = smbServer.getConnectionData(connId) 

911 errorCode = 0 

912 # Get the Tid associated 

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

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

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

916 

917 smbServer.setConnectionData(connId, connData) 

918 

919 return b'', b'', data, errorCode 

920 

921 @staticmethod 

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

923 connData = smbServer.getConnectionData(connId) 

924 

925 respSetup = b'' 

926 respParameters = b'' 

927 respData = b'' 

928 errorCode = STATUS_SUCCESS 

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

930 

931 sid = findNext2Parameters['SID'] 

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

933 if sid in connData['SIDs']: 

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

935 respParameters = smb.SMBFindNext2Response_Parameters() 

936 endOfSearch = 1 

937 searchCount = 1 

938 totalData = 0 

939 for i in enumerate(searchResult): 

940 data = i[1].getData() 

941 lenData = len(data) 

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

943 # We gotta stop here and continue on a find_next2 

944 endOfSearch = 0 

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

946 respParameters['LastNameOffset'] = totalData 

947 break 

948 else: 

949 searchCount += 1 

950 respData += data 

951 totalData += lenData 

952 

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

954 if endOfSearch > 0: 

955 # Let's remove the SID from our ConnData 

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

957 

958 respParameters['EndOfSearch'] = endOfSearch 

959 respParameters['SearchCount'] = searchCount 

960 else: 

961 errorCode = STATUS_INVALID_HANDLE 

962 else: 

963 errorCode = STATUS_SMB_BAD_TID 

964 

965 smbServer.setConnectionData(connId, connData) 

966 

967 return respSetup, respParameters, respData, errorCode 

968 

969 @staticmethod 

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

971 connData = smbServer.getConnectionData(connId) 

972 

973 respSetup = b'' 

974 respParameters = b'' 

975 respData = b'' 

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

977 

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

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

980 

981 searchResult, searchCount, errorCode = findFirst2(path, 

982 decodeSMBString(recvPacket['Flags2'], 

983 findFirst2Parameters['FileName']), 

984 findFirst2Parameters['InformationLevel'], 

985 findFirst2Parameters['SearchAttributes'], 

986 pktFlags=recvPacket['Flags2']) 

987 

988 if searchCount > 0: 

989 respParameters = smb.SMBFindFirst2Response_Parameters() 

990 endOfSearch = 1 

991 sid = 0x80 # default SID 

992 searchCount = 0 

993 totalData = 0 

994 for i in enumerate(searchResult): 

995 # i[1].dump() 

996 data = i[1].getData() 

997 lenData = len(data) 

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

999 # We gotta stop here and continue on a find_next2 

1000 endOfSearch = 0 

1001 # Simple way to generate a fid 

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

1003 sid = 1 

1004 else: 

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

1006 # Store the remaining search results in the ConnData SID 

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

1008 respParameters['LastNameOffset'] = totalData 

1009 break 

1010 else: 

1011 searchCount += 1 

1012 respData += data 

1013 

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

1015 respData += b'\xaa' * padLen 

1016 totalData += lenData + padLen 

1017 

1018 respParameters['SID'] = sid 

1019 respParameters['EndOfSearch'] = endOfSearch 

1020 respParameters['SearchCount'] = searchCount 

1021 

1022 # If we've empty files and errorCode was not already set, we return NO_SUCH_FILE 

1023 elif errorCode == 0: 

1024 errorCode = STATUS_NO_SUCH_FILE 

1025 else: 

1026 errorCode = STATUS_SMB_BAD_TID 

1027 

1028 smbServer.setConnectionData(connId, connData) 

1029 

1030 return respSetup, respParameters, respData, errorCode 

1031 

1032 

1033# Here we implement the commands handlers 

1034class SMBCommands: 

1035 

1036 @staticmethod 

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

1038 connData = smbServer.getConnectionData(connId) 

1039 

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

1041 

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

1043 

1044 # Do the stuff 

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

1046 # TODO: Handle partial parameters 

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

1048 else: 

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

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

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

1052 

1053 paramCount = transParameters['ParameterCount'] 

1054 transData['Trans_ParametersLength'] = paramCount 

1055 dataCount = transParameters['DataCount'] 

1056 transData['Trans_DataLength'] = dataCount 

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

1058 if transParameters['ParameterOffset'] > 0: 

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

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

1061 else: 

1062 transData['Trans_Parameters'] = b'' 

1063 

1064 if transParameters['DataOffset'] > 0: 

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

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

1067 else: 

1068 transData['Trans_Data'] = b'' 

1069 

1070 # Call the handler for this TRANSACTION 

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

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

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

1074 else: 

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

1076 

1077 if command in transCommands: 

1078 # Call the TRANS subcommand 

1079 setup = b'' 

1080 parameters = b'' 

1081 data = b'' 

1082 try: 

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

1084 smbServer, 

1085 recvPacket, 

1086 transData['Trans_Parameters'], 

1087 transData['Trans_Data'], 

1088 transParameters['MaxDataCount']) 

1089 except Exception as e: 

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

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

1092 errorCode = STATUS_ACCESS_DENIED 

1093 # raise 

1094 

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

1096 # Something wen't wrong 

1097 respParameters = b'' 

1098 respData = b'' 

1099 else: 

1100 # Build the answer 

1101 if hasattr(data, 'getData'): 

1102 data = data.getData() 

1103 remainingData = len(data) 

1104 if hasattr(parameters, 'getData'): 

1105 parameters = parameters.getData() 

1106 remainingParameters = len(parameters) 

1107 commands = [] 

1108 dataDisplacement = 0 

1109 while remainingData > 0 or remainingParameters > 0: 

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

1111 respParameters = smb.SMBTransactionResponse_Parameters() 

1112 respData = smb.SMBTransaction2Response_Data() 

1113 

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

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

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

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

1118 respParameters['DataDisplacement'] = dataDisplacement 

1119 

1120 # TODO: Do the same for parameters 

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

1122 # Answer doesn't fit in this packet 

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

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

1125 else: 

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

1127 

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

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

1130 respParameters['Setup'] = setup 

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

1132 if len(parameters) > 0: 

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

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

1135 padBytes = b'\xFF' * padLen 

1136 respData['Pad1'] = padBytes 

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

1138 else: 

1139 padLen = 0 

1140 respParameters['ParameterOffset'] = 0 

1141 respData['Pad1'] = b'' 

1142 

1143 if len(data) > 0: 

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

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

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

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

1148 else: 

1149 respParameters['DataOffset'] = 0 

1150 respData['Pad2'] = b'' 

1151 

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

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

1154 respSMBCommand['Parameters'] = respParameters 

1155 respSMBCommand['Data'] = respData 

1156 

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

1158 remainingData -= respParameters['DataCount'] 

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

1160 

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

1162 remainingParameters -= respParameters['ParameterCount'] 

1163 commands.append(respSMBCommand) 

1164 

1165 smbServer.setConnectionData(connId, connData) 

1166 return commands, None, errorCode 

1167 

1168 else: 

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

1170 respParameters = b'' 

1171 respData = b'' 

1172 errorCode = STATUS_NOT_IMPLEMENTED 

1173 

1174 respSMBCommand['Parameters'] = respParameters 

1175 respSMBCommand['Data'] = respData 

1176 smbServer.setConnectionData(connId, connData) 

1177 

1178 return [respSMBCommand], None, errorCode 

1179 

1180 @staticmethod 

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

1182 connData = smbServer.getConnectionData(connId) 

1183 

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

1185 

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

1187 # Do the stuff 

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

1189 # TODO: Handle partial parameters 

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

1191 else: 

1192 NTTransData = smb.SMBNTTransaction_Data() 

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

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

1195 

1196 paramCount = NTTransParameters['ParameterCount'] 

1197 NTTransData['NT_Trans_ParametersLength'] = paramCount 

1198 dataCount = NTTransParameters['DataCount'] 

1199 NTTransData['NT_Trans_DataLength'] = dataCount 

1200 

1201 if NTTransParameters['ParameterOffset'] > 0: 

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

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

1204 else: 

1205 NTTransData['NT_Trans_Parameters'] = b'' 

1206 

1207 if NTTransParameters['DataOffset'] > 0: 

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

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

1210 else: 

1211 NTTransData['NT_Trans_Data'] = b'' 

1212 

1213 # Call the handler for this TRANSACTION 

1214 command = NTTransParameters['Function'] 

1215 if command in transCommands: 

1216 # Call the NT TRANS subcommand 

1217 setup = b'' 

1218 parameters = b'' 

1219 data = b'' 

1220 try: 

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

1222 smbServer, 

1223 recvPacket, 

1224 NTTransData['NT_Trans_Parameters'], 

1225 NTTransData['NT_Trans_Data'], 

1226 NTTransParameters['MaxDataCount']) 

1227 except Exception as e: 

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

1229 errorCode = STATUS_ACCESS_DENIED 

1230 # raise 

1231 

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

1233 # Something wen't wrong 

1234 respParameters = b'' 

1235 respData = b'' 

1236 if errorCode == STATUS_SUCCESS: 

1237 errorCode = STATUS_ACCESS_DENIED 

1238 else: 

1239 # Build the answer 

1240 if hasattr(data, 'getData'): 

1241 data = data.getData() 

1242 remainingData = len(data) 

1243 if hasattr(parameters, 'getData'): 

1244 parameters = parameters.getData() 

1245 remainingParameters = len(parameters) 

1246 commands = [] 

1247 dataDisplacement = 0 

1248 while remainingData > 0 or remainingParameters > 0: 

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

1250 respParameters = smb.SMBNTTransactionResponse_Parameters() 

1251 respData = smb.SMBNTTransactionResponse_Data() 

1252 

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

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

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

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

1257 respParameters['DataDisplacement'] = dataDisplacement 

1258 # TODO: Do the same for parameters 

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

1260 # Answer doesn't fit in this packet 

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

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

1263 else: 

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

1265 

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

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

1268 respParameters['Setup'] = setup 

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

1270 if len(parameters) > 0: 

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

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

1273 padBytes = b'\xFF' * padLen 

1274 respData['Pad1'] = padBytes 

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

1276 else: 

1277 padLen = 0 

1278 respParameters['ParameterOffset'] = 0 

1279 respData['Pad1'] = b'' 

1280 

1281 if len(data) > 0: 

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

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

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

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

1286 else: 

1287 respParameters['DataOffset'] = 0 

1288 respData['Pad2'] = b'' 

1289 

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

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

1292 respSMBCommand['Parameters'] = respParameters 

1293 respSMBCommand['Data'] = respData 

1294 

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

1296 remainingData -= respParameters['DataCount'] 

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

1298 

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

1300 remainingParameters -= respParameters['ParameterCount'] 

1301 commands.append(respSMBCommand) 

1302 

1303 smbServer.setConnectionData(connId, connData) 

1304 return commands, None, errorCode 

1305 

1306 else: 

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

1308 respParameters = b'' 

1309 respData = b'' 

1310 errorCode = STATUS_NOT_IMPLEMENTED 

1311 

1312 respSMBCommand['Parameters'] = respParameters 

1313 respSMBCommand['Data'] = respData 

1314 

1315 smbServer.setConnectionData(connId, connData) 

1316 return [respSMBCommand], None, errorCode 

1317 

1318 @staticmethod 

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

1320 connData = smbServer.getConnectionData(connId) 

1321 

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

1323 

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

1325 

1326 # Do the stuff 

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

1328 # TODO: Handle partial parameters 

1329 # print "Unsupported partial parameters in TRANSACT2!" 

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

1331 else: 

1332 trans2Data = smb.SMBTransaction2_Data() 

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

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

1335 

1336 paramCount = trans2Parameters['ParameterCount'] 

1337 trans2Data['Trans_ParametersLength'] = paramCount 

1338 dataCount = trans2Parameters['DataCount'] 

1339 trans2Data['Trans_DataLength'] = dataCount 

1340 

1341 if trans2Parameters['ParameterOffset'] > 0: 

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

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

1344 else: 

1345 trans2Data['Trans_Parameters'] = b'' 

1346 

1347 if trans2Parameters['DataOffset'] > 0: 

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

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

1350 else: 

1351 trans2Data['Trans_Data'] = b'' 

1352 

1353 # Call the handler for this TRANSACTION 

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

1355 if command in transCommands: 

1356 # Call the TRANS2 subcommand 

1357 try: 

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

1359 smbServer, 

1360 recvPacket, 

1361 trans2Data['Trans_Parameters'], 

1362 trans2Data['Trans_Data'], 

1363 trans2Parameters['MaxDataCount']) 

1364 except Exception as e: 

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

1366 # import traceback 

1367 # traceback.print_exc() 

1368 raise 

1369 

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

1371 # Something wen't wrong 

1372 respParameters = b'' 

1373 respData = b'' 

1374 else: 

1375 # Build the answer 

1376 if hasattr(data, 'getData'): 

1377 data = data.getData() 

1378 remainingData = len(data) 

1379 if hasattr(parameters, 'getData'): 

1380 parameters = parameters.getData() 

1381 remainingParameters = len(parameters) 

1382 commands = [] 

1383 dataDisplacement = 0 

1384 while remainingData > 0 or remainingParameters > 0: 

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

1386 respParameters = smb.SMBTransaction2Response_Parameters() 

1387 respData = smb.SMBTransaction2Response_Data() 

1388 

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

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

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

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

1393 respParameters['DataDisplacement'] = dataDisplacement 

1394 # TODO: Do the same for parameters 

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

1396 # Answer doesn't fit in this packet 

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

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

1399 else: 

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

1401 

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

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

1404 respParameters['Setup'] = setup 

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

1406 if len(parameters) > 0: 

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

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

1409 padBytes = b'\xFF' * padLen 

1410 respData['Pad1'] = padBytes 

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

1412 else: 

1413 padLen = 0 

1414 respParameters['ParameterOffset'] = 0 

1415 respData['Pad1'] = b'' 

1416 

1417 if len(data) > 0: 

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

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

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

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

1422 else: 

1423 respParameters['DataOffset'] = 0 

1424 respData['Pad2'] = b'' 

1425 

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

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

1428 respSMBCommand['Parameters'] = respParameters 

1429 respSMBCommand['Data'] = respData 

1430 

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

1432 remainingData -= respParameters['DataCount'] 

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

1434 

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

1436 remainingParameters -= respParameters['ParameterCount'] 

1437 commands.append(respSMBCommand) 

1438 

1439 smbServer.setConnectionData(connId, connData) 

1440 return commands, None, errorCode 

1441 

1442 else: 

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

1444 respParameters = b'' 

1445 respData = b'' 

1446 errorCode = STATUS_NOT_IMPLEMENTED 

1447 

1448 respSMBCommand['Parameters'] = respParameters 

1449 respSMBCommand['Data'] = respData 

1450 

1451 smbServer.setConnectionData(connId, connData) 

1452 return [respSMBCommand], None, errorCode 

1453 

1454 @staticmethod 

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

1456 connData = smbServer.getConnectionData(connId) 

1457 

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

1459 respParameters = b'' 

1460 respData = b'' 

1461 

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

1463 errorCode = STATUS_SUCCESS 

1464 

1465 respSMBCommand['Parameters'] = respParameters 

1466 respSMBCommand['Data'] = respData 

1467 smbServer.setConnectionData(connId, connData) 

1468 

1469 return [respSMBCommand], None, errorCode 

1470 

1471 @staticmethod 

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

1473 connData = smbServer.getConnectionData(connId) 

1474 

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

1476 respParameters = b'' 

1477 respData = b'' 

1478 

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

1480 

1481 # Get the Tid associated 

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

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

1484 errorCode = STATUS_SUCCESS 

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

1486 try: 

1487 if fileHandle == PIPE_FILE_DESCRIPTOR: 

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

1489 elif fileHandle != VOID_FILE_DESCRIPTOR: 

1490 os.close(fileHandle) 

1491 except Exception as e: 

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

1493 errorCode = STATUS_ACCESS_DENIED 

1494 else: 

1495 # Check if the file was marked for removal 

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

1497 try: 

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

1499 except Exception as e: 

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

1501 errorCode = STATUS_ACCESS_DENIED 

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

1503 else: 

1504 errorCode = STATUS_INVALID_HANDLE 

1505 else: 

1506 errorCode = STATUS_SMB_BAD_TID 

1507 

1508 if errorCode > 0: 

1509 respParameters = b'' 

1510 respData = b'' 

1511 

1512 respSMBCommand['Parameters'] = respParameters 

1513 respSMBCommand['Data'] = respData 

1514 smbServer.setConnectionData(connId, connData) 

1515 

1516 return [respSMBCommand], None, errorCode 

1517 

1518 @staticmethod 

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

1520 connData = smbServer.getConnectionData(connId) 

1521 

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

1523 respParameters = smb.SMBWriteResponse_Parameters() 

1524 respData = b'' 

1525 

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

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

1528 

1529 # Get the Tid associated 

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

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

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

1533 errorCode = STATUS_SUCCESS 

1534 try: 

1535 if fileHandle != PIPE_FILE_DESCRIPTOR: 

1536 # TODO: Handle big size files 

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

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

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

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

1541 else: 

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

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

1544 respParameters['Count'] = comWriteParameters['Count'] 

1545 except Exception as e: 

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

1547 errorCode = STATUS_ACCESS_DENIED 

1548 else: 

1549 errorCode = STATUS_INVALID_HANDLE 

1550 else: 

1551 errorCode = STATUS_SMB_BAD_TID 

1552 

1553 if errorCode > 0: 

1554 respParameters = b'' 

1555 respData = b'' 

1556 

1557 respSMBCommand['Parameters'] = respParameters 

1558 respSMBCommand['Data'] = respData 

1559 smbServer.setConnectionData(connId, connData) 

1560 

1561 return [respSMBCommand], None, errorCode 

1562 

1563 @staticmethod 

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

1565 connData = smbServer.getConnectionData(connId) 

1566 

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

1568 respParameters = b'' 

1569 respData = b'' 

1570 

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

1572 

1573 # Get the Tid associated 

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

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

1576 errorCode = STATUS_SUCCESS 

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

1578 try: 

1579 os.fsync(fileHandle) 

1580 except Exception as e: 

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

1582 errorCode = STATUS_ACCESS_DENIED 

1583 else: 

1584 errorCode = STATUS_INVALID_HANDLE 

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 smbComCreateDirectory(connId, smbServer, SMBCommand, recvPacket): 

1600 connData = smbServer.getConnectionData(connId) 

1601 

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

1603 respParameters = b'' 

1604 respData = b'' 

1605 

1606 comCreateDirectoryData = smb.SMBCreateDirectory_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 = normalize_path(decodeSMBString(recvPacket['Flags2'], comCreateDirectoryData['DirectoryName'])) 

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

1614 

1615 if not isInFileJail(path, fileName): 

1616 smbServer.log("Path not in current working directory", logging.ERROR) 

1617 errorCode = STATUS_OBJECT_PATH_SYNTAX_BAD 

1618 

1619 elif os.path.exists(pathName): 

1620 errorCode = STATUS_OBJECT_NAME_COLLISION 

1621 

1622 else: 

1623 try: 

1624 os.mkdir(pathName) 

1625 except Exception as e: 

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

1627 errorCode = STATUS_ACCESS_DENIED 

1628 else: 

1629 errorCode = STATUS_SMB_BAD_TID 

1630 

1631 if errorCode > 0: 

1632 respParameters = b'' 

1633 respData = b'' 

1634 

1635 respSMBCommand['Parameters'] = respParameters 

1636 respSMBCommand['Data'] = respData 

1637 smbServer.setConnectionData(connId, connData) 

1638 

1639 return [respSMBCommand], None, errorCode 

1640 

1641 @staticmethod 

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

1643 connData = smbServer.getConnectionData(connId) 

1644 

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

1646 respParameters = b'' 

1647 respData = b'' 

1648 

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

1650 

1651 # Get the Tid associated 

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

1653 errorCode = STATUS_SUCCESS 

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

1655 oldFileName = normalize_path(decodeSMBString(recvPacket['Flags2'], comRenameData['OldFileName'])) 

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

1657 newFileName = normalize_path(decodeSMBString(recvPacket['Flags2'], comRenameData['NewFileName'])) 

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

1659 

1660 if not isInFileJail(path, oldFileName) or not isInFileJail(path, newFileName): 

1661 smbServer.log("Path not in current working directory", logging.ERROR) 

1662 errorCode = STATUS_OBJECT_PATH_SYNTAX_BAD 

1663 

1664 elif not os.path.exists(oldPathName): 

1665 errorCode = STATUS_NO_SUCH_FILE 

1666 

1667 else: 

1668 try: 

1669 os.rename(oldPathName, newPathName) 

1670 except OSError as e: 

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

1672 errorCode = STATUS_ACCESS_DENIED 

1673 else: 

1674 errorCode = STATUS_SMB_BAD_TID 

1675 

1676 if errorCode > 0: 

1677 respParameters = b'' 

1678 respData = b'' 

1679 

1680 respSMBCommand['Parameters'] = respParameters 

1681 respSMBCommand['Data'] = respData 

1682 smbServer.setConnectionData(connId, connData) 

1683 

1684 return [respSMBCommand], None, errorCode 

1685 

1686 @staticmethod 

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

1688 connData = smbServer.getConnectionData(connId) 

1689 

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

1691 respParameters = b'' 

1692 respData = b'' 

1693 

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

1695 

1696 # Get the Tid associated 

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

1698 errorCode = STATUS_SUCCESS 

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

1700 fileName = normalize_path(decodeSMBString(recvPacket['Flags2'], comDeleteData['FileName'])) 

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

1702 

1703 if not isInFileJail(path, fileName): 

1704 smbServer.log("Path not in current working directory", logging.ERROR) 

1705 errorCode = STATUS_OBJECT_PATH_SYNTAX_BAD 

1706 

1707 elif not os.path.exists(pathName): 

1708 errorCode = STATUS_NO_SUCH_FILE 

1709 

1710 else: 

1711 try: 

1712 os.remove(pathName) 

1713 except OSError as e: 

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

1715 errorCode = STATUS_ACCESS_DENIED 

1716 else: 

1717 errorCode = STATUS_SMB_BAD_TID 

1718 

1719 if errorCode > 0: 

1720 respParameters = b'' 

1721 respData = b'' 

1722 

1723 respSMBCommand['Parameters'] = respParameters 

1724 respSMBCommand['Data'] = respData 

1725 smbServer.setConnectionData(connId, connData) 

1726 

1727 return [respSMBCommand], None, errorCode 

1728 

1729 @staticmethod 

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

1731 connData = smbServer.getConnectionData(connId) 

1732 

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

1734 respParameters = b'' 

1735 respData = b'' 

1736 

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

1738 

1739 # Get the Tid associated 

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

1741 errorCode = STATUS_SUCCESS 

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

1743 fileName = normalize_path(decodeSMBString(recvPacket['Flags2'], comDeleteDirectoryData['DirectoryName'])) 

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

1745 

1746 if not isInFileJail(path, fileName): 

1747 smbServer.log("Path not in current working directory", logging.ERROR) 

1748 errorCode = STATUS_OBJECT_PATH_SYNTAX_BAD 

1749 

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

1751 errorCode = STATUS_NO_SUCH_FILE 

1752 

1753 else: 

1754 try: 

1755 os.rmdir(pathName) 

1756 except OSError as e: 

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

1758 if e.errno == errno.ENOTEMPTY: 

1759 errorCode = STATUS_DIRECTORY_NOT_EMPTY 

1760 else: 

1761 errorCode = STATUS_ACCESS_DENIED 

1762 else: 

1763 errorCode = STATUS_SMB_BAD_TID 

1764 

1765 if errorCode > 0: 

1766 respParameters = b'' 

1767 respData = b'' 

1768 

1769 respSMBCommand['Parameters'] = respParameters 

1770 respSMBCommand['Data'] = respData 

1771 smbServer.setConnectionData(connId, connData) 

1772 

1773 return [respSMBCommand], None, errorCode 

1774 

1775 @staticmethod 

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

1777 connData = smbServer.getConnectionData(connId) 

1778 

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

1780 respParameters = smb.SMBWriteAndXResponse_Parameters() 

1781 respData = b'' 

1782 

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

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

1785 writeAndXData = smb.SMBWriteAndX_Data_Short() 

1786 else: 

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

1788 writeAndXData = smb.SMBWriteAndX_Data() 

1789 writeAndXData['DataLength'] = writeAndX['DataLength'] 

1790 writeAndXData['DataOffset'] = writeAndX['DataOffset'] 

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

1792 

1793 # Get the Tid associated 

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

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

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

1797 errorCode = STATUS_SUCCESS 

1798 try: 

1799 if fileHandle != PIPE_FILE_DESCRIPTOR: 

1800 offset = writeAndX['Offset'] 

1801 if 'HighOffset' in writeAndX.fields: 

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

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

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

1805 os.lseek(fileHandle, offset, 0) 

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

1807 else: 

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

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

1810 

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

1812 respParameters['Available'] = 0xff 

1813 except Exception as e: 

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

1815 errorCode = STATUS_ACCESS_DENIED 

1816 else: 

1817 errorCode = STATUS_INVALID_HANDLE 

1818 else: 

1819 errorCode = STATUS_SMB_BAD_TID 

1820 

1821 if errorCode > 0: 

1822 respParameters = b'' 

1823 respData = b'' 

1824 

1825 respSMBCommand['Parameters'] = respParameters 

1826 respSMBCommand['Data'] = respData 

1827 smbServer.setConnectionData(connId, connData) 

1828 

1829 return [respSMBCommand], None, errorCode 

1830 

1831 @staticmethod 

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

1833 connData = smbServer.getConnectionData(connId) 

1834 

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

1836 respParameters = smb.SMBReadResponse_Parameters() 

1837 respData = smb.SMBReadResponse_Data() 

1838 

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

1840 

1841 # Get the Tid associated 

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

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

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

1845 errorCode = STATUS_SUCCESS 

1846 try: 

1847 if fileHandle != PIPE_FILE_DESCRIPTOR: 

1848 # TODO: Handle big size files 

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

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

1851 else: 

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

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

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

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

1856 respData['Data'] = content 

1857 except Exception as e: 

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

1859 errorCode = STATUS_ACCESS_DENIED 

1860 else: 

1861 errorCode = STATUS_INVALID_HANDLE 

1862 else: 

1863 errorCode = STATUS_SMB_BAD_TID 

1864 

1865 if errorCode > 0: 

1866 respParameters = b'' 

1867 respData = b'' 

1868 

1869 respSMBCommand['Parameters'] = respParameters 

1870 respSMBCommand['Data'] = respData 

1871 smbServer.setConnectionData(connId, connData) 

1872 

1873 return [respSMBCommand], None, errorCode 

1874 

1875 @staticmethod 

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

1877 connData = smbServer.getConnectionData(connId) 

1878 

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

1880 respParameters = smb.SMBReadAndXResponse_Parameters() 

1881 respData = b'' 

1882 

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

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

1885 else: 

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

1887 

1888 # Get the Tid associated 

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

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

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

1892 errorCode = 0 

1893 try: 

1894 if fileHandle != PIPE_FILE_DESCRIPTOR: 

1895 offset = readAndX['Offset'] 

1896 if 'HighOffset' in readAndX.fields: 

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

1898 os.lseek(fileHandle, offset, 0) 

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

1900 else: 

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

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

1903 respParameters['Remaining'] = 0xffff 

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

1905 respParameters['DataOffset'] = 59 

1906 respParameters['DataCount_Hi'] = 0 

1907 respData = content 

1908 except Exception as e: 

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

1910 errorCode = STATUS_ACCESS_DENIED 

1911 else: 

1912 errorCode = STATUS_INVALID_HANDLE 

1913 else: 

1914 errorCode = STATUS_SMB_BAD_TID 

1915 

1916 if errorCode > 0: 

1917 respParameters = b'' 

1918 respData = b'' 

1919 

1920 respSMBCommand['Parameters'] = respParameters 

1921 respSMBCommand['Data'] = respData 

1922 smbServer.setConnectionData(connId, connData) 

1923 

1924 return [respSMBCommand], None, errorCode 

1925 

1926 @staticmethod 

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

1928 connData = smbServer.getConnectionData(connId) 

1929 

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

1931 respParameters = smb.SMBQueryInformationResponse_Parameters() 

1932 respData = b'' 

1933 

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

1935 

1936 # Get the Tid associated 

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

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

1939 fileName = normalize_path(decodeSMBString(recvPacket['Flags2'], queryInformation['FileName'])) 

1940 if not isInFileJail(path, fileName): 

1941 smbServer.log("Path not in current working directory", logging.ERROR) 

1942 errorCode = STATUS_OBJECT_PATH_SYNTAX_BAD 

1943 

1944 else: 

1945 fileSize, lastWriteTime, fileAttributes = queryFsInformation(path, fileName, pktFlags=recvPacket['Flags2']) 

1946 

1947 respParameters['FileSize'] = fileSize 

1948 respParameters['LastWriteTime'] = lastWriteTime 

1949 respParameters['FileAttributes'] = fileAttributes 

1950 errorCode = STATUS_SUCCESS 

1951 else: 

1952 errorCode = STATUS_SMB_BAD_TID 

1953 

1954 if errorCode > 0: 

1955 respParameters = b'' 

1956 respData = b'' 

1957 

1958 respSMBCommand['Parameters'] = respParameters 

1959 respSMBCommand['Data'] = respData 

1960 

1961 smbServer.setConnectionData(connId, connData) 

1962 return [respSMBCommand], None, errorCode 

1963 

1964 @staticmethod 

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

1966 connData = smbServer.getConnectionData(connId) 

1967 

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

1969 respParameters = smb.SMBQueryInformationDiskResponse_Parameters() 

1970 respData = b'' 

1971 

1972 # Get the Tid associated 

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

1974 totalUnits, freeUnits = queryDiskInformation( 

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

1976 

1977 respParameters['TotalUnits'] = totalUnits 

1978 respParameters['BlocksPerUnit'] = 1 

1979 respParameters['BlockSize'] = 1 

1980 respParameters['FreeUnits'] = freeUnits 

1981 errorCode = STATUS_SUCCESS 

1982 else: 

1983 errorCode = STATUS_SMB_BAD_TID 

1984 

1985 if errorCode > 0: 

1986 respData = b'' 

1987 respParameters = b'' 

1988 

1989 respSMBCommand['Parameters'] = respParameters 

1990 respSMBCommand['Data'] = respData 

1991 

1992 smbServer.setConnectionData(connId, connData) 

1993 return [respSMBCommand], None, errorCode 

1994 

1995 @staticmethod 

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

1997 connData = smbServer.getConnectionData(connId) 

1998 

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

2000 respParameters = smb.SMBEchoResponse_Parameters() 

2001 respData = smb.SMBEchoResponse_Data() 

2002 

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

2004 

2005 respParameters['SequenceNumber'] = 1 

2006 respData['Data'] = echoData['Data'] 

2007 

2008 respSMBCommand['Parameters'] = respParameters 

2009 respSMBCommand['Data'] = respData 

2010 

2011 errorCode = STATUS_SUCCESS 

2012 smbServer.setConnectionData(connId, connData) 

2013 return [respSMBCommand], None, errorCode 

2014 

2015 @staticmethod 

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

2017 connData = smbServer.getConnectionData(connId) 

2018 

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

2020 

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

2022 respParameters = b'' 

2023 respData = b'' 

2024 

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

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

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

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

2029 errorCode = STATUS_SUCCESS 

2030 else: 

2031 errorCode = STATUS_SMB_BAD_TID 

2032 

2033 respSMBCommand['Parameters'] = respParameters 

2034 respSMBCommand['Data'] = respData 

2035 

2036 smbServer.setConnectionData(connId, connData) 

2037 return [respSMBCommand], None, errorCode 

2038 

2039 @staticmethod 

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

2041 connData = smbServer.getConnectionData(connId) 

2042 

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

2044 

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

2046 respParameters = b'' 

2047 respData = b'' 

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

2049 errorCode = STATUS_SMB_BAD_UID 

2050 else: 

2051 errorCode = STATUS_SUCCESS 

2052 

2053 respSMBCommand['Parameters'] = respParameters 

2054 respSMBCommand['Data'] = respData 

2055 connData['Uid'] = 0 

2056 connData['Authenticated'] = False 

2057 

2058 smbServer.setConnectionData(connId, connData) 

2059 

2060 return [respSMBCommand], None, errorCode 

2061 

2062 @staticmethod 

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

2064 connData = smbServer.getConnectionData(connId) 

2065 

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

2067 respParameters = smb.SMBQueryInformation2Response_Parameters() 

2068 respData = b'' 

2069 

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

2071 errorCode = 0xFF 

2072 

2073 # Get the Tid associated 

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

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

2076 errorCode = STATUS_SUCCESS 

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

2078 try: 

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

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

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

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

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

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

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

2086 respParameters['FileDataSize'] = size 

2087 respParameters['FileAllocationSize'] = size 

2088 attribs = 0 

2089 if os.path.isdir(pathName): 

2090 attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

2091 if os.path.isfile(pathName): 

2092 attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL 

2093 respParameters['FileAttributes'] = attribs 

2094 except Exception as e: 

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

2096 errorCode = STATUS_ACCESS_DENIED 

2097 else: 

2098 errorCode = STATUS_SMB_BAD_TID 

2099 

2100 if errorCode > 0: 

2101 respParameters = b'' 

2102 respData = b'' 

2103 

2104 respSMBCommand['Parameters'] = respParameters 

2105 respSMBCommand['Data'] = respData 

2106 smbServer.setConnectionData(connId, connData) 

2107 

2108 return [respSMBCommand], None, errorCode 

2109 

2110 @staticmethod 

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

2112 # TODO: Fully implement this 

2113 connData = smbServer.getConnectionData(connId) 

2114 

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

2116 respParameters = smb.SMBNtCreateAndXResponse_Parameters() 

2117 respData = b'' 

2118 

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

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

2121 

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

2123 # respParameters = smb.SMBNtCreateAndXExtendedResponse_Parameters() 

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

2125 

2126 # Get the Tid associated 

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

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

2129 errorCode = STATUS_SUCCESS 

2130 if ntCreateAndXParameters['RootFid'] > 0: 

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

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

2133 else: 

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

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

2136 else: 

2137 path = 'NONE' 

2138 errorCode = STATUS_ACCESS_DENIED 

2139 

2140 deleteOnClose = False 

2141 

2142 fileName = normalize_path(decodeSMBString(recvPacket['Flags2'], ntCreateAndXData['FileName'])) 

2143 if not isInFileJail(path, fileName): 

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

2145 respSMBCommand['Parameters'] = b'' 

2146 respSMBCommand['Data'] = b'' 

2147 return [respSMBCommand], None, STATUS_OBJECT_PATH_SYNTAX_BAD 

2148 

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

2150 createDisposition = ntCreateAndXParameters['Disposition'] 

2151 mode = 0 

2152 

2153 if createDisposition == smb.FILE_SUPERSEDE: 

2154 mode |= os.O_TRUNC | os.O_CREAT 

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

2156 mode |= os.O_TRUNC | os.O_CREAT 

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

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

2159 mode |= os.O_TRUNC 

2160 else: 

2161 errorCode = STATUS_NO_SUCH_FILE 

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

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

2164 mode |= os.O_TRUNC 

2165 else: 

2166 mode |= os.O_TRUNC | os.O_CREAT 

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

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

2169 errorCode = STATUS_OBJECT_NAME_COLLISION 

2170 else: 

2171 mode |= os.O_CREAT 

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

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

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

2175 errorCode = STATUS_NO_SUCH_FILE 

2176 

2177 if errorCode == STATUS_SUCCESS: 

2178 desiredAccess = ntCreateAndXParameters['AccessMask'] 

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

2180 mode |= os.O_RDONLY 

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

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

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

2184 else: 

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

2186 if desiredAccess & smb.GENERIC_ALL: 

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

2188 

2189 createOptions = ntCreateAndXParameters['CreateOptions'] 

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

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

2192 try: 

2193 # Let's create the directory 

2194 os.mkdir(pathName) 

2195 mode = os.O_RDONLY 

2196 except Exception as e: 

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

2198 errorCode = STATUS_ACCESS_DENIED 

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

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

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

2202 # response. 

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

2204 errorCode = STATUS_FILE_IS_A_DIRECTORY 

2205 

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

2207 deleteOnClose = True 

2208 

2209 if errorCode == STATUS_SUCCESS: 

2210 try: 

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

2212 fid = VOID_FILE_DESCRIPTOR 

2213 else: 

2214 if sys.platform == 'win32': 

2215 mode |= os.O_BINARY 

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

2217 fid = PIPE_FILE_DESCRIPTOR 

2218 sock = socket.socket() 

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

2220 else: 

2221 fid = os.open(pathName, mode) 

2222 except Exception as e: 

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

2224 # print e 

2225 fid = 0 

2226 errorCode = STATUS_ACCESS_DENIED 

2227 else: 

2228 errorCode = STATUS_SMB_BAD_TID 

2229 

2230 if errorCode == STATUS_SUCCESS: 

2231 # Simple way to generate a fid 

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

2233 fakefid = 1 

2234 else: 

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

2236 respParameters['Fid'] = fakefid 

2237 respParameters['CreateAction'] = createDisposition 

2238 if fid == PIPE_FILE_DESCRIPTOR: 

2239 respParameters['FileAttributes'] = 0x80 

2240 respParameters['IsDirectory'] = 0 

2241 respParameters['CreateTime'] = 0 

2242 respParameters['LastAccessTime'] = 0 

2243 respParameters['LastWriteTime'] = 0 

2244 respParameters['LastChangeTime'] = 0 

2245 respParameters['AllocationSize'] = 4096 

2246 respParameters['EndOfFile'] = 0 

2247 respParameters['FileType'] = 2 

2248 respParameters['IPCState'] = 0x5ff 

2249 else: 

2250 if os.path.isdir(pathName): 

2251 respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

2252 respParameters['IsDirectory'] = 1 

2253 else: 

2254 respParameters['IsDirectory'] = 0 

2255 respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes'] 

2256 # Let's get this file's information 

2257 respInfo, errorCode = queryPathInformation(path, fileName, level=smb.SMB_QUERY_FILE_ALL_INFO) 

2258 if errorCode == STATUS_SUCCESS: 

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

2260 respParameters['LastAccessTime'] = respInfo['LastAccessTime'] 

2261 respParameters['LastWriteTime'] = respInfo['LastWriteTime'] 

2262 respParameters['LastChangeTime'] = respInfo['LastChangeTime'] 

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

2264 respParameters['AllocationSize'] = respInfo['AllocationSize'] 

2265 respParameters['EndOfFile'] = respInfo['EndOfFile'] 

2266 else: 

2267 respParameters = b'' 

2268 respData = b'' 

2269 

2270 if errorCode == STATUS_SUCCESS: 

2271 # Let's store the fid for the connection 

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

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

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

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

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

2277 if fid == PIPE_FILE_DESCRIPTOR: 

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

2279 else: 

2280 respParameters = b'' 

2281 respData = b'' 

2282 

2283 respSMBCommand['Parameters'] = respParameters 

2284 respSMBCommand['Data'] = respData 

2285 smbServer.setConnectionData(connId, connData) 

2286 

2287 return [respSMBCommand], None, errorCode 

2288 

2289 @staticmethod 

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

2291 connData = smbServer.getConnectionData(connId) 

2292 

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

2294 respParameters = smb.SMBOpenAndXResponse_Parameters() 

2295 respData = b'' 

2296 

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

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

2299 

2300 # Get the Tid associated 

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

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

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

2304 decodeSMBString(recvPacket['Flags2'], 

2305 openAndXData['FileName']), 

2306 openAndXParameters['DesiredAccess'], 

2307 openAndXParameters['FileAttributes'], 

2308 openAndXParameters['OpenMode']) 

2309 else: 

2310 errorCode = STATUS_SMB_BAD_TID 

2311 

2312 if errorCode == STATUS_SUCCESS: 

2313 # Simple way to generate a fid 

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

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

2316 fid = 1 

2317 else: 

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

2319 respParameters['Fid'] = fid 

2320 if mode & os.O_CREAT: 

2321 # File did not exist and was created 

2322 respParameters['Action'] = 0x2 

2323 elif mode & os.O_RDONLY: 

2324 # File existed and was opened 

2325 respParameters['Action'] = 0x1 

2326 elif mode & os.O_APPEND: 

2327 # File existed and was opened 

2328 respParameters['Action'] = 0x1 

2329 else: 

2330 # File existed and was truncated 

2331 respParameters['Action'] = 0x3 

2332 

2333 # Let's store the fid for the connection 

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

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

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

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

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

2339 else: 

2340 respParameters = b'' 

2341 respData = b'' 

2342 

2343 respSMBCommand['Parameters'] = respParameters 

2344 respSMBCommand['Data'] = respData 

2345 smbServer.setConnectionData(connId, connData) 

2346 

2347 return [respSMBCommand], None, errorCode 

2348 

2349 @staticmethod 

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

2351 connData = smbServer.getConnectionData(connId) 

2352 

2353 resp = smb.NewSMBPacket() 

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

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

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

2357 

2358 resp['Tid'] = recvPacket['Tid'] 

2359 resp['Mid'] = recvPacket['Mid'] 

2360 resp['Pid'] = connData['Pid'] 

2361 

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

2363 respParameters = smb.SMBTreeConnectAndXResponse_Parameters() 

2364 respData = smb.SMBTreeConnectAndXResponse_Data() 

2365 

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

2367 

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

2369 respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters() 

2370 

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

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

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

2374 

2375 errorCode = STATUS_SUCCESS 

2376 

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

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

2379 

2380 # Is this a UNC? 

2381 if ntpath.ismount(UNCOrShare): 

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

2383 else: 

2384 path = ntpath.basename(UNCOrShare) 

2385 

2386 share = searchShare(connId, path, smbServer) 

2387 if share is not None: 

2388 # Simple way to generate a Tid 

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

2390 tid = 1 

2391 else: 

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

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

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

2395 resp['Tid'] = tid 

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

2397 else: 

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

2399 errorCode = STATUS_OBJECT_PATH_NOT_FOUND 

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

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

2402 ## 

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

2404 

2405 if path == 'IPC$': 

2406 respData['Service'] = 'IPC' 

2407 else: 

2408 respData['Service'] = path 

2409 respData['PadLen'] = 0 

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

2411 

2412 respSMBCommand['Parameters'] = respParameters 

2413 respSMBCommand['Data'] = respData 

2414 

2415 resp['Uid'] = connData['Uid'] 

2416 resp.addCommand(respSMBCommand) 

2417 

2418 # Sign the packet if needed 

2419 if connData['SignatureEnabled']: 

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

2421 smbServer.setConnectionData(connId, connData) 

2422 

2423 return None, [resp], errorCode 

2424 

2425 @staticmethod 

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

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

2428 

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

2430 

2431 # From [MS-SMB] 

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

2433 # request MUST take the following form 

2434 # [..] 

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

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

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

2438 respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters() 

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

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

2441 sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data() 

2442 sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength'] 

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

2444 connData['Capabilities'] = sessionSetupParameters['Capabilities'] 

2445 

2446 rawNTLM = False 

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

2448 # NEGOTIATE packet 

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

2450 token = blob['MechToken'] 

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

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

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

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

2455 # Nope, do we know it? 

2456 if mechType in MechTypes: 

2457 mechStr = MechTypes[mechType] 

2458 else: 

2459 mechStr = hexlify(mechType) 

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

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

2462 # we just support NTLM. 

2463 # ToDo: Build this into a SPNEGO_NegTokenResp() 

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

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

2466 respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] 

2467 respData['SecurityBlob'] = respToken 

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

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

2470 respSMBCommand['Parameters'] = respParameters 

2471 respSMBCommand['Data'] = respData 

2472 return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED 

2473 

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

2475 # AUTH packet 

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

2477 token = blob['ResponseToken'] 

2478 else: 

2479 # No GSSAPI stuff, raw NTLMSSP 

2480 rawNTLM = True 

2481 token = sessionSetupData['SecurityBlob'] 

2482 

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

2484 # authentication we are, we act on it 

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

2486 

2487 if messageType == 0x01: 

2488 # NEGOTIATE_MESSAGE 

2489 negotiateMessage = ntlm.NTLMAuthNegotiate() 

2490 negotiateMessage.fromString(token) 

2491 # Let's store it in the connection data 

2492 connData['NEGOTIATE_MESSAGE'] = negotiateMessage 

2493 # Let's build the answer flags 

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

2495 

2496 ansFlags = 0 

2497 

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

2499 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56 

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

2501 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128 

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

2503 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH 

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

2505 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 

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

2507 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE 

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

2509 ansFlags |= ntlm.NTLM_NEGOTIATE_OEM 

2510 

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

2512 

2513 # Generate the AV_PAIRS 

2514 av_pairs = ntlm.AV_PAIRS() 

2515 # TODO: Put the proper data from SMBSERVER config 

2516 av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ 

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

2518 av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ 

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

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

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

2522 

2523 challengeMessage = ntlm.NTLMAuthChallenge() 

2524 challengeMessage['flags'] = ansFlags 

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

2526 challengeMessage['domain_max_len'] = challengeMessage['domain_len'] 

2527 challengeMessage['domain_offset'] = 40 + 16 

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

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

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

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

2532 challengeMessage['TargetInfoFields'] = av_pairs 

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

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

2535 challengeMessage['VersionLen'] = 8 

2536 

2537 if rawNTLM is False: 

2538 respToken = SPNEGO_NegTokenResp() 

2539 # accept-incomplete. We want more data 

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

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

2542 

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

2544 else: 

2545 respToken = challengeMessage 

2546 

2547 # Setting the packet to STATUS_MORE_PROCESSING 

2548 errorCode = STATUS_MORE_PROCESSING_REQUIRED 

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

2550 # in the connection's data 

2551 # Picking a fixed value 

2552 # TODO: Manage more UIDs for the same session 

2553 connData['Uid'] = 10 

2554 # Let's store it in the connection data 

2555 connData['CHALLENGE_MESSAGE'] = challengeMessage 

2556 

2557 elif messageType == 0x02: 

2558 # CHALLENGE_MESSAGE 

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

2560 elif messageType == 0x03: 

2561 # AUTHENTICATE_MESSAGE, here we deal with authentication 

2562 authenticateMessage = ntlm.NTLMAuthChallengeResponse() 

2563 authenticateMessage.fromString(token) 

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

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

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

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

2568 # Do we have credentials to check? 

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

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

2571 # Do we have this user's credentials? 

2572 if identity in smbServer.getCredentials(): 

2573 # Process data: 

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

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

2576 

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

2578 authenticateMessage, connData['CHALLENGE_MESSAGE'], 

2579 connData['NEGOTIATE_MESSAGE']) 

2580 

2581 if sessionKey is not None: 

2582 connData['SignatureEnabled'] = False 

2583 connData['SigningSessionKey'] = sessionKey 

2584 connData['SignSequenceNumber'] = 1 

2585 else: 

2586 errorCode = STATUS_LOGON_FAILURE 

2587 else: 

2588 # No credentials provided, let's grant access 

2589 errorCode = STATUS_SUCCESS 

2590 

2591 if errorCode == STATUS_SUCCESS: 

2592 connData['Authenticated'] = True 

2593 respToken = SPNEGO_NegTokenResp() 

2594 # accept-completed 

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

2596 

2597 smbServer.log( 

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

2599 authenticateMessage['user_name'].decode( 

2600 'utf-16le'))) 

2601 # Let's store it in the connection data 

2602 connData['AUTHENTICATE_MESSAGE'] = authenticateMessage 

2603 try: 

2604 jtr_dump_path = smbServer.getJTRdumpPath() 

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

2606 authenticateMessage['user_name'], 

2607 authenticateMessage['domain_name'], 

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

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

2610 if jtr_dump_path != '': 

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

2612 jtr_dump_path) 

2613 except: 

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

2615 else: 

2616 respToken = SPNEGO_NegTokenResp() 

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

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

2619 else: 

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

2621 

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

2623 respData['SecurityBlobLength'] = respParameters['SecurityBlobLength'] 

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

2625 

2626 else: 

2627 # Process Standard Security 

2628 respParameters = smb.SMBSessionSetupAndXResponse_Parameters() 

2629 respData = smb.SMBSessionSetupAndXResponse_Data() 

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

2631 sessionSetupData = smb.SMBSessionSetupAndX_Data() 

2632 sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength'] 

2633 sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength'] 

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

2635 connData['Capabilities'] = sessionSetupParameters['Capabilities'] 

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

2637 # TODO: Manage more UIDs for the same session 

2638 errorCode = STATUS_SUCCESS 

2639 connData['Uid'] = 10 

2640 connData['Authenticated'] = True 

2641 respParameters['Action'] = 0 

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

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

2644 try: 

2645 jtr_dump_path = smbServer.getJTRdumpPath() 

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

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

2648 sessionSetupData['UnicodePwd']) 

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

2650 if jtr_dump_path != '': 

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

2652 except: 

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

2654 

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

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

2657 respSMBCommand['Parameters'] = respParameters 

2658 respSMBCommand['Data'] = respData 

2659 

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

2661 connData['Authenticated'] = True 

2662 # For now, just switching to nobody 

2663 # os.setregid(65534,65534) 

2664 # os.setreuid(65534,65534) 

2665 smbServer.setConnectionData(connId, connData) 

2666 

2667 return [respSMBCommand], None, errorCode 

2668 

2669 @staticmethod 

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

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

2672 connData['Pid'] = recvPacket['Pid'] 

2673 

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

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

2676 

2677 resp = smb.NewSMBPacket() 

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

2679 resp['Pid'] = connData['Pid'] 

2680 resp['Tid'] = recvPacket['Tid'] 

2681 resp['Mid'] = recvPacket['Mid'] 

2682 

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

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

2685 try: 

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

2687 # Let's fill the data for NTLM 

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

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

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

2691 _dialects_data = smb.SMBExtended_Security_Data() 

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

2693 blob = SPNEGO_NegTokenInit() 

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

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

2696 

2697 _dialects_parameters = smb.SMBExtended_Security_Parameters() 

2698 _dialects_parameters[ 

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

2700 _dialects_parameters['ChallengeLength'] = 0 

2701 

2702 else: 

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

2704 _dialects_parameters = smb.SMBNTLMDialect_Parameters() 

2705 _dialects_data = smb.SMBNTLMDialect_Data() 

2706 _dialects_data['Payload'] = '' 

2707 if 'EncryptionKey' in connData: 

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

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

2710 else: 

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

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

2713 _dialects_parameters['ChallengeLength'] = 8 

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

2715 

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

2717 config = smbServer.getServerConfig() 

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

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

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

2721 

2722 _dialects_parameters['DialectIndex'] = index 

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

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

2725 _dialects_parameters['MaxMpxCount'] = 1 

2726 _dialects_parameters['MaxNumberVcs'] = 1 

2727 _dialects_parameters['MaxBufferSize'] = 64000 

2728 _dialects_parameters['MaxRawSize'] = 65536 

2729 _dialects_parameters['SessionKey'] = 0 

2730 _dialects_parameters['LowDateTime'] = 0 

2731 _dialects_parameters['HighDateTime'] = 0 

2732 _dialects_parameters['ServerTimeZone'] = 0 

2733 

2734 respSMBCommand['Data'] = _dialects_data 

2735 respSMBCommand['Parameters'] = _dialects_parameters 

2736 connData['_dialects_data'] = _dialects_data 

2737 connData['_dialects_parameters'] = _dialects_parameters 

2738 

2739 except Exception as e: 

2740 # No NTLM throw an error 

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

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

2743 

2744 smbServer.setConnectionData(connId, connData) 

2745 

2746 resp.addCommand(respSMBCommand) 

2747 

2748 return None, [resp], STATUS_SUCCESS 

2749 

2750 @staticmethod 

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

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

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

2754 packet = smb.NewSMBPacket() 

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

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

2757 packet['Command'] = recvPacket['Command'] 

2758 packet['Pid'] = recvPacket['Pid'] 

2759 packet['Tid'] = recvPacket['Tid'] 

2760 packet['Mid'] = recvPacket['Mid'] 

2761 packet['Uid'] = recvPacket['Uid'] 

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

2763 errorCode = STATUS_NOT_IMPLEMENTED 

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

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

2766 

2767 return None, [packet], errorCode 

2768 

2769 

2770class SMB2Commands: 

2771 @staticmethod 

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

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

2774 

2775 respPacket = smb2.SMB2Packet() 

2776 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR 

2777 respPacket['Status'] = STATUS_SUCCESS 

2778 respPacket['CreditRequestResponse'] = 1 

2779 respPacket['Command'] = smb2.SMB2_NEGOTIATE 

2780 respPacket['SessionID'] = 0 

2781 if isSMB1 is False: 

2782 respPacket['MessageID'] = recvPacket['MessageID'] 

2783 else: 

2784 respPacket['MessageID'] = 0 

2785 respPacket['TreeID'] = 0 

2786 

2787 respSMBCommand = smb2.SMB2Negotiate_Response() 

2788 

2789 respSMBCommand['SecurityMode'] = 1 

2790 if isSMB1 is True: 

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

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

2793 

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

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

2796 respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002 

2797 else: 

2798 # Client does not support SMB2 fallbacking 

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

2800 else: 

2801 respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002 

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

2803 respSMBCommand['Capabilities'] = 0 

2804 respSMBCommand['MaxTransactSize'] = 65536 

2805 respSMBCommand['MaxReadSize'] = 65536 

2806 respSMBCommand['MaxWriteSize'] = 65536 

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

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

2809 respSMBCommand['SecurityBufferOffset'] = 0x80 

2810 

2811 blob = SPNEGO_NegTokenInit() 

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

2813 

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

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

2816 

2817 respPacket['Data'] = respSMBCommand 

2818 

2819 smbServer.setConnectionData(connId, connData) 

2820 

2821 return None, [respPacket], STATUS_SUCCESS 

2822 

2823 @staticmethod 

2824 def smb2SessionSetup(connId, smbServer, recvPacket): 

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

2826 

2827 respSMBCommand = smb2.SMB2SessionSetup_Response() 

2828 

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

2830 

2831 connData['Capabilities'] = sessionSetupData['Capabilities'] 

2832 

2833 securityBlob = sessionSetupData['Buffer'] 

2834 

2835 rawNTLM = False 

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

2837 # NEGOTIATE packet 

2838 blob = SPNEGO_NegTokenInit(securityBlob) 

2839 token = blob['MechToken'] 

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

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

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

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

2844 # Nope, do we know it? 

2845 if mechType in MechTypes: 

2846 mechStr = MechTypes[mechType] 

2847 else: 

2848 mechStr = hexlify(mechType) 

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

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

2851 # we just support NTLM. 

2852 # ToDo: Build this into a SPNEGO_NegTokenResp() 

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

2854 respSMBCommand['SecurityBufferOffset'] = 0x48 

2855 respSMBCommand['SecurityBufferLength'] = len(respToken) 

2856 respSMBCommand['Buffer'] = respToken 

2857 

2858 return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED 

2859 elif struct.unpack('B', securityBlob[0:1])[0] == ASN1_SUPPORTED_MECH: 

2860 # AUTH packet 

2861 blob = SPNEGO_NegTokenResp(securityBlob) 

2862 token = blob['ResponseToken'] 

2863 else: 

2864 # No GSSAPI stuff, raw NTLMSSP 

2865 rawNTLM = True 

2866 token = securityBlob 

2867 

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

2869 # authentication we are, we act on it 

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

2871 

2872 if messageType == 0x01: 

2873 # NEGOTIATE_MESSAGE 

2874 negotiateMessage = ntlm.NTLMAuthNegotiate() 

2875 negotiateMessage.fromString(token) 

2876 # Let's store it in the connection data 

2877 connData['NEGOTIATE_MESSAGE'] = negotiateMessage 

2878 # Let's build the answer flags 

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

2880 

2881 ansFlags = 0 

2882 

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

2884 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56 

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

2886 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128 

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

2888 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH 

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

2890 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY 

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

2892 ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE 

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

2894 ansFlags |= ntlm.NTLM_NEGOTIATE_OEM 

2895 

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

2897 

2898 # Generate the AV_PAIRS 

2899 av_pairs = ntlm.AV_PAIRS() 

2900 # TODO: Put the proper data from SMBSERVER config 

2901 av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ 

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

2903 av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ 

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

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

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

2907 

2908 challengeMessage = ntlm.NTLMAuthChallenge() 

2909 challengeMessage['flags'] = ansFlags 

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

2911 challengeMessage['domain_max_len'] = challengeMessage['domain_len'] 

2912 challengeMessage['domain_offset'] = 40 + 16 

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

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

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

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

2917 challengeMessage['TargetInfoFields'] = av_pairs 

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

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

2920 challengeMessage['VersionLen'] = 8 

2921 

2922 if rawNTLM is False: 

2923 respToken = SPNEGO_NegTokenResp() 

2924 # accept-incomplete. We want more data 

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

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

2927 

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

2929 else: 

2930 respToken = challengeMessage 

2931 

2932 # Setting the packet to STATUS_MORE_PROCESSING 

2933 errorCode = STATUS_MORE_PROCESSING_REQUIRED 

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

2935 # in the connection's data 

2936 # Picking a fixed value 

2937 # TODO: Manage more UIDs for the same session 

2938 connData['Uid'] = random.randint(1, 0xffffffff) 

2939 # Let's store it in the connection data 

2940 connData['CHALLENGE_MESSAGE'] = challengeMessage 

2941 

2942 elif messageType == 0x02: 

2943 # CHALLENGE_MESSAGE 

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

2945 elif messageType == 0x03: 

2946 # AUTHENTICATE_MESSAGE, here we deal with authentication 

2947 authenticateMessage = ntlm.NTLMAuthChallengeResponse() 

2948 authenticateMessage.fromString(token) 

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

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

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

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

2953 

2954 isGuest = False 

2955 isAnonymus = False 

2956 

2957 # TODO: Check the credentials! Now granting permissions 

2958 # Do we have credentials to check? 

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

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

2961 # Do we have this user's credentials? 

2962 if identity in smbServer.getCredentials(): 

2963 # Process data: 

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

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

2966 

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

2968 authenticateMessage, connData['CHALLENGE_MESSAGE'], 

2969 connData['NEGOTIATE_MESSAGE']) 

2970 

2971 if sessionKey is not None: 

2972 connData['SignatureEnabled'] = True 

2973 connData['SigningSessionKey'] = sessionKey 

2974 connData['SignSequenceNumber'] = 1 

2975 else: 

2976 errorCode = STATUS_LOGON_FAILURE 

2977 else: 

2978 # No credentials provided, let's grant access 

2979 if authenticateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_ANONYMOUS: 

2980 isAnonymus = True 

2981 if smbServer._SMBSERVER__anonymousLogon == False: 

2982 errorCode = STATUS_ACCESS_DENIED 

2983 else: 

2984 errorCode = STATUS_SUCCESS 

2985 else: 

2986 isGuest = True 

2987 errorCode = STATUS_SUCCESS 

2988 

2989 if errorCode == STATUS_SUCCESS: 

2990 connData['Authenticated'] = True 

2991 respToken = SPNEGO_NegTokenResp() 

2992 # accept-completed 

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

2994 smbServer.log('User %s\\%s authenticated successfully' % ( 

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

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

2997 # Let's store it in the connection data 

2998 connData['AUTHENTICATE_MESSAGE'] = authenticateMessage 

2999 try: 

3000 jtr_dump_path = smbServer.getJTRdumpPath() 

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

3002 authenticateMessage['user_name'], 

3003 authenticateMessage['domain_name'], 

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

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

3006 if jtr_dump_path != '': 

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

3008 jtr_dump_path) 

3009 except: 

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

3011 

3012 if isGuest: 

3013 respSMBCommand['SessionFlags'] = 1 

3014 elif isAnonymus: 

3015 respSMBCommand['SessionFlags'] = 2 

3016 

3017 else: 

3018 respToken = SPNEGO_NegTokenResp() 

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

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

3021 else: 

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

3023 

3024 respSMBCommand['SecurityBufferOffset'] = 0x48 

3025 respSMBCommand['SecurityBufferLength'] = len(respToken) 

3026 respSMBCommand['Buffer'] = respToken.getData() 

3027 

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

3029 connData['Authenticated'] = True 

3030 # For now, just switching to nobody 

3031 # os.setregid(65534,65534) 

3032 # os.setreuid(65534,65534) 

3033 smbServer.setConnectionData(connId, connData) 

3034 

3035 return [respSMBCommand], None, errorCode 

3036 

3037 @staticmethod 

3038 def smb2TreeConnect(connId, smbServer, recvPacket): 

3039 connData = smbServer.getConnectionData(connId) 

3040 

3041 respPacket = smb2.SMB2Packet() 

3042 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR 

3043 respPacket['Status'] = STATUS_SUCCESS 

3044 respPacket['CreditRequestResponse'] = 1 

3045 respPacket['Command'] = recvPacket['Command'] 

3046 respPacket['SessionID'] = connData['Uid'] 

3047 respPacket['Reserved'] = recvPacket['Reserved'] 

3048 respPacket['MessageID'] = recvPacket['MessageID'] 

3049 respPacket['TreeID'] = recvPacket['TreeID'] 

3050 

3051 respSMBCommand = smb2.SMB2TreeConnect_Response() 

3052 

3053 treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data']) 

3054 

3055 errorCode = STATUS_SUCCESS 

3056 

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

3058 path = recvPacket.getData()[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']] 

3059 UNCOrShare = path.decode('utf-16le') 

3060 

3061 # Is this a UNC? 

3062 if ntpath.ismount(UNCOrShare): 

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

3064 else: 

3065 path = ntpath.basename(UNCOrShare) 

3066 

3067 share = searchShare(connId, path.upper(), smbServer) 

3068 if share is not None: 

3069 # Simple way to generate a Tid 

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

3071 tid = 1 

3072 else: 

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

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

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

3076 respPacket['TreeID'] = tid 

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

3078 else: 

3079 smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR) 

3080 errorCode = STATUS_OBJECT_PATH_NOT_FOUND 

3081 respPacket['Status'] = errorCode 

3082 ## 

3083 

3084 if path.upper() == 'IPC$': 

3085 respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE 

3086 respSMBCommand['ShareFlags'] = 0x30 

3087 else: 

3088 respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK 

3089 respSMBCommand['ShareFlags'] = 0x0 

3090 

3091 respSMBCommand['Capabilities'] = 0 

3092 respSMBCommand['MaximalAccess'] = 0x000f01ff 

3093 

3094 respPacket['Data'] = respSMBCommand 

3095 

3096 # Sign the packet if needed 

3097 if connData['SignatureEnabled']: 

3098 smbServer.signSMBv2(respPacket, connData['SigningSessionKey']) 

3099 smbServer.setConnectionData(connId, connData) 

3100 

3101 return None, [respPacket], errorCode 

3102 

3103 @staticmethod 

3104 def smb2Create(connId, smbServer, recvPacket): 

3105 connData = smbServer.getConnectionData(connId) 

3106 

3107 respSMBCommand = smb2.SMB2Create_Response() 

3108 

3109 ntCreateRequest = smb2.SMB2Create(recvPacket['Data']) 

3110 

3111 respSMBCommand['Buffer'] = b'\x00' 

3112 # Get the Tid associated 

3113 if recvPacket['TreeID'] in connData['ConnectedShares']: 

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

3115 errorCode = STATUS_SUCCESS 

3116 if 'path' in connData['ConnectedShares'][recvPacket['TreeID']]: 

3117 path = connData['ConnectedShares'][recvPacket['TreeID']]['path'] 

3118 else: 

3119 path = 'NONE' 

3120 errorCode = STATUS_ACCESS_DENIED 

3121 

3122 deleteOnClose = False 

3123 

3124 fileName = normalize_path(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le')) 

3125 

3126 if not isInFileJail(path, fileName): 

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

3128 return [smb2.SMB2Error()], None, STATUS_OBJECT_PATH_SYNTAX_BAD 

3129 

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

3131 createDisposition = ntCreateRequest['CreateDisposition'] 

3132 mode = 0 

3133 

3134 if createDisposition == smb2.FILE_SUPERSEDE: 

3135 mode |= os.O_TRUNC | os.O_CREAT 

3136 elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF: 

3137 mode |= os.O_TRUNC | os.O_CREAT 

3138 elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE: 

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

3140 mode |= os.O_TRUNC 

3141 else: 

3142 errorCode = STATUS_NO_SUCH_FILE 

3143 elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF: 

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

3145 mode |= os.O_TRUNC 

3146 else: 

3147 mode |= os.O_TRUNC | os.O_CREAT 

3148 elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE: 

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

3150 errorCode = STATUS_OBJECT_NAME_COLLISION 

3151 else: 

3152 mode |= os.O_CREAT 

3153 elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN: 

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

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

3156 errorCode = STATUS_NO_SUCH_FILE 

3157 

3158 if errorCode == STATUS_SUCCESS: 

3159 desiredAccess = ntCreateRequest['DesiredAccess'] 

3160 if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ): 

3161 mode |= os.O_RDONLY 

3162 if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE): 

3163 if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ): 

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

3165 else: 

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

3167 if desiredAccess & smb2.GENERIC_ALL: 

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

3169 

3170 createOptions = ntCreateRequest['CreateOptions'] 

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

3172 if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE: 

3173 try: 

3174 # Let's create the directory 

3175 os.mkdir(pathName) 

3176 mode = os.O_RDONLY 

3177 except Exception as e: 

3178 smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName, mode, e), logging.ERROR) 

3179 errorCode = STATUS_ACCESS_DENIED 

3180 if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE: 

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

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

3183 # response. 

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

3185 errorCode = STATUS_FILE_IS_A_DIRECTORY 

3186 

3187 if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE: 

3188 deleteOnClose = True 

3189 

3190 if errorCode == STATUS_SUCCESS: 

3191 try: 

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

3193 fid = VOID_FILE_DESCRIPTOR 

3194 else: 

3195 if sys.platform == 'win32': 

3196 mode |= os.O_BINARY 

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

3198 fid = PIPE_FILE_DESCRIPTOR 

3199 sock = socket.socket() 

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

3201 else: 

3202 fid = os.open(pathName, mode) 

3203 except Exception as e: 

3204 smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName, mode, e), logging.ERROR) 

3205 # print e 

3206 fid = 0 

3207 errorCode = STATUS_ACCESS_DENIED 

3208 else: 

3209 errorCode = STATUS_SMB_BAD_TID 

3210 

3211 if errorCode == STATUS_SUCCESS: 

3212 # Simple way to generate a fid 

3213 fakefid = uuid.generate() 

3214 

3215 respSMBCommand['FileID'] = fakefid 

3216 respSMBCommand['CreateAction'] = createDisposition 

3217 

3218 if fid == PIPE_FILE_DESCRIPTOR: 

3219 respSMBCommand['CreationTime'] = 0 

3220 respSMBCommand['LastAccessTime'] = 0 

3221 respSMBCommand['LastWriteTime'] = 0 

3222 respSMBCommand['ChangeTime'] = 0 

3223 respSMBCommand['AllocationSize'] = 4096 

3224 respSMBCommand['EndOfFile'] = 0 

3225 respSMBCommand['FileAttributes'] = 0x80 

3226 

3227 else: 

3228 if os.path.isdir(pathName): 

3229 respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY 

3230 else: 

3231 respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes'] 

3232 # Let's get this file's information 

3233 respInfo, errorCode = queryPathInformation(path, fileName, level=smb.SMB_QUERY_FILE_ALL_INFO) 

3234 if errorCode == STATUS_SUCCESS: 

3235 respSMBCommand['CreationTime'] = respInfo['CreationTime'] 

3236 respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime'] 

3237 respSMBCommand['LastWriteTime'] = respInfo['LastWriteTime'] 

3238 respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime'] 

3239 respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes'] 

3240 respSMBCommand['AllocationSize'] = respInfo['AllocationSize'] 

3241 respSMBCommand['EndOfFile'] = respInfo['EndOfFile'] 

3242 

3243 if errorCode == STATUS_SUCCESS: 

3244 # Let's store the fid for the connection 

3245 # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode)) 

3246 connData['OpenedFiles'][fakefid] = {} 

3247 connData['OpenedFiles'][fakefid]['FileHandle'] = fid 

3248 connData['OpenedFiles'][fakefid]['FileName'] = pathName 

3249 connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose 

3250 connData['OpenedFiles'][fakefid]['Open'] = {} 

3251 connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0 

3252 connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = '' 

3253 if fid == PIPE_FILE_DESCRIPTOR: 

3254 connData['OpenedFiles'][fakefid]['Socket'] = sock 

3255 else: 

3256 respSMBCommand = smb2.SMB2Error() 

3257 

3258 if errorCode == STATUS_SUCCESS: 

3259 connData['LastRequest']['SMB2_CREATE'] = respSMBCommand 

3260 smbServer.setConnectionData(connId, connData) 

3261 

3262 return [respSMBCommand], None, errorCode 

3263 

3264 @staticmethod 

3265 def smb2Close(connId, smbServer, recvPacket): 

3266 connData = smbServer.getConnectionData(connId) 

3267 

3268 respSMBCommand = smb2.SMB2Close_Response() 

3269 

3270 closeRequest = smb2.SMB2Close(recvPacket['Data']) 

3271 

3272 if closeRequest['FileID'].getData() == b'\xff' * 16: 

3273 # Let's take the data from the lastRequest 

3274 if 'SMB2_CREATE' in connData['LastRequest']: 

3275 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3276 else: 

3277 fileID = closeRequest['FileID'].getData() 

3278 else: 

3279 fileID = closeRequest['FileID'].getData() 

3280 

3281 # Get the Tid associated 

3282 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3283 if fileID in connData['OpenedFiles']: 

3284 errorCode = STATUS_SUCCESS 

3285 fileHandle = connData['OpenedFiles'][fileID]['FileHandle'] 

3286 pathName = connData['OpenedFiles'][fileID]['FileName'] 

3287 infoRecord = None 

3288 try: 

3289 if fileHandle == PIPE_FILE_DESCRIPTOR: 

3290 connData['OpenedFiles'][fileID]['Socket'].close() 

3291 elif fileHandle != VOID_FILE_DESCRIPTOR: 

3292 os.close(fileHandle) 

3293 infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), 

3294 smb2.SMB2_FILE_NETWORK_OPEN_INFO) 

3295 except Exception as e: 

3296 smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR) 

3297 errorCode = STATUS_INVALID_HANDLE 

3298 else: 

3299 # Check if the file was marked for removal 

3300 if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True: 

3301 try: 

3302 if os.path.isdir(pathName): 

3303 shutil.rmtree(connData['OpenedFiles'][fileID]['FileName']) 

3304 else: 

3305 os.remove(connData['OpenedFiles'][fileID]['FileName']) 

3306 except Exception as e: 

3307 smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR) 

3308 errorCode = STATUS_ACCESS_DENIED 

3309 

3310 # Now fill out the response 

3311 if infoRecord is not None: 

3312 respSMBCommand['CreationTime'] = infoRecord['CreationTime'] 

3313 respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime'] 

3314 respSMBCommand['LastWriteTime'] = infoRecord['LastWriteTime'] 

3315 respSMBCommand['ChangeTime'] = infoRecord['ChangeTime'] 

3316 respSMBCommand['AllocationSize'] = infoRecord['AllocationSize'] 

3317 respSMBCommand['EndofFile'] = infoRecord['EndOfFile'] 

3318 respSMBCommand['FileAttributes'] = infoRecord['FileAttributes'] 

3319 if errorCode == STATUS_SUCCESS: 

3320 del (connData['OpenedFiles'][fileID]) 

3321 else: 

3322 errorCode = STATUS_INVALID_HANDLE 

3323 else: 

3324 errorCode = STATUS_SMB_BAD_TID 

3325 

3326 smbServer.setConnectionData(connId, connData) 

3327 return [respSMBCommand], None, errorCode 

3328 

3329 @staticmethod 

3330 def smb2QueryInfo(connId, smbServer, recvPacket): 

3331 connData = smbServer.getConnectionData(connId) 

3332 

3333 respSMBCommand = smb2.SMB2QueryInfo_Response() 

3334 

3335 queryInfo = smb2.SMB2QueryInfo(recvPacket['Data']) 

3336 

3337 errorCode = STATUS_SUCCESS 

3338 

3339 respSMBCommand['OutputBufferOffset'] = 0x48 

3340 respSMBCommand['Buffer'] = b'\x00' 

3341 

3342 if queryInfo['FileID'].getData() == b'\xff' * 16: 

3343 # Let's take the data from the lastRequest 

3344 if 'SMB2_CREATE' in connData['LastRequest']: 

3345 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3346 else: 

3347 fileID = queryInfo['FileID'].getData() 

3348 else: 

3349 fileID = queryInfo['FileID'].getData() 

3350 

3351 # Get the Tid associated 

3352 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3353 if fileID in connData['OpenedFiles']: 

3354 fileName = connData['OpenedFiles'][fileID]['FileName'] 

3355 

3356 if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE: 

3357 if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO: 

3358 # No need to call queryFileInformation, we have the data here 

3359 infoRecord = smb2.FILE_INTERNAL_INFORMATION() 

3360 infoRecord['IndexNumber'] = fileID 

3361 else: 

3362 infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), 

3363 os.path.basename(fileName), 

3364 queryInfo['FileInfoClass']) 

3365 elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM: 

3366 if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_EA_INFO: 

3367 infoRecord = b'\x00' * 4 

3368 else: 

3369 infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), 

3370 queryInfo['FileInfoClass']) 

3371 elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY: 

3372 # Failing for now, until we support it 

3373 infoRecord = None 

3374 errorCode = STATUS_ACCESS_DENIED 

3375 else: 

3376 smbServer.log("queryInfo not supported (%x)" % queryInfo['InfoType'], logging.ERROR) 

3377 

3378 if infoRecord is not None: 

3379 respSMBCommand['OutputBufferLength'] = len(infoRecord) 

3380 respSMBCommand['Buffer'] = infoRecord 

3381 else: 

3382 errorCode = STATUS_INVALID_HANDLE 

3383 else: 

3384 errorCode = STATUS_SMB_BAD_TID 

3385 

3386 smbServer.setConnectionData(connId, connData) 

3387 return [respSMBCommand], None, errorCode 

3388 

3389 @staticmethod 

3390 def smb2SetInfo(connId, smbServer, recvPacket): 

3391 connData = smbServer.getConnectionData(connId) 

3392 

3393 respSMBCommand = smb2.SMB2SetInfo_Response() 

3394 

3395 setInfo = smb2.SMB2SetInfo(recvPacket['Data']) 

3396 

3397 errorCode = STATUS_SUCCESS 

3398 

3399 if setInfo['FileID'].getData() == b'\xff' * 16: 

3400 # Let's take the data from the lastRequest 

3401 if 'SMB2_CREATE' in connData['LastRequest']: 

3402 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3403 else: 

3404 fileID = setInfo['FileID'].getData() 

3405 else: 

3406 fileID = setInfo['FileID'].getData() 

3407 

3408 # Get the Tid associated 

3409 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3410 path = connData['ConnectedShares'][recvPacket['TreeID']]['path'] 

3411 if fileID in connData['OpenedFiles']: 

3412 pathName = connData['OpenedFiles'][fileID]['FileName'] 

3413 

3414 if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE: 

3415 # The file information is being set 

3416 informationLevel = setInfo['FileInfoClass'] 

3417 if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO: 

3418 infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer']) 

3419 if infoRecord['DeletePending'] > 0: 

3420 # Mark this file for removal after closed 

3421 connData['OpenedFiles'][fileID]['DeleteOnClose'] = True 

3422 elif informationLevel == smb2.SMB2_FILE_BASIC_INFO: 

3423 infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer']) 

3424 # Creation time won't be set, the other ones we play with. 

3425 atime = infoRecord['LastWriteTime'] 

3426 if atime == 0: 

3427 atime = -1 

3428 else: 

3429 atime = getUnixTime(atime) 

3430 mtime = infoRecord['ChangeTime'] 

3431 if mtime == 0: 

3432 mtime = -1 

3433 else: 

3434 mtime = getUnixTime(mtime) 

3435 if atime > 0 and mtime > 0: 

3436 os.utime(pathName, (atime, mtime)) 

3437 elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO: 

3438 fileHandle = connData['OpenedFiles'][fileID]['FileHandle'] 

3439 infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer']) 

3440 if infoRecord['EndOfFile'] > 0: 

3441 os.lseek(fileHandle, infoRecord['EndOfFile'] - 1, 0) 

3442 os.write(fileHandle, b'\x00') 

3443 elif informationLevel == smb2.SMB2_FILE_RENAME_INFO: 

3444 renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer']) 

3445 newFileName = normalize_path(renameInfo['FileName'].decode('utf-16le')) 

3446 newPathName = os.path.join(path, newFileName) 

3447 if not isInFileJail(path, newFileName): 

3448 smbServer.log("Path not in current working directory", logging.ERROR) 

3449 return [smb2.SMB2Error()], None, STATUS_OBJECT_PATH_SYNTAX_BAD 

3450 

3451 if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName): 

3452 return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION 

3453 try: 

3454 os.rename(pathName, newPathName) 

3455 connData['OpenedFiles'][fileID]['FileName'] = newPathName 

3456 except Exception as e: 

3457 smbServer.log("smb2SetInfo: %s" % e, logging.ERROR) 

3458 errorCode = STATUS_ACCESS_DENIED 

3459 else: 

3460 smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR) 

3461 # UNSUPPORTED 

3462 errorCode = STATUS_NOT_SUPPORTED 

3463 # elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM: 

3464 # # The underlying object store information is being set. 

3465 # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass']) 

3466 # elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY: 

3467 # # The security information is being set. 

3468 # # Failing for now, until we support it 

3469 # infoRecord = None 

3470 # errorCode = STATUS_ACCESS_DENIED 

3471 # elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA: 

3472 # # The underlying object store quota information is being set. 

3473 # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass']) 

3474 else: 

3475 smbServer.log("setInfo not supported (%x)" % setInfo['InfoType'], logging.ERROR) 

3476 

3477 else: 

3478 errorCode = STATUS_INVALID_HANDLE 

3479 else: 

3480 errorCode = STATUS_SMB_BAD_TID 

3481 

3482 smbServer.setConnectionData(connId, connData) 

3483 return [respSMBCommand], None, errorCode 

3484 

3485 @staticmethod 

3486 def smb2Write(connId, smbServer, recvPacket): 

3487 connData = smbServer.getConnectionData(connId) 

3488 

3489 respSMBCommand = smb2.SMB2Write_Response() 

3490 writeRequest = smb2.SMB2Write(recvPacket['Data']) 

3491 

3492 respSMBCommand['Buffer'] = b'\x00' 

3493 

3494 if writeRequest['FileID'].getData() == b'\xff' * 16: 

3495 # Let's take the data from the lastRequest 

3496 if 'SMB2_CREATE' in connData['LastRequest']: 

3497 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3498 else: 

3499 fileID = writeRequest['FileID'].getData() 

3500 else: 

3501 fileID = writeRequest['FileID'].getData() 

3502 

3503 # Get the Tid associated 

3504 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3505 if fileID in connData['OpenedFiles']: 

3506 fileHandle = connData['OpenedFiles'][fileID]['FileHandle'] 

3507 errorCode = STATUS_SUCCESS 

3508 try: 

3509 if fileHandle != PIPE_FILE_DESCRIPTOR: 

3510 offset = writeRequest['Offset'] 

3511 # If we're trying to write past the file end we just skip the write call (Vista does this) 

3512 if os.lseek(fileHandle, 0, 2) >= offset: 

3513 os.lseek(fileHandle, offset, 0) 

3514 os.write(fileHandle, writeRequest['Buffer']) 

3515 else: 

3516 sock = connData['OpenedFiles'][fileID]['Socket'] 

3517 sock.send(writeRequest['Buffer']) 

3518 

3519 respSMBCommand['Count'] = writeRequest['Length'] 

3520 respSMBCommand['Remaining'] = 0xff 

3521 except Exception as e: 

3522 smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR) 

3523 errorCode = STATUS_ACCESS_DENIED 

3524 else: 

3525 errorCode = STATUS_INVALID_HANDLE 

3526 else: 

3527 errorCode = STATUS_SMB_BAD_TID 

3528 

3529 smbServer.setConnectionData(connId, connData) 

3530 return [respSMBCommand], None, errorCode 

3531 

3532 @staticmethod 

3533 def smb2Read(connId, smbServer, recvPacket): 

3534 connData = smbServer.getConnectionData(connId) 

3535 

3536 respSMBCommand = smb2.SMB2Read_Response() 

3537 readRequest = smb2.SMB2Read(recvPacket['Data']) 

3538 

3539 respSMBCommand['Buffer'] = b'\x00' 

3540 

3541 if readRequest['FileID'].getData() == b'\xff' * 16: 

3542 # Let's take the data from the lastRequest 

3543 if 'SMB2_CREATE' in connData['LastRequest']: 

3544 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3545 else: 

3546 fileID = readRequest['FileID'].getData() 

3547 else: 

3548 fileID = readRequest['FileID'].getData() 

3549 

3550 # Get the Tid associated 

3551 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3552 if fileID in connData['OpenedFiles']: 

3553 fileHandle = connData['OpenedFiles'][fileID]['FileHandle'] 

3554 errorCode = 0 

3555 try: 

3556 if fileHandle != PIPE_FILE_DESCRIPTOR: 

3557 offset = readRequest['Offset'] 

3558 os.lseek(fileHandle, offset, 0) 

3559 content = os.read(fileHandle, readRequest['Length']) 

3560 else: 

3561 sock = connData['OpenedFiles'][fileID]['Socket'] 

3562 content = sock.recv(readRequest['Length']) 

3563 

3564 respSMBCommand['DataOffset'] = 0x50 

3565 respSMBCommand['DataLength'] = len(content) 

3566 respSMBCommand['DataRemaining'] = 0 

3567 respSMBCommand['Buffer'] = content 

3568 except Exception as e: 

3569 smbServer.log('SMB2_READ: %s ' % e, logging.ERROR) 

3570 errorCode = STATUS_ACCESS_DENIED 

3571 else: 

3572 errorCode = STATUS_INVALID_HANDLE 

3573 else: 

3574 errorCode = STATUS_SMB_BAD_TID 

3575 

3576 smbServer.setConnectionData(connId, connData) 

3577 return [respSMBCommand], None, errorCode 

3578 

3579 @staticmethod 

3580 def smb2Flush(connId, smbServer, recvPacket): 

3581 connData = smbServer.getConnectionData(connId) 

3582 

3583 respSMBCommand = smb2.SMB2Flush_Response() 

3584 flushRequest = smb2.SMB2Flush(recvPacket['Data']) 

3585 

3586 # Get the Tid associated 

3587 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3588 if flushRequest['FileID'].getData() in connData['OpenedFiles']: 

3589 fileHandle = connData['OpenedFiles'][flushRequest['FileID'].getData()]['FileHandle'] 

3590 errorCode = STATUS_SUCCESS 

3591 try: 

3592 os.fsync(fileHandle) 

3593 except Exception as e: 

3594 smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR) 

3595 errorCode = STATUS_ACCESS_DENIED 

3596 else: 

3597 errorCode = STATUS_INVALID_HANDLE 

3598 else: 

3599 errorCode = STATUS_SMB_BAD_TID 

3600 

3601 smbServer.setConnectionData(connId, connData) 

3602 return [respSMBCommand], None, errorCode 

3603 

3604 @staticmethod 

3605 def smb2QueryDirectory(connId, smbServer, recvPacket): 

3606 connData = smbServer.getConnectionData(connId) 

3607 respSMBCommand = smb2.SMB2QueryDirectory_Response() 

3608 queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data']) 

3609 

3610 respSMBCommand['Buffer'] = b'\x00' 

3611 

3612 # The server MUST locate the tree connection, as specified in section 3.3.5.2.11. 

3613 if (recvPacket['TreeID'] in connData['ConnectedShares']) is False: 

3614 return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED 

3615 

3616 # Next, the server MUST locate the open for the directory to be queried 

3617 # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED 

3618 if queryDirectoryRequest['FileID'].getData() == b'\xff' * 16: 

3619 # Let's take the data from the lastRequest 

3620 if 'SMB2_CREATE' in connData['LastRequest']: 

3621 fileID = connData['LastRequest']['SMB2_CREATE']['FileID'] 

3622 else: 

3623 fileID = queryDirectoryRequest['FileID'].getData() 

3624 else: 

3625 fileID = queryDirectoryRequest['FileID'].getData() 

3626 

3627 if (fileID in connData['OpenedFiles']) is False: 

3628 return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED 

3629 

3630 # If the open is not an open to a directory, the request MUST be failed 

3631 # with STATUS_INVALID_PARAMETER. 

3632 if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False: 

3633 return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER 

3634 

3635 # If any other information class is specified in the FileInformationClass 

3636 # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the 

3637 # operation with STATUS_INVALID_INFO_CLASS. 

3638 if queryDirectoryRequest['FileInformationClass'] not in ( 

3639 smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, 

3640 smb2.FILEID_FULL_DIRECTORY_INFORMATION, 

3641 smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, 

3642 smb2.FILENAMES_INFORMATION): 

3643 return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS 

3644 

3645 # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY 

3646 # Request, the server SHOULD<326> set Open.EnumerationLocation to 0 

3647 # and Open.EnumerationSearchPattern to an empty string. 

3648 if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN: 

3649 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0 

3650 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = '' 

3651 

3652 # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2 

3653 # QUERY_DIRECTORY Request, the server MUST set 

3654 # Open.EnumerationLocation to 0. 

3655 if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS: 

3656 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0 

3657 

3658 # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern 

3659 # is an empty string, then Open.EnumerationSearchPattern MUST be set 

3660 # to the search pattern specified in the SMB2 QUERY_DIRECTORY by 

3661 # FileNameOffset and FileNameLength. If FileNameLength is 0, the server 

3662 # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries. 

3663 

3664 pattern = queryDirectoryRequest['Buffer'].decode('utf-16le') 

3665 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \ 

3666 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '': 

3667 if pattern == '': 

3668 pattern = '*' 

3669 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern 

3670 

3671 # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero, 

3672 # the server MUST set Open.EnumerationSearchPattern to the search pattern 

3673 # specified in the request by FileNameOffset and FileNameLength. 

3674 if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \ 

3675 queryDirectoryRequest['FileNameLength'] > 0: 

3676 connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern 

3677 

3678 pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']), pattern) 

3679 searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName), 

3680 os.path.basename(pathName), 

3681 queryDirectoryRequest['FileInformationClass'], 

3682 smb.ATTR_DIRECTORY, isSMB2=True) 

3683 

3684 if errorCode != STATUS_SUCCESS: 

3685 return [smb2.SMB2Error()], None, errorCode 

3686 

3687 if searchCount > 2 and pattern == '*': 

3688 # strip . and .. 

3689 searchCount -= 2 

3690 searchResult = searchResult[2:] 

3691 

3692 if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0: 

3693 return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE 

3694 

3695 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0: 

3696 return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES 

3697 

3698 totalData = 0 

3699 respData = b'' 

3700 for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount): 

3701 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1 

3702 if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY: 

3703 # If single entry is requested we must clear the NextEntryOffset 

3704 searchResult[nItem]['NextEntryOffset'] = 0 

3705 data = searchResult[nItem].getData() 

3706 lenData = len(data) 

3707 padLen = (8 - (lenData % 8)) % 8 

3708 

3709 if (totalData + lenData) >= queryDirectoryRequest['OutputBufferLength']: 

3710 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1 

3711 break 

3712 else: 

3713 respData += data + b'\x00' * padLen 

3714 totalData += lenData + padLen 

3715 

3716 if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY: 

3717 break 

3718 

3719 if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount: 

3720 connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1 

3721 

3722 respSMBCommand['OutputBufferOffset'] = 0x48 

3723 respSMBCommand['OutputBufferLength'] = totalData 

3724 respSMBCommand['Buffer'] = respData 

3725 

3726 smbServer.setConnectionData(connId, connData) 

3727 return [respSMBCommand], None, errorCode 

3728 

3729 @staticmethod 

3730 def smb2ChangeNotify(connId, smbServer, recvPacket): 

3731 

3732 return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED 

3733 

3734 @staticmethod 

3735 def smb2Echo(connId, smbServer, recvPacket): 

3736 

3737 respSMBCommand = smb2.SMB2Echo_Response() 

3738 

3739 return [respSMBCommand], None, STATUS_SUCCESS 

3740 

3741 @staticmethod 

3742 def smb2TreeDisconnect(connId, smbServer, recvPacket): 

3743 connData = smbServer.getConnectionData(connId) 

3744 

3745 respSMBCommand = smb2.SMB2TreeDisconnect_Response() 

3746 

3747 # Get the Tid associated 

3748 if recvPacket['TreeID'] in connData['ConnectedShares']: 

3749 smbServer.log("Disconnecting Share(%d:%s)" % ( 

3750 recvPacket['TreeID'], connData['ConnectedShares'][recvPacket['TreeID']]['shareName'])) 

3751 del (connData['ConnectedShares'][recvPacket['TreeID']]) 

3752 errorCode = STATUS_SUCCESS 

3753 else: 

3754 errorCode = STATUS_SMB_BAD_TID 

3755 

3756 smbServer.setConnectionData(connId, connData) 

3757 return [respSMBCommand], None, errorCode 

3758 

3759 @staticmethod 

3760 def smb2Logoff(connId, smbServer, recvPacket): 

3761 connData = smbServer.getConnectionData(connId) 

3762 

3763 respSMBCommand = smb2.SMB2Logoff_Response() 

3764 

3765 if recvPacket['SessionID'] != connData['Uid']: 

3766 # STATUS_SMB_BAD_UID 

3767 errorCode = STATUS_SMB_BAD_UID 

3768 else: 

3769 errorCode = STATUS_SUCCESS 

3770 

3771 connData['Uid'] = 0 

3772 connData['Authenticated'] = False 

3773 

3774 smbServer.setConnectionData(connId, connData) 

3775 return [respSMBCommand], None, errorCode 

3776 

3777 @staticmethod 

3778 def smb2Ioctl(connId, smbServer, recvPacket): 

3779 connData = smbServer.getConnectionData(connId) 

3780 

3781 respSMBCommand = smb2.SMB2Ioctl_Response() 

3782 ioctlRequest = smb2.SMB2Ioctl(recvPacket['Data']) 

3783 

3784 ioctls = smbServer.getIoctls() 

3785 if ioctlRequest['CtlCode'] in ioctls: 

3786 outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest) 

3787 if errorCode == STATUS_SUCCESS: 

3788 respSMBCommand['CtlCode'] = ioctlRequest['CtlCode'] 

3789 respSMBCommand['FileID'] = ioctlRequest['FileID'] 

3790 respSMBCommand['InputOffset'] = 0 

3791 respSMBCommand['InputCount'] = 0 

3792 respSMBCommand['OutputOffset'] = 0x70 

3793 respSMBCommand['OutputCount'] = len(outputData) 

3794 respSMBCommand['Flags'] = 0 

3795 respSMBCommand['Buffer'] = outputData 

3796 else: 

3797 respSMBCommand = outputData 

3798 else: 

3799 smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'], logging.DEBUG) 

3800 errorCode = STATUS_INVALID_DEVICE_REQUEST 

3801 respSMBCommand = smb2.SMB2Error() 

3802 

3803 smbServer.setConnectionData(connId, connData) 

3804 return [respSMBCommand], None, errorCode 

3805 

3806 @staticmethod 

3807 def smb2Lock(connId, smbServer, recvPacket): 

3808 connData = smbServer.getConnectionData(connId) 

3809 

3810 respSMBCommand = smb2.SMB2Lock_Response() 

3811 

3812 # I'm actually doing nothing.. just make MacOS happy ;) 

3813 errorCode = STATUS_SUCCESS 

3814 

3815 smbServer.setConnectionData(connId, connData) 

3816 return [respSMBCommand], None, errorCode 

3817 

3818 @staticmethod 

3819 def smb2Cancel(connId, smbServer, recvPacket): 

3820 # I'm actually doing nothing 

3821 return [smb2.SMB2Error()], None, STATUS_CANCELLED 

3822 

3823 @staticmethod 

3824 def default(connId, smbServer, recvPacket): 

3825 # By default we return an SMB Packet with error not implemented 

3826 smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'], logging.DEBUG) 

3827 return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED 

3828 

3829 

3830class Ioctls: 

3831 @staticmethod 

3832 def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest): 

3833 return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED 

3834 

3835 @staticmethod 

3836 def fsctlPipeTransceive(connId, smbServer, ioctlRequest): 

3837 connData = smbServer.getConnectionData(connId) 

3838 

3839 ioctlResponse = '' 

3840 

3841 if ioctlRequest['FileID'].getData() in connData['OpenedFiles']: 

3842 fileHandle = connData['OpenedFiles'][ioctlRequest['FileID'].getData()]['FileHandle'] 

3843 errorCode = STATUS_SUCCESS 

3844 try: 

3845 if fileHandle != PIPE_FILE_DESCRIPTOR: 

3846 errorCode = STATUS_INVALID_DEVICE_REQUEST 

3847 else: 

3848 sock = connData['OpenedFiles'][ioctlRequest['FileID'].getData()]['Socket'] 

3849 sock.sendall(ioctlRequest['Buffer']) 

3850 ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse']) 

3851 except Exception as e: 

3852 smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR) 

3853 errorCode = STATUS_ACCESS_DENIED 

3854 else: 

3855 errorCode = STATUS_INVALID_DEVICE_REQUEST 

3856 

3857 smbServer.setConnectionData(connId, connData) 

3858 return ioctlResponse, errorCode 

3859 

3860 @staticmethod 

3861 def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest): 

3862 connData = smbServer.getConnectionData(connId) 

3863 

3864 errorCode = STATUS_SUCCESS 

3865 

3866 validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer']) 

3867 validateNegotiateInfoResponse = smb2.VALIDATE_NEGOTIATE_INFO_RESPONSE() 

3868 validateNegotiateInfoResponse['Capabilities'] = 0 

3869 validateNegotiateInfoResponse['Guid'] = b'A' * 16 

3870 validateNegotiateInfoResponse['SecurityMode'] = 1 

3871 validateNegotiateInfoResponse['Dialect'] = smb2.SMB2_DIALECT_002 

3872 

3873 smbServer.setConnectionData(connId, connData) 

3874 return validateNegotiateInfoResponse.getData(), errorCode 

3875 

3876 

3877class SMBSERVERHandler(socketserver.BaseRequestHandler): 

3878 def __init__(self, request, client_address, server, select_poll=False): 

3879 self.__SMB = server 

3880 # In case of AF_INET6 the client_address contains 4 items, ignore the last 2 

3881 self.__ip, self.__port = client_address[:2] 

3882 self.__request = request 

3883 self.__connId = threading.current_thread().name 

3884 self.__timeOut = 60 * 5 

3885 self.__select_poll = select_poll 

3886 # self.__connId = os.getpid() 

3887 socketserver.BaseRequestHandler.__init__(self, request, client_address, server) 

3888 

3889 def handle(self): 

3890 self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port)) 

3891 self.__SMB.addConnection(self.__connId, self.__ip, self.__port) 

3892 while True: 

3893 try: 

3894 # First of all let's get the NETBIOS packet 

3895 session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(), 'HOST', self.__ip, sess_port=self.__port, 

3896 sock=self.__request, select_poll=self.__select_poll) 

3897 try: 

3898 p = session.recv_packet(self.__timeOut) 

3899 except nmb.NetBIOSTimeout: 

3900 raise 

3901 except nmb.NetBIOSError: 

3902 break 

3903 

3904 if p.get_type() == nmb.NETBIOS_SESSION_REQUEST: 

3905 # Someone is requesting a session, we're gonna accept them all :) 

3906 _, rn, my = p.get_trailer().split(b' ') 

3907 remote_name = nmb.decode_name(b'\x20' + rn) 

3908 myname = nmb.decode_name(b'\x20' + my) 

3909 self.__SMB.log( 

3910 "NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1])) 

3911 r = nmb.NetBIOSSessionPacket() 

3912 r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE) 

3913 r.set_trailer(p.get_trailer()) 

3914 self.__request.send(r.rawData()) 

3915 else: 

3916 resp = self.__SMB.processRequest(self.__connId, p.get_trailer()) 

3917 # Send all the packets received. Except for big transactions this should be 

3918 # a single packet 

3919 for i in resp: 

3920 if hasattr(i, 'getData'): 

3921 session.send_packet(i.getData()) 

3922 else: 

3923 session.send_packet(i) 

3924 except Exception as e: 

3925 self.__SMB.log("Handle: %s" % e) 

3926 # import traceback 

3927 # traceback.print_exc() 

3928 break 

3929 

3930 def finish(self): 

3931 # Thread/process is dying, we should tell the main SMB thread to remove all this thread data 

3932 self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port)) 

3933 self.__SMB.removeConnection(self.__connId) 

3934 return socketserver.BaseRequestHandler.finish(self) 

3935 

3936 

3937class SMBSERVER(socketserver.ThreadingMixIn, socketserver.TCPServer): 

3938 # class SMBSERVER(socketserver.ForkingMixIn, socketserver.TCPServer): 

3939 def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser=None): 

3940 socketserver.TCPServer.allow_reuse_address = True 

3941 socketserver.TCPServer.__init__(self, server_address, handler_class) 

3942 

3943 # Server name and OS to be presented whenever is necessary 

3944 self.__serverName = '' 

3945 self.__serverOS = '' 

3946 self.__serverDomain = '' 

3947 self.__challenge = '' 

3948 self.__log = None 

3949 

3950 # Our ConfigParser data 

3951 self.__serverConfig = config_parser 

3952 

3953 # Our credentials to be used during the server's lifetime 

3954 self.__credentials = {} 

3955 

3956 # Our log file 

3957 self.__logFile = '' 

3958 

3959 # Registered Named Pipes, format is PipeName,Socket 

3960 self.__registeredNamedPipes = {} 

3961 

3962 # JTR dump path 

3963 self.__jtr_dump_path = '' 

3964 

3965 # SMB2 Support flag = default not active 

3966 self.__SMB2Support = False 

3967 

3968 # Allow anonymous logon 

3969 self.__anonymousLogon = True 

3970 

3971 # Our list of commands we will answer, by default the NOT IMPLEMENTED one 

3972 self.__smbCommandsHandler = SMBCommands() 

3973 self.__smbTrans2Handler = TRANS2Commands() 

3974 self.__smbTransHandler = TRANSCommands() 

3975 self.__smbNTTransHandler = NTTRANSCommands() 

3976 self.__smb2CommandsHandler = SMB2Commands() 

3977 self.__IoctlHandler = Ioctls() 

3978 

3979 self.__smbNTTransCommands = { 

3980 # NT IOCTL, can't find doc for this 

3981 0xff: self.__smbNTTransHandler.default 

3982 } 

3983 

3984 self.__smbTransCommands = { 

3985 '\\PIPE\\LANMAN': self.__smbTransHandler.lanMan, 

3986 smb.SMB.TRANS_TRANSACT_NMPIPE: self.__smbTransHandler.transactNamedPipe, 

3987 } 

3988 self.__smbTrans2Commands = { 

3989 smb.SMB.TRANS2_FIND_FIRST2: self.__smbTrans2Handler.findFirst2, 

3990 smb.SMB.TRANS2_FIND_NEXT2: self.__smbTrans2Handler.findNext2, 

3991 smb.SMB.TRANS2_QUERY_FS_INFORMATION: self.__smbTrans2Handler.queryFsInformation, 

3992 smb.SMB.TRANS2_QUERY_PATH_INFORMATION: self.__smbTrans2Handler.queryPathInformation, 

3993 smb.SMB.TRANS2_QUERY_FILE_INFORMATION: self.__smbTrans2Handler.queryFileInformation, 

3994 smb.SMB.TRANS2_SET_FILE_INFORMATION: self.__smbTrans2Handler.setFileInformation, 

3995 smb.SMB.TRANS2_SET_PATH_INFORMATION: self.__smbTrans2Handler.setPathInformation 

3996 } 

3997 

3998 self.__smbCommands = { 

3999 smb.SMB.SMB_COM_FLUSH: self.__smbCommandsHandler.smbComFlush, 

4000 smb.SMB.SMB_COM_CREATE_DIRECTORY: self.__smbCommandsHandler.smbComCreateDirectory, 

4001 smb.SMB.SMB_COM_DELETE_DIRECTORY: self.__smbCommandsHandler.smbComDeleteDirectory, 

4002 smb.SMB.SMB_COM_RENAME: self.__smbCommandsHandler.smbComRename, 

4003 smb.SMB.SMB_COM_DELETE: self.__smbCommandsHandler.smbComDelete, 

4004 smb.SMB.SMB_COM_NEGOTIATE: self.__smbCommandsHandler.smbComNegotiate, 

4005 smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX, 

4006 smb.SMB.SMB_COM_LOGOFF_ANDX: self.__smbCommandsHandler.smbComLogOffAndX, 

4007 smb.SMB.SMB_COM_TREE_CONNECT_ANDX: self.__smbCommandsHandler.smbComTreeConnectAndX, 

4008 smb.SMB.SMB_COM_TREE_DISCONNECT: self.__smbCommandsHandler.smbComTreeDisconnect, 

4009 smb.SMB.SMB_COM_ECHO: self.__smbCommandsHandler.smbComEcho, 

4010 smb.SMB.SMB_COM_QUERY_INFORMATION: self.__smbCommandsHandler.smbQueryInformation, 

4011 smb.SMB.SMB_COM_TRANSACTION2: self.__smbCommandsHandler.smbTransaction2, 

4012 smb.SMB.SMB_COM_TRANSACTION: self.__smbCommandsHandler.smbTransaction, 

4013 # Not needed for now 

4014 smb.SMB.SMB_COM_NT_TRANSACT: self.__smbCommandsHandler.smbNTTransact, 

4015 smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk, 

4016 smb.SMB.SMB_COM_OPEN_ANDX: self.__smbCommandsHandler.smbComOpenAndX, 

4017 smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2, 

4018 smb.SMB.SMB_COM_READ_ANDX: self.__smbCommandsHandler.smbComReadAndX, 

4019 smb.SMB.SMB_COM_READ: self.__smbCommandsHandler.smbComRead, 

4020 smb.SMB.SMB_COM_WRITE_ANDX: self.__smbCommandsHandler.smbComWriteAndX, 

4021 smb.SMB.SMB_COM_WRITE: self.__smbCommandsHandler.smbComWrite, 

4022 smb.SMB.SMB_COM_CLOSE: self.__smbCommandsHandler.smbComClose, 

4023 smb.SMB.SMB_COM_LOCKING_ANDX: self.__smbCommandsHandler.smbComLockingAndX, 

4024 smb.SMB.SMB_COM_NT_CREATE_ANDX: self.__smbCommandsHandler.smbComNtCreateAndX, 

4025 0xFF: self.__smbCommandsHandler.default 

4026 } 

4027 

4028 self.__smb2Ioctls = { 

4029 smb2.FSCTL_DFS_GET_REFERRALS: self.__IoctlHandler.fsctlDfsGetReferrals, 

4030 # smb2.FSCTL_PIPE_PEEK: self.__IoctlHandler.fsctlPipePeek, 

4031 # smb2.FSCTL_PIPE_WAIT: self.__IoctlHandler.fsctlPipeWait, 

4032 smb2.FSCTL_PIPE_TRANSCEIVE: self.__IoctlHandler.fsctlPipeTransceive, 

4033 # smb2.FSCTL_SRV_COPYCHUNK: self.__IoctlHandler.fsctlSrvCopyChunk, 

4034 # smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS: self.__IoctlHandler.fsctlSrvEnumerateSnapshots, 

4035 # smb2.FSCTL_SRV_REQUEST_RESUME_KEY: self.__IoctlHandler.fsctlSrvRequestResumeKey, 

4036 # smb2.FSCTL_SRV_READ_HASH: self.__IoctlHandler.fsctlSrvReadHash, 

4037 # smb2.FSCTL_SRV_COPYCHUNK_WRITE: self.__IoctlHandler.fsctlSrvCopyChunkWrite, 

4038 # smb2.FSCTL_LMR_REQUEST_RESILIENCY: self.__IoctlHandler.fsctlLmrRequestResiliency, 

4039 # smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo, 

4040 # smb2.FSCTL_SET_REPARSE_POINT: self.__IoctlHandler.fsctlSetReparsePoint, 

4041 # smb2.FSCTL_DFS_GET_REFERRALS_EX: self.__IoctlHandler.fsctlDfsGetReferralsEx, 

4042 # smb2.FSCTL_FILE_LEVEL_TRIM: self.__IoctlHandler.fsctlFileLevelTrim, 

4043 smb2.FSCTL_VALIDATE_NEGOTIATE_INFO: self.__IoctlHandler.fsctlValidateNegotiateInfo, 

4044 } 

4045 

4046 self.__smb2Commands = { 

4047 smb2.SMB2_NEGOTIATE: self.__smb2CommandsHandler.smb2Negotiate, 

4048 smb2.SMB2_SESSION_SETUP: self.__smb2CommandsHandler.smb2SessionSetup, 

4049 smb2.SMB2_LOGOFF: self.__smb2CommandsHandler.smb2Logoff, 

4050 smb2.SMB2_TREE_CONNECT: self.__smb2CommandsHandler.smb2TreeConnect, 

4051 smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect, 

4052 smb2.SMB2_CREATE: self.__smb2CommandsHandler.smb2Create, 

4053 smb2.SMB2_CLOSE: self.__smb2CommandsHandler.smb2Close, 

4054 smb2.SMB2_FLUSH: self.__smb2CommandsHandler.smb2Flush, 

4055 smb2.SMB2_READ: self.__smb2CommandsHandler.smb2Read, 

4056 smb2.SMB2_WRITE: self.__smb2CommandsHandler.smb2Write, 

4057 smb2.SMB2_LOCK: self.__smb2CommandsHandler.smb2Lock, 

4058 smb2.SMB2_IOCTL: self.__smb2CommandsHandler.smb2Ioctl, 

4059 smb2.SMB2_CANCEL: self.__smb2CommandsHandler.smb2Cancel, 

4060 smb2.SMB2_ECHO: self.__smb2CommandsHandler.smb2Echo, 

4061 smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory, 

4062 smb2.SMB2_CHANGE_NOTIFY: self.__smb2CommandsHandler.smb2ChangeNotify, 

4063 smb2.SMB2_QUERY_INFO: self.__smb2CommandsHandler.smb2QueryInfo, 

4064 smb2.SMB2_SET_INFO: self.__smb2CommandsHandler.smb2SetInfo, 

4065 # smb2.SMB2_OPLOCK_BREAK: self.__smb2CommandsHandler.smb2SessionSetup, 

4066 0xFF: self.__smb2CommandsHandler.default 

4067 } 

4068 

4069 # List of active connections 

4070 self.__activeConnections = {} 

4071 

4072 def getIoctls(self): 

4073 return self.__smb2Ioctls 

4074 

4075 def getCredentials(self): 

4076 return self.__credentials 

4077 

4078 def removeConnection(self, name): 

4079 try: 

4080 del (self.__activeConnections[name]) 

4081 except: 

4082 pass 

4083 self.log("Remaining connections %s" % list(self.__activeConnections.keys())) 

4084 

4085 def addConnection(self, name, ip, port): 

4086 self.__activeConnections[name] = {} 

4087 # Let's init with some know stuff we will need to have 

4088 # TODO: Document what's in there 

4089 # print "Current Connections", self.__activeConnections.keys() 

4090 self.__activeConnections[name]['PacketNum'] = 0 

4091 self.__activeConnections[name]['ClientIP'] = ip 

4092 self.__activeConnections[name]['ClientPort'] = port 

4093 self.__activeConnections[name]['Uid'] = 0 

4094 self.__activeConnections[name]['ConnectedShares'] = {} 

4095 self.__activeConnections[name]['OpenedFiles'] = {} 

4096 # SID results for findfirst2 

4097 self.__activeConnections[name]['SIDs'] = {} 

4098 self.__activeConnections[name]['LastRequest'] = {} 

4099 self.__activeConnections[name]['SignatureEnabled'] = False 

4100 self.__activeConnections[name]['SigningChallengeResponse'] = '' 

4101 self.__activeConnections[name]['SigningSessionKey'] = b'' 

4102 self.__activeConnections[name]['Authenticated'] = False 

4103 

4104 def getActiveConnections(self): 

4105 return self.__activeConnections 

4106 

4107 def setConnectionData(self, connId, data): 

4108 self.__activeConnections[connId] = data 

4109 # print "setConnectionData" 

4110 # print self.__activeConnections 

4111 

4112 def getConnectionData(self, connId, checkStatus=True): 

4113 conn = self.__activeConnections[connId] 

4114 if checkStatus is True: 

4115 if ('Authenticated' in conn) is not True: 

4116 # Can't keep going further 

4117 raise Exception("User not Authenticated!") 

4118 return conn 

4119 

4120 def getRegisteredNamedPipes(self): 

4121 return self.__registeredNamedPipes 

4122 

4123 def registerNamedPipe(self, pipeName, address): 

4124 self.__registeredNamedPipes[str(pipeName)] = address 

4125 return True 

4126 

4127 def unregisterNamedPipe(self, pipeName): 

4128 if pipeName in self.__registeredNamedPipes: 

4129 del (self.__registeredNamedPipes[str(pipeName)]) 

4130 return True 

4131 return False 

4132 

4133 def unregisterTransaction(self, transCommand): 

4134 if transCommand in self.__smbTransCommands: 

4135 del (self.__smbTransCommands[transCommand]) 

4136 

4137 def hookTransaction(self, transCommand, callback): 

4138 # If you call this function, callback will replace 

4139 # the current Transaction sub command. 

4140 # (don't get confused with the Transaction smbCommand) 

4141 # If the transaction sub command doesn't not exist, it is added 

4142 # If the transaction sub command exists, it returns the original function # replaced 

4143 # 

4144 # callback MUST be declared as: 

4145 # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0) 

4146 # 

4147 # WHERE: 

4148 # 

4149 # connId : the connection Id, used to grab/update information about 

4150 # the current connection 

4151 # smbServer : the SMBServer instance available for you to ask 

4152 # configuration data 

4153 # recvPacket : the full SMBPacket that triggered this command 

4154 # parameters : the transaction parameters 

4155 # data : the transaction data 

4156 # maxDataCount: the max amount of data that can be transferred agreed 

4157 # with the client 

4158 # 

4159 # and MUST return: 

4160 # respSetup, respParameters, respData, errorCode 

4161 # 

4162 # WHERE: 

4163 # 

4164 # respSetup: the setup response of the transaction 

4165 # respParameters: the parameters response of the transaction 

4166 # respData: the data response of the transaction 

4167 # errorCode: the NT error code 

4168 

4169 if transCommand in self.__smbTransCommands: 

4170 originalCommand = self.__smbTransCommands[transCommand] 

4171 else: 

4172 originalCommand = None 

4173 

4174 self.__smbTransCommands[transCommand] = callback 

4175 return originalCommand 

4176 

4177 def unregisterTransaction2(self, transCommand): 

4178 if transCommand in self.__smbTrans2Commands: 

4179 del (self.__smbTrans2Commands[transCommand]) 

4180 

4181 def hookTransaction2(self, transCommand, callback): 

4182 # Here we should add to __smbTrans2Commands 

4183 # Same description as Transaction 

4184 if transCommand in self.__smbTrans2Commands: 

4185 originalCommand = self.__smbTrans2Commands[transCommand] 

4186 else: 

4187 originalCommand = None 

4188 

4189 self.__smbTrans2Commands[transCommand] = callback 

4190 return originalCommand 

4191 

4192 def unregisterNTTransaction(self, transCommand): 

4193 if transCommand in self.__smbNTTransCommands: 

4194 del (self.__smbNTTransCommands[transCommand]) 

4195 

4196 def hookNTTransaction(self, transCommand, callback): 

4197 # Here we should add to __smbNTTransCommands 

4198 # Same description as Transaction 

4199 if transCommand in self.__smbNTTransCommands: 

4200 originalCommand = self.__smbNTTransCommands[transCommand] 

4201 else: 

4202 originalCommand = None 

4203 

4204 self.__smbNTTransCommands[transCommand] = callback 

4205 return originalCommand 

4206 

4207 def unregisterSmbCommand(self, smbCommand): 

4208 if smbCommand in self.__smbCommands: 

4209 del (self.__smbCommands[smbCommand]) 

4210 

4211 def hookSmbCommand(self, smbCommand, callback): 

4212 # Here we should add to self.__smbCommands 

4213 # If you call this function, callback will replace 

4214 # the current smbCommand. 

4215 # If smbCommand doesn't not exist, it is added 

4216 # If SMB command exists, it returns the original function replaced 

4217 # 

4218 # callback MUST be declared as: 

4219 # callback(connId, smbServer, SMBCommand, recvPacket) 

4220 # 

4221 # WHERE: 

4222 # 

4223 # connId : the connection Id, used to grab/update information about 

4224 # the current connection 

4225 # smbServer : the SMBServer instance available for you to ask 

4226 # configuration data 

4227 # SMBCommand: the SMBCommand itself, with its data and parameters. 

4228 # Check smb.py:SMBCommand() for a reference 

4229 # recvPacket: the full SMBPacket that triggered this command 

4230 # 

4231 # and MUST return: 

4232 # <list of respSMBCommands>, <list of packets>, errorCode 

4233 # <list of packets> has higher preference over commands, in case you 

4234 # want to change the whole packet 

4235 # errorCode: the NT error code 

4236 # 

4237 # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT 

4238 # the callback function is slightly different: 

4239 # 

4240 # callback(connId, smbServer, SMBCommand, recvPacket, transCommands) 

4241 # 

4242 # WHERE: 

4243 # 

4244 # transCommands: a list of transaction subcommands already registered 

4245 # 

4246 

4247 if smbCommand in self.__smbCommands: 

4248 originalCommand = self.__smbCommands[smbCommand] 

4249 else: 

4250 originalCommand = None 

4251 

4252 self.__smbCommands[smbCommand] = callback 

4253 return originalCommand 

4254 

4255 def unregisterSmb2Command(self, smb2Command): 

4256 if smb2Command in self.__smb2Commands: 

4257 del (self.__smb2Commands[smb2Command]) 

4258 

4259 def hookSmb2Command(self, smb2Command, callback): 

4260 if smb2Command in self.__smb2Commands: 

4261 originalCommand = self.__smb2Commands[smb2Command] 

4262 else: 

4263 originalCommand = None 

4264 

4265 self.__smb2Commands[smb2Command] = callback 

4266 return originalCommand 

4267 

4268 def log(self, msg, level=logging.INFO): 

4269 self.__log.log(level, msg) 

4270 

4271 def getServerName(self): 

4272 return self.__serverName 

4273 

4274 def getServerOS(self): 

4275 return self.__serverOS 

4276 

4277 def getServerDomain(self): 

4278 return self.__serverDomain 

4279 

4280 def getSMBChallenge(self): 

4281 return self.__challenge 

4282 

4283 def getServerConfig(self): 

4284 return self.__serverConfig 

4285 

4286 def setServerConfig(self, config): 

4287 self.__serverConfig = config 

4288 

4289 def getJTRdumpPath(self): 

4290 return self.__jtr_dump_path 

4291 

4292 def verify_request(self, request, client_address): 

4293 # TODO: Control here the max amount of processes we want to launch 

4294 # returning False, closes the connection 

4295 return True 

4296 

4297 def signSMBv1(self, connData, packet, signingSessionKey, signingChallengeResponse): 

4298 # This logic MUST be applied for messages sent in response to any of the higher-layer actions and in 

4299 # compliance with the message sequencing rules. 

4300 # * The client or server that sends the message MUST provide the 32-bit sequence number for this 

4301 # message, as specified in sections 3.2.4.1 and 3.3.4.1. 

4302 # * The SMB_FLAGS2_SMB_SECURITY_SIGNATURE flag in the header MUST be set. 

4303 # * To generate the signature, a 32-bit sequence number is copied into the 

4304 # least significant 32 bits of the SecuritySignature field and the remaining 

4305 # 4 bytes are set to 0x00. 

4306 # * The MD5 algorithm, as specified in [RFC1321], MUST be used to generate a hash of the SMB 

4307 # message from the start of the SMB Header, which is defined as follows. 

4308 # CALL MD5Init( md5context ) 

4309 # CALL MD5Update( md5context, Connection.SigningSessionKey ) 

4310 # CALL MD5Update( md5context, Connection.SigningChallengeResponse ) 

4311 # CALL MD5Update( md5context, SMB message ) 

4312 # CALL MD5Final( digest, md5context ) 

4313 # SET signature TO the first 8 bytes of the digest 

4314 # The resulting 8-byte signature MUST be copied into the SecuritySignature field of the SMB Header, 

4315 # after which the message can be transmitted. 

4316 

4317 # print "seq(%d) signingSessionKey %r, signingChallengeResponse %r" % (connData['SignSequenceNumber'], signingSessionKey, signingChallengeResponse) 

4318 packet['SecurityFeatures'] = struct.pack('<q', connData['SignSequenceNumber']) 

4319 # Sign with the sequence 

4320 m = hashlib.md5() 

4321 m.update(signingSessionKey) 

4322 m.update(signingChallengeResponse) 

4323 if hasattr(packet, 'getData'): 

4324 m.update(packet.getData()) 

4325 else: 

4326 m.update(packet) 

4327 # Replace sequence with acual hash 

4328 packet['SecurityFeatures'] = m.digest()[:8] 

4329 connData['SignSequenceNumber'] += 2 

4330 

4331 def signSMBv2(self, packet, signingSessionKey): 

4332 packet['Signature'] = b'\x00' * 16 

4333 packet['Flags'] |= smb2.SMB2_FLAGS_SIGNED 

4334 signature = hmac.new(signingSessionKey, packet.getData(), hashlib.sha256).digest() 

4335 packet['Signature'] = signature[:16] 

4336 # print "%s" % packet['Signature'].encode('hex') 

4337 

4338 def processRequest(self, connId, data): 

4339 

4340 # TODO: Process batched commands. 

4341 isSMB2 = False 

4342 SMBCommand = None 

4343 try: 

4344 packet = smb.NewSMBPacket(data=data) 

4345 SMBCommand = smb.SMBCommand(packet['Data'][0]) 

4346 except: 

4347 # Maybe a SMB2 packet? 

4348 packet = smb2.SMB2Packet(data=data) 

4349 connData = self.getConnectionData(connId, False) 

4350 self.signSMBv2(packet, connData['SigningSessionKey']) 

4351 isSMB2 = True 

4352 

4353 connData = self.getConnectionData(connId, False) 

4354 

4355 # We might have compound requests 

4356 compoundedPacketsResponse = [] 

4357 compoundedPackets = [] 

4358 try: 

4359 # Search out list of implemented commands 

4360 # We provide them with: 

4361 # connId : representing the data for this specific connection 

4362 # self : the SMBSERVER if they want to ask data to it 

4363 # SMBCommand : the SMBCommand they are expecting to process 

4364 # packet : the received packet itself, in case they need more data than the actual command 

4365 # Only for Transactions 

4366 # transCommand: a list of transaction subcommands 

4367 # We expect to get: 

4368 # respCommands: a list of answers for the commands processed 

4369 # respPacket : if the commands chose to directly craft packet/s, we use this and not the previous 

4370 # this MUST be a list 

4371 # errorCode : self explanatory 

4372 if isSMB2 is False: 

4373 # Is the client authenticated already? 

4374 if connData['Authenticated'] is False and packet['Command'] not in ( 

4375 smb.SMB.SMB_COM_NEGOTIATE, smb.SMB.SMB_COM_SESSION_SETUP_ANDX): 

4376 # Nope.. in that case he should only ask for a few commands, if not throw him out. 

4377 errorCode = STATUS_ACCESS_DENIED 

4378 respPackets = None 

4379 respCommands = [smb.SMBCommand(packet['Command'])] 

4380 else: 

4381 if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2: 

4382 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4383 connId, 

4384 self, 

4385 SMBCommand, 

4386 packet, 

4387 self.__smbTrans2Commands) 

4388 elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT: 

4389 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4390 connId, 

4391 self, 

4392 SMBCommand, 

4393 packet, 

4394 self.__smbNTTransCommands) 

4395 elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION: 

4396 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4397 connId, 

4398 self, 

4399 SMBCommand, 

4400 packet, 

4401 self.__smbTransCommands) 

4402 else: 

4403 if packet['Command'] in self.__smbCommands: 

4404 if self.__SMB2Support is True: 

4405 if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE: 

4406 try: 

4407 respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE]( 

4408 connId, self, packet, True) 

4409 isSMB2 = True 

4410 except Exception as e: 

4411 import traceback 

4412 traceback.print_exc() 

4413 self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR) 

4414 # If something went wrong, let's fallback to SMB1 

4415 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4416 connId, 

4417 self, 

4418 SMBCommand, 

4419 packet) 

4420 # self.__SMB2Support = False 

4421 pass 

4422 else: 

4423 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4424 connId, 

4425 self, 

4426 SMBCommand, 

4427 packet) 

4428 else: 

4429 respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']]( 

4430 connId, 

4431 self, 

4432 SMBCommand, 

4433 packet) 

4434 else: 

4435 respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, 

4436 packet) 

4437 

4438 compoundedPacketsResponse.append((respCommands, respPackets, errorCode)) 

4439 compoundedPackets.append(packet) 

4440 

4441 else: 

4442 # Is the client authenticated already? 

4443 if connData['Authenticated'] is False and packet['Command'] not in ( 

4444 smb2.SMB2_NEGOTIATE, smb2.SMB2_SESSION_SETUP): 

4445 # Nope.. in that case he should only ask for a few commands, if not throw him out. 

4446 errorCode = STATUS_ACCESS_DENIED 

4447 respPackets = None 

4448 respCommands = [''] 

4449 compoundedPacketsResponse.append((respCommands, respPackets, errorCode)) 

4450 compoundedPackets.append(packet) 

4451 else: 

4452 done = False 

4453 while not done: 

4454 if packet['Command'] in self.__smb2Commands: 

4455 if self.__SMB2Support is True: 

4456 respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']]( 

4457 connId, 

4458 self, 

4459 packet) 

4460 else: 

4461 respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet) 

4462 else: 

4463 respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet) 

4464 # Let's store the result for this compounded packet 

4465 compoundedPacketsResponse.append((respCommands, respPackets, errorCode)) 

4466 compoundedPackets.append(packet) 

4467 if packet['NextCommand'] != 0: 

4468 data = data[packet['NextCommand']:] 

4469 packet = smb2.SMB2Packet(data=data) 

4470 else: 

4471 done = True 

4472 

4473 except Exception as e: 

4474 # import traceback 

4475 # traceback.print_exc() 

4476 # Something wen't wrong, defaulting to Bad user ID 

4477 self.log('processRequest (0x%x,%s)' % (packet['Command'], e), logging.ERROR) 

4478 raise 

4479 

4480 # We prepare the response packet to commands don't need to bother about that. 

4481 connData = self.getConnectionData(connId, False) 

4482 

4483 # Force reconnection loop.. This is just a test.. client will send me back credentials :) 

4484 # connData['PacketNum'] += 1 

4485 # if connData['PacketNum'] == 15: 

4486 # connData['PacketNum'] = 0 

4487 # # Something wen't wrong, defaulting to Bad user ID 

4488 # self.log('Sending BAD USER ID!', logging.ERROR) 

4489 # #raise 

4490 # packet['Flags1'] |= smb.SMB.FLAGS1_REPLY 

4491 # packet['Flags2'] = 0 

4492 # errorCode = STATUS_SMB_BAD_UID 

4493 # packet['ErrorCode'] = errorCode >> 16 

4494 # packet['ErrorClass'] = errorCode & 0xff 

4495 # return [packet] 

4496 

4497 self.setConnectionData(connId, connData) 

4498 

4499 packetsToSend = [] 

4500 for packetNum in range(len(compoundedPacketsResponse)): 

4501 respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum] 

4502 packet = compoundedPackets[packetNum] 

4503 if respPackets is None: 

4504 for respCommand in respCommands: 

4505 if isSMB2 is False: 

4506 respPacket = smb.NewSMBPacket() 

4507 respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY 

4508 

4509 # TODO this should come from a per session configuration 

4510 respPacket[ 

4511 'Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | \ 

4512 packet['Flags2'] & smb.SMB.FLAGS2_UNICODE 

4513 # respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES 

4514 # respPacket['Flags1'] = 0x98 

4515 # respPacket['Flags2'] = 0xc807 

4516 

4517 respPacket['Tid'] = packet['Tid'] 

4518 respPacket['Mid'] = packet['Mid'] 

4519 respPacket['Pid'] = packet['Pid'] 

4520 respPacket['Uid'] = connData['Uid'] 

4521 

4522 respPacket['ErrorCode'] = errorCode >> 16 

4523 respPacket['_reserved'] = errorCode >> 8 & 0xff 

4524 respPacket['ErrorClass'] = errorCode & 0xff 

4525 respPacket.addCommand(respCommand) 

4526 

4527 if connData['SignatureEnabled']: 

4528 respPacket['Flags2'] |= smb.SMB.FLAGS2_SMB_SECURITY_SIGNATURE 

4529 self.signSMBv1(connData, respPacket, connData['SigningSessionKey'], 

4530 connData['SigningChallengeResponse']) 

4531 

4532 packetsToSend.append(respPacket) 

4533 else: 

4534 respPacket = smb2.SMB2Packet() 

4535 respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR 

4536 if packetNum > 0: 

4537 respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS 

4538 respPacket['Status'] = errorCode 

4539 respPacket['CreditRequestResponse'] = packet['CreditRequestResponse'] 

4540 respPacket['Command'] = packet['Command'] 

4541 respPacket['CreditCharge'] = packet['CreditCharge'] 

4542 # respPacket['CreditCharge'] = 0 

4543 respPacket['Reserved'] = packet['Reserved'] 

4544 respPacket['SessionID'] = connData['Uid'] 

4545 respPacket['MessageID'] = packet['MessageID'] 

4546 respPacket['TreeID'] = packet['TreeID'] 

4547 if hasattr(respCommand, 'getData'): 

4548 respPacket['Data'] = respCommand.getData() 

4549 else: 

4550 respPacket['Data'] = str(respCommand) 

4551 

4552 if connData['SignatureEnabled']: 

4553 self.signSMBv2(respPacket, connData['SigningSessionKey']) 

4554 

4555 packetsToSend.append(respPacket) 

4556 else: 

4557 # The SMBCommand took care of building the packet 

4558 packetsToSend = respPackets 

4559 

4560 if isSMB2 is True: 

4561 # Let's build a compound answer 

4562 finalData = b'' 

4563 i = 0 

4564 for i in range(len(packetsToSend) - 1): 

4565 packet = packetsToSend[i] 

4566 # Align to 8-bytes 

4567 padLen = (8 - (len(packet) % 8)) % 8 

4568 packet['NextCommand'] = len(packet) + padLen 

4569 if hasattr(packet, 'getData'): 

4570 finalData += packet.getData() + padLen * b'\x00' 

4571 else: 

4572 finalData += packet + padLen * b'\x00' 

4573 

4574 # Last one 

4575 if hasattr(packetsToSend[len(packetsToSend) - 1], 'getData'): 

4576 finalData += packetsToSend[len(packetsToSend) - 1].getData() 

4577 else: 

4578 finalData += packetsToSend[len(packetsToSend) - 1] 

4579 packetsToSend = [finalData] 

4580 

4581 # We clear the compound requests 

4582 connData['LastRequest'] = {} 

4583 

4584 return packetsToSend 

4585 

4586 def processConfigFile(self, configFile=None): 

4587 # TODO: Do a real config parser 

4588 if self.__serverConfig is None: 

4589 if configFile is None: 

4590 configFile = 'smb.conf' 

4591 self.__serverConfig = configparser.ConfigParser() 

4592 self.__serverConfig.read(configFile) 

4593 

4594 self.__serverName = self.__serverConfig.get('global', 'server_name') 

4595 self.__serverOS = self.__serverConfig.get('global', 'server_os') 

4596 self.__serverDomain = self.__serverConfig.get('global', 'server_domain') 

4597 self.__logFile = self.__serverConfig.get('global', 'log_file') 

4598 if self.__serverConfig.has_option('global', 'challenge'): 

4599 self.__challenge = unhexlify(self.__serverConfig.get('global', 'challenge')) 

4600 else: 

4601 self.__challenge = b'A' * 16 

4602 

4603 if self.__serverConfig.has_option("global", "jtr_dump_path"): 

4604 self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path") 

4605 

4606 if self.__serverConfig.has_option("global", "SMB2Support"): 

4607 self.__SMB2Support = self.__serverConfig.getboolean("global", "SMB2Support") 

4608 else: 

4609 self.__SMB2Support = False 

4610 

4611 

4612 if self.__serverConfig.has_option("global", "anonymous_logon"): 

4613 self.__anonymousLogon = self.__serverConfig.getboolean("global", "anonymous_logon") 

4614 else: 

4615 self.__anonymousLogon = True 

4616 

4617 if self.__logFile != 'None': 

4618 logging.basicConfig(filename=self.__logFile, 

4619 level=logging.DEBUG, 

4620 format="%(asctime)s: %(levelname)s: %(message)s", 

4621 datefmt='%m/%d/%Y %I:%M:%S %p') 

4622 self.__log = LOG 

4623 

4624 # Process the credentials 

4625 credentials_fname = self.__serverConfig.get('global', 'credentials_file') 

4626 if credentials_fname != "": 

4627 cred = open(credentials_fname) 

4628 line = cred.readline() 

4629 while line: 

4630 name, uid, lmhash, nthash = line.split(':') 

4631 self.__credentials[name.lower()] = (uid, lmhash, nthash.strip('\r\n')) 

4632 line = cred.readline() 

4633 cred.close() 

4634 self.log('Config file parsed') 

4635 

4636 def addCredential(self, name, uid, lmhash, nthash): 

4637 # If we have hashes, normalize them 

4638 if lmhash != '' or nthash != '': 

4639 if len(lmhash) % 2: 

4640 lmhash = '0%s' % lmhash 

4641 if len(nthash) % 2: 

4642 nthash = '0%s' % nthash 

4643 try: # just in case they were converted already 

4644 lmhash = a2b_hex(lmhash) 

4645 nthash = a2b_hex(nthash) 

4646 except: 

4647 pass 

4648 self.__credentials[name.lower()] = (uid, lmhash, nthash) 

4649 

4650 

4651# For windows platforms, opening a directory is not an option, so we set a void FD 

4652VOID_FILE_DESCRIPTOR = -1 

4653PIPE_FILE_DESCRIPTOR = -2 

4654 

4655###################################################################### 

4656# HELPER CLASSES 

4657###################################################################### 

4658 

4659from impacket.dcerpc.v5.rpcrt import DCERPCServer 

4660from impacket.dcerpc.v5.dtypes import NULL 

4661from impacket.dcerpc.v5.srvs import NetrShareEnum, NetrShareEnumResponse, SHARE_INFO_1, NetrServerGetInfo, \ 

4662 NetrServerGetInfoResponse, NetrShareGetInfo, NetrShareGetInfoResponse 

4663from impacket.dcerpc.v5.wkst import NetrWkstaGetInfo, NetrWkstaGetInfoResponse 

4664from impacket.system_errors import ERROR_INVALID_LEVEL 

4665 

4666 

4667class WKSTServer(DCERPCServer): 

4668 def __init__(self): 

4669 DCERPCServer.__init__(self) 

4670 self.wkssvcCallBacks = { 

4671 0: self.NetrWkstaGetInfo, 

4672 } 

4673 self.addCallbacks(('6BFFD098-A112-3610-9833-46C3F87E345A', '1.0'), '\\PIPE\\wkssvc', self.wkssvcCallBacks) 

4674 

4675 def NetrWkstaGetInfo(self, data): 

4676 request = NetrWkstaGetInfo(data) 

4677 self.log("NetrWkstaGetInfo Level: %d" % request['Level']) 

4678 

4679 answer = NetrWkstaGetInfoResponse() 

4680 

4681 if request['Level'] not in (100, 101): 

4682 answer['ErrorCode'] = ERROR_INVALID_LEVEL 

4683 return answer 

4684 

4685 answer['WkstaInfo']['tag'] = request['Level'] 

4686 

4687 if request['Level'] == 100: 

4688 # Windows. Decimal value 500. 

4689 answer['WkstaInfo']['WkstaInfo100']['wki100_platform_id'] = 0x000001F4 

4690 answer['WkstaInfo']['WkstaInfo100']['wki100_computername'] = NULL 

4691 answer['WkstaInfo']['WkstaInfo100']['wki100_langroup'] = NULL 

4692 answer['WkstaInfo']['WkstaInfo100']['wki100_ver_major'] = 5 

4693 answer['WkstaInfo']['WkstaInfo100']['wki100_ver_minor'] = 0 

4694 else: 

4695 # Windows. Decimal value 500. 

4696 answer['WkstaInfo']['WkstaInfo101']['wki101_platform_id'] = 0x000001F4 

4697 answer['WkstaInfo']['WkstaInfo101']['wki101_computername'] = NULL 

4698 answer['WkstaInfo']['WkstaInfo101']['wki101_langroup'] = NULL 

4699 answer['WkstaInfo']['WkstaInfo101']['wki101_ver_major'] = 5 

4700 answer['WkstaInfo']['WkstaInfo101']['wki101_ver_minor'] = 0 

4701 answer['WkstaInfo']['WkstaInfo101']['wki101_lanroot'] = NULL 

4702 

4703 return answer 

4704 

4705 

4706class SRVSServer(DCERPCServer): 

4707 def __init__(self): 

4708 DCERPCServer.__init__(self) 

4709 

4710 self._shares = {} 

4711 self.__serverConfig = None 

4712 self.__logFile = None 

4713 

4714 self.srvsvcCallBacks = { 

4715 15: self.NetrShareEnum, 

4716 16: self.NetrShareGetInfo, 

4717 21: self.NetrServerGetInfo, 

4718 } 

4719 

4720 self.addCallbacks(('4B324FC8-1670-01D3-1278-5A47BF6EE188', '3.0'), '\\PIPE\\srvsvc', self.srvsvcCallBacks) 

4721 

4722 def setServerConfig(self, config): 

4723 self.__serverConfig = config 

4724 

4725 def processConfigFile(self, configFile=None): 

4726 if configFile is not None: 

4727 self.__serverConfig = configparser.ConfigParser() 

4728 self.__serverConfig.read(configFile) 

4729 sections = self.__serverConfig.sections() 

4730 # Let's check the log file 

4731 self.__logFile = self.__serverConfig.get('global', 'log_file') 

4732 if self.__logFile != 'None': 

4733 logging.basicConfig(filename=self.__logFile, 

4734 level=logging.DEBUG, 

4735 format="%(asctime)s: %(levelname)s: %(message)s", 

4736 datefmt='%m/%d/%Y %I:%M:%S %p') 

4737 

4738 # Remove the global one 

4739 del (sections[sections.index('global')]) 

4740 self._shares = {} 

4741 for i in sections: 

4742 self._shares[i] = dict(self.__serverConfig.items(i)) 

4743 

4744 def NetrShareGetInfo(self, data): 

4745 request = NetrShareGetInfo(data) 

4746 self.log("NetrGetShareInfo Level: %d" % request['Level']) 

4747 

4748 s = request['NetName'][:-1].upper() 

4749 answer = NetrShareGetInfoResponse() 

4750 if s in self._shares: 

4751 share = self._shares[s] 

4752 

4753 answer['InfoStruct']['tag'] = 1 

4754 answer['InfoStruct']['ShareInfo1']['shi1_netname'] = s + '\x00' 

4755 answer['InfoStruct']['ShareInfo1']['shi1_type'] = share['share type'] 

4756 answer['InfoStruct']['ShareInfo1']['shi1_remark'] = share['comment'] + '\x00' 

4757 answer['ErrorCode'] = 0 

4758 else: 

4759 answer['InfoStruct']['tag'] = 1 

4760 answer['InfoStruct']['ShareInfo1'] = NULL 

4761 answer['ErrorCode'] = 0x0906 # WERR_NET_NAME_NOT_FOUND 

4762 

4763 return answer 

4764 

4765 def NetrServerGetInfo(self, data): 

4766 request = NetrServerGetInfo(data) 

4767 self.log("NetrServerGetInfo Level: %d" % request['Level']) 

4768 answer = NetrServerGetInfoResponse() 

4769 answer['InfoStruct']['tag'] = 101 

4770 # PLATFORM_ID_NT = 500 

4771 answer['InfoStruct']['ServerInfo101']['sv101_platform_id'] = 500 

4772 answer['InfoStruct']['ServerInfo101']['sv101_name'] = request['ServerName'] 

4773 # Windows 7 = 6.1 

4774 answer['InfoStruct']['ServerInfo101']['sv101_version_major'] = 6 

4775 answer['InfoStruct']['ServerInfo101']['sv101_version_minor'] = 1 

4776 # Workstation = 1 

4777 answer['InfoStruct']['ServerInfo101']['sv101_type'] = 1 

4778 answer['InfoStruct']['ServerInfo101']['sv101_comment'] = NULL 

4779 answer['ErrorCode'] = 0 

4780 return answer 

4781 

4782 def NetrShareEnum(self, data): 

4783 request = NetrShareEnum(data) 

4784 self.log("NetrShareEnum Level: %d" % request['InfoStruct']['Level']) 

4785 shareEnum = NetrShareEnumResponse() 

4786 shareEnum['InfoStruct']['Level'] = 1 

4787 shareEnum['InfoStruct']['ShareInfo']['tag'] = 1 

4788 shareEnum['TotalEntries'] = len(self._shares) 

4789 shareEnum['InfoStruct']['ShareInfo']['Level1']['EntriesRead'] = len(self._shares) 

4790 shareEnum['ErrorCode'] = 0 

4791 

4792 for i in self._shares: 

4793 shareInfo = SHARE_INFO_1() 

4794 shareInfo['shi1_netname'] = i + '\x00' 

4795 shareInfo['shi1_type'] = self._shares[i]['share type'] 

4796 shareInfo['shi1_remark'] = self._shares[i]['comment'] + '\x00' 

4797 shareEnum['InfoStruct']['ShareInfo']['Level1']['Buffer'].append(shareInfo) 

4798 

4799 return shareEnum 

4800 

4801 

4802class SimpleSMBServer: 

4803 """ 

4804 SimpleSMBServer class - Implements a simple, customizable SMB Server 

4805 

4806 :param string listenAddress: the address you want the server to listen on 

4807 :param integer listenPort: the port number you want the server to listen on 

4808 :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 

4809 """ 

4810 

4811 def __init__(self, listenAddress='0.0.0.0', listenPort=445, configFile=''): 

4812 if configFile != '': 

4813 self.__server = SMBSERVER((listenAddress, listenPort)) 

4814 self.__server.processConfigFile(configFile) 

4815 self.__smbConfig = None 

4816 else: 

4817 # Here we write a mini config for the server 

4818 self.__smbConfig = configparser.ConfigParser() 

4819 self.__smbConfig.add_section('global') 

4820 self.__smbConfig.set('global', 'server_name', 

4821 ''.join([random.choice(string.ascii_letters) for _ in range(8)])) 

4822 self.__smbConfig.set('global', 'server_os', ''.join([random.choice(string.ascii_letters) for _ in range(8)]) 

4823 ) 

4824 self.__smbConfig.set('global', 'server_domain', 

4825 ''.join([random.choice(string.ascii_letters) for _ in range(8)]) 

4826 ) 

4827 self.__smbConfig.set('global', 'log_file', 'None') 

4828 self.__smbConfig.set('global', 'rpc_apis', 'yes') 

4829 self.__smbConfig.set('global', 'credentials_file', '') 

4830 self.__smbConfig.set('global', 'challenge', "A" * 16) 

4831 

4832 # IPC always needed 

4833 self.__smbConfig.add_section('IPC$') 

4834 self.__smbConfig.set('IPC$', 'comment', '') 

4835 self.__smbConfig.set('IPC$', 'read only', 'yes') 

4836 self.__smbConfig.set('IPC$', 'share type', '3') 

4837 self.__smbConfig.set('IPC$', 'path', '') 

4838 self.__server = SMBSERVER((listenAddress, listenPort), config_parser=self.__smbConfig) 

4839 self.__server.processConfigFile() 

4840 

4841 # Now we have to register the MS-SRVS server. This specially important for 

4842 # Windows 7+ and Mavericks clients since they WON'T (specially OSX) 

4843 # ask for shares using MS-RAP. 

4844 

4845 self.__srvsServer = SRVSServer() 

4846 self.__srvsServer.daemon = True 

4847 self.__wkstServer = WKSTServer() 

4848 self.__wkstServer.daemon = True 

4849 self.__server.registerNamedPipe('srvsvc', ('127.0.0.1', self.__srvsServer.getListenPort())) 

4850 self.__server.registerNamedPipe('wkssvc', ('127.0.0.1', self.__wkstServer.getListenPort())) 

4851 

4852 def start(self): 

4853 self.__srvsServer.start() 

4854 self.__wkstServer.start() 

4855 self.__server.serve_forever() 

4856 

4857 def stop(self): 

4858 self.__server.server_close() 

4859 

4860 def registerNamedPipe(self, pipeName, address): 

4861 return self.__server.registerNamedPipe(pipeName, address) 

4862 

4863 def unregisterNamedPipe(self, pipeName): 

4864 return self.__server.unregisterNamedPipe(pipeName) 

4865 

4866 def getRegisteredNamedPipes(self): 

4867 return self.__server.getRegisteredNamedPipes() 

4868 

4869 def addShare(self, shareName, sharePath, shareComment='', shareType='0', readOnly='no'): 

4870 share = shareName.upper() 

4871 self.__smbConfig.add_section(share) 

4872 self.__smbConfig.set(share, 'comment', shareComment) 

4873 self.__smbConfig.set(share, 'read only', readOnly) 

4874 self.__smbConfig.set(share, 'share type', shareType) 

4875 self.__smbConfig.set(share, 'path', sharePath) 

4876 self.__server.setServerConfig(self.__smbConfig) 

4877 self.__srvsServer.setServerConfig(self.__smbConfig) 

4878 self.__server.processConfigFile() 

4879 self.__srvsServer.processConfigFile() 

4880 

4881 def removeShare(self, shareName): 

4882 self.__smbConfig.remove_section(shareName.upper()) 

4883 self.__server.setServerConfig(self.__smbConfig) 

4884 self.__srvsServer.setServerConfig(self.__smbConfig) 

4885 self.__server.processConfigFile() 

4886 self.__srvsServer.processConfigFile() 

4887 

4888 def setSMBChallenge(self, challenge): 

4889 if challenge != '': 

4890 self.__smbConfig.set('global', 'challenge', challenge) 

4891 self.__server.setServerConfig(self.__smbConfig) 

4892 self.__server.processConfigFile() 

4893 

4894 def setLogFile(self, logFile): 

4895 self.__smbConfig.set('global', 'log_file', logFile) 

4896 self.__server.setServerConfig(self.__smbConfig) 

4897 self.__server.processConfigFile() 

4898 

4899 def setCredentialsFile(self, logFile): 

4900 self.__smbConfig.set('global', 'credentials_file', logFile) 

4901 self.__server.setServerConfig(self.__smbConfig) 

4902 self.__server.processConfigFile() 

4903 

4904 def addCredential(self, name, uid, lmhash, nthash): 

4905 self.__server.addCredential(name, uid, lmhash, nthash) 

4906 

4907 def setSMB2Support(self, value): 

4908 if value is True: 

4909 self.__smbConfig.set("global", "SMB2Support", "True") 

4910 else: 

4911 self.__smbConfig.set("global", "SMB2Support", "False") 

4912 self.__server.setServerConfig(self.__smbConfig) 

4913 self.__server.processConfigFile()