aboutsummaryrefslogtreecommitdiff
path: root/tests/python_dependencies/impacket/smbserver.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/python_dependencies/impacket/smbserver.py')
-rw-r--r--tests/python_dependencies/impacket/smbserver.py4178
1 files changed, 0 insertions, 4178 deletions
diff --git a/tests/python_dependencies/impacket/smbserver.py b/tests/python_dependencies/impacket/smbserver.py
deleted file mode 100644
index a74bd9414..000000000
--- a/tests/python_dependencies/impacket/smbserver.py
+++ /dev/null
@@ -1,4178 +0,0 @@
-# Copyright (c) 2003-2016 CORE Security Technologies
-#
-# This software is provided under under a slightly modified version
-# of the Apache Software License. See the accompanying LICENSE file
-# for more information.
-#
-# Author: Alberto Solino (@agsolino)
-#
-# TODO:
-# [-] Functions should return NT error codes
-# [-] Handling errors in all situations, right now it's just raising exceptions.
-# [*] Standard authentication support
-# [ ] Organize the connectionData stuff
-# [*] Add capability to send a bad user ID if the user is not authenticated,
-# right now you can ask for any command without actually being authenticated
-# [ ] PATH TRAVERSALS EVERYWHERE.. BE WARNED!
-# [ ] Check the credentials.. now we're just letting everybody to log in.
-# [ ] Check error situation (now many places assume the right data is coming)
-# [ ] Implement IPC to the main process so the connectionData is on a single place
-# [ ] Hence.. implement locking
-# estamos en la B
-
-from __future__ import with_statement
-import calendar
-import socket
-import time
-import datetime
-import struct
-import sys
-if sys.version_info.major >= 3:
- import configparser
- import socketserver
-else:
- import ConfigParser as configparser
- import SocketServer as socketserver
-import threading
-import logging
-import logging.config
-import ntpath
-import os
-import fnmatch
-import errno
-import random
-import shutil
-from binascii import hexlify
-
-# For signing
-from impacket import smb, nmb, ntlm, uuid, LOG
-from impacket import smb3structs as smb2
-from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, MechTypes, SPNEGO_NegTokenResp, ASN1_AID, ASN1_SUPPORTED_MECH
-from impacket.nt_errors import STATUS_NO_MORE_FILES, STATUS_NETWORK_NAME_DELETED, STATUS_INVALID_PARAMETER, \
- STATUS_FILE_CLOSED, STATUS_MORE_PROCESSING_REQUIRED, STATUS_OBJECT_PATH_NOT_FOUND, STATUS_DIRECTORY_NOT_EMPTY, \
- STATUS_FILE_IS_A_DIRECTORY, STATUS_NOT_IMPLEMENTED, STATUS_INVALID_HANDLE, STATUS_OBJECT_NAME_COLLISION, \
- STATUS_NO_SUCH_FILE, STATUS_CANCELLED, STATUS_OBJECT_NAME_NOT_FOUND, STATUS_SUCCESS, STATUS_ACCESS_DENIED, \
- STATUS_NOT_SUPPORTED, STATUS_INVALID_DEVICE_REQUEST, STATUS_FS_DRIVER_REQUIRED, STATUS_INVALID_INFO_CLASS
-
-# These ones not defined in nt_errors
-STATUS_SMB_BAD_UID = 0x005B0002
-STATUS_SMB_BAD_TID = 0x00050002
-
-try:
- unicode # Python 2
-except NameError:
- unicode = str # Python 3
-
-
-# Utility functions
-# and general functions.
-# There are some common functions that can be accessed from more than one SMB
-# command (or either TRANSACTION). That's why I'm putting them here
-# TODO: Return NT ERROR Codes
-
-def outputToJohnFormat(challenge, username, domain, lmresponse, ntresponse):
-# We don't want to add a possible failure here, since this is an
-# extra bonus. We try, if it fails, returns nothing
- ret_value = ''
- try:
- if len(ntresponse) > 24:
- # Extended Security - NTLMv2
- ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
- else:
- # NTLMv1
- ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username.decode('utf-16le'), domain.decode('utf-16le'), hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
- except:
- # Let's try w/o decoding Unicode
- try:
- if len(ntresponse) > 24:
- # Extended Security - NTLMv2
- ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(challenge), hexlify(ntresponse)[:32], hexlify(ntresponse)[32:]), 'hash_version':'ntlmv2'}
- else:
- # NTLMv1
- ret_value = {'hash_string':'%s::%s:%s:%s:%s' % (username, domain, hexlify(lmresponse), hexlify(ntresponse), hexlify(challenge)), 'hash_version':'ntlm'}
- except Exception as e:
- LOG.error("outputToJohnFormat: %s" % e)
- pass
-
- return ret_value
-
-def writeJohnOutputToFile(hash_string, hash_version, file_name):
- fn_data = os.path.splitext(file_name)
- if hash_version == "ntlmv2":
- output_filename = fn_data[0] + "_ntlmv2" + fn_data[1]
- else:
- output_filename = fn_data[0] + "_ntlm" + fn_data[1]
-
- with open(output_filename,"a") as f:
- f.write(hash_string)
- f.write('\n')
-
-
-def decodeSMBString( flags, text ):
- if flags & smb.SMB.FLAGS2_UNICODE:
- return text.decode('utf-16le')
- else:
- return text
-
-def encodeSMBString( flags, text ):
- if flags & smb.SMB.FLAGS2_UNICODE:
- return (text).encode('utf-16le')
- else:
- return text
-
-def getFileTime(t):
- t *= 10000000
- t += 116444736000000000
- return t
-
-def getUnixTime(t):
- t -= 116444736000000000
- t /= 10000000
- return t
-
-def getSMBDate(t):
- # TODO: Fix this :P
- d = datetime.date.fromtimestamp(t)
- year = d.year - 1980
- ret = (year << 8) + (d.month << 4) + d.day
- return ret
-
-def getSMBTime(t):
- # TODO: Fix this :P
- d = datetime.datetime.fromtimestamp(t)
- return (d.hour << 8) + (d.minute << 4) + d.second
-
-def getShares(connId, smbServer):
- config = smbServer.getServerConfig()
- sections = config.sections()
- # Remove the global one
- del(sections[sections.index('global')])
- shares = {}
- for i in sections:
- shares[i] = dict(config.items(i))
- return shares
-
-def searchShare(connId, share, smbServer):
- config = smbServer.getServerConfig()
- if config.has_section(share):
- return dict(config.items(share))
- else:
- return None
-
-def openFile(path,fileName, accessMode, fileAttributes, openMode):
- fileName = os.path.normpath(fileName.replace('\\','/'))
- errorCode = 0
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- mode = 0
- # Check the Open Mode
- if openMode & 0x10:
- # If the file does not exist, create it.
- mode = os.O_CREAT
- else:
- # If file does not exist, return an error
- if os.path.exists(pathName) is not True:
- errorCode = STATUS_NO_SUCH_FILE
- return 0,mode, pathName, errorCode
-
- if os.path.isdir(pathName) and (fileAttributes & smb.ATTR_DIRECTORY) == 0:
- # Request to open a normal file and this is actually a directory
- errorCode = STATUS_FILE_IS_A_DIRECTORY
- return 0, mode, pathName, errorCode
- # Check the Access Mode
- if accessMode & 0x7 == 1:
- mode |= os.O_WRONLY
- elif accessMode & 0x7 == 2:
- mode |= os.O_RDWR
- else:
- mode = os.O_RDONLY
-
- try:
- if sys.platform == 'win32':
- mode |= os.O_BINARY
- fid = os.open(pathName, mode)
- except Exception as e:
- LOG.error("openFile: %s,%s" % (pathName, mode) ,e)
- fid = 0
- errorCode = STATUS_ACCESS_DENIED
-
- return fid, mode, pathName, errorCode
-
-def queryFsInformation(path, filename, level=0):
-
- if isinstance(filename,unicode):
- encoding = 'utf-16le'
- flags = smb.SMB.FLAGS2_UNICODE
- else:
- encoding = 'ascii'
- flags = 0
-
- fileName = os.path.normpath(filename.replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- fileSize = os.path.getsize(pathName)
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
- if level == smb.SMB_QUERY_FS_ATTRIBUTE_INFO or level == smb2.SMB2_FILESYSTEM_ATTRIBUTE_INFO:
- data = smb.SMBQueryFsAttributeInfo()
- data['FileSystemAttributes'] = smb.FILE_CASE_SENSITIVE_SEARCH | smb.FILE_CASE_PRESERVED_NAMES
- data['MaxFilenNameLengthInBytes'] = 255
- data['LengthOfFileSystemName'] = len('XTFS')*2
- data['FileSystemName'] = 'XTFS'.encode('utf-16le')
- return data.getData()
- elif level == smb.SMB_INFO_VOLUME:
- data = smb.SMBQueryFsInfoVolume( flags = flags )
- data['VolumeLabel'] = 'SHARE'.encode(encoding)
- return data.getData()
- elif level == smb.SMB_QUERY_FS_VOLUME_INFO or level == smb2.SMB2_FILESYSTEM_VOLUME_INFO:
- data = smb.SMBQueryFsVolumeInfo()
- data['VolumeLabel'] = ''
- data['VolumeCreationTime'] = getFileTime(ctime)
- return data.getData()
- elif level == smb.SMB_QUERY_FS_SIZE_INFO:
- data = smb.SMBQueryFsSizeInfo()
- return data.getData()
- elif level == smb.FILE_FS_FULL_SIZE_INFORMATION:
- data = smb.SMBFileFsFullSizeInformation()
- return data.getData()
- elif level == smb.FILE_FS_SIZE_INFORMATION:
- data = smb.FileFsSizeInformation()
- return data.getData()
- else:
- lastWriteTime = mtime
- attribs = 0
- if os.path.isdir(pathName):
- attribs |= smb.SMB_FILE_ATTRIBUTE_DIRECTORY
- if os.path.isfile(pathName):
- attribs |= smb.SMB_FILE_ATTRIBUTE_NORMAL
- fileAttributes = attribs
- return fileSize, lastWriteTime, fileAttributes
-
-def findFirst2(path, fileName, level, searchAttributes, isSMB2 = False):
- # TODO: Depending on the level, this could be done much simpler
-
- #print "FindFirs2 path:%s, filename:%s" % (path, fileName)
- fileName = os.path.normpath(fileName.replace('\\','/'))
- # Let's choose the right encoding depending on the request
- if isinstance(fileName,unicode):
- encoding = 'utf-16le'
- flags = smb.SMB.FLAGS2_UNICODE
- else:
- encoding = 'ascii'
- flags = 0
-
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
-
- pathName = os.path.join(path,fileName)
- files = []
-
- if pathName.find('*') == -1 and pathName.find('?') == -1:
- # No search patterns
- pattern = ''
- else:
- pattern = os.path.basename(pathName)
- dirName = os.path.dirname(pathName)
-
- # Always add . and .. Not that important for Windows, but Samba whines if
- # not present (for * search only)
- if pattern == '*':
- files.append(os.path.join(dirName,'.'))
- files.append(os.path.join(dirName,'..'))
-
- if pattern != '':
- for file in os.listdir(dirName):
- if fnmatch.fnmatch(file.lower(),pattern.lower()):
- entry = os.path.join(dirName, file)
- if os.path.isdir(entry):
- if searchAttributes & smb.ATTR_DIRECTORY:
- files.append(entry)
- else:
- files.append(entry)
- else:
- if os.path.exists(pathName):
- files.append(pathName)
-
- searchResult = []
- searchCount = len(files)
- errorCode = STATUS_SUCCESS
-
- for i in files:
- if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
- item = smb.SMBFindFileBothDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO or level == smb2.SMB2_FILE_DIRECTORY_INFO:
- item = smb.SMBFindFileDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
- item = smb.SMBFindFileFullDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_INFO_STANDARD:
- item = smb.SMBFindInfoStandard( flags = flags )
- elif level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_FULL_DIRECTORY_INFO:
- item = smb.SMBFindFileIdFullDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO:
- item = smb.SMBFindFileIdBothDirectoryInfo( flags = flags )
- elif level == smb.SMB_FIND_FILE_NAMES_INFO or level == smb2.SMB2_FILE_NAMES_INFO:
- item = smb.SMBFindFileNamesInfo( flags = flags )
- else:
- LOG.error("Wrong level %d!" % level)
- return searchResult, searchCount, STATUS_NOT_SUPPORTED
-
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(i)
- if os.path.isdir(i):
- item['ExtFileAttributes'] = smb.ATTR_DIRECTORY
- else:
- item['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
-
- item['FileName'] = os.path.basename(i).encode(encoding)
-
- if level == smb.SMB_FIND_FILE_BOTH_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_ID_BOTH_DIRECTORY_INFO or level == smb2.SMB2_FILE_BOTH_DIRECTORY_INFO:
- item['EaSize'] = 0
- item['EndOfFile'] = size
- item['AllocationSize'] = size
- item['CreationTime'] = getFileTime(ctime)
- item['LastAccessTime'] = getFileTime(atime)
- item['LastWriteTime'] = getFileTime(mtime)
- item['LastChangeTime'] = getFileTime(mtime)
- item['ShortName'] = '\x00'*24
- item['FileName'] = os.path.basename(i).encode(encoding)
- padLen = (8-(len(item) % 8)) % 8
- item['NextEntryOffset'] = len(item) + padLen
- elif level == smb.SMB_FIND_FILE_DIRECTORY_INFO:
- item['EndOfFile'] = size
- item['AllocationSize'] = size
- item['CreationTime'] = getFileTime(ctime)
- item['LastAccessTime'] = getFileTime(atime)
- item['LastWriteTime'] = getFileTime(mtime)
- item['LastChangeTime'] = getFileTime(mtime)
- item['FileName'] = os.path.basename(i).encode(encoding)
- padLen = (8-(len(item) % 8)) % 8
- item['NextEntryOffset'] = len(item) + padLen
- elif level == smb.SMB_FIND_FILE_FULL_DIRECTORY_INFO or level == smb.SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO or level == smb2.SMB2_FULL_DIRECTORY_INFO:
- item['EaSize'] = 0
- item['EndOfFile'] = size
- item['AllocationSize'] = size
- item['CreationTime'] = getFileTime(ctime)
- item['LastAccessTime'] = getFileTime(atime)
- item['LastWriteTime'] = getFileTime(mtime)
- item['LastChangeTime'] = getFileTime(mtime)
- padLen = (8-(len(item) % 8)) % 8
- item['NextEntryOffset'] = len(item) + padLen
- elif level == smb.SMB_FIND_INFO_STANDARD:
- item['EaSize'] = size
- item['CreationDate'] = getSMBDate(ctime)
- item['CreationTime'] = getSMBTime(ctime)
- item['LastAccessDate'] = getSMBDate(atime)
- item['LastAccessTime'] = getSMBTime(atime)
- item['LastWriteDate'] = getSMBDate(mtime)
- item['LastWriteTime'] = getSMBTime(mtime)
- searchResult.append(item)
-
- # No more files
- if (level >= smb.SMB_FIND_FILE_DIRECTORY_INFO or isSMB2 == True) and searchCount > 0:
- searchResult[-1]['NextEntryOffset'] = 0
-
- return searchResult, searchCount, errorCode
-
-def queryFileInformation(path, filename, level):
- #print "queryFileInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
- return queryPathInformation(path,filename, level)
-
-def queryPathInformation(path, filename, level):
- # TODO: Depending on the level, this could be done much simpler
- #print "queryPathInfo path: %s, filename: %s, level:0x%x" % (path,filename,level)
- try:
- errorCode = 0
- fileName = os.path.normpath(filename.replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName):
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
- if level == smb.SMB_QUERY_FILE_BASIC_INFO:
- infoRecord = smb.SMBQueryFileBasicInfo()
- infoRecord['CreationTime'] = getFileTime(ctime)
- infoRecord['LastAccessTime'] = getFileTime(atime)
- infoRecord['LastWriteTime'] = getFileTime(mtime)
- infoRecord['LastChangeTime'] = getFileTime(mtime)
- if os.path.isdir(pathName):
- infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
- else:
- infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
- elif level == smb.SMB_QUERY_FILE_STANDARD_INFO:
- infoRecord = smb.SMBQueryFileStandardInfo()
- infoRecord['AllocationSize'] = size
- infoRecord['EndOfFile'] = size
- if os.path.isdir(pathName):
- infoRecord['Directory'] = 1
- else:
- infoRecord['Directory'] = 0
- elif level == smb.SMB_QUERY_FILE_ALL_INFO or level == smb2.SMB2_FILE_ALL_INFO:
- infoRecord = smb.SMBQueryFileAllInfo()
- infoRecord['CreationTime'] = getFileTime(ctime)
- infoRecord['LastAccessTime'] = getFileTime(atime)
- infoRecord['LastWriteTime'] = getFileTime(mtime)
- infoRecord['LastChangeTime'] = getFileTime(mtime)
- if os.path.isdir(pathName):
- infoRecord['ExtFileAttributes'] = smb.ATTR_DIRECTORY
- else:
- infoRecord['ExtFileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
- infoRecord['AllocationSize'] = size
- infoRecord['EndOfFile'] = size
- if os.path.isdir(pathName):
- infoRecord['Directory'] = 1
- else:
- infoRecord['Directory'] = 0
- infoRecord['FileName'] = filename.encode('utf-16le')
- elif level == smb2.SMB2_FILE_NETWORK_OPEN_INFO:
- infoRecord = smb.SMBFileNetworkOpenInfo()
- infoRecord['CreationTime'] = getFileTime(ctime)
- infoRecord['LastAccessTime'] = getFileTime(atime)
- infoRecord['LastWriteTime'] = getFileTime(mtime)
- infoRecord['ChangeTime'] = getFileTime(mtime)
- infoRecord['AllocationSize'] = size
- infoRecord['EndOfFile'] = size
- if os.path.isdir(pathName):
- infoRecord['FileAttributes'] = smb.ATTR_DIRECTORY
- else:
- infoRecord['FileAttributes'] = smb.ATTR_NORMAL | smb.ATTR_ARCHIVE
- elif level == smb.SMB_QUERY_FILE_EA_INFO or level == smb2.SMB2_FILE_EA_INFO:
- infoRecord = smb.SMBQueryFileEaInfo()
- elif level == smb2.SMB2_FILE_STREAM_INFO:
- infoRecord = smb.SMBFileStreamInformation()
- else:
- LOG.error('Unknown level for query path info! 0x%x' % level)
- # UNSUPPORTED
- return None, STATUS_NOT_SUPPORTED
-
- return infoRecord, errorCode
- else:
- # NOT FOUND
- return None, STATUS_OBJECT_NAME_NOT_FOUND
- except Exception as e:
- LOG.error('queryPathInfo: %s' % e)
- raise
-
-def queryDiskInformation(path):
-# TODO: Do something useful here :)
-# For now we just return fake values
- totalUnits = 65535
- freeUnits = 65535
- return totalUnits, freeUnits
-
-# Here we implement the NT transaction handlers
-class NTTRANSCommands:
- def default(self, connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- pass
-
-# Here we implement the NT transaction handlers
-class TRANSCommands:
- @staticmethod
- def lanMan(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- # Minimal [MS-RAP] implementation, just to return the shares
- connData = smbServer.getConnectionData(connId)
-
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- if struct.unpack('<H',parameters[:2])[0] == 0:
- # NetShareEnum Request
- netShareEnum = smb.SMBNetShareEnum(parameters)
- if netShareEnum['InfoLevel'] == 1:
- shares = getShares(connId, smbServer)
- respParameters = smb.SMBNetShareEnumResponse()
- respParameters['EntriesReturned'] = len(shares)
- respParameters['EntriesAvailable'] = len(shares)
- tailData = ''
- for i in shares:
- # NetShareInfo1 len == 20
- entry = smb.NetShareInfo1()
- entry['NetworkName'] = i + '\x00'*(13-len(i))
- entry['Type'] = int(shares[i]['share type'])
- # (beto) If offset == 0 it crashes explorer.exe on windows 7
- entry['RemarkOffsetLow'] = 20 * len(shares) + len(tailData)
- respData += entry.getData()
- if 'comment' in shares[i]:
- tailData += shares[i]['comment'] + '\x00'
- else:
- tailData += '\x00'
- respData += tailData
- else:
- # We don't support other info levels
- errorCode = STATUS_NOT_SUPPORTED
- elif struct.unpack('<H',parameters[:2])[0] == 13:
- # NetrServerGetInfo Request
- respParameters = smb.SMBNetServerGetInfoResponse()
- netServerInfo = smb.SMBNetServerInfo1()
- netServerInfo['ServerName'] = smbServer.getServerName()
- respData = str(netServerInfo)
- respParameters['TotalBytesAvailable'] = len(respData)
- elif struct.unpack('<H',parameters[:2])[0] == 1:
- # NetrShareGetInfo Request
- request = smb.SMBNetShareGetInfo(parameters)
- respParameters = smb.SMBNetShareGetInfoResponse()
- shares = getShares(connId, smbServer)
- share = shares[request['ShareName'].upper()]
- shareInfo = smb.NetShareInfo1()
- shareInfo['NetworkName'] = request['ShareName'].upper() + '\x00'
- shareInfo['Type'] = int(share['share type'])
- respData = shareInfo.getData()
- if 'comment' in share:
- shareInfo['RemarkOffsetLow'] = len(respData)
- respData += share['comment'] + '\x00'
- respParameters['TotalBytesAvailable'] = len(respData)
-
- else:
- # We don't know how to handle anything else
- errorCode = STATUS_NOT_SUPPORTED
-
- smbServer.setConnectionData(connId, connData)
-
- return respSetup, respParameters, respData, errorCode
-
- @staticmethod
- def transactNamedPipe(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
-
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
- transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
-
- # Extract the FID
- fid = struct.unpack('<H', transParameters['Setup'][2:])[0]
-
- if fid in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][fid]['FileHandle']
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- os.write(fileHandle,data)
- respData = os.read(fileHandle,data)
- else:
- sock = connData['OpenedFiles'][fid]['Socket']
- sock.send(data)
- respData = sock.recv(maxDataCount)
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- smbServer.setConnectionData(connId, connData)
-
- return respSetup, respParameters, respData, errorCode
-
-# Here we implement the transaction2 handlers
-class TRANS2Commands:
- # All these commands return setup, parameters, data, errorCode
- @staticmethod
- def setPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
-
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- setPathInfoParameters = smb.SMBSetPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
- if recvPacket['Tid'] in connData['ConnectedShares']:
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- fileName = decodeSMBString(recvPacket['Flags2'], setPathInfoParameters['FileName'])
- fileName = os.path.normpath(fileName.replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\') and path != '':
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName):
- informationLevel = setPathInfoParameters['InformationLevel']
- if informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
- infoRecord = smb.SMBSetFileBasicInfo(data)
- # Creation time won't be set, the other ones we play with.
- atime = infoRecord['LastAccessTime']
- if atime == 0:
- atime = -1
- else:
- atime = getUnixTime(atime)
- mtime = infoRecord['LastWriteTime']
- if mtime == 0:
- mtime = -1
- else:
- mtime = getUnixTime(mtime)
- if mtime != -1 or atime != -1:
- os.utime(pathName,(atime,mtime))
- else:
- smbServer.log('Unknown level for set path info! 0x%x' % setPathInfoParameters['InformationLevel'], logging.ERROR)
- # UNSUPPORTED
- errorCode = STATUS_NOT_SUPPORTED
- else:
- errorCode = STATUS_OBJECT_NAME_NOT_FOUND
-
- if errorCode == STATUS_SUCCESS:
- respParameters = smb.SMBSetPathInformationResponse_Parameters()
-
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- smbServer.setConnectionData(connId, connData)
-
- return respSetup, respParameters, respData, errorCode
-
-
- @staticmethod
- def setFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
-
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- setFileInfoParameters = smb.SMBSetFileInformation_Parameters(parameters)
-
- if recvPacket['Tid'] in connData['ConnectedShares']:
- if setFileInfoParameters['FID'] in connData['OpenedFiles']:
- fileName = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileName']
- informationLevel = setFileInfoParameters['InformationLevel']
- if informationLevel == smb.SMB_SET_FILE_DISPOSITION_INFO:
- infoRecord = smb.SMBSetFileDispositionInfo(parameters)
- if infoRecord['DeletePending'] > 0:
- # Mark this file for removal after closed
- connData['OpenedFiles'][setFileInfoParameters['FID']]['DeleteOnClose'] = True
- respParameters = smb.SMBSetFileInformationResponse_Parameters()
- elif informationLevel == smb.SMB_SET_FILE_BASIC_INFO:
- infoRecord = smb.SMBSetFileBasicInfo(data)
- # Creation time won't be set, the other ones we play with.
- atime = infoRecord['LastAccessTime']
- if atime == 0:
- atime = -1
- else:
- atime = getUnixTime(atime)
- mtime = infoRecord['LastWriteTime']
- if mtime == 0:
- mtime = -1
- else:
- mtime = getUnixTime(mtime)
- os.utime(fileName,(atime,mtime))
- elif informationLevel == smb.SMB_SET_FILE_END_OF_FILE_INFO:
- fileHandle = connData['OpenedFiles'][setFileInfoParameters['FID']]['FileHandle']
- infoRecord = smb.SMBSetFileEndOfFileInfo(data)
- if infoRecord['EndOfFile'] > 0:
- os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
- os.write(fileHandle, '\x00')
- else:
- smbServer.log('Unknown level for set file info! 0x%x' % setFileInfoParameters['InformationLevel'], logging.ERROR)
- # UNSUPPORTED
- errorCode = STATUS_NOT_SUPPORTED
- else:
- errorCode = STATUS_NO_SUCH_FILE
-
- if errorCode == STATUS_SUCCESS:
- respParameters = smb.SMBSetFileInformationResponse_Parameters()
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- smbServer.setConnectionData(connId, connData)
-
- return respSetup, respParameters, respData, errorCode
-
- @staticmethod
- def queryFileInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
-
- respSetup = ''
- respParameters = ''
- respData = ''
-
- queryFileInfoParameters = smb.SMBQueryFileInformation_Parameters(parameters)
-
- if recvPacket['Tid'] in connData['ConnectedShares']:
- if queryFileInfoParameters['FID'] in connData['OpenedFiles']:
- fileName = connData['OpenedFiles'][queryFileInfoParameters['FID']]['FileName']
-
- infoRecord, errorCode = queryFileInformation('', fileName, queryFileInfoParameters['InformationLevel'])
-
- if infoRecord is not None:
- respParameters = smb.SMBQueryFileInformationResponse_Parameters()
- respData = infoRecord
- else:
- errorCode = STATUS_INVALID_HANDLE
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- smbServer.setConnectionData(connId, connData)
-
- return respSetup, respParameters, respData, errorCode
-
- @staticmethod
- def queryPathInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
-
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = 0
-
- queryPathInfoParameters = smb.SMBQueryPathInformation_Parameters(flags = recvPacket['Flags2'], data = parameters)
-
- if recvPacket['Tid'] in connData['ConnectedShares']:
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- try:
- infoRecord, errorCode = queryPathInformation(path, decodeSMBString(recvPacket['Flags2'], queryPathInfoParameters['FileName']), queryPathInfoParameters['InformationLevel'])
- except Exception as e:
- smbServer.log("queryPathInformation: %s" % e,logging.ERROR)
-
- if infoRecord is not None:
- respParameters = smb.SMBQueryPathInformationResponse_Parameters()
- respData = infoRecord
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- smbServer.setConnectionData(connId, connData)
-
- return respSetup, respParameters, respData, errorCode
-
- @staticmethod
- def queryFsInformation(connId, smbServer, recvPacket, parameters, data, maxDataCount = 0):
- connData = smbServer.getConnectionData(connId)
- errorCode = 0
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- data = queryFsInformation(connData['ConnectedShares'][recvPacket['Tid']]['path'], '', struct.unpack('<H',parameters)[0])
-
- smbServer.setConnectionData(connId, connData)
-
- return '','', data, errorCode
-
- @staticmethod
- def findNext2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
- connData = smbServer.getConnectionData(connId)
-
- respSetup = ''
- respParameters = ''
- respData = ''
- errorCode = STATUS_SUCCESS
- findNext2Parameters = smb.SMBFindNext2_Parameters(flags = recvPacket['Flags2'], data = parameters)
-
- sid = findNext2Parameters['SID']
- if recvPacket['Tid'] in connData['ConnectedShares']:
- if sid in connData['SIDs']:
- searchResult = connData['SIDs'][sid]
- respParameters = smb.SMBFindNext2Response_Parameters()
- endOfSearch = 1
- searchCount = 1
- totalData = 0
- for i in enumerate(searchResult):
- data = i[1].getData()
- lenData = len(data)
- if (totalData+lenData) >= maxDataCount or (i[0]+1) >= findNext2Parameters['SearchCount']:
- # We gotta stop here and continue on a find_next2
- endOfSearch = 0
- connData['SIDs'][sid] = searchResult[i[0]:]
- respParameters['LastNameOffset'] = totalData
- break
- else:
- searchCount +=1
- respData += data
- totalData += lenData
-
- # Have we reached the end of the search or still stuff to send?
- if endOfSearch > 0:
- # Let's remove the SID from our ConnData
- del(connData['SIDs'][sid])
-
- respParameters['EndOfSearch'] = endOfSearch
- respParameters['SearchCount'] = searchCount
- else:
- errorCode = STATUS_INVALID_HANDLE
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- smbServer.setConnectionData(connId, connData)
-
- return respSetup, respParameters, respData, errorCode
-
- @staticmethod
- def findFirst2(connId, smbServer, recvPacket, parameters, data, maxDataCount):
- connData = smbServer.getConnectionData(connId)
-
- respSetup = ''
- respParameters = ''
- respData = ''
- findFirst2Parameters = smb.SMBFindFirst2_Parameters( recvPacket['Flags2'], data = parameters)
-
- if recvPacket['Tid'] in connData['ConnectedShares']:
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
-
- searchResult, searchCount, errorCode = findFirst2(path,
- decodeSMBString( recvPacket['Flags2'], findFirst2Parameters['FileName'] ),
- findFirst2Parameters['InformationLevel'],
- findFirst2Parameters['SearchAttributes'] )
-
- respParameters = smb.SMBFindFirst2Response_Parameters()
- endOfSearch = 1
- sid = 0x80 # default SID
- searchCount = 0
- totalData = 0
- for i in enumerate(searchResult):
- #i[1].dump()
- data = i[1].getData()
- lenData = len(data)
- if (totalData+lenData) >= maxDataCount or (i[0]+1) > findFirst2Parameters['SearchCount']:
- # We gotta stop here and continue on a find_next2
- endOfSearch = 0
- # Simple way to generate a fid
- if len(connData['SIDs']) == 0:
- sid = 1
- else:
- sid = connData['SIDs'].keys()[-1] + 1
- # Store the remaining search results in the ConnData SID
- connData['SIDs'][sid] = searchResult[i[0]:]
- respParameters['LastNameOffset'] = totalData
- break
- else:
- searchCount +=1
- respData += data
-
- padLen = (8-(lenData % 8)) %8
- respData += '\xaa'*padLen
- totalData += lenData + padLen
-
- respParameters['SID'] = sid
- respParameters['EndOfSearch'] = endOfSearch
- respParameters['SearchCount'] = searchCount
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- smbServer.setConnectionData(connId, connData)
-
- return respSetup, respParameters, respData, errorCode
-
-# Here we implement the commands handlers
-class SMBCommands:
-
- @staticmethod
- def smbTransaction(connId, smbServer, SMBCommand, recvPacket, transCommands):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
-
- transParameters= smb.SMBTransaction_Parameters(SMBCommand['Parameters'])
-
- # Do the stuff
- if transParameters['ParameterCount'] != transParameters['TotalParameterCount']:
- # TODO: Handle partial parameters
- raise Exception("Unsupported partial parameters in TRANSACT2!")
- else:
- transData = smb.SMBTransaction_SData(flags = recvPacket['Flags2'])
- # Standard says servers shouldn't trust Parameters and Data comes
- # in order, so we have to parse the offsets, ugly
-
- paramCount = transParameters['ParameterCount']
- transData['Trans_ParametersLength'] = paramCount
- dataCount = transParameters['DataCount']
- transData['Trans_DataLength'] = dataCount
- transData.fromString(SMBCommand['Data'])
- if transParameters['ParameterOffset'] > 0:
- paramOffset = transParameters['ParameterOffset'] - 63 - transParameters['SetupLength']
- transData['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
- else:
- transData['Trans_Parameters'] = ''
-
- if transParameters['DataOffset'] > 0:
- dataOffset = transParameters['DataOffset'] - 63 - transParameters['SetupLength']
- transData['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
- else:
- transData['Trans_Data'] = ''
-
- # Call the handler for this TRANSACTION
- if transParameters['SetupCount'] == 0:
- # No subcommand, let's play with the Name
- command = decodeSMBString(recvPacket['Flags2'],transData['Name'])
- else:
- command = struct.unpack('<H', transParameters['Setup'][:2])[0]
-
- if command in transCommands:
- # Call the TRANS subcommand
- setup = ''
- parameters = ''
- data = ''
- try:
- setup, parameters, data, errorCode = transCommands[command](connId,
- smbServer,
- recvPacket,
- transData['Trans_Parameters'],
- transData['Trans_Data'],
- transParameters['MaxDataCount'])
- except Exception as e:
- #print 'Transaction: %s' % e,e
- smbServer.log('Transaction: (%r,%s)' % (command, e), logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- #raise
-
- if setup == '' and parameters == '' and data == '':
- # Something wen't wrong
- respParameters = ''
- respData = ''
- else:
- # Build the answer
- data = str(data)
- remainingData = len(data)
- parameters = str(parameters)
- remainingParameters = len(parameters)
- commands = []
- dataDisplacement = 0
- while remainingData > 0 or remainingParameters > 0:
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- respParameters = smb.SMBTransactionResponse_Parameters()
- respData = smb.SMBTransaction2Response_Data()
-
- respParameters['TotalParameterCount'] = len(parameters)
- respParameters['ParameterCount'] = len(parameters)
- respData['Trans_ParametersLength'] = len(parameters)
- respParameters['TotalDataCount'] = len(data)
- respParameters['DataDisplacement'] = dataDisplacement
-
- # TODO: Do the same for parameters
- if len(data) > transParameters['MaxDataCount']:
- # Answer doesn't fit in this packet
- LOG.debug("Lowering answer from %d to %d" % (len(data),transParameters['MaxDataCount']) )
- respParameters['DataCount'] = transParameters['MaxDataCount']
- else:
- respParameters['DataCount'] = len(data)
-
- respData['Trans_DataLength'] = respParameters['DataCount']
- respParameters['SetupCount'] = len(setup)
- respParameters['Setup'] = setup
- # TODO: Make sure we're calculating the pad right
- if len(parameters) > 0:
- #padLen = 4 - (55 + len(setup)) % 4
- padLen = (4 - (55 + len(setup)) % 4 ) % 4
- padBytes = '\xFF' * padLen
- respData['Pad1'] = padBytes
- respParameters['ParameterOffset'] = 55 + len(setup) + padLen
- else:
- padLen = 0
- respParameters['ParameterOffset'] = 0
- respData['Pad1'] = ''
-
- if len(data) > 0:
- #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
- pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
- respData['Pad2'] = '\xFF' * pad2Len
- respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
- else:
- respParameters['DataOffset'] = 0
- respData['Pad2'] = ''
-
- respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
- respData['Trans_Data'] = data[:respParameters['DataCount']]
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- data = data[respParameters['DataCount']:]
- remainingData -= respParameters['DataCount']
- dataDisplacement += respParameters['DataCount'] + 1
-
- parameters = parameters[respParameters['ParameterCount']:]
- remainingParameters -= respParameters['ParameterCount']
- commands.append(respSMBCommand)
-
- smbServer.setConnectionData(connId, connData)
- return commands, None, errorCode
-
- else:
- smbServer.log("Unsupported Transact command %r" % command, logging.ERROR)
- respParameters = ''
- respData = ''
- errorCode = STATUS_NOT_IMPLEMENTED
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
-
- @staticmethod
- def smbNTTransact(connId, smbServer, SMBCommand, recvPacket, transCommands):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
-
- NTTransParameters= smb.SMBNTTransaction_Parameters(SMBCommand['Parameters'])
- # Do the stuff
- if NTTransParameters['ParameterCount'] != NTTransParameters['TotalParameterCount']:
- # TODO: Handle partial parameters
- raise Exception("Unsupported partial parameters in NTTrans!")
- else:
- NTTransData = smb.SMBNTTransaction_Data()
- # Standard says servers shouldn't trust Parameters and Data comes
- # in order, so we have to parse the offsets, ugly
-
- paramCount = NTTransParameters['ParameterCount']
- NTTransData['NT_Trans_ParametersLength'] = paramCount
- dataCount = NTTransParameters['DataCount']
- NTTransData['NT_Trans_DataLength'] = dataCount
-
- if NTTransParameters['ParameterOffset'] > 0:
- paramOffset = NTTransParameters['ParameterOffset'] - 73 - NTTransParameters['SetupLength']
- NTTransData['NT_Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
- else:
- NTTransData['NT_Trans_Parameters'] = ''
-
- if NTTransParameters['DataOffset'] > 0:
- dataOffset = NTTransParameters['DataOffset'] - 73 - NTTransParameters['SetupLength']
- NTTransData['NT_Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
- else:
- NTTransData['NT_Trans_Data'] = ''
-
- # Call the handler for this TRANSACTION
- command = NTTransParameters['Function']
- if command in transCommands:
- # Call the NT TRANS subcommand
- setup = ''
- parameters = ''
- data = ''
- try:
- setup, parameters, data, errorCode = transCommands[command](connId,
- smbServer,
- recvPacket,
- NTTransData['NT_Trans_Parameters'],
- NTTransData['NT_Trans_Data'],
- NTTransParameters['MaxDataCount'])
- except Exception as e:
- smbServer.log('NTTransaction: (0x%x,%s)' % (command, e), logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- #raise
-
- if setup == '' and parameters == '' and data == '':
- # Something wen't wrong
- respParameters = ''
- respData = ''
- if errorCode == STATUS_SUCCESS:
- errorCode = STATUS_ACCESS_DENIED
- else:
- # Build the answer
- data = str(data)
- remainingData = len(data)
- parameters = str(parameters)
- remainingParameters = len(parameters)
- commands = []
- dataDisplacement = 0
- while remainingData > 0 or remainingParameters > 0:
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- respParameters = smb.SMBNTTransactionResponse_Parameters()
- respData = smb.SMBNTTransactionResponse_Data()
-
- respParameters['TotalParameterCount'] = len(parameters)
- respParameters['ParameterCount'] = len(parameters)
- respData['Trans_ParametersLength'] = len(parameters)
- respParameters['TotalDataCount'] = len(data)
- respParameters['DataDisplacement'] = dataDisplacement
- # TODO: Do the same for parameters
- if len(data) > NTTransParameters['MaxDataCount']:
- # Answer doesn't fit in this packet
- LOG.debug("Lowering answer from %d to %d" % (len(data),NTTransParameters['MaxDataCount']) )
- respParameters['DataCount'] = NTTransParameters['MaxDataCount']
- else:
- respParameters['DataCount'] = len(data)
-
- respData['NT_Trans_DataLength'] = respParameters['DataCount']
- respParameters['SetupCount'] = len(setup)
- respParameters['Setup'] = setup
- # TODO: Make sure we're calculating the pad right
- if len(parameters) > 0:
- #padLen = 4 - (71 + len(setup)) % 4
- padLen = (4 - (73 + len(setup)) % 4 ) % 4
- padBytes = '\xFF' * padLen
- respData['Pad1'] = padBytes
- respParameters['ParameterOffset'] = 73 + len(setup) + padLen
- else:
- padLen = 0
- respParameters['ParameterOffset'] = 0
- respData['Pad1'] = ''
-
- if len(data) > 0:
- #pad2Len = 4 - (71 + len(setup) + padLen + len(parameters)) % 4
- pad2Len = (4 - (73 + len(setup) + padLen + len(parameters)) % 4) % 4
- respData['Pad2'] = '\xFF' * pad2Len
- respParameters['DataOffset'] = 73 + len(setup) + padLen + len(parameters) + pad2Len
- else:
- respParameters['DataOffset'] = 0
- respData['Pad2'] = ''
-
- respData['NT_Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
- respData['NT_Trans_Data'] = data[:respParameters['DataCount']]
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- data = data[respParameters['DataCount']:]
- remainingData -= respParameters['DataCount']
- dataDisplacement += respParameters['DataCount'] + 1
-
- parameters = parameters[respParameters['ParameterCount']:]
- remainingParameters -= respParameters['ParameterCount']
- commands.append(respSMBCommand)
-
- smbServer.setConnectionData(connId, connData)
- return commands, None, errorCode
-
- else:
- #smbServer.log("Unsupported NTTransact command 0x%x" % command, logging.ERROR)
- respParameters = ''
- respData = ''
- errorCode = STATUS_NOT_IMPLEMENTED
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
-
- @staticmethod
- def smbTransaction2(connId, smbServer, SMBCommand, recvPacket, transCommands):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
-
- trans2Parameters= smb.SMBTransaction2_Parameters(SMBCommand['Parameters'])
-
- # Do the stuff
- if trans2Parameters['ParameterCount'] != trans2Parameters['TotalParameterCount']:
- # TODO: Handle partial parameters
- #print "Unsupported partial parameters in TRANSACT2!"
- raise Exception("Unsupported partial parameters in TRANSACT2!")
- else:
- trans2Data = smb.SMBTransaction2_Data()
- # Standard says servers shouldn't trust Parameters and Data comes
- # in order, so we have to parse the offsets, ugly
-
- paramCount = trans2Parameters['ParameterCount']
- trans2Data['Trans_ParametersLength'] = paramCount
- dataCount = trans2Parameters['DataCount']
- trans2Data['Trans_DataLength'] = dataCount
-
- if trans2Parameters['ParameterOffset'] > 0:
- paramOffset = trans2Parameters['ParameterOffset'] - 63 - trans2Parameters['SetupLength']
- trans2Data['Trans_Parameters'] = SMBCommand['Data'][paramOffset:paramOffset+paramCount]
- else:
- trans2Data['Trans_Parameters'] = ''
-
- if trans2Parameters['DataOffset'] > 0:
- dataOffset = trans2Parameters['DataOffset'] - 63 - trans2Parameters['SetupLength']
- trans2Data['Trans_Data'] = SMBCommand['Data'][dataOffset:dataOffset + dataCount]
- else:
- trans2Data['Trans_Data'] = ''
-
- # Call the handler for this TRANSACTION
- command = struct.unpack('<H', trans2Parameters['Setup'])[0]
- if command in transCommands:
- # Call the TRANS2 subcommand
- try:
- setup, parameters, data, errorCode = transCommands[command](connId,
- smbServer,
- recvPacket,
- trans2Data['Trans_Parameters'],
- trans2Data['Trans_Data'],
- trans2Parameters['MaxDataCount'])
- except Exception as e:
- smbServer.log('Transaction2: (0x%x,%s)' % (command, e), logging.ERROR)
- #import traceback
- #traceback.print_exc()
- raise
-
- if setup == '' and parameters == '' and data == '':
- # Something wen't wrong
- respParameters = ''
- respData = ''
- else:
- # Build the answer
- data = str(data)
- remainingData = len(data)
- parameters = str(parameters)
- remainingParameters = len(parameters)
- commands = []
- dataDisplacement = 0
- while remainingData > 0 or remainingParameters > 0:
- respSMBCommand = smb.SMBCommand(recvPacket['Command'])
- respParameters = smb.SMBTransaction2Response_Parameters()
- respData = smb.SMBTransaction2Response_Data()
-
- respParameters['TotalParameterCount'] = len(parameters)
- respParameters['ParameterCount'] = len(parameters)
- respData['Trans_ParametersLength'] = len(parameters)
- respParameters['TotalDataCount'] = len(data)
- respParameters['DataDisplacement'] = dataDisplacement
- # TODO: Do the same for parameters
- if len(data) > trans2Parameters['MaxDataCount']:
- # Answer doesn't fit in this packet
- LOG.debug("Lowering answer from %d to %d" % (len(data),trans2Parameters['MaxDataCount']) )
- respParameters['DataCount'] = trans2Parameters['MaxDataCount']
- else:
- respParameters['DataCount'] = len(data)
-
- respData['Trans_DataLength'] = respParameters['DataCount']
- respParameters['SetupCount'] = len(setup)
- respParameters['Setup'] = setup
- # TODO: Make sure we're calculating the pad right
- if len(parameters) > 0:
- #padLen = 4 - (55 + len(setup)) % 4
- padLen = (4 - (55 + len(setup)) % 4 ) % 4
- padBytes = '\xFF' * padLen
- respData['Pad1'] = padBytes
- respParameters['ParameterOffset'] = 55 + len(setup) + padLen
- else:
- padLen = 0
- respParameters['ParameterOffset'] = 0
- respData['Pad1'] = ''
-
- if len(data) > 0:
- #pad2Len = 4 - (55 + len(setup) + padLen + len(parameters)) % 4
- pad2Len = (4 - (55 + len(setup) + padLen + len(parameters)) % 4) % 4
- respData['Pad2'] = '\xFF' * pad2Len
- respParameters['DataOffset'] = 55 + len(setup) + padLen + len(parameters) + pad2Len
- else:
- respParameters['DataOffset'] = 0
- respData['Pad2'] = ''
-
- respData['Trans_Parameters'] = parameters[:respParameters['ParameterCount']]
- respData['Trans_Data'] = data[:respParameters['DataCount']]
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- data = data[respParameters['DataCount']:]
- remainingData -= respParameters['DataCount']
- dataDisplacement += respParameters['DataCount'] + 1
-
- parameters = parameters[respParameters['ParameterCount']:]
- remainingParameters -= respParameters['ParameterCount']
- commands.append(respSMBCommand)
-
- smbServer.setConnectionData(connId, connData)
- return commands, None, errorCode
-
- else:
- smbServer.log("Unsupported Transact/2 command 0x%x" % command, logging.ERROR)
- respParameters = ''
- respData = ''
- errorCode = STATUS_NOT_IMPLEMENTED
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComLockingAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOCKING_ANDX)
- respParameters = ''
- respData = ''
-
- # I'm actually doing nothing.. just make MacOS happy ;)
- errorCode = STATUS_SUCCESS
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
-
- @staticmethod
- def smbComClose(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CLOSE)
- respParameters = ''
- respData = ''
-
- comClose = smb.SMBClose_Parameters(SMBCommand['Parameters'])
-
- if comClose['FID'] in connData['OpenedFiles']:
- errorCode = STATUS_SUCCESS
- fileHandle = connData['OpenedFiles'][comClose['FID']]['FileHandle']
- try:
- if fileHandle == PIPE_FILE_DESCRIPTOR:
- connData['OpenedFiles'][comClose['FID']]['Socket'].close()
- elif fileHandle != VOID_FILE_DESCRIPTOR:
- os.close(fileHandle)
- except Exception as e:
- smbServer.log("comClose %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- # Check if the file was marked for removal
- if connData['OpenedFiles'][comClose['FID']]['DeleteOnClose'] is True:
- try:
- os.remove(connData['OpenedFiles'][comClose['FID']]['FileName'])
- except Exception as e:
- smbServer.log("comClose %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- del(connData['OpenedFiles'][comClose['FID']])
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComWrite(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE)
- respParameters = smb.SMBWriteResponse_Parameters()
- respData = ''
-
- comWriteParameters = smb.SMBWrite_Parameters(SMBCommand['Parameters'])
- comWriteData = smb.SMBWrite_Data(SMBCommand['Data'])
-
- if comWriteParameters['Fid'] in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][comWriteParameters['Fid']]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- # TODO: Handle big size files
- # If we're trying to write past the file end we just skip the write call (Vista does this)
- if os.lseek(fileHandle, 0, 2) >= comWriteParameters['Offset']:
- os.lseek(fileHandle,comWriteParameters['Offset'],0)
- os.write(fileHandle,comWriteData['Data'])
- else:
- sock = connData['OpenedFiles'][comWriteParameters['Fid']]['Socket']
- sock.send(comWriteData['Data'])
- respParameters['Count'] = comWriteParameters['Count']
- except Exception as e:
- smbServer.log('smbComWrite: %s' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
-
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComFlush(connId, smbServer, SMBCommand,recvPacket ):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_FLUSH)
- respParameters = ''
- respData = ''
-
- comFlush = smb.SMBFlush_Parameters(SMBCommand['Parameters'])
-
- if comFlush['FID'] in connData['OpenedFiles']:
- errorCode = STATUS_SUCCESS
- fileHandle = connData['OpenedFiles'][comFlush['FID']]['FileHandle']
- try:
- os.fsync(fileHandle)
- except Exception as e:
- smbServer.log("comFlush %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
-
- @staticmethod
- def smbComCreateDirectory(connId, smbServer, SMBCommand,recvPacket ):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_CREATE_DIRECTORY)
- respParameters = ''
- respData = ''
-
- comCreateDirectoryData= smb.SMBCreateDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
-
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- errorCode = STATUS_SUCCESS
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comCreateDirectoryData['DirectoryName']).replace('\\','/'))
- if len(fileName) > 0:
- if fileName[0] == '/' or fileName[0] == '\\':
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName):
- errorCode = STATUS_OBJECT_NAME_COLLISION
-
- # TODO: More checks here in the future.. Specially when we support
- # user access
- else:
- try:
- os.mkdir(pathName)
- except Exception as e:
- smbServer.log("smbComCreateDirectory: %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
-
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComRename(connId, smbServer, SMBCommand, recvPacket ):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_RENAME)
- respParameters = ''
- respData = ''
-
- comRenameData = smb.SMBRename_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- errorCode = STATUS_SUCCESS
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- oldFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['OldFileName']).replace('\\','/'))
- newFileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comRenameData['NewFileName']).replace('\\','/'))
- if len(oldFileName) > 0 and (oldFileName[0] == '/' or oldFileName[0] == '\\'):
- # strip leading '/'
- oldFileName = oldFileName[1:]
- oldPathName = os.path.join(path,oldFileName)
- if len(newFileName) > 0 and (newFileName[0] == '/' or newFileName[0] == '\\'):
- # strip leading '/'
- newFileName = newFileName[1:]
- newPathName = os.path.join(path,newFileName)
-
- if os.path.exists(oldPathName) is not True:
- errorCode = STATUS_NO_SUCH_FILE
-
- # TODO: More checks here in the future.. Specially when we support
- # user access
- else:
- try:
- os.rename(oldPathName,newPathName)
- except OSError as e:
- smbServer.log("smbComRename: %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
-
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComDelete(connId, smbServer, SMBCommand, recvPacket ):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE)
- respParameters = ''
- respData = ''
-
- comDeleteData = smb.SMBDelete_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
-
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- errorCode = STATUS_SUCCESS
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteData['FileName']).replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName) is not True:
- errorCode = STATUS_NO_SUCH_FILE
-
- # TODO: More checks here in the future.. Specially when we support
- # user access
- else:
- try:
- os.remove(pathName)
- except OSError as e:
- smbServer.log("smbComDelete: %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
-
- @staticmethod
- def smbComDeleteDirectory(connId, smbServer, SMBCommand, recvPacket ):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_DELETE_DIRECTORY)
- respParameters = ''
- respData = ''
-
- comDeleteDirectoryData= smb.SMBDeleteDirectory_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
-
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- errorCode = STATUS_SUCCESS
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],comDeleteDirectoryData['DirectoryName']).replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- if os.path.exists(pathName) is not True:
- errorCode = STATUS_NO_SUCH_FILE
-
- # TODO: More checks here in the future.. Specially when we support
- # user access
- else:
- try:
- os.rmdir(pathName)
- except OSError as e:
- smbServer.log("smbComDeleteDirectory: %s" % e,logging.ERROR)
- if e.errno == errno.ENOTEMPTY:
- errorCode = STATUS_DIRECTORY_NOT_EMPTY
- else:
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
-
- @staticmethod
- def smbComWriteAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_WRITE_ANDX)
- respParameters = smb.SMBWriteAndXResponse_Parameters()
- respData = ''
-
- if SMBCommand['WordCount'] == 0x0C:
- writeAndX = smb.SMBWriteAndX_Parameters_Short(SMBCommand['Parameters'])
- writeAndXData = smb.SMBWriteAndX_Data_Short()
- else:
- writeAndX = smb.SMBWriteAndX_Parameters(SMBCommand['Parameters'])
- writeAndXData = smb.SMBWriteAndX_Data()
- writeAndXData['DataLength'] = writeAndX['DataLength']
- writeAndXData['DataOffset'] = writeAndX['DataOffset']
- writeAndXData.fromString(SMBCommand['Data'])
-
-
- if writeAndX['Fid'] in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][writeAndX['Fid']]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- offset = writeAndX['Offset']
- if 'HighOffset' in writeAndX.fields:
- offset += (writeAndX['HighOffset'] << 32)
- # If we're trying to write past the file end we just skip the write call (Vista does this)
- if os.lseek(fileHandle, 0, 2) >= offset:
- os.lseek(fileHandle,offset,0)
- os.write(fileHandle,writeAndXData['Data'])
- else:
- sock = connData['OpenedFiles'][writeAndX['Fid']]['Socket']
- sock.send(writeAndXData['Data'])
-
- respParameters['Count'] = writeAndX['DataLength']
- respParameters['Available']= 0xff
- except Exception as e:
- smbServer.log('smbComWriteAndx: %s' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComRead(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ)
- respParameters = smb.SMBReadResponse_Parameters()
- respData = smb.SMBReadResponse_Data()
-
- comReadParameters = smb.SMBRead_Parameters(SMBCommand['Parameters'])
-
- if comReadParameters['Fid'] in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][comReadParameters['Fid']]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- # TODO: Handle big size files
- os.lseek(fileHandle,comReadParameters['Offset'],0)
- content = os.read(fileHandle,comReadParameters['Count'])
- else:
- sock = connData['OpenedFiles'][comReadParameters['Fid']]['Socket']
- content = sock.recv(comReadParameters['Count'])
- respParameters['Count'] = len(content)
- respData['DataLength'] = len(content)
- respData['Data'] = content
- except Exception as e:
- smbServer.log('smbComRead: %s ' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComReadAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_READ_ANDX)
- respParameters = smb.SMBReadAndXResponse_Parameters()
- respData = ''
-
- if SMBCommand['WordCount'] == 0x0A:
- readAndX = smb.SMBReadAndX_Parameters2(SMBCommand['Parameters'])
- else:
- readAndX = smb.SMBReadAndX_Parameters(SMBCommand['Parameters'])
-
- if readAndX['Fid'] in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][readAndX['Fid']]['FileHandle']
- errorCode = 0
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- offset = readAndX['Offset']
- if 'HighOffset' in readAndX.fields:
- offset += (readAndX['HighOffset'] << 32)
- os.lseek(fileHandle,offset,0)
- content = os.read(fileHandle,readAndX['MaxCount'])
- else:
- sock = connData['OpenedFiles'][readAndX['Fid']]['Socket']
- content = sock.recv(readAndX['MaxCount'])
- respParameters['Remaining'] = 0xffff
- respParameters['DataCount'] = len(content)
- respParameters['DataOffset'] = 59
- respParameters['DataCount_Hi'] = 0
- respData = content
- except Exception as e:
- smbServer.log('smbComReadAndX: %s ' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbQueryInformation(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION)
- respParameters = smb.SMBQueryInformationResponse_Parameters()
- respData = ''
-
- queryInformation= smb.SMBQueryInformation_Data(flags = recvPacket['Flags2'], data = SMBCommand['Data'])
-
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- fileSize, lastWriteTime, fileAttributes = queryFsInformation(
- connData['ConnectedShares'][recvPacket['Tid']]['path'],
- decodeSMBString(recvPacket['Flags2'],queryInformation['FileName']))
-
- respParameters['FileSize'] = fileSize
- respParameters['LastWriteTime'] = lastWriteTime
- respParameters['FileAttributes'] = fileAttributes
- errorCode = STATUS_SUCCESS
- else:
- # STATUS_SMB_BAD_TID
- errorCode = STATUS_SMB_BAD_TID
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbQueryInformationDisk(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION_DISK)
- respParameters = smb.SMBQueryInformationDiskResponse_Parameters()
- respData = ''
-
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- totalUnits, freeUnits = queryDiskInformation(
- connData['ConnectedShares'][recvPacket['Tid']]['path'])
-
- respParameters['TotalUnits'] = totalUnits
- respParameters['BlocksPerUnit'] = 1
- respParameters['BlockSize'] = 1
- respParameters['FreeUnits'] = freeUnits
- errorCode = STATUS_SUCCESS
- else:
- # STATUS_SMB_BAD_TID
- respData = ''
- respParameters = ''
- errorCode = STATUS_SMB_BAD_TID
-
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComEcho(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_ECHO)
- respParameters = smb.SMBEchoResponse_Parameters()
- respData = smb.SMBEchoResponse_Data()
-
- echoData = smb.SMBEcho_Data(SMBCommand['Data'])
-
- respParameters['SequenceNumber'] = 1
- respData['Data'] = echoData['Data']
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- errorCode = STATUS_SUCCESS
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComTreeDisconnect(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_DISCONNECT)
-
- # Check if the Tid matches the Tid trying to disconnect
- respParameters = ''
- respData = ''
-
- if recvPacket['Tid'] in connData['ConnectedShares']:
- smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['Tid'],connData['ConnectedShares'][recvPacket['Tid']]['shareName']))
- del(connData['ConnectedShares'][recvPacket['Tid']])
- errorCode = STATUS_SUCCESS
- else:
- # STATUS_SMB_BAD_TID
- errorCode = STATUS_SMB_BAD_TID
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComLogOffAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_LOGOFF_ANDX)
-
- # Check if the Uid matches the user trying to logoff
- respParameters = ''
- respData = ''
- if recvPacket['Uid'] != connData['Uid']:
- # STATUS_SMB_BAD_UID
- errorCode = STATUS_SMB_BAD_UID
- else:
- errorCode = STATUS_SUCCESS
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- connData['Uid'] = 0
-
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComQueryInformation2(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_QUERY_INFORMATION2)
- respParameters = smb.SMBQueryInformation2Response_Parameters()
- respData = ''
-
- queryInformation2 = smb.SMBQueryInformation2_Parameters(SMBCommand['Parameters'])
- errorCode = 0xFF
- if queryInformation2['Fid'] in connData['OpenedFiles']:
- errorCode = STATUS_SUCCESS
- pathName = connData['OpenedFiles'][queryInformation2['Fid']]['FileName']
- try:
- (mode, ino, dev, nlink, uid, gid, size, atime, mtime, ctime) = os.stat(pathName)
- respParameters['CreateDate'] = getSMBDate(ctime)
- respParameters['CreationTime'] = getSMBTime(ctime)
- respParameters['LastAccessDate'] = getSMBDate(atime)
- respParameters['LastAccessTime'] = getSMBTime(atime)
- respParameters['LastWriteDate'] = getSMBDate(mtime)
- respParameters['LastWriteTime'] = getSMBTime(mtime)
- respParameters['FileDataSize'] = size
- respParameters['FileAllocationSize'] = size
- attribs = 0
- if os.path.isdir(pathName):
- attribs = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
- if os.path.isfile(pathName):
- attribs = smb.SMB_FILE_ATTRIBUTE_NORMAL
- respParameters['FileAttributes'] = attribs
- except Exception as e:
- smbServer.log('smbComQueryInformation2 %s' % e,logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
-
- if errorCode > 0:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComNtCreateAndX(connId, smbServer, SMBCommand, recvPacket):
- # TODO: Fully implement this
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NT_CREATE_ANDX)
- respParameters = smb.SMBNtCreateAndXResponse_Parameters()
- respData = ''
-
- ntCreateAndXParameters = smb.SMBNtCreateAndX_Parameters(SMBCommand['Parameters'])
- ntCreateAndXData = smb.SMBNtCreateAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
-
- #if ntCreateAndXParameters['CreateFlags'] & 0x10: # NT_CREATE_REQUEST_EXTENDED_RESPONSE
- # respParameters = smb.SMBNtCreateAndXExtendedResponse_Parameters()
- # respParameters['VolumeGUID'] = '\x00'
-
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- # If we have a rootFid, the path is relative to that fid
- errorCode = STATUS_SUCCESS
- if ntCreateAndXParameters['RootFid'] > 0:
- path = connData['OpenedFiles'][ntCreateAndXParameters['RootFid']]['FileName']
- LOG.debug("RootFid present %s!" % path)
- else:
- if 'path' in connData['ConnectedShares'][recvPacket['Tid']]:
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- else:
- path = 'NONE'
- errorCode = STATUS_ACCESS_DENIED
-
- deleteOnClose = False
-
- fileName = os.path.normpath(decodeSMBString(recvPacket['Flags2'],ntCreateAndXData['FileName']).replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- createDisposition = ntCreateAndXParameters['Disposition']
- mode = 0
-
- if createDisposition == smb.FILE_SUPERSEDE:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb.FILE_OVERWRITE_IF == smb.FILE_OVERWRITE_IF:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb.FILE_OVERWRITE == smb.FILE_OVERWRITE:
- if os.path.exists(pathName) is True:
- mode |= os.O_TRUNC
- else:
- errorCode = STATUS_NO_SUCH_FILE
- elif createDisposition & smb.FILE_OPEN_IF == smb.FILE_OPEN_IF:
- if os.path.exists(pathName) is True:
- mode |= os.O_TRUNC
- else:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb.FILE_CREATE == smb.FILE_CREATE:
- if os.path.exists(pathName) is True:
- errorCode = STATUS_OBJECT_NAME_COLLISION
- else:
- mode |= os.O_CREAT
- elif createDisposition & smb.FILE_OPEN == smb.FILE_OPEN:
- if os.path.exists(pathName) is not True and (unicode(pathName) in smbServer.getRegisteredNamedPipes()) is not True:
- errorCode = STATUS_NO_SUCH_FILE
-
- if errorCode == STATUS_SUCCESS:
- desiredAccess = ntCreateAndXParameters['AccessMask']
- if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
- mode |= os.O_RDONLY
- if (desiredAccess & smb.FILE_WRITE_DATA) or (desiredAccess & smb.GENERIC_WRITE):
- if (desiredAccess & smb.FILE_READ_DATA) or (desiredAccess & smb.GENERIC_READ):
- mode |= os.O_RDWR #| os.O_APPEND
- else:
- mode |= os.O_WRONLY #| os.O_APPEND
- if desiredAccess & smb.GENERIC_ALL:
- mode |= os.O_RDWR #| os.O_APPEND
-
- createOptions = ntCreateAndXParameters['CreateOptions']
- if mode & os.O_CREAT == os.O_CREAT:
- if createOptions & smb.FILE_DIRECTORY_FILE == smb.FILE_DIRECTORY_FILE:
- try:
- # Let's create the directory
- os.mkdir(pathName)
- mode = os.O_RDONLY
- except Exception as e:
- smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- if createOptions & smb.FILE_NON_DIRECTORY_FILE == smb.FILE_NON_DIRECTORY_FILE:
- # If the file being opened is a directory, the server MUST fail the request with
- # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
- # response.
- if os.path.isdir(pathName) is True:
- errorCode = STATUS_FILE_IS_A_DIRECTORY
-
- if createOptions & smb.FILE_DELETE_ON_CLOSE == smb.FILE_DELETE_ON_CLOSE:
- deleteOnClose = True
-
- if errorCode == STATUS_SUCCESS:
- try:
- if os.path.isdir(pathName) and sys.platform == 'win32':
- fid = VOID_FILE_DESCRIPTOR
- else:
- if sys.platform == 'win32':
- mode |= os.O_BINARY
- if unicode(pathName) in smbServer.getRegisteredNamedPipes():
- fid = PIPE_FILE_DESCRIPTOR
- sock = socket.socket()
- sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
- else:
- fid = os.open(pathName, mode)
- except Exception as e:
- smbServer.log("NTCreateAndX: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
- #print e
- fid = 0
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- if errorCode == STATUS_SUCCESS:
- # Simple way to generate a fid
- if len(connData['OpenedFiles']) == 0:
- fakefid = 1
- else:
- fakefid = connData['OpenedFiles'].keys()[-1] + 1
- respParameters['Fid'] = fakefid
- respParameters['CreateAction'] = createDisposition
- if fid == PIPE_FILE_DESCRIPTOR:
- respParameters['FileAttributes'] = 0x80
- respParameters['IsDirectory'] = 0
- respParameters['CreateTime'] = 0
- respParameters['LastAccessTime'] = 0
- respParameters['LastWriteTime'] = 0
- respParameters['LastChangeTime'] = 0
- respParameters['AllocationSize'] = 4096
- respParameters['EndOfFile'] = 0
- respParameters['FileType'] = 2
- respParameters['IPCState'] = 0x5ff
- else:
- if os.path.isdir(pathName):
- respParameters['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
- respParameters['IsDirectory'] = 1
- else:
- respParameters['IsDirectory'] = 0
- respParameters['FileAttributes'] = ntCreateAndXParameters['FileAttributes']
- # Let's get this file's information
- respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
- if errorCode == STATUS_SUCCESS:
- respParameters['CreateTime'] = respInfo['CreationTime']
- respParameters['LastAccessTime'] = respInfo['LastAccessTime']
- respParameters['LastWriteTime'] = respInfo['LastWriteTime']
- respParameters['LastChangeTime'] = respInfo['LastChangeTime']
- respParameters['FileAttributes'] = respInfo['ExtFileAttributes']
- respParameters['AllocationSize'] = respInfo['AllocationSize']
- respParameters['EndOfFile'] = respInfo['EndOfFile']
- else:
- respParameters = ''
- respData = ''
-
- if errorCode == STATUS_SUCCESS:
- # Let's store the fid for the connection
- # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
- connData['OpenedFiles'][fakefid] = {}
- connData['OpenedFiles'][fakefid]['FileHandle'] = fid
- connData['OpenedFiles'][fakefid]['FileName'] = pathName
- connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
- if fid == PIPE_FILE_DESCRIPTOR:
- connData['OpenedFiles'][fakefid]['Socket'] = sock
- else:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComOpenAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_OPEN_ANDX)
- respParameters = smb.SMBOpenAndXResponse_Parameters()
- respData = ''
-
- openAndXParameters = smb.SMBOpenAndX_Parameters(SMBCommand['Parameters'])
- openAndXData = smb.SMBOpenAndX_Data( flags = recvPacket['Flags2'], data = SMBCommand['Data'])
-
- # Get the Tid associated
- if recvPacket['Tid'] in connData['ConnectedShares']:
- path = connData['ConnectedShares'][recvPacket['Tid']]['path']
- openedFile, mode, pathName, errorCode = openFile(path,
- decodeSMBString(recvPacket['Flags2'],openAndXData['FileName']),
- openAndXParameters['DesiredAccess'],
- openAndXParameters['FileAttributes'],
- openAndXParameters['OpenMode'])
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- if errorCode == STATUS_SUCCESS:
- # Simple way to generate a fid
- fid = len(connData['OpenedFiles']) + 1
- if len(connData['OpenedFiles']) == 0:
- fid = 1
- else:
- fid = connData['OpenedFiles'].keys()[-1] + 1
- respParameters['Fid'] = fid
- if mode & os.O_CREAT:
- # File did not exist and was created
- respParameters['Action'] = 0x2
- elif mode & os.O_RDONLY:
- # File existed and was opened
- respParameters['Action'] = 0x1
- elif mode & os.O_APPEND:
- # File existed and was opened
- respParameters['Action'] = 0x1
- else:
- # File existed and was truncated
- respParameters['Action'] = 0x3
-
- # Let's store the fid for the connection
- #smbServer.log('Opening file %s' % pathName)
- connData['OpenedFiles'][fid] = {}
- connData['OpenedFiles'][fid]['FileHandle'] = openedFile
- connData['OpenedFiles'][fid]['FileName'] = pathName
- connData['OpenedFiles'][fid]['DeleteOnClose'] = False
- else:
- respParameters = ''
- respData = ''
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComTreeConnectAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- resp = smb.NewSMBPacket()
- resp['Flags1'] = smb.SMB.FLAGS1_REPLY
- resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | recvPacket['Flags2'] & smb.SMB.FLAGS2_UNICODE
-
- resp['Tid'] = recvPacket['Tid']
- resp['Mid'] = recvPacket['Mid']
- resp['Pid'] = connData['Pid']
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_TREE_CONNECT_ANDX)
- respParameters = smb.SMBTreeConnectAndXResponse_Parameters()
- respData = smb.SMBTreeConnectAndXResponse_Data()
-
- treeConnectAndXParameters = smb.SMBTreeConnectAndX_Parameters(SMBCommand['Parameters'])
-
- if treeConnectAndXParameters['Flags'] & 0x8:
- respParameters = smb.SMBTreeConnectAndXExtendedResponse_Parameters()
-
- treeConnectAndXData = smb.SMBTreeConnectAndX_Data( flags = recvPacket['Flags2'] )
- treeConnectAndXData['_PasswordLength'] = treeConnectAndXParameters['PasswordLength']
- treeConnectAndXData.fromString(SMBCommand['Data'])
-
- errorCode = STATUS_SUCCESS
-
- ## Process here the request, does the share exist?
- UNCOrShare = decodeSMBString(recvPacket['Flags2'], treeConnectAndXData['Path'])
-
- # Is this a UNC?
- if ntpath.ismount(UNCOrShare):
- path = UNCOrShare.split('\\')[3]
- else:
- path = ntpath.basename(UNCOrShare)
-
- share = searchShare(connId, path, smbServer)
- if share is not None:
- # Simple way to generate a Tid
- if len(connData['ConnectedShares']) == 0:
- tid = 1
- else:
- tid = connData['ConnectedShares'].keys()[-1] + 1
- connData['ConnectedShares'][tid] = share
- connData['ConnectedShares'][tid]['shareName'] = path
- resp['Tid'] = tid
- #smbServer.log("Connecting Share(%d:%s)" % (tid,path))
- else:
- smbServer.log("TreeConnectAndX not found %s" % path, logging.ERROR)
- errorCode = STATUS_OBJECT_PATH_NOT_FOUND
- resp['ErrorCode'] = errorCode >> 16
- resp['ErrorClass'] = errorCode & 0xff
- ##
- respParameters['OptionalSupport'] = smb.SMB.SMB_SUPPORT_SEARCH_BITS
-
- if path == 'IPC$':
- respData['Service'] = 'IPC'
- else:
- respData['Service'] = path
- respData['PadLen'] = 0
- respData['NativeFileSystem'] = encodeSMBString(recvPacket['Flags2'], 'NTFS' )
-
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- resp['Uid'] = connData['Uid']
- resp.addCommand(respSMBCommand)
- smbServer.setConnectionData(connId, connData)
-
- return None, [resp], errorCode
-
- @staticmethod
- def smbComSessionSetupAndX(connId, smbServer, SMBCommand, recvPacket):
- connData = smbServer.getConnectionData(connId, checkStatus = False)
-
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_SESSION_SETUP_ANDX)
-
- # From [MS-SMB]
- # When extended security is being used (see section 3.2.4.2.4), the
- # request MUST take the following form
- # [..]
- # WordCount (1 byte): The value of this field MUST be 0x0C.
- if SMBCommand['WordCount'] == 12:
- # Extended security. Here we deal with all SPNEGO stuff
- respParameters = smb.SMBSessionSetupAndX_Extended_Response_Parameters()
- respData = smb.SMBSessionSetupAndX_Extended_Response_Data(flags = recvPacket['Flags2'])
- sessionSetupParameters = smb.SMBSessionSetupAndX_Extended_Parameters(SMBCommand['Parameters'])
- sessionSetupData = smb.SMBSessionSetupAndX_Extended_Data()
- sessionSetupData['SecurityBlobLength'] = sessionSetupParameters['SecurityBlobLength']
- sessionSetupData.fromString(SMBCommand['Data'])
- connData['Capabilities'] = sessionSetupParameters['Capabilities']
-
- rawNTLM = False
- if struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_AID:
- # NEGOTIATE packet
- blob = SPNEGO_NegTokenInit(sessionSetupData['SecurityBlob'])
- token = blob['MechToken']
- if len(blob['MechTypes'][0]) > 0:
- # Is this GSSAPI NTLM or something else we don't support?
- mechType = blob['MechTypes'][0]
- if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
- # Nope, do we know it?
- if mechType in MechTypes:
- mechStr = MechTypes[mechType]
- else:
- mechStr = hexlify(mechType)
- smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
- # We don't know the token, we answer back again saying
- # we just support NTLM.
- # ToDo: Build this into a SPNEGO_NegTokenResp()
- respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
- respParameters['SecurityBlobLength'] = len(respToken)
- respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
- respData['SecurityBlob'] = respToken
- respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
- respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
- return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
-
- elif struct.unpack('B',sessionSetupData['SecurityBlob'][0])[0] == ASN1_SUPPORTED_MECH:
- # AUTH packet
- blob = SPNEGO_NegTokenResp(sessionSetupData['SecurityBlob'])
- token = blob['ResponseToken']
- else:
- # No GSSAPI stuff, raw NTLMSSP
- rawNTLM = True
- token = sessionSetupData['SecurityBlob']
-
- # Here we only handle NTLMSSP, depending on what stage of the
- # authentication we are, we act on it
- messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
-
- if messageType == 0x01:
- # NEGOTIATE_MESSAGE
- negotiateMessage = ntlm.NTLMAuthNegotiate()
- negotiateMessage.fromString(token)
- # Let's store it in the connection data
- connData['NEGOTIATE_MESSAGE'] = negotiateMessage
- # Let's build the answer flags
- # TODO: Parse all the flags. With this we're leaving some clients out
-
- ansFlags = 0
-
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
- if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
- ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
-
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
-
- # Generate the AV_PAIRS
- av_pairs = ntlm.AV_PAIRS()
- # TODO: Put the proper data from SMBSERVER config
- av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
- av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
- av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
-
- challengeMessage = ntlm.NTLMAuthChallenge()
- challengeMessage['flags'] = ansFlags
- challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
- challengeMessage['domain_max_len'] = challengeMessage['domain_len']
- challengeMessage['domain_offset'] = 40 + 16
- challengeMessage['challenge'] = smbServer.getSMBChallenge()
- challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
- challengeMessage['TargetInfoFields_len'] = len(av_pairs)
- challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
- challengeMessage['TargetInfoFields'] = av_pairs
- challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
- challengeMessage['Version'] = '\xff'*8
- challengeMessage['VersionLen'] = 8
-
- if rawNTLM is False:
- respToken = SPNEGO_NegTokenResp()
- # accept-incomplete. We want more data
- respToken['NegResult'] = '\x01'
- respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
-
- respToken['ResponseToken'] = challengeMessage.getData()
- else:
- respToken = challengeMessage
-
- # Setting the packet to STATUS_MORE_PROCESSING
- errorCode = STATUS_MORE_PROCESSING_REQUIRED
- # Let's set up an UID for this connection and store it
- # in the connection's data
- # Picking a fixed value
- # TODO: Manage more UIDs for the same session
- connData['Uid'] = 10
- # Let's store it in the connection data
- connData['CHALLENGE_MESSAGE'] = challengeMessage
-
- elif messageType == 0x02:
- # CHALLENGE_MESSAGE
- raise Exception('Challenge Message raise, not implemented!')
- elif messageType == 0x03:
- # AUTHENTICATE_MESSAGE, here we deal with authentication
- authenticateMessage = ntlm.NTLMAuthChallengeResponse()
- authenticateMessage.fromString(token)
- smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
- # TODO: Check the credentials! Now granting permissions
-
- respToken = SPNEGO_NegTokenResp()
- # accept-completed
- respToken['NegResult'] = '\x00'
-
- # Status SUCCESS
- errorCode = STATUS_SUCCESS
- smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
- # Let's store it in the connection data
- connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
- try:
- jtr_dump_path = smbServer.getJTRdumpPath()
- ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
- smbServer.log(ntlm_hash_data['hash_string'])
- if jtr_dump_path is not '':
- writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
- except:
- smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
- else:
- raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
-
- respParameters['SecurityBlobLength'] = len(respToken)
- respData['SecurityBlobLength'] = respParameters['SecurityBlobLength']
- respData['SecurityBlob'] = respToken.getData()
-
- else:
- # Process Standard Security
- respParameters = smb.SMBSessionSetupAndXResponse_Parameters()
- respData = smb.SMBSessionSetupAndXResponse_Data()
- sessionSetupParameters = smb.SMBSessionSetupAndX_Parameters(SMBCommand['Parameters'])
- sessionSetupData = smb.SMBSessionSetupAndX_Data()
- sessionSetupData['AnsiPwdLength'] = sessionSetupParameters['AnsiPwdLength']
- sessionSetupData['UnicodePwdLength'] = sessionSetupParameters['UnicodePwdLength']
- sessionSetupData.fromString(SMBCommand['Data'])
- connData['Capabilities'] = sessionSetupParameters['Capabilities']
- # Do the verification here, for just now we grant access
- # TODO: Manage more UIDs for the same session
- errorCode = STATUS_SUCCESS
- connData['Uid'] = 10
- respParameters['Action'] = 0
- smbServer.log('User %s\\%s authenticated successfully (basic)' % (sessionSetupData['PrimaryDomain'], sessionSetupData['Account']))
- try:
- jtr_dump_path = smbServer.getJTRdumpPath()
- ntlm_hash_data = outputToJohnFormat( '', sessionSetupData['Account'], sessionSetupData['PrimaryDomain'], sessionSetupData['AnsiPwd'], sessionSetupData['UnicodePwd'] )
- smbServer.log(ntlm_hash_data['hash_string'])
- if jtr_dump_path is not '':
- writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
- except:
- smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
-
- respData['NativeOS'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
- respData['NativeLanMan'] = encodeSMBString(recvPacket['Flags2'], smbServer.getServerOS())
- respSMBCommand['Parameters'] = respParameters
- respSMBCommand['Data'] = respData
-
- # From now on, the client can ask for other commands
- connData['Authenticated'] = True
- # For now, just switching to nobody
- #os.setregid(65534,65534)
- #os.setreuid(65534,65534)
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smbComNegotiate(connId, smbServer, SMBCommand, recvPacket ):
- connData = smbServer.getConnectionData(connId, checkStatus = False)
- connData['Pid'] = recvPacket['Pid']
-
- SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
- respSMBCommand = smb.SMBCommand(smb.SMB.SMB_COM_NEGOTIATE)
-
- resp = smb.NewSMBPacket()
- resp['Flags1'] = smb.SMB.FLAGS1_REPLY
- resp['Pid'] = connData['Pid']
- resp['Tid'] = recvPacket['Tid']
- resp['Mid'] = recvPacket['Mid']
-
- # TODO: We support more dialects, and parse them accordingly
- dialects = SMBCommand['Data'].split('\x02')
- try:
- index = dialects.index('NT LM 0.12\x00') - 1
- # Let's fill the data for NTLM
- if recvPacket['Flags2'] & smb.SMB.FLAGS2_EXTENDED_SECURITY:
- resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
- #resp['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS
- _dialects_data = smb.SMBExtended_Security_Data()
- _dialects_data['ServerGUID'] = 'A'*16
- blob = SPNEGO_NegTokenInit()
- blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
- _dialects_data['SecurityBlob'] = blob.getData()
-
- _dialects_parameters = smb.SMBExtended_Security_Parameters()
- _dialects_parameters['Capabilities'] = smb.SMB.CAP_EXTENDED_SECURITY | smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS | smb.SMB.CAP_UNICODE
- _dialects_parameters['ChallengeLength'] = 0
-
- else:
- resp['Flags2'] = smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_UNICODE
- _dialects_parameters = smb.SMBNTLMDialect_Parameters()
- _dialects_data= smb.SMBNTLMDialect_Data()
- _dialects_data['Payload'] = ''
- if 'EncryptionKey' in connData:
- _dialects_data['Challenge'] = connData['EncryptionKey']
- _dialects_parameters['ChallengeLength'] = len(str(_dialects_data))
- else:
- # TODO: Handle random challenges, now one that can be used with rainbow tables
- _dialects_data['Challenge'] = '\x11\x22\x33\x44\x55\x66\x77\x88'
- _dialects_parameters['ChallengeLength'] = 8
- _dialects_parameters['Capabilities'] = smb.SMB.CAP_USE_NT_ERRORS | smb.SMB.CAP_NT_SMBS
-
- # Let's see if we need to support RPC_REMOTE_APIS
- config = smbServer.getServerConfig()
- if config.has_option('global','rpc_apis'):
- if config.getboolean('global', 'rpc_apis') is True:
- _dialects_parameters['Capabilities'] |= smb.SMB.CAP_RPC_REMOTE_APIS
-
- _dialects_parameters['DialectIndex'] = index
- _dialects_parameters['SecurityMode'] = smb.SMB.SECURITY_AUTH_ENCRYPTED | smb.SMB.SECURITY_SHARE_USER
- _dialects_parameters['MaxMpxCount'] = 1
- _dialects_parameters['MaxNumberVcs'] = 1
- _dialects_parameters['MaxBufferSize'] = 64000
- _dialects_parameters['MaxRawSize'] = 65536
- _dialects_parameters['SessionKey'] = 0
- _dialects_parameters['LowDateTime'] = 0
- _dialects_parameters['HighDateTime'] = 0
- _dialects_parameters['ServerTimeZone'] = 0
-
-
- respSMBCommand['Data'] = _dialects_data
- respSMBCommand['Parameters'] = _dialects_parameters
- connData['_dialects_data'] = _dialects_data
- connData['_dialects_parameters'] = _dialects_parameters
-
- except Exception as e:
- # No NTLM throw an error
- smbServer.log('smbComNegotiate: %s' % e, logging.ERROR)
- respSMBCommand['Data'] = struct.pack('<H',0xffff)
-
-
- smbServer.setConnectionData(connId, connData)
-
- resp.addCommand(respSMBCommand)
-
- return None, [resp], STATUS_SUCCESS
-
- @staticmethod
- def default(connId, smbServer, SMBCommand, recvPacket):
- # By default we return an SMB Packet with error not implemented
- smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
- packet = smb.NewSMBPacket()
- packet['Flags1'] = smb.SMB.FLAGS1_REPLY
- packet['Flags2'] = smb.SMB.FLAGS2_NT_STATUS
- packet['Command'] = recvPacket['Command']
- packet['Pid'] = recvPacket['Pid']
- packet['Tid'] = recvPacket['Tid']
- packet['Mid'] = recvPacket['Mid']
- packet['Uid'] = recvPacket['Uid']
- packet['Data'] = '\x00\x00\x00'
- errorCode = STATUS_NOT_IMPLEMENTED
- packet['ErrorCode'] = errorCode >> 16
- packet['ErrorClass'] = errorCode & 0xff
-
- return None, [packet], errorCode
-
-class SMB2Commands:
- @staticmethod
- def smb2Negotiate(connId, smbServer, recvPacket, isSMB1 = False):
- connData = smbServer.getConnectionData(connId, checkStatus = False)
-
- respPacket = smb2.SMB2Packet()
- respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
- respPacket['Status'] = STATUS_SUCCESS
- respPacket['CreditRequestResponse'] = 1
- respPacket['Command'] = smb2.SMB2_NEGOTIATE
- respPacket['SessionID'] = 0
- if isSMB1 is False:
- respPacket['MessageID'] = recvPacket['MessageID']
- else:
- respPacket['MessageID'] = 0
- respPacket['TreeID'] = 0
-
-
- respSMBCommand = smb2.SMB2Negotiate_Response()
-
- respSMBCommand['SecurityMode'] = 1
- if isSMB1 is True:
- # Let's first parse the packet to see if the client supports SMB2
- SMBCommand = smb.SMBCommand(recvPacket['Data'][0])
-
- dialects = SMBCommand['Data'].split('\x02')
- if 'SMB 2.002\x00' in dialects or 'SMB 2.???\x00' in dialects:
- respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
- else:
- # Client does not support SMB2 fallbacking
- raise Exception('SMB2 not supported, fallbacking')
- else:
- respSMBCommand['DialectRevision'] = smb2.SMB2_DIALECT_002
- respSMBCommand['ServerGuid'] = 'A'*16
- respSMBCommand['Capabilities'] = 0
- respSMBCommand['MaxTransactSize'] = 65536
- respSMBCommand['MaxReadSize'] = 65536
- respSMBCommand['MaxWriteSize'] = 65536
- respSMBCommand['SystemTime'] = getFileTime(calendar.timegm(time.gmtime()))
- respSMBCommand['ServerStartTime'] = getFileTime(calendar.timegm(time.gmtime()))
- respSMBCommand['SecurityBufferOffset'] = 0x80
-
- blob = SPNEGO_NegTokenInit()
- blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']]
-
- respSMBCommand['Buffer'] = blob.getData()
- respSMBCommand['SecurityBufferLength'] = len(respSMBCommand['Buffer'])
-
- respPacket['Data'] = respSMBCommand
-
- smbServer.setConnectionData(connId, connData)
-
- return None, [respPacket], STATUS_SUCCESS
-
- @staticmethod
- def smb2SessionSetup(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId, checkStatus = False)
-
- respSMBCommand = smb2.SMB2SessionSetup_Response()
-
- sessionSetupData = smb2.SMB2SessionSetup(recvPacket['Data'])
-
- connData['Capabilities'] = sessionSetupData['Capabilities']
-
- securityBlob = sessionSetupData['Buffer']
-
- rawNTLM = False
- if struct.unpack('B',securityBlob[0])[0] == ASN1_AID:
- # NEGOTIATE packet
- blob = SPNEGO_NegTokenInit(securityBlob)
- token = blob['MechToken']
- if len(blob['MechTypes'][0]) > 0:
- # Is this GSSAPI NTLM or something else we don't support?
- mechType = blob['MechTypes'][0]
- if mechType != TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']:
- # Nope, do we know it?
- if mechType in MechTypes:
- mechStr = MechTypes[mechType]
- else:
- mechStr = hexlify(mechType)
- smbServer.log("Unsupported MechType '%s'" % mechStr, logging.CRITICAL)
- # We don't know the token, we answer back again saying
- # we just support NTLM.
- # ToDo: Build this into a SPNEGO_NegTokenResp()
- respToken = '\xa1\x15\x30\x13\xa0\x03\x0a\x01\x03\xa1\x0c\x06\x0a\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a'
- respSMBCommand['SecurityBufferOffset'] = 0x48
- respSMBCommand['SecurityBufferLength'] = len(respToken)
- respSMBCommand['Buffer'] = respToken
-
- return [respSMBCommand], None, STATUS_MORE_PROCESSING_REQUIRED
- elif struct.unpack('B',securityBlob[0])[0] == ASN1_SUPPORTED_MECH:
- # AUTH packet
- blob = SPNEGO_NegTokenResp(securityBlob)
- token = blob['ResponseToken']
- else:
- # No GSSAPI stuff, raw NTLMSSP
- rawNTLM = True
- token = securityBlob
-
- # Here we only handle NTLMSSP, depending on what stage of the
- # authentication we are, we act on it
- messageType = struct.unpack('<L',token[len('NTLMSSP\x00'):len('NTLMSSP\x00')+4])[0]
-
- if messageType == 0x01:
- # NEGOTIATE_MESSAGE
- negotiateMessage = ntlm.NTLMAuthNegotiate()
- negotiateMessage.fromString(token)
- # Let's store it in the connection data
- connData['NEGOTIATE_MESSAGE'] = negotiateMessage
- # Let's build the answer flags
- # TODO: Parse all the flags. With this we're leaving some clients out
-
- ansFlags = 0
-
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_56:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_56
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_128:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_128
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_KEY_EXCH
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_EXTENDED_SESSIONSECURITY
- if negotiateMessage['flags'] & ntlm.NTLMSSP_NEGOTIATE_UNICODE:
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_UNICODE
- if negotiateMessage['flags'] & ntlm.NTLM_NEGOTIATE_OEM:
- ansFlags |= ntlm.NTLM_NEGOTIATE_OEM
-
- ansFlags |= ntlm.NTLMSSP_NEGOTIATE_VERSION | ntlm.NTLMSSP_NEGOTIATE_TARGET_INFO | ntlm.NTLMSSP_TARGET_TYPE_SERVER | ntlm.NTLMSSP_NEGOTIATE_NTLM | ntlm.NTLMSSP_REQUEST_TARGET
-
- # Generate the AV_PAIRS
- av_pairs = ntlm.AV_PAIRS()
- # TODO: Put the proper data from SMBSERVER config
- av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_HOSTNAME] = smbServer.getServerName().encode('utf-16le')
- av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] = smbServer.getServerDomain().encode('utf-16le')
- av_pairs[ntlm.NTLMSSP_AV_TIME] = struct.pack('<q', (116444736000000000 + calendar.timegm(time.gmtime()) * 10000000) )
-
- challengeMessage = ntlm.NTLMAuthChallenge()
- challengeMessage['flags'] = ansFlags
- challengeMessage['domain_len'] = len(smbServer.getServerDomain().encode('utf-16le'))
- challengeMessage['domain_max_len'] = challengeMessage['domain_len']
- challengeMessage['domain_offset'] = 40 + 16
- challengeMessage['challenge'] = smbServer.getSMBChallenge()
- challengeMessage['domain_name'] = smbServer.getServerDomain().encode('utf-16le')
- challengeMessage['TargetInfoFields_len'] = len(av_pairs)
- challengeMessage['TargetInfoFields_max_len'] = len(av_pairs)
- challengeMessage['TargetInfoFields'] = av_pairs
- challengeMessage['TargetInfoFields_offset'] = 40 + 16 + len(challengeMessage['domain_name'])
- challengeMessage['Version'] = '\xff'*8
- challengeMessage['VersionLen'] = 8
-
- if rawNTLM is False:
- respToken = SPNEGO_NegTokenResp()
- # accept-incomplete. We want more data
- respToken['NegResult'] = '\x01'
- respToken['SupportedMech'] = TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']
-
- respToken['ResponseToken'] = challengeMessage.getData()
- else:
- respToken = challengeMessage
-
- # Setting the packet to STATUS_MORE_PROCESSING
- errorCode = STATUS_MORE_PROCESSING_REQUIRED
- # Let's set up an UID for this connection and store it
- # in the connection's data
- # Picking a fixed value
- # TODO: Manage more UIDs for the same session
- connData['Uid'] = random.randint(1,0xffffffff)
- # Let's store it in the connection data
- connData['CHALLENGE_MESSAGE'] = challengeMessage
-
- elif messageType == 0x02:
- # CHALLENGE_MESSAGE
- raise Exception('Challenge Message raise, not implemented!')
- elif messageType == 0x03:
- # AUTHENTICATE_MESSAGE, here we deal with authentication
- authenticateMessage = ntlm.NTLMAuthChallengeResponse()
- authenticateMessage.fromString(token)
- smbServer.log("AUTHENTICATE_MESSAGE (%s\\%s,%s)" % (authenticateMessage['domain_name'], authenticateMessage['user_name'], authenticateMessage['host_name']))
- # TODO: Check the credentials! Now granting permissions
-
- respToken = SPNEGO_NegTokenResp()
- # accept-completed
- respToken['NegResult'] = '\x00'
-
- # Status SUCCESS
- errorCode = STATUS_SUCCESS
- smbServer.log('User %s\\%s authenticated successfully' % (authenticateMessage['user_name'], authenticateMessage['host_name']))
- # Let's store it in the connection data
- connData['AUTHENTICATE_MESSAGE'] = authenticateMessage
- try:
- jtr_dump_path = smbServer.getJTRdumpPath()
- ntlm_hash_data = outputToJohnFormat( connData['CHALLENGE_MESSAGE']['challenge'], authenticateMessage['user_name'], authenticateMessage['domain_name'], authenticateMessage['lanman'], authenticateMessage['ntlm'] )
- smbServer.log(ntlm_hash_data['hash_string'])
- if jtr_dump_path is not '':
- writeJohnOutputToFile(ntlm_hash_data['hash_string'], ntlm_hash_data['hash_version'], jtr_dump_path)
- except:
- smbServer.log("Could not write NTLM Hashes to the specified JTR_Dump_Path %s" % jtr_dump_path)
- respSMBCommand['SessionFlags'] = 1
- else:
- raise Exception("Unknown NTLMSSP MessageType %d" % messageType)
-
- respSMBCommand['SecurityBufferOffset'] = 0x48
- respSMBCommand['SecurityBufferLength'] = len(respToken)
- respSMBCommand['Buffer'] = respToken.getData()
-
- # From now on, the client can ask for other commands
- connData['Authenticated'] = True
- # For now, just switching to nobody
- #os.setregid(65534,65534)
- #os.setreuid(65534,65534)
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2TreeConnect(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respPacket = smb2.SMB2Packet()
- respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
- respPacket['Status'] = STATUS_SUCCESS
- respPacket['CreditRequestResponse'] = 1
- respPacket['Command'] = recvPacket['Command']
- respPacket['SessionID'] = connData['Uid']
- respPacket['Reserved'] = recvPacket['Reserved']
- respPacket['MessageID'] = recvPacket['MessageID']
- respPacket['TreeID'] = recvPacket['TreeID']
-
- respSMBCommand = smb2.SMB2TreeConnect_Response()
-
- treeConnectRequest = smb2.SMB2TreeConnect(recvPacket['Data'])
-
- errorCode = STATUS_SUCCESS
-
- ## Process here the request, does the share exist?
- path = str(recvPacket)[treeConnectRequest['PathOffset']:][:treeConnectRequest['PathLength']]
- UNCOrShare = path.decode('utf-16le')
-
- # Is this a UNC?
- if ntpath.ismount(UNCOrShare):
- path = UNCOrShare.split('\\')[3]
- else:
- path = ntpath.basename(UNCOrShare)
-
- share = searchShare(connId, path.upper(), smbServer)
- if share is not None:
- # Simple way to generate a Tid
- if len(connData['ConnectedShares']) == 0:
- tid = 1
- else:
- tid = connData['ConnectedShares'].keys()[-1] + 1
- connData['ConnectedShares'][tid] = share
- connData['ConnectedShares'][tid]['shareName'] = path
- respPacket['TreeID'] = tid
- smbServer.log("Connecting Share(%d:%s)" % (tid,path))
- else:
- smbServer.log("SMB2_TREE_CONNECT not found %s" % path, logging.ERROR)
- errorCode = STATUS_OBJECT_PATH_NOT_FOUND
- respPacket['Status'] = errorCode
- ##
-
- if path == 'IPC$':
- respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_PIPE
- respSMBCommand['ShareFlags'] = 0x30
- else:
- respSMBCommand['ShareType'] = smb2.SMB2_SHARE_TYPE_DISK
- respSMBCommand['ShareFlags'] = 0x0
-
- respSMBCommand['Capabilities'] = 0
- respSMBCommand['MaximalAccess'] = 0x000f01ff
-
- respPacket['Data'] = respSMBCommand
-
- smbServer.setConnectionData(connId, connData)
-
- return None, [respPacket], errorCode
-
- @staticmethod
- def smb2Create(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2Create_Response()
-
- ntCreateRequest = smb2.SMB2Create(recvPacket['Data'])
-
- respSMBCommand['Buffer'] = '\x00'
- # Get the Tid associated
- if recvPacket['TreeID'] in connData['ConnectedShares']:
- # If we have a rootFid, the path is relative to that fid
- errorCode = STATUS_SUCCESS
- if 'path' in connData['ConnectedShares'][recvPacket['TreeID']]:
- path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
- else:
- path = 'NONE'
- errorCode = STATUS_ACCESS_DENIED
-
- deleteOnClose = False
-
- fileName = os.path.normpath(ntCreateRequest['Buffer'][:ntCreateRequest['NameLength']].decode('utf-16le').replace('\\','/'))
- if len(fileName) > 0 and (fileName[0] == '/' or fileName[0] == '\\'):
- # strip leading '/'
- fileName = fileName[1:]
- pathName = os.path.join(path,fileName)
- createDisposition = ntCreateRequest['CreateDisposition']
- mode = 0
-
- if createDisposition == smb2.FILE_SUPERSEDE:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb2.FILE_OVERWRITE_IF == smb2.FILE_OVERWRITE_IF:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb2.FILE_OVERWRITE == smb2.FILE_OVERWRITE:
- if os.path.exists(pathName) is True:
- mode |= os.O_TRUNC
- else:
- errorCode = STATUS_NO_SUCH_FILE
- elif createDisposition & smb2.FILE_OPEN_IF == smb2.FILE_OPEN_IF:
- if os.path.exists(pathName) is True:
- mode |= os.O_TRUNC
- else:
- mode |= os.O_TRUNC | os.O_CREAT
- elif createDisposition & smb2.FILE_CREATE == smb2.FILE_CREATE:
- if os.path.exists(pathName) is True:
- errorCode = STATUS_OBJECT_NAME_COLLISION
- else:
- mode |= os.O_CREAT
- elif createDisposition & smb2.FILE_OPEN == smb2.FILE_OPEN:
- if os.path.exists(pathName) is not True and (unicode(pathName) in smbServer.getRegisteredNamedPipes()) is not True:
- errorCode = STATUS_NO_SUCH_FILE
-
- if errorCode == STATUS_SUCCESS:
- desiredAccess = ntCreateRequest['DesiredAccess']
- if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
- mode |= os.O_RDONLY
- if (desiredAccess & smb2.FILE_WRITE_DATA) or (desiredAccess & smb2.GENERIC_WRITE):
- if (desiredAccess & smb2.FILE_READ_DATA) or (desiredAccess & smb2.GENERIC_READ):
- mode |= os.O_RDWR #| os.O_APPEND
- else:
- mode |= os.O_WRONLY #| os.O_APPEND
- if desiredAccess & smb2.GENERIC_ALL:
- mode |= os.O_RDWR #| os.O_APPEND
-
- createOptions = ntCreateRequest['CreateOptions']
- if mode & os.O_CREAT == os.O_CREAT:
- if createOptions & smb2.FILE_DIRECTORY_FILE == smb2.FILE_DIRECTORY_FILE:
- try:
- # Let's create the directory
- os.mkdir(pathName)
- mode = os.O_RDONLY
- except Exception as e:
- smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- if createOptions & smb2.FILE_NON_DIRECTORY_FILE == smb2.FILE_NON_DIRECTORY_FILE:
- # If the file being opened is a directory, the server MUST fail the request with
- # STATUS_FILE_IS_A_DIRECTORY in the Status field of the SMB Header in the server
- # response.
- if os.path.isdir(pathName) is True:
- errorCode = STATUS_FILE_IS_A_DIRECTORY
-
- if createOptions & smb2.FILE_DELETE_ON_CLOSE == smb2.FILE_DELETE_ON_CLOSE:
- deleteOnClose = True
-
- if errorCode == STATUS_SUCCESS:
- try:
- if os.path.isdir(pathName) and sys.platform == 'win32':
- fid = VOID_FILE_DESCRIPTOR
- else:
- if sys.platform == 'win32':
- mode |= os.O_BINARY
- if unicode(pathName) in smbServer.getRegisteredNamedPipes():
- fid = PIPE_FILE_DESCRIPTOR
- sock = socket.socket()
- sock.connect(smbServer.getRegisteredNamedPipes()[unicode(pathName)])
- else:
- fid = os.open(pathName, mode)
- except Exception as e:
- smbServer.log("SMB2_CREATE: %s,%s,%s" % (pathName,mode,e),logging.ERROR)
- #print e
- fid = 0
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_SMB_BAD_TID
-
- if errorCode == STATUS_SUCCESS:
- # Simple way to generate a fid
- fakefid = uuid.generate()
-
- respSMBCommand['FileID'] = fakefid
- respSMBCommand['CreateAction'] = createDisposition
-
- if fid == PIPE_FILE_DESCRIPTOR:
- respSMBCommand['CreationTime'] = 0
- respSMBCommand['LastAccessTime'] = 0
- respSMBCommand['LastWriteTime'] = 0
- respSMBCommand['ChangeTime'] = 0
- respSMBCommand['AllocationSize'] = 4096
- respSMBCommand['EndOfFile'] = 0
- respSMBCommand['FileAttributes'] = 0x80
-
- else:
- if os.path.isdir(pathName):
- respSMBCommand['FileAttributes'] = smb.SMB_FILE_ATTRIBUTE_DIRECTORY
- else:
- respSMBCommand['FileAttributes'] = ntCreateRequest['FileAttributes']
- # Let's get this file's information
- respInfo, errorCode = queryPathInformation('',pathName,level= smb.SMB_QUERY_FILE_ALL_INFO)
- if errorCode == STATUS_SUCCESS:
- respSMBCommand['CreationTime'] = respInfo['CreationTime']
- respSMBCommand['LastAccessTime'] = respInfo['LastAccessTime']
- respSMBCommand['LastWriteTime'] = respInfo['LastWriteTime']
- respSMBCommand['LastChangeTime'] = respInfo['LastChangeTime']
- respSMBCommand['FileAttributes'] = respInfo['ExtFileAttributes']
- respSMBCommand['AllocationSize'] = respInfo['AllocationSize']
- respSMBCommand['EndOfFile'] = respInfo['EndOfFile']
-
- if errorCode == STATUS_SUCCESS:
- # Let's store the fid for the connection
- # smbServer.log('Create file %s, mode:0x%x' % (pathName, mode))
- connData['OpenedFiles'][fakefid] = {}
- connData['OpenedFiles'][fakefid]['FileHandle'] = fid
- connData['OpenedFiles'][fakefid]['FileName'] = pathName
- connData['OpenedFiles'][fakefid]['DeleteOnClose'] = deleteOnClose
- connData['OpenedFiles'][fakefid]['Open'] = {}
- connData['OpenedFiles'][fakefid]['Open']['EnumerationLocation'] = 0
- connData['OpenedFiles'][fakefid]['Open']['EnumerationSearchPattern'] = ''
- if fid == PIPE_FILE_DESCRIPTOR:
- connData['OpenedFiles'][fakefid]['Socket'] = sock
- else:
- respSMBCommand = smb2.SMB2Error()
-
- if errorCode == STATUS_SUCCESS:
- connData['LastRequest']['SMB2_CREATE'] = respSMBCommand
- smbServer.setConnectionData(connId, connData)
-
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2Close(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2Close_Response()
-
- closeRequest = smb2.SMB2Close(recvPacket['Data'])
-
- if str(closeRequest['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if 'SMB2_CREATE' in connData['LastRequest']:
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(closeRequest['FileID'])
- else:
- fileID = str(closeRequest['FileID'])
-
- if fileID in connData['OpenedFiles']:
- errorCode = STATUS_SUCCESS
- fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
- pathName = connData['OpenedFiles'][fileID]['FileName']
- infoRecord = None
- try:
- if fileHandle == PIPE_FILE_DESCRIPTOR:
- connData['OpenedFiles'][fileID]['Socket'].close()
- elif fileHandle != VOID_FILE_DESCRIPTOR:
- os.close(fileHandle)
- infoRecord, errorCode = queryFileInformation(os.path.dirname(pathName), os.path.basename(pathName), smb2.SMB2_FILE_NETWORK_OPEN_INFO)
- except Exception as e:
- smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
- errorCode = STATUS_INVALID_HANDLE
- else:
- # Check if the file was marked for removal
- if connData['OpenedFiles'][fileID]['DeleteOnClose'] is True:
- try:
- if os.path.isdir(pathName):
- shutil.rmtree(connData['OpenedFiles'][fileID]['FileName'])
- else:
- os.remove(connData['OpenedFiles'][fileID]['FileName'])
- except Exception as e:
- smbServer.log("SMB2_CLOSE %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
-
- # Now fill out the response
- if infoRecord is not None:
- respSMBCommand['CreationTime'] = infoRecord['CreationTime']
- respSMBCommand['LastAccessTime'] = infoRecord['LastAccessTime']
- respSMBCommand['LastWriteTime'] = infoRecord['LastWriteTime']
- respSMBCommand['ChangeTime'] = infoRecord['ChangeTime']
- respSMBCommand['AllocationSize'] = infoRecord['AllocationSize']
- respSMBCommand['EndofFile'] = infoRecord['EndOfFile']
- respSMBCommand['FileAttributes'] = infoRecord['FileAttributes']
- if errorCode == STATUS_SUCCESS:
- del(connData['OpenedFiles'][fileID])
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2QueryInfo(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2QueryInfo_Response()
-
- queryInfo = smb2.SMB2QueryInfo(recvPacket['Data'])
-
- errorCode = STATUS_SUCCESS
-
- respSMBCommand['OutputBufferOffset'] = 0x48
- respSMBCommand['Buffer'] = '\x00'
-
- if str(queryInfo['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if 'SMB2_CREATE' in connData['LastRequest']:
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(queryInfo['FileID'])
- else:
- fileID = str(queryInfo['FileID'])
-
- if recvPacket['TreeID'] in connData['ConnectedShares']:
- if fileID in connData['OpenedFiles']:
- fileName = connData['OpenedFiles'][fileID]['FileName']
-
- if queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
- if queryInfo['FileInfoClass'] == smb2.SMB2_FILE_INTERNAL_INFO:
- # No need to call queryFileInformation, we have the data here
- infoRecord = smb2.FileInternalInformation()
- infoRecord['IndexNumber'] = fileID
- else:
- infoRecord, errorCode = queryFileInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
- elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
- infoRecord = queryFsInformation(os.path.dirname(fileName), os.path.basename(fileName), queryInfo['FileInfoClass'])
- elif queryInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
- # Failing for now, until we support it
- infoRecord = None
- errorCode = STATUS_ACCESS_DENIED
- else:
- smbServer.log("queryInfo not supported (%x)" % queryInfo['InfoType'], logging.ERROR)
-
- if infoRecord is not None:
- respSMBCommand['OutputBufferLength'] = len(infoRecord)
- respSMBCommand['Buffer'] = infoRecord
- else:
- errorCode = STATUS_INVALID_HANDLE
- else:
- errorCode = STATUS_SMB_BAD_TID
-
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2SetInfo(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2SetInfo_Response()
-
- setInfo = smb2.SMB2SetInfo(recvPacket['Data'])
-
- errorCode = STATUS_SUCCESS
-
- if str(setInfo['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if 'SMB2_CREATE' in connData['LastRequest']:
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(setInfo['FileID'])
- else:
- fileID = str(setInfo['FileID'])
-
- if recvPacket['TreeID'] in connData['ConnectedShares']:
- path = connData['ConnectedShares'][recvPacket['TreeID']]['path']
- if fileID in connData['OpenedFiles']:
- pathName = connData['OpenedFiles'][fileID]['FileName']
-
- if setInfo['InfoType'] == smb2.SMB2_0_INFO_FILE:
- # The file information is being set
- informationLevel = setInfo['FileInfoClass']
- if informationLevel == smb2.SMB2_FILE_DISPOSITION_INFO:
- infoRecord = smb.SMBSetFileDispositionInfo(setInfo['Buffer'])
- if infoRecord['DeletePending'] > 0:
- # Mark this file for removal after closed
- connData['OpenedFiles'][fileID]['DeleteOnClose'] = True
- elif informationLevel == smb2.SMB2_FILE_BASIC_INFO:
- infoRecord = smb.SMBSetFileBasicInfo(setInfo['Buffer'])
- # Creation time won't be set, the other ones we play with.
- atime = infoRecord['LastWriteTime']
- if atime == 0:
- atime = -1
- else:
- atime = getUnixTime(atime)
- mtime = infoRecord['ChangeTime']
- if mtime == 0:
- mtime = -1
- else:
- mtime = getUnixTime(mtime)
- if atime > 0 and mtime > 0:
- os.utime(pathName,(atime,mtime))
- elif informationLevel == smb2.SMB2_FILE_END_OF_FILE_INFO:
- fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
- infoRecord = smb.SMBSetFileEndOfFileInfo(setInfo['Buffer'])
- if infoRecord['EndOfFile'] > 0:
- os.lseek(fileHandle, infoRecord['EndOfFile']-1, 0)
- os.write(fileHandle, '\x00')
- elif informationLevel == smb2.SMB2_FILE_RENAME_INFO:
- renameInfo = smb2.FILE_RENAME_INFORMATION_TYPE_2(setInfo['Buffer'])
- newPathName = os.path.join(path,renameInfo['FileName'].decode('utf-16le').replace('\\', '/'))
- if renameInfo['ReplaceIfExists'] == 0 and os.path.exists(newPathName):
- return [smb2.SMB2Error()], None, STATUS_OBJECT_NAME_COLLISION
- try:
- os.rename(pathName,newPathName)
- connData['OpenedFiles'][fileID]['FileName'] = newPathName
- except Exception as e:
- smbServer.log("smb2SetInfo: %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- smbServer.log('Unknown level for set file info! 0x%x' % informationLevel, logging.ERROR)
- # UNSUPPORTED
- errorCode = STATUS_NOT_SUPPORTED
- #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_FILESYSTEM:
- # # The underlying object store information is being set.
- # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
- #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_SECURITY:
- # # The security information is being set.
- # # Failing for now, until we support it
- # infoRecord = None
- # errorCode = STATUS_ACCESS_DENIED
- #elif setInfo['InfoType'] == smb2.SMB2_0_INFO_QUOTA:
- # # The underlying object store quota information is being set.
- # setInfo = queryFsInformation('/', fileName, queryInfo['FileInfoClass'])
- else:
- smbServer.log("setInfo not supported (%x)" % setInfo['InfoType'], logging.ERROR)
-
- else:
- errorCode = STATUS_INVALID_HANDLE
- else:
- errorCode = STATUS_SMB_BAD_TID
-
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2Write(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2Write_Response()
- writeRequest = smb2.SMB2Write(recvPacket['Data'])
-
- respSMBCommand['Buffer'] = '\x00'
-
- if str(writeRequest['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if 'SMB2_CREATE' in connData['LastRequest']:
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(writeRequest['FileID'])
- else:
- fileID = str(writeRequest['FileID'])
-
- if fileID in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- offset = writeRequest['Offset']
- # If we're trying to write past the file end we just skip the write call (Vista does this)
- if os.lseek(fileHandle, 0, 2) >= offset:
- os.lseek(fileHandle,offset,0)
- os.write(fileHandle,writeRequest['Buffer'])
- else:
- sock = connData['OpenedFiles'][fileID]['Socket']
- sock.send(writeRequest['Buffer'])
-
- respSMBCommand['Count'] = writeRequest['Length']
- respSMBCommand['Remaining']= 0xff
- except Exception as e:
- smbServer.log('SMB2_WRITE: %s' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2Read(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2Read_Response()
- readRequest = smb2.SMB2Read(recvPacket['Data'])
-
- respSMBCommand['Buffer'] = '\x00'
-
- if str(readRequest['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if 'SMB2_CREATE' in connData['LastRequest']:
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(readRequest['FileID'])
- else:
- fileID = str(readRequest['FileID'])
-
- if fileID in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][fileID]['FileHandle']
- errorCode = 0
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- offset = readRequest['Offset']
- os.lseek(fileHandle,offset,0)
- content = os.read(fileHandle,readRequest['Length'])
- else:
- sock = connData['OpenedFiles'][fileID]['Socket']
- content = sock.recv(readRequest['Length'])
-
- respSMBCommand['DataOffset'] = 0x50
- respSMBCommand['DataLength'] = len(content)
- respSMBCommand['DataRemaining']= 0
- respSMBCommand['Buffer'] = content
- except Exception as e:
- smbServer.log('SMB2_READ: %s ' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2Flush(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2Flush_Response()
- flushRequest = smb2.SMB2Flush(recvPacket['Data'])
-
- if str(flushRequest['FileID']) in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][str(flushRequest['FileID'])]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- os.fsync(fileHandle)
- except Exception as e:
- smbServer.log("SMB2_FLUSH %s" % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_HANDLE
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
-
- @staticmethod
- def smb2QueryDirectory(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
- respSMBCommand = smb2.SMB2QueryDirectory_Response()
- queryDirectoryRequest = smb2.SMB2QueryDirectory(recvPacket['Data'])
-
- respSMBCommand['Buffer'] = '\x00'
-
- # The server MUST locate the tree connection, as specified in section 3.3.5.2.11.
- if (recvPacket['TreeID'] in connData['ConnectedShares']) is False:
- return [smb2.SMB2Error()], None, STATUS_NETWORK_NAME_DELETED
-
- # Next, the server MUST locate the open for the directory to be queried
- # If no open is found, the server MUST fail the request with STATUS_FILE_CLOSED
- if str(queryDirectoryRequest['FileID']) == '\xff'*16:
- # Let's take the data from the lastRequest
- if 'SMB2_CREATE' in connData['LastRequest']:
- fileID = connData['LastRequest']['SMB2_CREATE']['FileID']
- else:
- fileID = str(queryDirectoryRequest['FileID'])
- else:
- fileID = str(queryDirectoryRequest['FileID'])
-
- if (fileID in connData['OpenedFiles']) is False:
- return [smb2.SMB2Error()], None, STATUS_FILE_CLOSED
-
- # If the open is not an open to a directory, the request MUST be failed
- # with STATUS_INVALID_PARAMETER.
- if os.path.isdir(connData['OpenedFiles'][fileID]['FileName']) is False:
- return [smb2.SMB2Error()], None, STATUS_INVALID_PARAMETER
-
- # If any other information class is specified in the FileInformationClass
- # field of the SMB2 QUERY_DIRECTORY Request, the server MUST fail the
- # operation with STATUS_INVALID_INFO_CLASS.
- if queryDirectoryRequest['FileInformationClass'] not in (
- smb2.FILE_DIRECTORY_INFORMATION, smb2.FILE_FULL_DIRECTORY_INFORMATION, smb2.FILEID_FULL_DIRECTORY_INFORMATION,
- smb2.FILE_BOTH_DIRECTORY_INFORMATION, smb2.FILEID_BOTH_DIRECTORY_INFORMATION, smb2.FILENAMES_INFORMATION):
- return [smb2.SMB2Error()], None, STATUS_INVALID_INFO_CLASS
-
- # If SMB2_REOPEN is set in the Flags field of the SMB2 QUERY_DIRECTORY
- # Request, the server SHOULD<326> set Open.EnumerationLocation to 0
- # and Open.EnumerationSearchPattern to an empty string.
- if queryDirectoryRequest['Flags'] & smb2.SMB2_REOPEN:
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
- connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = ''
-
- # If SMB2_RESTART_SCANS is set in the Flags field of the SMB2
- # QUERY_DIRECTORY Request, the server MUST set
- # Open.EnumerationLocation to 0.
- if queryDirectoryRequest['Flags'] & smb2.SMB2_RESTART_SCANS:
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = 0
-
- # If Open.EnumerationLocation is 0 and Open.EnumerationSearchPattern
- # is an empty string, then Open.EnumerationSearchPattern MUST be set
- # to the search pattern specified in the SMB2 QUERY_DIRECTORY by
- # FileNameOffset and FileNameLength. If FileNameLength is 0, the server
- # SHOULD<327> set Open.EnumerationSearchPattern as "*" to search all entries.
-
- pattern = queryDirectoryRequest['Buffer'].decode('utf-16le')
- if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0 and \
- connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] == '':
- if pattern == '':
- pattern = '*'
- connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
-
- # If SMB2_INDEX_SPECIFIED is set and FileNameLength is not zero,
- # the server MUST set Open.EnumerationSearchPattern to the search pattern
- # specified in the request by FileNameOffset and FileNameLength.
- if queryDirectoryRequest['Flags'] & smb2.SMB2_INDEX_SPECIFIED and \
- queryDirectoryRequest['FileNameLength'] > 0:
- connData['OpenedFiles'][fileID]['Open']['EnumerationSearchPattern'] = pattern
-
- pathName = os.path.join(os.path.normpath(connData['OpenedFiles'][fileID]['FileName']),pattern)
- searchResult, searchCount, errorCode = findFirst2(os.path.dirname(pathName),
- os.path.basename(pathName),
- queryDirectoryRequest['FileInformationClass'],
- smb.ATTR_DIRECTORY, isSMB2 = True )
-
- if errorCode != STATUS_SUCCESS:
- return [smb2.SMB2Error()], None, errorCode
-
- if searchCount > 2 and pattern == '*':
- # strip . and ..
- searchCount -= 2
- searchResult = searchResult[2:]
-
- if searchCount == 0 and connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] == 0:
- return [smb2.SMB2Error()], None, STATUS_NO_SUCH_FILE
-
- if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] < 0:
- return [smb2.SMB2Error()], None, STATUS_NO_MORE_FILES
-
- totalData = 0
- respData = ''
- for nItem in range(connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'], searchCount):
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] += 1
- if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
- # If single entry is requested we must clear the NextEntryOffset
- searchResult[nItem]['NextEntryOffset'] = 0
- data = searchResult[nItem].getData()
- lenData = len(data)
- padLen = (8-(lenData % 8)) %8
-
- if (totalData+lenData) >= queryDirectoryRequest['OutputBufferLength']:
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] -= 1
- break
- else:
- respData += data + '\x00'*padLen
- totalData += lenData + padLen
-
- if queryDirectoryRequest['Flags'] & smb2.SL_RETURN_SINGLE_ENTRY:
- break
-
- if connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] >= searchCount:
- connData['OpenedFiles'][fileID]['Open']['EnumerationLocation'] = -1
-
- respSMBCommand['OutputBufferOffset'] = 0x48
- respSMBCommand['OutputBufferLength'] = totalData
- respSMBCommand['Buffer'] = respData
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2ChangeNotify(connId, smbServer, recvPacket):
-
- return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
-
- @staticmethod
- def smb2Echo(connId, smbServer, recvPacket):
-
- respSMBCommand = smb2.SMB2Echo_Response()
-
- return [respSMBCommand], None, STATUS_SUCCESS
-
- @staticmethod
- def smb2TreeDisconnect(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2TreeDisconnect_Response()
-
- if recvPacket['TreeID'] in connData['ConnectedShares']:
- smbServer.log("Disconnecting Share(%d:%s)" % (recvPacket['TreeID'],connData['ConnectedShares'][recvPacket['TreeID']]['shareName']))
- del(connData['ConnectedShares'][recvPacket['TreeID']])
- errorCode = STATUS_SUCCESS
- else:
- # STATUS_SMB_BAD_TID
- errorCode = STATUS_SMB_BAD_TID
-
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2Logoff(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2Logoff_Response()
-
- if recvPacket['SessionID'] != connData['Uid']:
- # STATUS_SMB_BAD_UID
- errorCode = STATUS_SMB_BAD_UID
- else:
- errorCode = STATUS_SUCCESS
-
- connData['Uid'] = 0
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2Ioctl(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2Ioctl_Response()
- ioctlRequest = smb2.SMB2Ioctl(recvPacket['Data'])
-
- ioctls = smbServer.getIoctls()
- if ioctlRequest['CtlCode'] in ioctls:
- outputData, errorCode = ioctls[ioctlRequest['CtlCode']](connId, smbServer, ioctlRequest)
- if errorCode == STATUS_SUCCESS:
- respSMBCommand['CtlCode'] = ioctlRequest['CtlCode']
- respSMBCommand['FileID'] = ioctlRequest['FileID']
- respSMBCommand['InputOffset'] = 0
- respSMBCommand['InputCount'] = 0
- respSMBCommand['OutputOffset'] = 0x70
- respSMBCommand['OutputCount'] = len(outputData)
- respSMBCommand['Flags'] = 0
- respSMBCommand['Buffer'] = outputData
- else:
- respSMBCommand = outputData
- else:
- smbServer.log("Ioctl not implemented command: 0x%x" % ioctlRequest['CtlCode'],logging.DEBUG)
- errorCode = STATUS_INVALID_DEVICE_REQUEST
- respSMBCommand = smb2.SMB2Error()
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2Lock(connId, smbServer, recvPacket):
- connData = smbServer.getConnectionData(connId)
-
- respSMBCommand = smb2.SMB2Lock_Response()
-
- # I'm actually doing nothing.. just make MacOS happy ;)
- errorCode = STATUS_SUCCESS
-
- smbServer.setConnectionData(connId, connData)
- return [respSMBCommand], None, errorCode
-
- @staticmethod
- def smb2Cancel(connId, smbServer, recvPacket):
- # I'm actually doing nothing
- return [smb2.SMB2Error()], None, STATUS_CANCELLED
-
- @staticmethod
- def default(connId, smbServer, recvPacket):
- # By default we return an SMB Packet with error not implemented
- smbServer.log("Not implemented command: 0x%x" % recvPacket['Command'],logging.DEBUG)
- return [smb2.SMB2Error()], None, STATUS_NOT_SUPPORTED
-
-class Ioctls:
- @staticmethod
- def fsctlDfsGetReferrals(connId, smbServer, ioctlRequest):
- return smb2.SMB2Error(), STATUS_FS_DRIVER_REQUIRED
-
- @staticmethod
- def fsctlPipeTransceive(connId, smbServer, ioctlRequest):
- connData = smbServer.getConnectionData(connId)
-
- ioctlResponse = ''
-
- if str(ioctlRequest['FileID']) in connData['OpenedFiles']:
- fileHandle = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['FileHandle']
- errorCode = STATUS_SUCCESS
- try:
- if fileHandle != PIPE_FILE_DESCRIPTOR:
- errorCode = STATUS_INVALID_DEVICE_REQUEST
- else:
- sock = connData['OpenedFiles'][str(ioctlRequest['FileID'])]['Socket']
- sock.sendall(ioctlRequest['Buffer'])
- ioctlResponse = sock.recv(ioctlRequest['MaxOutputResponse'])
- except Exception as e:
- smbServer.log('fsctlPipeTransceive: %s ' % e, logging.ERROR)
- errorCode = STATUS_ACCESS_DENIED
- else:
- errorCode = STATUS_INVALID_DEVICE_REQUEST
-
- smbServer.setConnectionData(connId, connData)
- return ioctlResponse, errorCode
-
- @staticmethod
- def fsctlValidateNegotiateInfo(connId, smbServer, ioctlRequest):
- connData = smbServer.getConnectionData(connId)
-
- errorCode = STATUS_SUCCESS
-
- validateNegotiateInfo = smb2.VALIDATE_NEGOTIATE_INFO(ioctlRequest['Buffer'])
- validateNegotiateInfo['Capabilities'] = 0
- validateNegotiateInfo['Guid'] = 'A'*16
- validateNegotiateInfo['SecurityMode'] = 1
- validateNegotiateInfo['Dialects'] = (smb2.SMB2_DIALECT_002,)
-
- smbServer.setConnectionData(connId, connData)
- return validateNegotiateInfo.getData(), errorCode
-
-
-class SMBSERVERHandler(socketserver.BaseRequestHandler):
- def __init__(self, request, client_address, server, select_poll = False):
- self.__SMB = server
- self.__ip, self.__port = client_address
- self.__request = request
- self.__connId = threading.currentThread().getName()
- self.__timeOut = 60*5
- self.__select_poll = select_poll
- #self.__connId = os.getpid()
- socketserver.BaseRequestHandler.__init__(self, request, client_address, server)
-
- def handle(self):
- self.__SMB.log("Incoming connection (%s,%d)" % (self.__ip, self.__port))
- self.__SMB.addConnection(self.__connId, self.__ip, self.__port)
- while True:
- try:
- # Firt of all let's get the NETBIOS packet
- session = nmb.NetBIOSTCPSession(self.__SMB.getServerName(),'HOST', self.__ip, sess_port = self.__port, sock = self.__request, select_poll = self.__select_poll)
- try:
- p = session.recv_packet(self.__timeOut)
- except nmb.NetBIOSTimeout:
- raise
- except nmb.NetBIOSError:
- break
-
- if p.get_type() == nmb.NETBIOS_SESSION_REQUEST:
- # Someone is requesting a session, we're gonna accept them all :)
- _, rn, my = p.get_trailer().split(' ')
- remote_name = nmb.decode_name('\x20'+rn)
- myname = nmb.decode_name('\x20'+my)
- self.__SMB.log("NetBIOS Session request (%s,%s,%s)" % (self.__ip, remote_name[1].strip(), myname[1]))
- r = nmb.NetBIOSSessionPacket()
- r.set_type(nmb.NETBIOS_SESSION_POSITIVE_RESPONSE)
- r.set_trailer(p.get_trailer())
- self.__request.send(r.rawData())
- else:
- resp = self.__SMB.processRequest(self.__connId, p.get_trailer())
- # Send all the packets recevied. Except for big transactions this should be
- # a single packet
- for i in resp:
- session.send_packet(str(i))
- except Exception as e:
- self.__SMB.log("Handle: %s" % e)
- #import traceback
- #traceback.print_exc()
- break
-
- def finish(self):
- # Thread/process is dying, we should tell the main SMB thread to remove all this thread data
- self.__SMB.log("Closing down connection (%s,%d)" % (self.__ip, self.__port))
- self.__SMB.removeConnection(self.__connId)
- return socketserver.BaseRequestHandler.finish(self)
-
-class SMBSERVER(socketserver.ThreadingMixIn, socketserver.TCPServer):
-#class SMBSERVER(socketserver.ForkingMixIn, socketserver.TCPServer):
- def __init__(self, server_address, handler_class=SMBSERVERHandler, config_parser = None):
- socketserver.TCPServer.allow_reuse_address = True
- socketserver.TCPServer.__init__(self, server_address, handler_class)
-
- # Server name and OS to be presented whenever is necessary
- self.__serverName = ''
- self.__serverOS = ''
- self.__serverDomain = ''
- self.__challenge = ''
- self.__log = None
-
- # Our ConfigParser data
- self.__serverConfig = config_parser
-
- # Our credentials to be used during the server's lifetime
- self.__credentials = {}
-
- # Our log file
- self.__logFile = ''
-
- # Registered Named Pipes, format is PipeName,Socket
- self.__registeredNamedPipes = {}
-
- # JTR dump path
- self.__jtr_dump_path = ''
-
- # SMB2 Support flag = default not active
- self.__SMB2Support = False
-
- # Our list of commands we will answer, by default the NOT IMPLEMENTED one
- self.__smbCommandsHandler = SMBCommands()
- self.__smbTrans2Handler = TRANS2Commands()
- self.__smbTransHandler = TRANSCommands()
- self.__smbNTTransHandler = NTTRANSCommands()
- self.__smb2CommandsHandler = SMB2Commands()
- self.__IoctlHandler = Ioctls()
-
- self.__smbNTTransCommands = {
- # NT IOCTL, can't find doc for this
- 0xff :self.__smbNTTransHandler.default
- }
-
- self.__smbTransCommands = {
-'\\PIPE\\LANMAN' :self.__smbTransHandler.lanMan,
-smb.SMB.TRANS_TRANSACT_NMPIPE :self.__smbTransHandler.transactNamedPipe,
- }
- self.__smbTrans2Commands = {
- smb.SMB.TRANS2_FIND_FIRST2 :self.__smbTrans2Handler.findFirst2,
- smb.SMB.TRANS2_FIND_NEXT2 :self.__smbTrans2Handler.findNext2,
- smb.SMB.TRANS2_QUERY_FS_INFORMATION :self.__smbTrans2Handler.queryFsInformation,
- smb.SMB.TRANS2_QUERY_PATH_INFORMATION :self.__smbTrans2Handler.queryPathInformation,
- smb.SMB.TRANS2_QUERY_FILE_INFORMATION :self.__smbTrans2Handler.queryFileInformation,
- smb.SMB.TRANS2_SET_FILE_INFORMATION :self.__smbTrans2Handler.setFileInformation,
- smb.SMB.TRANS2_SET_PATH_INFORMATION :self.__smbTrans2Handler.setPathInformation
- }
-
- self.__smbCommands = {
- #smb.SMB.SMB_COM_FLUSH: self.__smbCommandsHandler.smbComFlush,
- smb.SMB.SMB_COM_CREATE_DIRECTORY: self.__smbCommandsHandler.smbComCreateDirectory,
- smb.SMB.SMB_COM_DELETE_DIRECTORY: self.__smbCommandsHandler.smbComDeleteDirectory,
- smb.SMB.SMB_COM_RENAME: self.__smbCommandsHandler.smbComRename,
- smb.SMB.SMB_COM_DELETE: self.__smbCommandsHandler.smbComDelete,
- smb.SMB.SMB_COM_NEGOTIATE: self.__smbCommandsHandler.smbComNegotiate,
- smb.SMB.SMB_COM_SESSION_SETUP_ANDX: self.__smbCommandsHandler.smbComSessionSetupAndX,
- smb.SMB.SMB_COM_LOGOFF_ANDX: self.__smbCommandsHandler.smbComLogOffAndX,
- smb.SMB.SMB_COM_TREE_CONNECT_ANDX: self.__smbCommandsHandler.smbComTreeConnectAndX,
- smb.SMB.SMB_COM_TREE_DISCONNECT: self.__smbCommandsHandler.smbComTreeDisconnect,
- smb.SMB.SMB_COM_ECHO: self.__smbCommandsHandler.smbComEcho,
- smb.SMB.SMB_COM_QUERY_INFORMATION: self.__smbCommandsHandler.smbQueryInformation,
- smb.SMB.SMB_COM_TRANSACTION2: self.__smbCommandsHandler.smbTransaction2,
- smb.SMB.SMB_COM_TRANSACTION: self.__smbCommandsHandler.smbTransaction,
- # Not needed for now
- smb.SMB.SMB_COM_NT_TRANSACT: self.__smbCommandsHandler.smbNTTransact,
- smb.SMB.SMB_COM_QUERY_INFORMATION_DISK: self.__smbCommandsHandler.smbQueryInformationDisk,
- smb.SMB.SMB_COM_OPEN_ANDX: self.__smbCommandsHandler.smbComOpenAndX,
- smb.SMB.SMB_COM_QUERY_INFORMATION2: self.__smbCommandsHandler.smbComQueryInformation2,
- smb.SMB.SMB_COM_READ_ANDX: self.__smbCommandsHandler.smbComReadAndX,
- smb.SMB.SMB_COM_READ: self.__smbCommandsHandler.smbComRead,
- smb.SMB.SMB_COM_WRITE_ANDX: self.__smbCommandsHandler.smbComWriteAndX,
- smb.SMB.SMB_COM_WRITE: self.__smbCommandsHandler.smbComWrite,
- smb.SMB.SMB_COM_CLOSE: self.__smbCommandsHandler.smbComClose,
- smb.SMB.SMB_COM_LOCKING_ANDX: self.__smbCommandsHandler.smbComLockingAndX,
- smb.SMB.SMB_COM_NT_CREATE_ANDX: self.__smbCommandsHandler.smbComNtCreateAndX,
- 0xFF: self.__smbCommandsHandler.default
-}
-
- self.__smb2Ioctls = {
- smb2.FSCTL_DFS_GET_REFERRALS: self.__IoctlHandler.fsctlDfsGetReferrals,
-# smb2.FSCTL_PIPE_PEEK: self.__IoctlHandler.fsctlPipePeek,
-# smb2.FSCTL_PIPE_WAIT: self.__IoctlHandler.fsctlPipeWait,
- smb2.FSCTL_PIPE_TRANSCEIVE: self.__IoctlHandler.fsctlPipeTransceive,
-# smb2.FSCTL_SRV_COPYCHUNK: self.__IoctlHandler.fsctlSrvCopyChunk,
-# smb2.FSCTL_SRV_ENUMERATE_SNAPSHOTS: self.__IoctlHandler.fsctlSrvEnumerateSnapshots,
-# smb2.FSCTL_SRV_REQUEST_RESUME_KEY: self.__IoctlHandler.fsctlSrvRequestResumeKey,
-# smb2.FSCTL_SRV_READ_HASH: self.__IoctlHandler.fsctlSrvReadHash,
-# smb2.FSCTL_SRV_COPYCHUNK_WRITE: self.__IoctlHandler.fsctlSrvCopyChunkWrite,
-# smb2.FSCTL_LMR_REQUEST_RESILIENCY: self.__IoctlHandler.fsctlLmrRequestResiliency,
-# smb2.FSCTL_QUERY_NETWORK_INTERFACE_INFO: self.__IoctlHandler.fsctlQueryNetworkInterfaceInfo,
-# smb2.FSCTL_SET_REPARSE_POINT: self.__IoctlHandler.fsctlSetReparsePoint,
-# smb2.FSCTL_DFS_GET_REFERRALS_EX: self.__IoctlHandler.fsctlDfsGetReferralsEx,
-# smb2.FSCTL_FILE_LEVEL_TRIM: self.__IoctlHandler.fsctlFileLevelTrim,
- smb2.FSCTL_VALIDATE_NEGOTIATE_INFO: self.__IoctlHandler.fsctlValidateNegotiateInfo,
-}
-
- self.__smb2Commands = {
- smb2.SMB2_NEGOTIATE: self.__smb2CommandsHandler.smb2Negotiate,
- smb2.SMB2_SESSION_SETUP: self.__smb2CommandsHandler.smb2SessionSetup,
- smb2.SMB2_LOGOFF: self.__smb2CommandsHandler.smb2Logoff,
- smb2.SMB2_TREE_CONNECT: self.__smb2CommandsHandler.smb2TreeConnect,
- smb2.SMB2_TREE_DISCONNECT: self.__smb2CommandsHandler.smb2TreeDisconnect,
- smb2.SMB2_CREATE: self.__smb2CommandsHandler.smb2Create,
- smb2.SMB2_CLOSE: self.__smb2CommandsHandler.smb2Close,
- smb2.SMB2_FLUSH: self.__smb2CommandsHandler.smb2Flush,
- smb2.SMB2_READ: self.__smb2CommandsHandler.smb2Read,
- smb2.SMB2_WRITE: self.__smb2CommandsHandler.smb2Write,
- smb2.SMB2_LOCK: self.__smb2CommandsHandler.smb2Lock,
- smb2.SMB2_IOCTL: self.__smb2CommandsHandler.smb2Ioctl,
- smb2.SMB2_CANCEL: self.__smb2CommandsHandler.smb2Cancel,
- smb2.SMB2_ECHO: self.__smb2CommandsHandler.smb2Echo,
- smb2.SMB2_QUERY_DIRECTORY: self.__smb2CommandsHandler.smb2QueryDirectory,
- smb2.SMB2_CHANGE_NOTIFY: self.__smb2CommandsHandler.smb2ChangeNotify,
- smb2.SMB2_QUERY_INFO: self.__smb2CommandsHandler.smb2QueryInfo,
- smb2.SMB2_SET_INFO: self.__smb2CommandsHandler.smb2SetInfo,
-# smb2.SMB2_OPLOCK_BREAK: self.__smb2CommandsHandler.smb2SessionSetup,
- 0xFF: self.__smb2CommandsHandler.default
-}
-
- # List of active connections
- self.__activeConnections = {}
-
- def getIoctls(self):
- return self.__smb2Ioctls
-
- def getCredentials(self):
- return self.__credentials
-
- def removeConnection(self, name):
- try:
- del(self.__activeConnections[name])
- except:
- pass
- self.log("Remaining connections %s" % self.__activeConnections.keys())
-
- def addConnection(self, name, ip, port):
- self.__activeConnections[name] = {}
- # Let's init with some know stuff we will need to have
- # TODO: Document what's in there
- #print "Current Connections", self.__activeConnections.keys()
- self.__activeConnections[name]['PacketNum'] = 0
- self.__activeConnections[name]['ClientIP'] = ip
- self.__activeConnections[name]['ClientPort'] = port
- self.__activeConnections[name]['Uid'] = 0
- self.__activeConnections[name]['ConnectedShares'] = {}
- self.__activeConnections[name]['OpenedFiles'] = {}
- # SID results for findfirst2
- self.__activeConnections[name]['SIDs'] = {}
- self.__activeConnections[name]['LastRequest'] = {}
-
- def getActiveConnections(self):
- return self.__activeConnections
-
- def setConnectionData(self, connId, data):
- self.__activeConnections[connId] = data
- #print "setConnectionData"
- #print self.__activeConnections
-
- def getConnectionData(self, connId, checkStatus = True):
- conn = self.__activeConnections[connId]
- if checkStatus is True:
- if ('Authenticated' in conn) is not True:
- # Can't keep going further
- raise Exception("User not Authenticated!")
- return conn
-
- def getRegisteredNamedPipes(self):
- return self.__registeredNamedPipes
-
- def registerNamedPipe(self, pipeName, address):
- self.__registeredNamedPipes[unicode(pipeName)] = address
- return True
-
- def unregisterNamedPipe(self, pipeName):
- if pipeName in self.__registeredNamedPipes:
- del(self.__registeredNamedPipes[unicode(pipeName)])
- return True
- return False
-
- def unregisterTransaction(self, transCommand):
- if transCommand in self.__smbTransCommands:
- del(self.__smbTransCommands[transCommand])
-
- def hookTransaction(self, transCommand, callback):
- # If you call this function, callback will replace
- # the current Transaction sub command.
- # (don't get confused with the Transaction smbCommand)
- # If the transaction sub command doesn't not exist, it is added
- # If the transaction sub command exists, it returns the original function # replaced
- #
- # callback MUST be declared as:
- # callback(connId, smbServer, recvPacket, parameters, data, maxDataCount=0)
- #
- # WHERE:
- #
- # connId : the connection Id, used to grab/update information about
- # the current connection
- # smbServer : the SMBServer instance available for you to ask
- # configuration data
- # recvPacket : the full SMBPacket that triggered this command
- # parameters : the transaction parameters
- # data : the transaction data
- # maxDataCount: the max amount of data that can be transfered agreed
- # with the client
- #
- # and MUST return:
- # respSetup, respParameters, respData, errorCode
- #
- # WHERE:
- #
- # respSetup: the setup response of the transaction
- # respParameters: the parameters response of the transaction
- # respData: the data reponse of the transaction
- # errorCode: the NT error code
-
- if transCommand in self.__smbTransCommands:
- originalCommand = self.__smbTransCommands[transCommand]
- else:
- originalCommand = None
-
- self.__smbTransCommands[transCommand] = callback
- return originalCommand
-
- def unregisterTransaction2(self, transCommand):
- if transCommand in self.__smbTrans2Commands:
- del(self.__smbTrans2Commands[transCommand])
-
- def hookTransaction2(self, transCommand, callback):
- # Here we should add to __smbTrans2Commands
- # Same description as Transaction
- if transCommand in self.__smbTrans2Commands:
- originalCommand = self.__smbTrans2Commands[transCommand]
- else:
- originalCommand = None
-
- self.__smbTrans2Commands[transCommand] = callback
- return originalCommand
-
- def unregisterNTTransaction(self, transCommand):
- if transCommand in self.__smbNTTransCommands:
- del(self.__smbNTTransCommands[transCommand])
-
- def hookNTTransaction(self, transCommand, callback):
- # Here we should add to __smbNTTransCommands
- # Same description as Transaction
- if transCommand in self.__smbNTTransCommands:
- originalCommand = self.__smbNTTransCommands[transCommand]
- else:
- originalCommand = None
-
- self.__smbNTTransCommands[transCommand] = callback
- return originalCommand
-
- def unregisterSmbCommand(self, smbCommand):
- if smbCommand in self.__smbCommands:
- del(self.__smbCommands[smbCommand])
-
- def hookSmbCommand(self, smbCommand, callback):
- # Here we should add to self.__smbCommands
- # If you call this function, callback will replace
- # the current smbCommand.
- # If smbCommand doesn't not exist, it is added
- # If SMB command exists, it returns the original function replaced
- #
- # callback MUST be declared as:
- # callback(connId, smbServer, SMBCommand, recvPacket)
- #
- # WHERE:
- #
- # connId : the connection Id, used to grab/update information about
- # the current connection
- # smbServer : the SMBServer instance available for you to ask
- # configuration data
- # SMBCommand: the SMBCommand itself, with its data and parameters.
- # Check smb.py:SMBCommand() for a reference
- # recvPacket: the full SMBPacket that triggered this command
- #
- # and MUST return:
- # <list of respSMBCommands>, <list of packets>, errorCode
- # <list of packets> has higher preference over commands, in case you
- # want to change the whole packet
- # errorCode: the NT error code
- #
- # For SMB_COM_TRANSACTION2, SMB_COM_TRANSACTION and SMB_COM_NT_TRANSACT
- # the callback function is slightly different:
- #
- # callback(connId, smbServer, SMBCommand, recvPacket, transCommands)
- #
- # WHERE:
- #
- # transCommands: a list of transaction subcommands already registered
- #
-
- if smbCommand in self.__smbCommands:
- originalCommand = self.__smbCommands[smbCommand]
- else:
- originalCommand = None
-
- self.__smbCommands[smbCommand] = callback
- return originalCommand
-
- def unregisterSmb2Command(self, smb2Command):
- if smb2Command in self.__smb2Commands:
- del(self.__smb2Commands[smb2Command])
-
- def hookSmb2Command(self, smb2Command, callback):
- if smb2Command in self.__smb2Commands:
- originalCommand = self.__smb2Commands[smb2Command]
- else:
- originalCommand = None
-
- self.__smb2Commands[smb2Command] = callback
- return originalCommand
-
- def log(self, msg, level=logging.INFO):
- self.__log.log(level,msg)
-
- def getServerName(self):
- return self.__serverName
-
- def getServerOS(self):
- return self.__serverOS
-
- def getServerDomain(self):
- return self.__serverDomain
-
- def getSMBChallenge(self):
- return self.__challenge
-
- def getServerConfig(self):
- return self.__serverConfig
-
- def setServerConfig(self, config):
- self.__serverConfig = config
-
- def getJTRdumpPath(self):
- return self.__jtr_dump_path
-
- def verify_request(self, request, client_address):
- # TODO: Control here the max amount of processes we want to launch
- # returning False, closes the connection
- return True
-
- def processRequest(self, connId, data):
-
- # TODO: Process batched commands.
- isSMB2 = False
- SMBCommand = None
- try:
- packet = smb.NewSMBPacket(data = data)
- SMBCommand = smb.SMBCommand(packet['Data'][0])
- except:
- # Maybe a SMB2 packet?
- packet = smb2.SMB2Packet(data = data)
- isSMB2 = True
-
- # We might have compound requests
- compoundedPacketsResponse = []
- compoundedPackets = []
- try:
- # Search out list of implemented commands
- # We provide them with:
- # connId : representing the data for this specific connection
- # self : the SMBSERVER if they want to ask data to it
- # SMBCommand : the SMBCommand they are expecting to process
- # packet : the received packet itself, in case they need more data than the actual command
- # Only for Transactions
- # transCommand: a list of transaction subcommands
- # We expect to get:
- # respCommands: a list of answers for the commands processed
- # respPacket : if the commands chose to directly craft packet/s, we use this and not the previous
- # this MUST be a list
- # errorCode : self explanatory
- if isSMB2 is False:
- if packet['Command'] == smb.SMB.SMB_COM_TRANSACTION2:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet,
- self.__smbTrans2Commands)
- elif packet['Command'] == smb.SMB.SMB_COM_NT_TRANSACT:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet,
- self.__smbNTTransCommands)
- elif packet['Command'] == smb.SMB.SMB_COM_TRANSACTION:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet,
- self.__smbTransCommands)
- else:
- if packet['Command'] in self.__smbCommands:
- if self.__SMB2Support is True:
- if packet['Command'] == smb.SMB.SMB_COM_NEGOTIATE:
- try:
- respCommands, respPackets, errorCode = self.__smb2Commands[smb2.SMB2_NEGOTIATE](connId, self, packet, True)
- isSMB2 = True
- except Exception as e:
- self.log('SMB2_NEGOTIATE: %s' % e, logging.ERROR)
- # If something went wrong, let's fallback to SMB1
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet)
- #self.__SMB2Support = False
- pass
- else:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet)
- else:
- respCommands, respPackets, errorCode = self.__smbCommands[packet['Command']](
- connId,
- self,
- SMBCommand,
- packet)
- else:
- respCommands, respPackets, errorCode = self.__smbCommands[255](connId, self, SMBCommand, packet)
-
- compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
- compoundedPackets.append(packet)
-
- else:
- done = False
- while not done:
- if packet['Command'] in self.__smb2Commands:
- if self.__SMB2Support is True:
- respCommands, respPackets, errorCode = self.__smb2Commands[packet['Command']](
- connId,
- self,
- packet)
- else:
- respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
- else:
- respCommands, respPackets, errorCode = self.__smb2Commands[255](connId, self, packet)
- # Let's store the result for this compounded packet
- compoundedPacketsResponse.append((respCommands, respPackets, errorCode))
- compoundedPackets.append(packet)
- if packet['NextCommand'] != 0:
- data = data[packet['NextCommand']:]
- packet = smb2.SMB2Packet(data = data)
- else:
- done = True
-
- except Exception as e:
- #import traceback
- #traceback.print_exc()
- # Something wen't wrong, defaulting to Bad user ID
- self.log('processRequest (0x%x,%s)' % (packet['Command'],e), logging.ERROR)
- raise
-
- # We prepare the response packet to commands don't need to bother about that.
- connData = self.getConnectionData(connId, False)
-
- # Force reconnection loop.. This is just a test.. client will send me back credentials :)
- #connData['PacketNum'] += 1
- #if connData['PacketNum'] == 15:
- # connData['PacketNum'] = 0
- # # Something wen't wrong, defaulting to Bad user ID
- # self.log('Sending BAD USER ID!', logging.ERROR)
- # #raise
- # packet['Flags1'] |= smb.SMB.FLAGS1_REPLY
- # packet['Flags2'] = 0
- # errorCode = STATUS_SMB_BAD_UID
- # packet['ErrorCode'] = errorCode >> 16
- # packet['ErrorClass'] = errorCode & 0xff
- # return [packet]
-
- self.setConnectionData(connId, connData)
-
- packetsToSend = []
- for packetNum in range(len(compoundedPacketsResponse)):
- respCommands, respPackets, errorCode = compoundedPacketsResponse[packetNum]
- packet = compoundedPackets[packetNum]
- if respPackets is None:
- for respCommand in respCommands:
- if isSMB2 is False:
- respPacket = smb.NewSMBPacket()
- respPacket['Flags1'] = smb.SMB.FLAGS1_REPLY
-
- # TODO this should come from a per session configuration
- respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES | packet['Flags2'] & smb.SMB.FLAGS2_UNICODE
- #respPacket['Flags2'] = smb.SMB.FLAGS2_EXTENDED_SECURITY | smb.SMB.FLAGS2_NT_STATUS | smb.SMB.FLAGS2_LONG_NAMES
- #respPacket['Flags1'] = 0x98
- #respPacket['Flags2'] = 0xc807
-
-
- respPacket['Tid'] = packet['Tid']
- respPacket['Mid'] = packet['Mid']
- respPacket['Pid'] = packet['Pid']
- respPacket['Uid'] = connData['Uid']
-
- respPacket['ErrorCode'] = errorCode >> 16
- respPacket['_reserved'] = errorCode >> 8 & 0xff
- respPacket['ErrorClass'] = errorCode & 0xff
- respPacket.addCommand(respCommand)
-
- packetsToSend.append(respPacket)
- else:
- respPacket = smb2.SMB2Packet()
- respPacket['Flags'] = smb2.SMB2_FLAGS_SERVER_TO_REDIR
- if packetNum > 0:
- respPacket['Flags'] |= smb2.SMB2_FLAGS_RELATED_OPERATIONS
- respPacket['Status'] = errorCode
- respPacket['CreditRequestResponse'] = packet['CreditRequestResponse']
- respPacket['Command'] = packet['Command']
- respPacket['CreditCharge'] = packet['CreditCharge']
- #respPacket['CreditCharge'] = 0
- respPacket['Reserved'] = packet['Reserved']
- respPacket['SessionID'] = connData['Uid']
- respPacket['MessageID'] = packet['MessageID']
- respPacket['TreeID'] = packet['TreeID']
- respPacket['Data'] = str(respCommand)
- packetsToSend.append(respPacket)
- else:
- # The SMBCommand took care of building the packet
- packetsToSend = respPackets
-
- if isSMB2 is True:
- # Let's build a compound answer
- finalData = ''
- i = 0
- for i in range(len(packetsToSend)-1):
- packet = packetsToSend[i]
- # Align to 8-bytes
- padLen = (8 - (len(packet) % 8) ) % 8
- packet['NextCommand'] = len(packet) + padLen
- finalData += str(packet) + padLen*'\x00'
-
- # Last one
- finalData += str(packetsToSend[len(packetsToSend)-1])
- packetsToSend = [finalData]
-
- # We clear the compound requests
- connData['LastRequest'] = {}
-
- return packetsToSend
-
- def processConfigFile(self, configFile = None):
- # TODO: Do a real config parser
- if self.__serverConfig is None:
- if configFile is None:
- configFile = 'smb.conf'
- self.__serverConfig = configparser.ConfigParser()
- self.__serverConfig.read(configFile)
-
- self.__serverName = self.__serverConfig.get('global','server_name')
- self.__serverOS = self.__serverConfig.get('global','server_os')
- self.__serverDomain = self.__serverConfig.get('global','server_domain')
- self.__logFile = self.__serverConfig.get('global','log_file')
- if self.__serverConfig.has_option('global', 'challenge'):
- self.__challenge = self.__serverConfig.get('global', 'challenge')
- else:
- self.__challenge = 'A'*8
-
- if self.__serverConfig.has_option("global", "jtr_dump_path"):
- self.__jtr_dump_path = self.__serverConfig.get("global", "jtr_dump_path")
-
- if self.__serverConfig.has_option("global", "SMB2Support"):
- self.__SMB2Support = self.__serverConfig.getboolean("global","SMB2Support")
- else:
- self.__SMB2Support = False
-
- if self.__logFile != 'None':
- logging.basicConfig(filename = self.__logFile,
- level = logging.DEBUG,
- format="%(asctime)s: %(levelname)s: %(message)s",
- datefmt = '%m/%d/%Y %I:%M:%S %p')
- self.__log = LOG
-
- # Process the credentials
- credentials_fname = self.__serverConfig.get('global','credentials_file')
- if credentials_fname is not "":
- cred = open(credentials_fname)
- line = cred.readline()
- while line:
- name, domain, lmhash, nthash = line.split(':')
- self.__credentials[name] = (domain, lmhash, nthash.strip('\r\n'))
- line = cred.readline()
- cred.close()
- self.log('Config file parsed')
-
-# For windows platforms, opening a directory is not an option, so we set a void FD
-VOID_FILE_DESCRIPTOR = -1
-PIPE_FILE_DESCRIPTOR = -2