# 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. # # Copyright (C) 2001 Michael Teo <michaelteo@bigfoot.com> # smb.py - SMB/CIFS library # # This software is provided 'as-is', without any express or implied warranty. # In no event will the author be held liable for any damages arising from the # use of this software. # # Permission is granted to anyone to use this software for any purpose, # including commercial applications, and to alter it and redistribute it # freely, subject to the following restrictions: # # 1. The origin of this software must not be misrepresented; you must not # claim that you wrote the original software. If you use this software # in a product, an acknowledgment in the product documentation would be # appreciated but is not required. # # 2. Altered source versions must be plainly marked as such, and must not be # misrepresented as being the original software. # # 3. This notice cannot be removed or altered from any source distribution. # # Altered source done by Alberto Solino (@agsolino) # Todo: # [ ] Try [SMB]transport fragmentation using Transact requests # [ ] Try other methods of doing write (write_raw, transact2, write, write_and_unlock, write_and_close, write_mpx) # [-] Try replacements for SMB_COM_NT_CREATE_ANDX (CREATE, T_TRANSACT_CREATE, OPEN_ANDX works # [x] Fix forceWriteAndx, which needs to send a RecvRequest, because recv() will not send it # [x] Fix Recv() when using RecvAndx and the answer comes splet in several packets # [ ] Try [SMB]transport fragmentation with overlaping segments # [ ] Try [SMB]transport fragmentation with out of order segments # [x] Do chained AndX requests # [ ] Transform the rest of the calls to structure # [X] Implement TRANS/TRANS2 reassembly for list_path import os import socket import string from binascii import a2b_hex import datetime from struct import pack, unpack from contextlib import contextmanager from impacket import nmb, ntlm, nt_errors, LOG from impacket.structure import Structure from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, SPNEGO_NegTokenResp # For signing import hashlib unicode_support = 0 unicode_convert = 1 try: from cStringIO import StringIO except ImportError: from StringIO import StringIO # Dialect for SMB1 SMB_DIALECT = 'NT LM 0.12' # Shared Device Type SHARED_DISK = 0x00 SHARED_DISK_HIDDEN = 0x80000000 SHARED_PRINT_QUEUE = 0x01 SHARED_DEVICE = 0x02 SHARED_IPC = 0x03 # Extended attributes mask ATTR_ARCHIVE = 0x020 ATTR_COMPRESSED = 0x800 ATTR_NORMAL = 0x080 ATTR_HIDDEN = 0x002 ATTR_READONLY = 0x001 ATTR_TEMPORARY = 0x100 ATTR_DIRECTORY = 0x010 ATTR_SYSTEM = 0x004 # Service Type SERVICE_DISK = 'A:' SERVICE_PRINTER = 'LPT1:' SERVICE_IPC = 'IPC' SERVICE_COMM = 'COMM' SERVICE_ANY = '?????' # Server Type (Can be used to mask with SMBMachine.get_type() or SMBDomain.get_type()) SV_TYPE_WORKSTATION = 0x00000001 SV_TYPE_SERVER = 0x00000002 SV_TYPE_SQLSERVER = 0x00000004 SV_TYPE_DOMAIN_CTRL = 0x00000008 SV_TYPE_DOMAIN_BAKCTRL = 0x00000010 SV_TYPE_TIME_SOURCE = 0x00000020 SV_TYPE_AFP = 0x00000040 SV_TYPE_NOVELL = 0x00000080 SV_TYPE_DOMAIN_MEMBER = 0x00000100 SV_TYPE_PRINTQ_SERVER = 0x00000200 SV_TYPE_DIALIN_SERVER = 0x00000400 SV_TYPE_XENIX_SERVER = 0x00000800 SV_TYPE_NT = 0x00001000 SV_TYPE_WFW = 0x00002000 SV_TYPE_SERVER_NT = 0x00004000 SV_TYPE_POTENTIAL_BROWSER = 0x00010000 SV_TYPE_BACKUP_BROWSER = 0x00020000 SV_TYPE_MASTER_BROWSER = 0x00040000 SV_TYPE_DOMAIN_MASTER = 0x00080000 SV_TYPE_LOCAL_LIST_ONLY = 0x40000000 SV_TYPE_DOMAIN_ENUM = 0x80000000 # Options values for SMB.stor_file and SMB.retr_file SMB_O_CREAT = 0x10 # Create the file if file does not exists. Otherwise, operation fails. SMB_O_EXCL = 0x00 # When used with SMB_O_CREAT, operation fails if file exists. Cannot be used with SMB_O_OPEN. SMB_O_OPEN = 0x01 # Open the file if the file exists SMB_O_TRUNC = 0x02 # Truncate the file if the file exists # Share Access Mode SMB_SHARE_COMPAT = 0x00 SMB_SHARE_DENY_EXCL = 0x10 SMB_SHARE_DENY_WRITE = 0x20 SMB_SHARE_DENY_READEXEC = 0x30 SMB_SHARE_DENY_NONE = 0x40 SMB_ACCESS_READ = 0x00 SMB_ACCESS_WRITE = 0x01 SMB_ACCESS_READWRITE = 0x02 SMB_ACCESS_EXEC = 0x03 TRANS_DISCONNECT_TID = 1 TRANS_NO_RESPONSE = 2 STATUS_SUCCESS = 0x00000000 STATUS_LOGON_FAILURE = 0xC000006D STATUS_LOGON_TYPE_NOT_GRANTED = 0xC000015B MAX_TFRAG_SIZE = 5840 EVASION_NONE = 0 EVASION_LOW = 1 EVASION_HIGH = 2 EVASION_MAX = 3 RPC_X_BAD_STUB_DATA = 0x6F7 # SMB_FILE_ATTRIBUTES SMB_FILE_ATTRIBUTE_NORMAL = 0x0000 SMB_FILE_ATTRIBUTE_READONLY = 0x0001 SMB_FILE_ATTRIBUTE_HIDDEN = 0x0002 SMB_FILE_ATTRIBUTE_SYSTEM = 0x0004 SMB_FILE_ATTRIBUTE_VOLUME = 0x0008 SMB_FILE_ATTRIBUTE_DIRECTORY = 0x0010 SMB_FILE_ATTRIBUTE_ARCHIVE = 0x0020 SMB_SEARCH_ATTRIBUTE_READONLY = 0x0100 SMB_SEARCH_ATTRIBUTE_HIDDEN = 0x0200 SMB_SEARCH_ATTRIBUTE_SYSTEM = 0x0400 SMB_SEARCH_ATTRIBUTE_DIRECTORY = 0x1000 SMB_SEARCH_ATTRIBUTE_ARCHIVE = 0x2000 # Session SetupAndX Action flags SMB_SETUP_GUEST = 0x01 SMB_SETUP_USE_LANMAN_KEY = 0x02 # QUERY_INFORMATION levels SMB_INFO_ALLOCATION = 0x0001 SMB_INFO_VOLUME = 0x0002 FILE_FS_SIZE_INFORMATION = 0x0003 SMB_QUERY_FS_VOLUME_INFO = 0x0102 SMB_QUERY_FS_SIZE_INFO = 0x0103 SMB_QUERY_FILE_EA_INFO = 0x0103 SMB_QUERY_FS_DEVICE_INFO = 0x0104 SMB_QUERY_FS_ATTRIBUTE_INFO = 0x0105 SMB_QUERY_FILE_BASIC_INFO = 0x0101 SMB_QUERY_FILE_STANDARD_INFO = 0x0102 SMB_QUERY_FILE_ALL_INFO = 0x0107 FILE_FS_FULL_SIZE_INFORMATION = 0x03EF # SET_INFORMATION levels SMB_SET_FILE_DISPOSITION_INFO = 0x0102 SMB_SET_FILE_BASIC_INFO = 0x0101 SMB_SET_FILE_END_OF_FILE_INFO = 0x0104 # File System Attributes FILE_CASE_SENSITIVE_SEARCH = 0x00000001 FILE_CASE_PRESERVED_NAMES = 0x00000002 FILE_UNICODE_ON_DISK = 0x00000004 FILE_PERSISTENT_ACLS = 0x00000008 FILE_FILE_COMPRESSION = 0x00000010 FILE_VOLUME_IS_COMPRESSED = 0x00008000 # FIND_FIRST2 flags and levels SMB_FIND_CLOSE_AFTER_REQUEST = 0x0001 SMB_FIND_CLOSE_AT_EOS = 0x0002 SMB_FIND_RETURN_RESUME_KEYS = 0x0004 SMB_FIND_CONTINUE_FROM_LAST = 0x0008 SMB_FIND_WITH_BACKUP_INTENT = 0x0010 FILE_DIRECTORY_FILE = 0x00000001 FILE_DELETE_ON_CLOSE = 0x00001000 FILE_NON_DIRECTORY_FILE = 0x00000040 SMB_FIND_INFO_STANDARD = 0x0001 SMB_FIND_FILE_DIRECTORY_INFO = 0x0101 SMB_FIND_FILE_FULL_DIRECTORY_INFO= 0x0102 SMB_FIND_FILE_NAMES_INFO = 0x0103 SMB_FIND_FILE_BOTH_DIRECTORY_INFO= 0x0104 SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO = 0x105 SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO = 0x106 # DesiredAccess flags FILE_READ_DATA = 0x00000001 FILE_WRITE_DATA = 0x00000002 FILE_APPEND_DATA = 0x00000004 FILE_EXECUTE = 0x00000020 MAXIMUM_ALLOWED = 0x02000000 GENERIC_ALL = 0x10000000 GENERIC_EXECUTE = 0x20000000 GENERIC_WRITE = 0x40000000 GENERIC_READ = 0x80000000 # ShareAccess flags FILE_SHARE_NONE = 0x00000000 FILE_SHARE_READ = 0x00000001 FILE_SHARE_WRITE = 0x00000002 FILE_SHARE_DELETE = 0x00000004 # CreateDisposition flags FILE_SUPERSEDE = 0x00000000 FILE_OPEN = 0x00000001 FILE_CREATE = 0x00000002 FILE_OPEN_IF = 0x00000003 FILE_OVERWRITE = 0x00000004 FILE_OVERWRITE_IF = 0x00000005 def strerror(errclass, errcode): if errclass == 0x01: return 'OS error', ERRDOS.get(errcode, 'Unknown error') elif errclass == 0x02: return 'Server error', ERRSRV.get(errcode, 'Unknown error') elif errclass == 0x03: return 'Hardware error', ERRHRD.get(errcode, 'Unknown error') # This is not a standard error class for SMB #elif errclass == 0x80: # return 'Browse error', ERRBROWSE.get(errcode, 'Unknown error') elif errclass == 0xff: return 'Bad command', 'Bad command. Please file bug report' else: return 'Unknown error', 'Unknown error' # Raised when an error has occured during a session class SessionError(Exception): # SMB X/Open error codes for the ERRDOS error class ERRsuccess = 0 ERRbadfunc = 1 ERRbadfile = 2 ERRbadpath = 3 ERRnofids = 4 ERRnoaccess = 5 ERRbadfid = 6 ERRbadmcb = 7 ERRnomem = 8 ERRbadmem = 9 ERRbadenv = 10 ERRbadaccess = 12 ERRbaddata = 13 ERRres = 14 ERRbaddrive = 15 ERRremcd = 16 ERRdiffdevice = 17 ERRnofiles = 18 ERRgeneral = 31 ERRbadshare = 32 ERRlock = 33 ERRunsup = 50 ERRnetnamedel = 64 ERRnosuchshare = 67 ERRfilexists = 80 ERRinvalidparam = 87 ERRcannotopen = 110 ERRinsufficientbuffer = 122 ERRinvalidname = 123 ERRunknownlevel = 124 ERRnotlocked = 158 ERRrename = 183 ERRbadpipe = 230 ERRpipebusy = 231 ERRpipeclosing = 232 ERRnotconnected = 233 ERRmoredata = 234 ERRnomoreitems = 259 ERRbaddirectory = 267 ERReasnotsupported = 282 ERRlogonfailure = 1326 ERRbuftoosmall = 2123 ERRunknownipc = 2142 ERRnosuchprintjob = 2151 ERRinvgroup = 2455 # here's a special one from observing NT ERRnoipc = 66 # These errors seem to be only returned by the NT printer driver system ERRdriveralreadyinstalled = 1795 ERRunknownprinterport = 1796 ERRunknownprinterdriver = 1797 ERRunknownprintprocessor = 1798 ERRinvalidseparatorfile = 1799 ERRinvalidjobpriority = 1800 ERRinvalidprintername = 1801 ERRprinteralreadyexists = 1802 ERRinvalidprintercommand = 1803 ERRinvaliddatatype = 1804 ERRinvalidenvironment = 1805 ERRunknownprintmonitor = 3000 ERRprinterdriverinuse = 3001 ERRspoolfilenotfound = 3002 ERRnostartdoc = 3003 ERRnoaddjob = 3004 ERRprintprocessoralreadyinstalled = 3005 ERRprintmonitoralreadyinstalled = 3006 ERRinvalidprintmonitor = 3007 ERRprintmonitorinuse = 3008 ERRprinterhasjobsqueued = 3009 # Error codes for the ERRSRV class ERRerror = 1 ERRbadpw = 2 ERRbadtype = 3 ERRaccess = 4 ERRinvnid = 5 ERRinvnetname = 6 ERRinvdevice = 7 ERRqfull = 49 ERRqtoobig = 50 ERRinvpfid = 52 ERRsmbcmd = 64 ERRsrverror = 65 ERRfilespecs = 67 ERRbadlink = 68 ERRbadpermits = 69 ERRbadpid = 70 ERRsetattrmode = 71 ERRpaused = 81 ERRmsgoff = 82 ERRnoroom = 83 ERRrmuns = 87 ERRtimeout = 88 ERRnoresource = 89 ERRtoomanyuids = 90 ERRbaduid = 91 ERRuseMPX = 250 ERRuseSTD = 251 ERRcontMPX = 252 ERRbadPW = None ERRnosupport = 0 ERRunknownsmb = 22 # Error codes for the ERRHRD class ERRnowrite = 19 ERRbadunit = 20 ERRnotready = 21 ERRbadcmd = 22 ERRdata = 23 ERRbadreq = 24 ERRseek = 25 ERRbadmedia = 26 ERRbadsector = 27 ERRnopaper = 28 ERRwrite = 29 ERRread = 30 ERRwrongdisk = 34 ERRFCBunavail = 35 ERRsharebufexc = 36 ERRdiskfull = 39 hard_msgs = { 19: ("ERRnowrite", "Attempt to write on write-protected diskette."), 20: ("ERRbadunit", "Unknown unit."), 21: ("ERRnotready", "Drive not ready."), 22: ("ERRbadcmd", "Unknown command."), 23: ("ERRdata", "Data error (CRC)."), 24: ("ERRbadreq", "Bad request structure length."), 25: ("ERRseek", "Seek error."), 26: ("ERRbadmedia", "Unknown media type."), 27: ("ERRbadsector", "Sector not found."), 28: ("ERRnopaper", "Printer out of paper."), 29: ("ERRwrite", "Write fault."), 30: ("ERRread", "Read fault."), 31: ("ERRgeneral", "General failure."), 32: ("ERRbadshare", "An open conflicts with an existing open."), 33: ("ERRlock", "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."), 34: ("ERRwrongdisk", "The wrong disk was found in a drive."), 35: ("ERRFCBUnavail", "No FCBs are available to process request."), 36: ("ERRsharebufexc", "A sharing buffer has been exceeded.") } dos_msgs = { ERRbadfunc: ("ERRbadfunc", "Invalid function."), ERRbadfile: ("ERRbadfile", "File not found."), ERRbadpath: ("ERRbadpath", "Directory invalid."), ERRnofids: ("ERRnofids", "No file descriptors available"), ERRnoaccess: ("ERRnoaccess", "Access denied."), ERRbadfid: ("ERRbadfid", "Invalid file handle."), ERRbadmcb: ("ERRbadmcb", "Memory control blocks destroyed."), ERRnomem: ("ERRnomem", "Insufficient server memory to perform the requested function."), ERRbadmem: ("ERRbadmem", "Invalid memory block address."), ERRbadenv: ("ERRbadenv", "Invalid environment."), 11: ("ERRbadformat", "Invalid format."), ERRbadaccess: ("ERRbadaccess", "Invalid open mode."), ERRbaddata: ("ERRbaddata", "Invalid data."), ERRres: ("ERRres", "reserved."), ERRbaddrive: ("ERRbaddrive", "Invalid drive specified."), ERRremcd: ("ERRremcd", "A Delete Directory request attempted to remove the server's current directory."), ERRdiffdevice: ("ERRdiffdevice", "Not same device."), ERRnofiles: ("ERRnofiles", "A File Search command can find no more files matching the specified criteria."), ERRbadshare: ("ERRbadshare", "The sharing mode specified for an Open conflicts with existing FIDs on the file."), ERRlock: ("ERRlock", "A Lock request conflicted with an existing lock or specified an invalid mode, or an Unlock requested attempted to remove a lock held by another process."), ERRunsup: ("ERRunsup", "The operation is unsupported"), ERRnosuchshare: ("ERRnosuchshare", "You specified an invalid share name"), ERRfilexists: ("ERRfilexists", "The file named in a Create Directory, Make New File or Link request already exists."), ERRinvalidname: ("ERRinvalidname", "Invalid name"), ERRbadpipe: ("ERRbadpipe", "Pipe invalid."), ERRpipebusy: ("ERRpipebusy", "All instances of the requested pipe are busy."), ERRpipeclosing: ("ERRpipeclosing", "Pipe close in progress."), ERRnotconnected: ("ERRnotconnected", "No process on other end of pipe."), ERRmoredata: ("ERRmoredata", "There is more data to be returned."), ERRinvgroup: ("ERRinvgroup", "Invalid workgroup (try the -W option)"), ERRlogonfailure: ("ERRlogonfailure", "Logon failure"), ERRdiskfull: ("ERRdiskfull", "Disk full"), ERRgeneral: ("ERRgeneral", "General failure"), ERRunknownlevel: ("ERRunknownlevel", "Unknown info level") } server_msgs = { 1: ("ERRerror", "Non-specific error code."), 2: ("ERRbadpw", "Bad password - name/password pair in a Tree Connect or Session Setup are invalid."), 3: ("ERRbadtype", "reserved."), 4: ("ERRaccess", "The requester does not have the necessary access rights within the specified context for the requested function. The context is defined by the TID or the UID."), 5: ("ERRinvnid", "The tree ID (TID) specified in a command was invalid."), 6: ("ERRinvnetname", "Invalid network name in tree connect."), 7: ("ERRinvdevice", "Invalid device - printer request made to non-printer connection or non-printer request made to printer connection."), 49: ("ERRqfull", "Print queue full (files) -- returned by open print file."), 50: ("ERRqtoobig", "Print queue full -- no space."), 51: ("ERRqeof", "EOF on print queue dump."), 52: ("ERRinvpfid", "Invalid print file FID."), 64: ("ERRsmbcmd", "The server did not recognize the command received."), 65: ("ERRsrverror","The server encountered an internal error, e.g., system file unavailable."), 67: ("ERRfilespecs", "The file handle (FID) and pathname parameters contained an invalid combination of values."), 68: ("ERRreserved", "reserved."), 69: ("ERRbadpermits", "The access permissions specified for a file or directory are not a valid combination. The server cannot set the requested attribute."), 70: ("ERRreserved", "reserved."), 71: ("ERRsetattrmode", "The attribute mode in the Set File Attribute request is invalid."), 81: ("ERRpaused", "Server is paused."), 82: ("ERRmsgoff", "Not receiving messages."), 83: ("ERRnoroom", "No room to buffer message."), 87: ("ERRrmuns", "Too many remote user names."), 88: ("ERRtimeout", "Operation timed out."), 89: ("ERRnoresource", "No resources currently available for request."), 90: ("ERRtoomanyuids", "Too many UIDs active on this session."), 91: ("ERRbaduid", "The UID is not known as a valid ID on this session."), 250: ("ERRusempx","Temp unable to support Raw, use MPX mode."), 251: ("ERRusestd","Temp unable to support Raw, use standard read/write."), 252: ("ERRcontmpx", "Continue in MPX mode."), 253: ("ERRreserved", "reserved."), 254: ("ERRreserved", "reserved."), 0xFFFF: ("ERRnosupport", "Function not supported.") } # Error clases ERRDOS = 0x1 error_classes = { 0: ("SUCCESS", {}), ERRDOS: ("ERRDOS", dos_msgs), 0x02: ("ERRSRV",server_msgs), 0x03: ("ERRHRD",hard_msgs), 0x04: ("ERRXOS", {} ), 0xE1: ("ERRRMX1", {} ), 0xE2: ("ERRRMX2", {} ), 0xE3: ("ERRRMX3", {} ), 0xFF: ("ERRCMD", {} ) } def __init__( self, error_string, error_class, error_code, nt_status = 0): Exception.__init__(self, error_string) self.nt_status = nt_status self._args = error_string if nt_status: self.error_class = 0 self.error_code = (error_code << 16) + error_class else: self.error_class = error_class self.error_code = error_code def get_error_class( self ): return self.error_class def get_error_code( self ): return self.error_code def __str__( self ): error_class = SessionError.error_classes.get( self.error_class, None ) if not error_class: error_code_str = self.error_code error_class_str = self.error_class else: error_class_str = error_class[0] error_code = error_class[1].get( self.error_code, None ) if not error_code: error_code_str = self.error_code else: error_code_str = '%s(%s)' % error_code if self.nt_status: return 'SMB SessionError: %s(%s)' % nt_errors.ERROR_MESSAGES[self.error_code] else: # Fall back to the old format return 'SMB SessionError: class: %s, code: %s' % (error_class_str, error_code_str) # Raised when an supported feature is present/required in the protocol but is not # currently supported by pysmb class UnsupportedFeature(Exception): pass # Contains information about a SMB shared device/service class SharedDevice: def __init__(self, name, share_type, comment): self.__name = name self.__type = share_type self.__comment = comment def get_name(self): return self.__name def get_type(self): return self.__type def get_comment(self): return self.__comment def __repr__(self): return '<SharedDevice instance: name=' + self.__name + ', type=' + str(self.__type) + ', comment="' + self.__comment + '">' # Contains information about the shared file/directory class SharedFile: def __init__(self, ctime, atime, mtime, filesize, allocsize, attribs, shortname, longname): self.__ctime = ctime self.__atime = atime self.__mtime = mtime self.__filesize = filesize self.__allocsize = allocsize self.__attribs = attribs try: self.__shortname = shortname[:string.index(shortname, '\0')] except ValueError: self.__shortname = shortname try: self.__longname = longname[:string.index(longname, '\0')] except ValueError: self.__longname = longname def get_ctime(self): return self.__ctime def get_ctime_epoch(self): return self.__convert_smbtime(self.__ctime) def get_mtime(self): return self.__mtime def get_mtime_epoch(self): return self.__convert_smbtime(self.__mtime) def get_atime(self): return self.__atime def get_atime_epoch(self): return self.__convert_smbtime(self.__atime) def get_filesize(self): return self.__filesize def get_allocsize(self): return self.__allocsize def get_attributes(self): return self.__attribs def is_archive(self): return self.__attribs & ATTR_ARCHIVE def is_compressed(self): return self.__attribs & ATTR_COMPRESSED def is_normal(self): return self.__attribs & ATTR_NORMAL def is_hidden(self): return self.__attribs & ATTR_HIDDEN def is_readonly(self): return self.__attribs & ATTR_READONLY def is_temporary(self): return self.__attribs & ATTR_TEMPORARY def is_directory(self): return self.__attribs & ATTR_DIRECTORY def is_system(self): return self.__attribs & ATTR_SYSTEM def get_shortname(self): return self.__shortname def get_longname(self): return self.__longname def __repr__(self): return '<SharedFile instance: shortname="' + self.__shortname + '", longname="' + self.__longname + '", filesize=' + str(self.__filesize) + '>' @staticmethod def __convert_smbtime(t): x = t >> 32 y = t & 0xffffffff geo_cal_offset = 11644473600.0 # = 369.0 * 365.25 * 24 * 60 * 60 - (3.0 * 24 * 60 * 60 + 6.0 * 60 * 60) return (x * 4.0 * (1 << 30) + (y & 0xfff00000)) * 1.0e-7 - geo_cal_offset # Contain information about a SMB machine class SMBMachine: def __init__(self, nbname, nbt_type, comment): self.__nbname = nbname self.__type = nbt_type self.__comment = comment def __repr__(self): return '<SMBMachine instance: nbname="' + self.__nbname + '", type=' + hex(self.__type) + ', comment="' + self.__comment + '">' class SMBDomain: def __init__(self, nbgroup, domain_type, master_browser): self.__nbgroup = nbgroup self.__type = domain_type self.__master_browser = master_browser def __repr__(self): return '<SMBDomain instance: nbgroup="' + self.__nbgroup + '", type=' + hex(self.__type) + ', master browser="' + self.__master_browser + '">' # Represents a SMB Packet class NewSMBPacket(Structure): structure = ( ('Signature', '"\xffSMB'), ('Command','B=0'), ('ErrorClass','B=0'), ('_reserved','B=0'), ('ErrorCode','<H=0'), ('Flags1','B=0'), ('Flags2','<H=0'), ('PIDHigh','<H=0'), ('SecurityFeatures','8s=""'), ('Reserved','<H=0'), ('Tid','<H=0xffff'), ('Pid','<H=0'), ('Uid','<H=0'), ('Mid','<H=0'), ('Data','*:'), ) def __init__(self, **kargs): Structure.__init__(self, **kargs) if ('Flags2' in self.fields) is False: self['Flags2'] = 0 if ('Flags1' in self.fields) is False: self['Flags1'] = 0 if 'data' not in kargs: self['Data'] = [] def addCommand(self, command): if len(self['Data']) == 0: self['Command'] = command.command else: self['Data'][-1]['Parameters']['AndXCommand'] = command.command self['Data'][-1]['Parameters']['AndXOffset'] = len(self) self['Data'].append(command) def isMoreData(self): return (self['Command'] in [SMB.SMB_COM_TRANSACTION, SMB.SMB_COM_READ_ANDX, SMB.SMB_COM_READ_RAW] and self['ErrorClass'] == 1 and self['ErrorCode'] == SessionError.ERRmoredata) def isMoreProcessingRequired(self): return self['ErrorClass'] == 0x16 and self['ErrorCode'] == 0xc000 def isValidAnswer(self, cmd): # this was inside a loop reading more from the net (with recv_packet(None)) if self['Command'] == cmd: if (self['ErrorClass'] == 0x00 and self['ErrorCode'] == 0x00): return 1 elif self.isMoreData(): return 1 elif self.isMoreProcessingRequired(): return 1 raise SessionError("SMB Library Error", self['ErrorClass'] + (self['_reserved'] << 8), self['ErrorCode'], self['Flags2'] & SMB.FLAGS2_NT_STATUS) else: raise UnsupportedFeature("Unexpected answer from server: Got %d, Expected %d" % (self['Command'], cmd)) class SMBCommand(Structure): structure = ( ('WordCount', 'B=len(Parameters)/2'), ('_ParametersLength','_-Parameters','WordCount*2'), ('Parameters',':'), # default set by constructor ('ByteCount','<H-Data'), ('Data',':'), # default set by constructor ) def __init__(self, commandOrData = None, data = None, **kargs): if type(commandOrData) == type(0): self.command = commandOrData else: data = data or commandOrData Structure.__init__(self, data = data, **kargs) if data is None: self['Parameters'] = '' self['Data'] = '' class AsciiOrUnicodeStructure(Structure): UnicodeStructure = () AsciiStructure = () def __init__(self, flags = 0, **kargs): if flags & SMB.FLAGS2_UNICODE: self.structure = self.UnicodeStructure else: self.structure = self.AsciiStructure Structure.__init__(self, **kargs) class SMBCommand_Parameters(Structure): pass class SMBAndXCommand_Parameters(Structure): commonHdr = ( ('AndXCommand','B=0xff'), ('_reserved','B=0'), ('AndXOffset','<H=0'), ) structure = ( # default structure, overriden by subclasses ('Data',':=""'), ) ############# TRANSACTIONS RELATED # TRANS2_QUERY_FS_INFORMATION # QUERY_FS Information Levels # SMB_QUERY_FS_ATTRIBUTE_INFO class SMBQueryFsAttributeInfo(Structure): structure = ( ('FileSystemAttributes','<L'), ('MaxFilenNameLengthInBytes','<L'), ('LengthOfFileSystemName','<L-FileSystemName'), ('FileSystemName',':'), ) class SMBQueryFsInfoVolume(AsciiOrUnicodeStructure): commonHdr = ( ('ulVolSerialNbr','<L=0xABCDEFAA'), ('cCharCount','<B-VolumeLabel'), ) AsciiStructure = ( ('VolumeLabel','z'), ) UnicodeStructure = ( ('VolumeLabel','u'), ) # FILE_FS_SIZE_INFORMATION class FileFsSizeInformation(Structure): structure = ( ('TotalAllocationUnits','<q=148529400'), ('AvailableAllocationUnits','<q=14851044'), ('SectorsPerAllocationUnit','<L=2'), ('BytesPerSector','<L=512'), ) # SMB_QUERY_FS_SIZE_INFO class SMBQueryFsSizeInfo(Structure): structure = ( ('TotalAllocationUnits','<q=148529400'), ('TotalFreeAllocationUnits','<q=14851044'), ('SectorsPerAllocationUnit','<L=2'), ('BytesPerSector','<L=512'), ) # FILE_FS_FULL_SIZE_INFORMATION class SMBFileFsFullSizeInformation(Structure): structure = ( ('TotalAllocationUnits','<q=148529400'), ('CallerAvailableAllocationUnits','<q=148529400'), ('ActualAvailableAllocationUnits','<q=148529400'), ('SectorsPerAllocationUnit','<L=15'), ('BytesPerSector','<L=512') ) # SMB_QUERY_FS_VOLUME_INFO class SMBQueryFsVolumeInfo(Structure): structure = ( ('VolumeCreationTime','<q'), ('SerialNumber','<L=0xABCDEFAA'), ('VolumeLabelSize','<L=len(VolumeLabel)'), ('Reserved','<H=0x10'), ('VolumeLabel',':') ) # SMB_FIND_FILE_BOTH_DIRECTORY_INFO level class SMBFindFileBothDirectoryInfo(AsciiOrUnicodeStructure): commonHdr = ( ('NextEntryOffset','<L=0'), ('FileIndex','<L=0'), ('CreationTime','<q'), ('LastAccessTime','<q'), ('LastWriteTime','<q'), ('LastChangeTime','<q'), ('EndOfFile','<q=0'), ('AllocationSize','<q=0'), ('ExtFileAttributes','<L=0'), ) AsciiStructure = ( ('FileNameLength','<L-FileName','len(FileName)'), ('EaSize','<L=0'), ('ShortNameLength','<B=0'), ('Reserved','<B=0'), ('ShortName','24s'), ('FileName',':'), ) UnicodeStructure = ( ('FileNameLength','<L-FileName','len(FileName)*2'), ('EaSize','<L=0'), ('ShortNameLength','<B=0'), ('Reserved','<B=0'), ('ShortName','24s'), ('FileName',':'), ) # SMB_FIND_FILE_ID_FULL_DIRECTORY_INFO level class SMBFindFileIdFullDirectoryInfo(AsciiOrUnicodeStructure): commonHdr = ( ('NextEntryOffset','<L=0'), ('FileIndex','<L=0'), ('CreationTime','<q'), ('LastAccessTime','<q'), ('LastWriteTime','<q'), ('LastChangeTime','<q'), ('EndOfFile','<q=0'), ('AllocationSize','<q=0'), ('ExtFileAttributes','<L=0'), ) AsciiStructure = ( ('FileNameLength','<L-FileName','len(FileName)'), ('EaSize','<L=0'), ('FileID','<q=0'), ('FileName',':'), ) UnicodeStructure = ( ('FileNameLength','<L-FileName','len(FileName)*2'), ('EaSize','<L=0'), ('FileID','<q=0'), ('FileName',':'), ) # SMB_FIND_FILE_ID_BOTH_DIRECTORY_INFO level class SMBFindFileIdBothDirectoryInfo(AsciiOrUnicodeStructure): commonHdr = ( ('NextEntryOffset','<L=0'), ('FileIndex','<L=0'), ('CreationTime','<q'), ('LastAccessTime','<q'), ('LastWriteTime','<q'), ('LastChangeTime','<q'), ('EndOfFile','<q=0'), ('AllocationSize','<q=0'), ('ExtFileAttributes','<L=0'), ) AsciiStructure = ( ('FileNameLength','<L-FileName','len(FileName)'), ('EaSize','<L=0'), ('ShortNameLength','<B=0'), ('Reserved','<B=0'), ('ShortName','24s'), ('Reserved','<H=0'), ('FileID','<q=0'), ('FileName','z'), ) UnicodeStructure = ( ('FileNameLength','<L-FileName','len(FileName)*2'), ('EaSize','<L=0'), ('ShortNameLength','<B=0'), ('Reserved','<B=0'), ('ShortName','24s'), ('Reserved','<H=0'), ('FileID','<q=0'), ('FileName',':'), ) # SMB_FIND_FILE_DIRECTORY_INFO level class SMBFindFileDirectoryInfo(AsciiOrUnicodeStructure): commonHdr = ( ('NextEntryOffset','<L=0'), ('FileIndex','<L=0'), ('CreationTime','<q'), ('LastAccessTime','<q'), ('LastWriteTime','<q'), ('LastChangeTime','<q'), ('EndOfFile','<q=0'), ('AllocationSize','<q=1'), ('ExtFileAttributes','<L=0'), ) AsciiStructure = ( ('FileNameLength','<L-FileName','len(FileName)'), ('FileName','z'), ) UnicodeStructure = ( ('FileNameLength','<L-FileName','len(FileName)*2'), ('FileName',':'), ) # SMB_FIND_FILE_NAMES_INFO level class SMBFindFileNamesInfo(AsciiOrUnicodeStructure): commonHdr = ( ('NextEntryOffset','<L=0'), ('FileIndex','<L=0'), ) AsciiStructure = ( ('FileNameLength','<L-FileName','len(FileName)'), ('FileName','z'), ) UnicodeStructure = ( ('FileNameLength','<L-FileName','len(FileName)*2'), ('FileName',':'), ) # SMB_FIND_FILE_FULL_DIRECTORY_INFO level class SMBFindFileFullDirectoryInfo(AsciiOrUnicodeStructure): commonHdr = ( ('NextEntryOffset','<L=0'), ('FileIndex','<L=0'), ('CreationTime','<q'), ('LastAccessTime','<q'), ('LastWriteTime','<q'), ('LastChangeTime','<q'), ('EndOfFile','<q=0'), ('AllocationSize','<q=1'), ('ExtFileAttributes','<L=0'), ) AsciiStructure = ( ('FileNameLength','<L-FileName','len(FileName)'), ('EaSize','<L'), ('FileName','z'), ) UnicodeStructure = ( ('FileNameLength','<L-FileName','len(FileName)*2'), ('EaSize','<L'), ('FileName',':'), ) # SMB_FIND_INFO_STANDARD level class SMBFindInfoStandard(AsciiOrUnicodeStructure): commonHdr = ( ('ResumeKey','<L=0xff'), ('CreationDate','<H=0'), ('CreationTime','<H=0'), ('LastAccessDate','<H=0'), ('LastAccessTime','<H=0'), ('LastWriteDate','<H=0'), ('LastWriteTime','<H=0'), ('EaSize','<L'), ('AllocationSize','<L=1'), ('ExtFileAttributes','<H=0'), ) AsciiStructure = ( ('FileNameLength','<B-FileName','len(FileName)'), ('FileName','z'), ) UnicodeStructure = ( ('FileNameLength','<B-FileName','len(FileName)*2'), ('FileName',':'), ) # SET_FILE_INFORMATION structures # SMB_SET_FILE_DISPOSITION_INFO class SMBSetFileDispositionInfo(Structure): structure = ( ('DeletePending','<B'), ) # SMB_SET_FILE_BASIC_INFO class SMBSetFileBasicInfo(Structure): structure = ( ('CreationTime','<q'), ('LastAccessTime','<q'), ('LastWriteTime','<q'), ('ChangeTime','<q'), ('ExtFileAttributes','<H'), ('Reserved','<L'), ) # FILE_STREAM_INFORMATION class SMBFileStreamInformation(Structure): commonHdr = ( ('NextEntryOffset','<L=0'), ('StreamNameLength','<L=0'), ('StreamSize','<q=0'), ('StreamAllocationSize','<q=0'), ('StreamName',':=""'), ) # FILE_NETWORK_OPEN_INFORMATION class SMBFileNetworkOpenInfo(Structure): structure = ( ('CreationTime','<q=0'), ('LastAccessTime','<q=0'), ('LastWriteTime','<q=0'), ('ChangeTime','<q=0'), ('AllocationSize','<q=0'), ('EndOfFile','<q=0'), ('FileAttributes','<L=0'), ('Reserved','<L=0'), ) # SMB_SET_FILE_END_OF_FILE_INFO class SMBSetFileEndOfFileInfo(Structure): structure = ( ('EndOfFile','<q'), ) # TRANS2_FIND_NEXT2 class SMBFindNext2_Parameters(AsciiOrUnicodeStructure): commonHdr = ( ('SID','<H'), ('SearchCount','<H'), ('InformationLevel','<H'), ('ResumeKey','<L'), ('Flags','<H'), ) AsciiStructure = ( ('FileName','z'), ) UnicodeStructure = ( ('FileName','u'), ) class SMBFindNext2Response_Parameters(Structure): structure = ( ('SearchCount','<H'), ('EndOfSearch','<H=1'), ('EaErrorOffset','<H=0'), ('LastNameOffset','<H=0'), ) class SMBFindNext2_Data(Structure): structure = ( ('GetExtendedAttributesListLength','_-GetExtendedAttributesList', 'self["GetExtendedAttributesListLength"]'), ('GetExtendedAttributesList',':'), ) # TRANS2_FIND_FIRST2 class SMBFindFirst2Response_Parameters(Structure): structure = ( ('SID','<H'), ('SearchCount','<H'), ('EndOfSearch','<H=1'), ('EaErrorOffset','<H=0'), ('LastNameOffset','<H=0'), ) class SMBFindFirst2_Parameters(AsciiOrUnicodeStructure): commonHdr = ( ('SearchAttributes','<H'), ('SearchCount','<H'), ('Flags','<H'), ('InformationLevel','<H'), ('SearchStorageType','<L'), ) AsciiStructure = ( ('FileName','z'), ) UnicodeStructure = ( ('FileName','u'), ) class SMBFindFirst2_Data(Structure): structure = ( ('GetExtendedAttributesListLength','_-GetExtendedAttributesList', 'self["GetExtendedAttributesListLength"]'), ('GetExtendedAttributesList',':'), ) # TRANS2_SET_PATH_INFORMATION class SMBSetPathInformation_Parameters(AsciiOrUnicodeStructure): commonHdr = ( ('InformationLevel','<H'), ('Reserved','<L'), ) AsciiStructure = ( ('FileName','z'), ) UnicodeStructure = ( ('FileName','u'), ) class SMBSetPathInformationResponse_Parameters(Structure): structure = ( ('EaErrorOffset','<H=0'), ) # TRANS2_SET_FILE_INFORMATION class SMBSetFileInformation_Parameters(Structure): structure = ( ('FID','<H'), ('InformationLevel','<H'), ('Reserved','<H'), ) class SMBSetFileInformationResponse_Parameters(Structure): structure = ( ('EaErrorOffset','<H=0'), ) # TRANS2_QUERY_FILE_INFORMATION class SMBQueryFileInformation_Parameters(Structure): structure = ( ('FID','<H'), ('InformationLevel','<H'), ) class SMBQueryFileInformationResponse_Parameters(Structure): structure = ( ('EaErrorOffset','<H=0'), ) class SMBQueryFileInformation_Data(Structure): structure = ( ('GetExtendedAttributeList',':'), ) # TRANS2_QUERY_PATH_INFORMATION class SMBQueryPathInformationResponse_Parameters(Structure): structure = ( ('EaErrorOffset','<H=0'), ) class SMBQueryPathInformation_Parameters(AsciiOrUnicodeStructure): commonHdr = ( ('InformationLevel','<H'), ('Reserved','<L=0'), ) AsciiStructure = ( ('FileName','z'), ) UnicodeStructure = ( ('FileName','u'), ) class SMBQueryPathInformation_Data(Structure): structure = ( ('GetExtendedAttributeList',':'), ) # SMB_QUERY_FILE_EA_INFO class SMBQueryFileEaInfo(Structure): structure = ( ('EaSize','<L=0'), ) # SMB_QUERY_FILE_BASIC_INFO class SMBQueryFileBasicInfo(Structure): structure = ( ('CreationTime','<q'), ('LastAccessTime','<q'), ('LastWriteTime','<q'), ('LastChangeTime','<q'), ('ExtFileAttributes','<L'), #('Reserved','<L=0'), ) # SMB_QUERY_FILE_STANDARD_INFO class SMBQueryFileStandardInfo(Structure): structure = ( ('AllocationSize','<q'), ('EndOfFile','<q'), ('NumberOfLinks','<L=0'), ('DeletePending','<B=0'), ('Directory','<B'), ) # SMB_QUERY_FILE_ALL_INFO class SMBQueryFileAllInfo(Structure): structure = ( ('CreationTime','<q'), ('LastAccessTime','<q'), ('LastWriteTime','<q'), ('LastChangeTime','<q'), ('ExtFileAttributes','<L'), ('Reserved','<L=0'), ('AllocationSize','<q'), ('EndOfFile','<q'), ('NumberOfLinks','<L=0'), ('DeletePending','<B=0'), ('Directory','<B'), ('Reserved','<H=0'), ('EaSize','<L=0'), ('FileNameLength','<L-FileName','len(FileName)'), ('FileName',':'), ) # \PIPE\LANMAN NetShareEnum class SMBNetShareEnum(Structure): structure = ( ('RAPOpcode','<H=0'), ('ParamDesc','z'), ('DataDesc','z'), ('InfoLevel','<H'), ('ReceiveBufferSize','<H'), ) class SMBNetShareEnumResponse(Structure): structure = ( ('Status','<H=0'), ('Convert','<H=0'), ('EntriesReturned','<H'), ('EntriesAvailable','<H'), ) class NetShareInfo1(Structure): structure = ( ('NetworkName','13s'), ('Pad','<B=0'), ('Type','<H=0'), ('RemarkOffsetLow','<H=0'), ('RemarkOffsetHigh','<H=0'), ) # \PIPE\LANMAN NetServerGetInfo class SMBNetServerGetInfoResponse(Structure): structure = ( ('Status','<H=0'), ('Convert','<H=0'), ('TotalBytesAvailable','<H'), ) class SMBNetServerInfo1(Structure): # Level 1 Response structure = ( ('ServerName','16s'), ('MajorVersion','B=5'), ('MinorVersion','B=0'), ('ServerType','<L=3'), ('ServerCommentLow','<H=0'), ('ServerCommentHigh','<H=0'), ) # \PIPE\LANMAN NetShareGetInfo class SMBNetShareGetInfo(Structure): structure = ( ('RAPOpcode','<H=0'), ('ParamDesc','z'), ('DataDesc','z'), ('ShareName','z'), ('InfoLevel','<H'), ('ReceiveBufferSize','<H'), ) class SMBNetShareGetInfoResponse(Structure): structure = ( ('Status','<H=0'), ('Convert','<H=0'), ('TotalBytesAvailable','<H'), ) ############# Security Features class SecurityFeatures(Structure): structure = ( ('Key','<L=0'), ('CID','<H=0'), ('SequenceNumber','<H=0'), ) ############# SMB_COM_QUERY_INFORMATION2 (0x23) class SMBQueryInformation2_Parameters(Structure): structure = ( ('Fid','<H'), ) class SMBQueryInformation2Response_Parameters(Structure): structure = ( ('CreateDate','<H'), ('CreationTime','<H'), ('LastAccessDate','<H'), ('LastAccessTime','<H'), ('LastWriteDate','<H'), ('LastWriteTime','<H'), ('FileDataSize','<L'), ('FileAllocationSize','<L'), ('FileAttributes','<L'), ) ############# SMB_COM_SESSION_SETUP_ANDX (0x73) class SMBSessionSetupAndX_Parameters(SMBAndXCommand_Parameters): structure = ( ('MaxBuffer','<H'), ('MaxMpxCount','<H'), ('VCNumber','<H'), ('SessionKey','<L'), ('AnsiPwdLength','<H'), ('UnicodePwdLength','<H'), ('_reserved','<L=0'), ('Capabilities','<L'), ) class SMBSessionSetupAndX_Extended_Parameters(SMBAndXCommand_Parameters): structure = ( ('MaxBufferSize','<H'), ('MaxMpxCount','<H'), ('VcNumber','<H'), ('SessionKey','<L'), ('SecurityBlobLength','<H'), ('Reserved','<L=0'), ('Capabilities','<L'), ) class SMBSessionSetupAndX_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('AnsiPwdLength','_-AnsiPwd','self["AnsiPwdLength"]'), ('UnicodePwdLength','_-UnicodePwd','self["UnicodePwdLength"]'), ('AnsiPwd',':=""'), ('UnicodePwd',':=""'), ('Account','z=""'), ('PrimaryDomain','z=""'), ('NativeOS','z=""'), ('NativeLanMan','z=""'), ) UnicodeStructure = ( ('AnsiPwdLength','_-AnsiPwd','self["AnsiPwdLength"]'), ('UnicodePwdLength','_-UnicodePwd','self["UnicodePwdLength"]'), ('AnsiPwd',':=""'), ('UnicodePwd',':=""'), ('Account','u=""'), ('PrimaryDomain','u=""'), ('NativeOS','u=""'), ('NativeLanMan','u=""'), ) class SMBSessionSetupAndX_Extended_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('SecurityBlobLength','_-SecurityBlob','self["SecurityBlobLength"]'), ('SecurityBlob',':'), ('NativeOS','z=""'), ('NativeLanMan','z=""'), ) UnicodeStructure = ( ('SecurityBlobLength','_-SecurityBlob','self["SecurityBlobLength"]'), ('SecurityBlob',':'), ('NativeOS','u=""'), ('NativeLanMan','u=""'), ) class SMBSessionSetupAndXResponse_Parameters(SMBAndXCommand_Parameters): structure = ( ('Action','<H'), ) class SMBSessionSetupAndX_Extended_Response_Parameters(SMBAndXCommand_Parameters): structure = ( ('Action','<H=0'), ('SecurityBlobLength','<H'), ) class SMBSessionSetupAndXResponse_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('NativeOS','z=""'), ('NativeLanMan','z=""'), ('PrimaryDomain','z=""'), ) UnicodeStructure = ( ('NativeOS','u=""'), ('NativeLanMan','u=""'), ('PrimaryDomain','u=""'), ) class SMBSessionSetupAndX_Extended_Response_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('SecurityBlobLength','_-SecurityBlob','self["SecurityBlobLength"]'), ('SecurityBlob',':'), ('NativeOS','z=""'), ('NativeLanMan','z=""'), ) UnicodeStructure = ( ('SecurityBlobLength','_-SecurityBlob','self["SecurityBlobLength"]'), ('SecurityBlob',':'), ('NativeOS','u=""'), ('NativeLanMan','u=""'), ) ############# SMB_COM_TREE_CONNECT (0x70) class SMBTreeConnect_Parameters(SMBCommand_Parameters): structure = ( ) class SMBTreeConnect_Data(SMBCommand_Parameters): structure = ( ('PathFormat','"\x04'), ('Path','z'), ('PasswordFormat','"\x04'), ('Password','z'), ('ServiceFormat','"\x04'), ('Service','z'), ) ############# SMB_COM_TREE_CONNECT_ANDX (0x75) class SMBTreeConnectAndX_Parameters(SMBAndXCommand_Parameters): structure = ( ('Flags','<H=0'), ('PasswordLength','<H'), ) class SMBTreeConnectAndXResponse_Parameters(SMBAndXCommand_Parameters): structure = ( ('OptionalSupport','<H=0'), ) class SMBTreeConnectAndXExtendedResponse_Parameters(SMBAndXCommand_Parameters): structure = ( ('OptionalSupport','<H=1'), ('MaximalShareAccessRights','<L=0x1fffff'), ('GuestMaximalShareAccessRights','<L=0x1fffff'), ) class SMBTreeConnectAndX_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('_PasswordLength','_-Password','self["_PasswordLength"]'), ('Password',':'), ('Path','z'), ('Service','z'), ) UnicodeStructure = ( ('_PasswordLength','_-Password','self["_PasswordLength"] if self["_PasswordLength"] > 0 else 1'), ('Password',':'), ('Path','u'), ('Service','z'), ) class SMBTreeConnectAndXResponse_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('Service','z'), ('PadLen','_-Pad','self["PadLen"]'), ('Pad',':=""'), ('NativeFileSystem','z'), ) UnicodeStructure = ( ('Service','z'), ('PadLen','_-Pad','self["PadLen"]'), ('Pad',':=""'), ('NativeFileSystem','u'), ) ############# SMB_COM_NT_CREATE_ANDX (0xA2) class SMBNtCreateAndX_Parameters(SMBAndXCommand_Parameters): structure = ( ('_reserved', 'B=0'), ('FileNameLength','<H'), # NameLength ('CreateFlags','<L'), # Flags ('RootFid','<L=0'), # RootDirectoryFID ('AccessMask','<L'), # DesiredAccess ('AllocationSizeLo','<L=0'), # AllocationSize ('AllocationSizeHi','<L=0'), ('FileAttributes','<L=0'), # ExtFileAttributes ('ShareAccess','<L=3'), # ('Disposition','<L=1'), # CreateDisposition ('CreateOptions','<L'), # CreateOptions ('Impersonation','<L=2'), ('SecurityFlags','B=3'), ) class SMBNtCreateAndXResponse_Parameters(SMBAndXCommand_Parameters): # XXX Is there a memory leak in the response for NTCreate (where the Data section would be) in Win 2000, Win XP, and Win 2003? structure = ( ('OplockLevel', 'B=0'), ('Fid','<H'), ('CreateAction','<L'), ('CreateTime','<q=0'), ('LastAccessTime','<q=0'), ('LastWriteTime','<q=0'), ('LastChangeTime','<q=0'), ('FileAttributes','<L=0x80'), ('AllocationSize','<q=0'), ('EndOfFile','<q=0'), ('FileType','<H=0'), ('IPCState','<H=0'), ('IsDirectory','B'), ) class SMBNtCreateAndXExtendedResponse_Parameters(SMBAndXCommand_Parameters): # [MS-SMB] Extended response description structure = ( ('OplockLevel', 'B=0'), ('Fid','<H'), ('CreateAction','<L'), ('CreateTime','<q=0'), ('LastAccessTime','<q=0'), ('LastWriteTime','<q=0'), ('LastChangeTime','<q=0'), ('FileAttributes','<L=0x80'), ('AllocationSize','<q=0'), ('EndOfFile','<q=0'), ('FileType','<H=0'), ('IPCState','<H=0'), ('IsDirectory','B'), ('VolumeGUID','16s'), ('FileIdLow','<L=0'), ('FileIdHigh','<L=0'), ('MaximalAccessRights','<L=0x12019b'), ('GuestMaximalAccessRights','<L=0x120089'), ) class SMBNtCreateAndX_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('FileName','z'), ) UnicodeStructure = ( ('Pad','B'), ('FileName','u'), ) ############# SMB_COM_OPEN_ANDX (0xD2) class SMBOpenAndX_Parameters(SMBAndXCommand_Parameters): structure = ( ('Flags','<H=0'), ('DesiredAccess','<H=0'), ('SearchAttributes','<H=0'), ('FileAttributes','<H=0'), ('CreationTime','<L=0'), ('OpenMode','<H=1'), # SMB_O_OPEN = 1 ('AllocationSize','<L=0'), ('Reserved','8s=""'), ) class SMBOpenAndX_Data(SMBNtCreateAndX_Data): pass class SMBOpenAndXResponse_Parameters(SMBAndXCommand_Parameters): structure = ( ('Fid','<H=0'), ('FileAttributes','<H=0'), ('LastWriten','<L=0'), ('FileSize','<L=0'), ('GrantedAccess','<H=0'), ('FileType','<H=0'), ('IPCState','<H=0'), ('Action','<H=0'), ('ServerFid','<L=0'), ('_reserved','<H=0'), ) ############# SMB_COM_WRITE (0x0B) class SMBWrite_Parameters(SMBCommand_Parameters): structure = ( ('Fid','<H'), ('Count','<H'), ('Offset','<L'), ('Remaining','<H'), ) class SMBWriteResponse_Parameters(SMBCommand_Parameters): structure = ( ('Count','<H'), ) class SMBWrite_Data(Structure): structure = ( ('BufferFormat','<B=1'), ('DataLength','<H-Data'), ('Data',':'), ) ############# SMB_COM_WRITE_ANDX (0x2F) class SMBWriteAndX_Parameters(SMBAndXCommand_Parameters): structure = ( ('Fid','<H=0'), ('Offset','<L=0'), ('_reserved','<L=0xff'), ('WriteMode','<H=8'), ('Remaining','<H=0'), ('DataLength_Hi','<H=0'), ('DataLength','<H=0'), ('DataOffset','<H=0'), ('HighOffset','<L=0'), ) class SMBWriteAndX_Data_Short(Structure): structure = ( ('_PadLen','_-Pad','self["DataOffset"] - 59'), ('Pad',':'), #('Pad','<B=0'), ('DataLength','_-Data','self["DataLength"]'), ('Data',':'), ) class SMBWriteAndX_Data(Structure): structure = ( ('_PadLen','_-Pad','self["DataOffset"] - 63'), ('Pad',':'), #('Pad','<B=0'), ('DataLength','_-Data','self["DataLength"]'), ('Data',':'), ) class SMBWriteAndX_Parameters_Short(SMBAndXCommand_Parameters): structure = ( ('Fid','<H'), ('Offset','<L'), ('_reserved','<L=0xff'), ('WriteMode','<H=8'), ('Remaining','<H'), ('DataLength_Hi','<H=0'), ('DataLength','<H'), ('DataOffset','<H=0'), ) class SMBWriteAndXResponse_Parameters(SMBAndXCommand_Parameters): structure = ( ('Count','<H'), ('Available','<H'), ('Reserved','<L=0'), ) ############# SMB_COM_WRITE_RAW (0x1D) class SMBWriteRaw_Parameters(SMBCommand_Parameters): structure = ( ('Fid','<H'), ('Count','<H'), ('_reserved','<H=0'), ('Offset','<L'), ('Timeout','<L=0'), ('WriteMode','<H=0'), ('_reserved2','<L=0'), ('DataLength','<H'), ('DataOffset','<H=0'), ) ############# SMB_COM_READ (0x0A) class SMBRead_Parameters(SMBCommand_Parameters): structure = ( ('Fid','<H'), ('Count','<H'), ('Offset','<L'), ('Remaining','<H=Count'), ) class SMBReadResponse_Parameters(Structure): structure = ( ('Count','<H=0'), ('_reserved','8s=""'), ) class SMBReadResponse_Data(Structure): structure = ( ('BufferFormat','<B=0x1'), ('DataLength','<H-Data'), ('Data',':'), ) ############# SMB_COM_READ_RAW (0x1A) class SMBReadRaw_Parameters(SMBCommand_Parameters): structure = ( ('Fid','<H'), ('Offset','<L'), ('MaxCount','<H'), ('MinCount','<H=MaxCount'), ('Timeout','<L=0'), ('_reserved','<H=0'), ) ############# SMB_COM_NT_TRANSACT (0xA0) class SMBNTTransaction_Parameters(SMBCommand_Parameters): structure = ( ('MaxSetupCount','<B=0'), ('Reserved1','<H=0'), ('TotalParameterCount','<L'), ('TotalDataCount','<L'), ('MaxParameterCount','<L=1024'), ('MaxDataCount','<L=65504'), ('ParameterCount','<L'), ('ParameterOffset','<L'), ('DataCount','<L'), ('DataOffset','<L'), ('SetupCount','<B=len(Setup)/2'), ('Function','<H=0'), ('SetupLength','_-Setup','SetupCount*2'), ('Setup',':'), ) class SMBNTTransactionResponse_Parameters(SMBCommand_Parameters): structure = ( ('Reserved1','3s=""'), ('TotalParameterCount','<L'), ('TotalDataCount','<L'), ('ParameterCount','<L'), ('ParameterOffset','<L'), ('ParameterDisplacement','<L=0'), ('DataCount','<L'), ('DataOffset','<L'), ('DataDisplacement','<L=0'), ('SetupCount','<B=0'), ('SetupLength','_-Setup','SetupCount*2'), ('Setup',':'), ) class SMBNTTransaction_Data(Structure): structure = ( ('Pad1Length','_-Pad1','self["Pad1Length"]'), ('Pad1',':'), ('NT_Trans_ParametersLength','_-NT_Trans_Parameters','self["NT_Trans_ParametersLength"]'), ('NT_Trans_Parameters',':'), ('Pad2Length','_-Pad2','self["Pad2Length"]'), ('Pad2',':'), ('NT_Trans_DataLength','_-NT_Trans_Data','self["NT_Trans_DataLength"]'), ('NT_Trans_Data',':'), ) class SMBNTTransactionResponse_Data(Structure): structure = ( ('Pad1Length','_-Pad1','self["Pad1Length"]'), ('Pad1',':'), ('Trans_ParametersLength','_-Trans_Parameters','self["Trans_ParametersLength"]'), ('Trans_Parameters',':'), ('Pad2Length','_-Pad2','self["Pad2Length"]'), ('Pad2',':'), ('Trans_DataLength','_-Trans_Data','self["Trans_DataLength"]'), ('Trans_Data',':'), ) ############# SMB_COM_TRANSACTION2_SECONDARY (0x33) class SMBTransaction2Secondary_Parameters(SMBCommand_Parameters): structure = ( ('TotalParameterCount','<H'), ('TotalDataCount','<H'), ('ParameterCount','<H'), ('ParameterOffset','<H'), ('DataCount','<H'), ('DataOffset','<H'), ('DataDisplacement','<H=0'), ('FID','<H'), ) class SMBTransaction2Secondary_Data(Structure): structure = ( ('Pad1Length','_-Pad1','self["Pad1Length"]'), ('Pad1',':'), ('Trans_ParametersLength','_-Trans_Parameters','self["Trans_ParametersLength"]'), ('Trans_Parameters',':'), ('Pad2Length','_-Pad2','self["Pad2Length"]'), ('Pad2',':'), ('Trans_DataLength','_-Trans_Data','self["Trans_DataLength"]'), ('Trans_Data',':'), ) ############# SMB_COM_TRANSACTION2 (0x32) class SMBTransaction2_Parameters(SMBCommand_Parameters): structure = ( ('TotalParameterCount','<H'), ('TotalDataCount','<H'), ('MaxParameterCount','<H=1024'), ('MaxDataCount','<H=65504'), ('MaxSetupCount','<B=0'), ('Reserved1','<B=0'), ('Flags','<H=0'), ('Timeout','<L=0'), ('Reserved2','<H=0'), ('ParameterCount','<H'), ('ParameterOffset','<H'), ('DataCount','<H'), ('DataOffset','<H'), ('SetupCount','<B=len(Setup)/2'), ('Reserved3','<B=0'), ('SetupLength','_-Setup','SetupCount*2'), ('Setup',':'), ) class SMBTransaction2Response_Parameters(SMBCommand_Parameters): structure = ( ('TotalParameterCount','<H'), ('TotalDataCount','<H'), ('Reserved1','<H=0'), ('ParameterCount','<H'), ('ParameterOffset','<H'), ('ParameterDisplacement','<H=0'), ('DataCount','<H'), ('DataOffset','<H'), ('DataDisplacement','<H=0'), ('SetupCount','<B=0'), ('Reserved2','<B=0'), ('SetupLength','_-Setup','SetupCount*2'), ('Setup',':'), ) class SMBTransaction2_Data(Structure): structure = ( # ('NameLength','_-Name','1'), # ('Name',':'), ('Pad1Length','_-Pad1','self["Pad1Length"]'), ('Pad1',':'), ('Trans_ParametersLength','_-Trans_Parameters','self["Trans_ParametersLength"]'), ('Trans_Parameters',':'), ('Pad2Length','_-Pad2','self["Pad2Length"]'), ('Pad2',':'), ('Trans_DataLength','_-Trans_Data','self["Trans_DataLength"]'), ('Trans_Data',':'), ) class SMBTransaction2Response_Data(Structure): structure = ( ('Pad1Length','_-Pad1','self["Pad1Length"]'), ('Pad1',':'), ('Trans_ParametersLength','_-Trans_Parameters','self["Trans_ParametersLength"]'), ('Trans_Parameters',':'), ('Pad2Length','_-Pad2','self["Pad2Length"]'), ('Pad2',':'), ('Trans_DataLength','_-Trans_Data','self["Trans_DataLength"]'), ('Trans_Data',':'), ) ############# SMB_COM_QUERY_INFORMATION (0x08) class SMBQueryInformation_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('BufferFormat','B=4'), ('FileName','z'), ) UnicodeStructure = ( ('BufferFormat','B=4'), ('FileName','u'), ) class SMBQueryInformationResponse_Parameters(Structure): structure = ( ('FileAttributes','<H'), ('LastWriteTime','<L'), ('FileSize','<L'), ('Reserved','"0123456789'), ) ############# SMB_COM_TRANSACTION (0x25) class SMBTransaction_Parameters(SMBCommand_Parameters): structure = ( ('TotalParameterCount','<H'), ('TotalDataCount','<H'), ('MaxParameterCount','<H=1024'), ('MaxDataCount','<H=65504'), ('MaxSetupCount','<B=0'), ('Reserved1','<B=0'), ('Flags','<H=0'), ('Timeout','<L=0'), ('Reserved2','<H=0'), ('ParameterCount','<H'), ('ParameterOffset','<H'), ('DataCount','<H'), ('DataOffset','<H'), ('SetupCount','<B=len(Setup)/2'), ('Reserved3','<B=0'), ('SetupLength','_-Setup','SetupCount*2'), ('Setup',':'), ) class SMBTransactionResponse_Parameters(SMBCommand_Parameters): structure = ( ('TotalParameterCount','<H'), ('TotalDataCount','<H'), ('Reserved1','<H=0'), ('ParameterCount','<H'), ('ParameterOffset','<H'), ('ParameterDisplacement','<H=0'), ('DataCount','<H'), ('DataOffset','<H'), ('DataDisplacement','<H=0'), ('SetupCount','<B'), ('Reserved2','<B=0'), ('SetupLength','_-Setup','SetupCount*2'), ('Setup',':'), ) # TODO: We should merge these both. But this will require fixing # the instances where this structure is used on the client side class SMBTransaction_SData(AsciiOrUnicodeStructure): AsciiStructure = ( ('Name','z'), ('Trans_ParametersLength','_-Trans_Parameters'), ('Trans_Parameters',':'), ('Trans_DataLength','_-Trans_Data'), ('Trans_Data',':'), ) UnicodeStructure = ( ('Pad','B'), ('Name','u'), ('Trans_ParametersLength','_-Trans_Parameters'), ('Trans_Parameters',':'), ('Trans_DataLength','_-Trans_Data'), ('Trans_Data',':'), ) class SMBTransaction_Data(Structure): structure = ( ('NameLength','_-Name'), ('Name',':'), ('Trans_ParametersLength','_-Trans_Parameters'), ('Trans_Parameters',':'), ('Trans_DataLength','_-Trans_Data'), ('Trans_Data',':'), ) class SMBTransactionResponse_Data(Structure): structure = ( ('Trans_ParametersLength','_-Trans_Parameters'), ('Trans_Parameters',':'), ('Trans_DataLength','_-Trans_Data'), ('Trans_Data',':'), ) ############# SMB_COM_READ_ANDX (0x2E) class SMBReadAndX_Parameters(SMBAndXCommand_Parameters): structure = ( ('Fid','<H'), ('Offset','<L'), ('MaxCount','<H'), ('MinCount','<H=MaxCount'), ('_reserved','<L=0x0'), ('Remaining','<H=MaxCount'), ('HighOffset','<L=0'), ) class SMBReadAndX_Parameters2(SMBAndXCommand_Parameters): structure = ( ('Fid','<H'), ('Offset','<L'), ('MaxCount','<H'), ('MinCount','<H=MaxCount'), ('_reserved','<L=0xffffffff'), ('Remaining','<H=MaxCount'), ) class SMBReadAndXResponse_Parameters(SMBAndXCommand_Parameters): structure = ( ('Remaining','<H=0'), ('DataMode','<H=0'), ('_reserved','<H=0'), ('DataCount','<H'), ('DataOffset','<H'), ('DataCount_Hi','<L'), ('_reserved2','6s=""'), ) ############# SMB_COM_ECHO (0x2B) class SMBEcho_Data(Structure): structure = ( ('Data',':'), ) class SMBEcho_Parameters(Structure): structure = ( ('EchoCount','<H'), ) class SMBEchoResponse_Data(Structure): structure = ( ('Data',':'), ) class SMBEchoResponse_Parameters(Structure): structure = ( ('SequenceNumber','<H=1'), ) ############# SMB_COM_QUERY_INFORMATION_DISK (0x80) class SMBQueryInformationDiskResponse_Parameters(Structure): structure = ( ('TotalUnits','<H'), ('BlocksPerUnit','<H'), ('BlockSize','<H'), ('FreeUnits','<H'), ('Reserved','<H=0'), ) ############# SMB_COM_LOGOFF_ANDX (0x74) class SMBLogOffAndX(SMBAndXCommand_Parameters): strucure = () ############# SMB_COM_CLOSE (0x04) class SMBClose_Parameters(SMBCommand_Parameters): structure = ( ('FID','<H'), ('Time','<L=0'), ) ############# SMB_COM_FLUSH (0x05) class SMBFlush_Parameters(SMBCommand_Parameters): structure = ( ('FID','<H'), ) ############# SMB_COM_CREATE_DIRECTORY (0x00) class SMBCreateDirectory_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('BufferFormat','<B=4'), ('DirectoryName','z'), ) UnicodeStructure = ( ('BufferFormat','<B=4'), ('DirectoryName','u'), ) ############# SMB_COM_DELETE (0x06) class SMBDelete_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('BufferFormat','<B=4'), ('FileName','z'), ) UnicodeStructure = ( ('BufferFormat','<B=4'), ('FileName','u'), ) class SMBDelete_Parameters(Structure): structure = ( ('SearchAttributes','<H'), ) ############# SMB_COM_DELETE_DIRECTORY (0x01) class SMBDeleteDirectory_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('BufferFormat','<B=4'), ('DirectoryName','z'), ) UnicodeStructure = ( ('BufferFormat','<B=4'), ('DirectoryName','u'), ) ############# SMB_COM_CHECK_DIRECTORY (0x10) class SMBCheckDirectory_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('BufferFormat','<B=4'), ('DirectoryName','z'), ) UnicodeStructure = ( ('BufferFormat','<B=4'), ('DirectoryName','u'), ) ############# SMB_COM_RENAME (0x07) class SMBRename_Parameters(SMBCommand_Parameters): structure = ( ('SearchAttributes','<H'), ) class SMBRename_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('BufferFormat1','<B=4'), ('OldFileName','z'), ('BufferFormat2','<B=4'), ('NewFileName','z'), ) UnicodeStructure = ( ('BufferFormat1','<B=4'), ('OldFileName','u'), ('BufferFormat2','<B=4'), ('Pad','B=0'), ('NewFileName','u'), ) ############# SMB_COM_OPEN (0x02) class SMBOpen_Parameters(SMBCommand_Parameters): structure = ( ('DesiredAccess','<H=0'), ('SearchAttributes','<H=0'), ) class SMBOpen_Data(AsciiOrUnicodeStructure): AsciiStructure = ( ('FileNameFormat','"\x04'), ('FileName','z'), ) UnicodeStructure = ( ('FileNameFormat','"\x04'), ('FileName','z'), ) class SMBOpenResponse_Parameters(SMBCommand_Parameters): structure = ( ('Fid','<H=0'), ('FileAttributes','<H=0'), ('LastWriten','<L=0'), ('FileSize','<L=0'), ('GrantedAccess','<H=0'), ) ############# EXTENDED SECURITY CLASSES class SMBExtended_Security_Parameters(Structure): structure = ( ('DialectIndex','<H'), ('SecurityMode','<B'), ('MaxMpxCount','<H'), ('MaxNumberVcs','<H'), ('MaxBufferSize','<L'), ('MaxRawSize','<L'), ('SessionKey','<L'), ('Capabilities','<L'), ('LowDateTime','<L'), ('HighDateTime','<L'), ('ServerTimeZone','<H'), ('ChallengeLength','<B'), ) class SMBExtended_Security_Data(Structure): structure = ( ('ServerGUID','16s'), ('SecurityBlob',':'), ) class SMBNTLMDialect_Parameters(Structure): structure = ( ('DialectIndex','<H'), ('SecurityMode','<B'), ('MaxMpxCount','<H'), ('MaxNumberVcs','<H'), ('MaxBufferSize','<L'), ('MaxRawSize','<L'), ('SessionKey','<L'), ('Capabilities','<L'), ('LowDateTime','<L'), ('HighDateTime','<L'), ('ServerTimeZone','<H'), ('ChallengeLength','<B'), ) class SMBNTLMDialect_Data(Structure): structure = ( ('ChallengeLength','_-Challenge','self["ChallengeLength"]'), ('Challenge',':'), ('Payload',':'), # For some reason on an old Linux this field is not present, we have to check this out. There must be a flag stating this. ('DomainName','_'), ('ServerName','_'), ) def __init__(self,data = None, alignment = 0): Structure.__init__(self,data,alignment) #self['ChallengeLength']=8 def fromString(self,data): Structure.fromString(self,data) self['DomainName'] = '' self['ServerName'] = '' class SMB: # SMB Command Codes SMB_COM_CREATE_DIRECTORY = 0x00 SMB_COM_DELETE_DIRECTORY = 0x01 SMB_COM_OPEN = 0x02 SMB_COM_CREATE = 0x03 SMB_COM_CLOSE = 0x04 SMB_COM_FLUSH = 0x05 SMB_COM_DELETE = 0x06 SMB_COM_RENAME = 0x07 SMB_COM_QUERY_INFORMATION = 0x08 SMB_COM_SET_INFORMATION = 0x09 SMB_COM_READ = 0x0A SMB_COM_WRITE = 0x0B SMB_COM_LOCK_BYTE_RANGE = 0x0C SMB_COM_UNLOCK_BYTE_RANGE = 0x0D SMB_COM_CREATE_TEMPORARY = 0x0E SMB_COM_CREATE_NEW = 0x0F SMB_COM_CHECK_DIRECTORY = 0x10 SMB_COM_PROCESS_EXIT = 0x11 SMB_COM_SEEK = 0x12 SMB_COM_LOCK_AND_READ = 0x13 SMB_COM_WRITE_AND_UNLOCK = 0x14 SMB_COM_READ_RAW = 0x1A SMB_COM_READ_MPX = 0x1B SMB_COM_READ_MPX_SECONDARY = 0x1C SMB_COM_WRITE_RAW = 0x1D SMB_COM_WRITE_MPX = 0x1E SMB_COM_WRITE_MPX_SECONDARY = 0x1F SMB_COM_WRITE_COMPLETE = 0x20 SMB_COM_QUERY_SERVER = 0x21 SMB_COM_SET_INFORMATION2 = 0x22 SMB_COM_QUERY_INFORMATION2 = 0x23 SMB_COM_LOCKING_ANDX = 0x24 SMB_COM_TRANSACTION = 0x25 SMB_COM_TRANSACTION_SECONDARY = 0x26 SMB_COM_IOCTL = 0x27 SMB_COM_IOCTL_SECONDARY = 0x28 SMB_COM_COPY = 0x29 SMB_COM_MOVE = 0x2A SMB_COM_ECHO = 0x2B SMB_COM_WRITE_AND_CLOSE = 0x2C SMB_COM_OPEN_ANDX = 0x2D SMB_COM_READ_ANDX = 0x2E SMB_COM_WRITE_ANDX = 0x2F SMB_COM_NEW_FILE_SIZE = 0x30 SMB_COM_CLOSE_AND_TREE_DISC = 0x31 SMB_COM_TRANSACTION2 = 0x32 SMB_COM_TRANSACTION2_SECONDARY = 0x33 SMB_COM_FIND_CLOSE2 = 0x34 SMB_COM_FIND_NOTIFY_CLOSE = 0x35 # Used by Xenix/Unix 0x60 - 0x6E SMB_COM_TREE_CONNECT = 0x70 SMB_COM_TREE_DISCONNECT = 0x71 SMB_COM_NEGOTIATE = 0x72 SMB_COM_SESSION_SETUP_ANDX = 0x73 SMB_COM_LOGOFF_ANDX = 0x74 SMB_COM_TREE_CONNECT_ANDX = 0x75 SMB_COM_QUERY_INFORMATION_DISK = 0x80 SMB_COM_SEARCH = 0x81 SMB_COM_FIND = 0x82 SMB_COM_FIND_UNIQUE = 0x83 SMB_COM_FIND_CLOSE = 0x84 SMB_COM_NT_TRANSACT = 0xA0 SMB_COM_NT_TRANSACT_SECONDARY = 0xA1 SMB_COM_NT_CREATE_ANDX = 0xA2 SMB_COM_NT_CANCEL = 0xA4 SMB_COM_NT_RENAME = 0xA5 SMB_COM_OPEN_PRINT_FILE = 0xC0 SMB_COM_WRITE_PRINT_FILE = 0xC1 SMB_COM_CLOSE_PRINT_FILE = 0xC2 SMB_COM_GET_PRINT_QUEUE = 0xC3 SMB_COM_READ_BULK = 0xD8 SMB_COM_WRITE_BULK = 0xD9 SMB_COM_WRITE_BULK_DATA = 0xDA # TRANSACT codes TRANS_TRANSACT_NMPIPE = 0x26 # TRANSACT2 codes TRANS2_FIND_FIRST2 = 0x0001 TRANS2_FIND_NEXT2 = 0x0002 TRANS2_QUERY_FS_INFORMATION = 0x0003 TRANS2_QUERY_PATH_INFORMATION = 0x0005 TRANS2_QUERY_FILE_INFORMATION = 0x0007 TRANS2_SET_FILE_INFORMATION = 0x0008 TRANS2_SET_PATH_INFORMATION = 0x0006 # Security Share Mode (Used internally by SMB class) SECURITY_SHARE_MASK = 0x01 SECURITY_SHARE_SHARE = 0x00 SECURITY_SHARE_USER = 0x01 SECURITY_SIGNATURES_ENABLED = 0X04 SECURITY_SIGNATURES_REQUIRED = 0X08 # Security Auth Mode (Used internally by SMB class) SECURITY_AUTH_MASK = 0x02 SECURITY_AUTH_ENCRYPTED = 0x02 SECURITY_AUTH_PLAINTEXT = 0x00 # Raw Mode Mask (Used internally by SMB class. Good for dialect up to and including LANMAN2.1) RAW_READ_MASK = 0x01 RAW_WRITE_MASK = 0x02 # Capabilities Mask (Used internally by SMB class. Good for dialect NT LM 0.12) CAP_RAW_MODE = 0x00000001 CAP_MPX_MODE = 0x0002 CAP_UNICODE = 0x0004 CAP_LARGE_FILES = 0x0008 CAP_EXTENDED_SECURITY = 0x80000000 CAP_USE_NT_ERRORS = 0x40 CAP_NT_SMBS = 0x10 CAP_LARGE_READX = 0x00004000 CAP_LARGE_WRITEX = 0x00008000 CAP_RPC_REMOTE_APIS = 0x20 # Flags1 Mask FLAGS1_LOCK_AND_READ_OK = 0x01 FLAGS1_PATHCASELESS = 0x08 FLAGS1_CANONICALIZED_PATHS = 0x10 FLAGS1_REPLY = 0x80 # Flags2 Mask FLAGS2_LONG_NAMES = 0x0001 FLAGS2_EAS = 0x0002 FLAGS2_SMB_SECURITY_SIGNATURE = 0x0004 FLAGS2_IS_LONG_NAME = 0x0040 FLAGS2_DFS = 0x1000 FLAGS2_PAGING_IO = 0x2000 FLAGS2_NT_STATUS = 0x4000 FLAGS2_UNICODE = 0x8000 FLAGS2_COMPRESSED = 0x0008 FLAGS2_SMB_SECURITY_SIGNATURE_REQUIRED = 0x0010 FLAGS2_EXTENDED_SECURITY = 0x0800 # Dialect's Security Mode flags NEGOTIATE_USER_SECURITY = 0x01 NEGOTIATE_ENCRYPT_PASSWORDS = 0x02 NEGOTIATE_SECURITY_SIGNATURE_ENABLE = 0x04 NEGOTIATE_SECURITY_SIGNATURE_REQUIRED = 0x08 # Tree Connect AndX Response optionalSuppor flags SMB_SUPPORT_SEARCH_BITS = 0x01 SMB_SHARE_IS_IN_DFS = 0x02 def __init__(self, remote_name, remote_host, my_name = None, host_type = nmb.TYPE_SERVER, sess_port = 445, timeout=None, UDP = 0, session = None, negPacket = None): # The uid attribute will be set when the client calls the login() method self._uid = 0 self.__server_name = '' self.__server_os = '' self.__server_os_major = None self.__server_os_minor = None self.__server_os_build = None self.__server_lanman = '' self.__server_domain = '' self.__server_dns_domain_name = '' self.__remote_name = string.upper(remote_name) self.__remote_host = remote_host self.__isNTLMv2 = True self._dialects_parameters = None self._dialects_data = None # Credentials self.__userName = '' self.__password = '' self.__domain = '' self.__lmhash = '' self.__nthash = '' self.__aesKey = '' self.__kdc = '' self.__TGT = None self.__TGS = None # Negotiate Protocol Result, used everywhere # Could be extended or not, flags should be checked before self._dialect_data = 0 self._dialect_parameters = 0 self._action = 0 self._sess = None self.encrypt_passwords = True self.tid = 0 self.fid = 0 # Signing stuff self._SignSequenceNumber = 0 self._SigningSessionKey = '' self._SigningChallengeResponse = '' self._SignatureEnabled = False self._SignatureVerificationEnabled = False self._SignatureRequired = False # Base flags (default flags, can be overriden using set_flags()) self.__flags1 = SMB.FLAGS1_PATHCASELESS | SMB.FLAGS1_CANONICALIZED_PATHS self.__flags2 = SMB.FLAGS2_EXTENDED_SECURITY | SMB.FLAGS2_NT_STATUS | SMB.FLAGS2_LONG_NAMES if timeout is None: self.__timeout = 60 else: self.__timeout = timeout # If port 445 and the name sent is *SMBSERVER we're setting the name to the IP. # This is to help some old applications still believing # *SMSBSERVER will work against modern OSes. If port is NETBIOS_SESSION_PORT the user better # know about *SMBSERVER's limitations if sess_port == 445 and remote_name == '*SMBSERVER': self.__remote_name = remote_host if session is None: if not my_name: my_name = socket.gethostname() i = string.find(my_name, '.') if i > -1: my_name = my_name[:i] if UDP: self._sess = nmb.NetBIOSUDPSession(my_name, remote_name, remote_host, host_type, sess_port, self.__timeout) else: self._sess = nmb.NetBIOSTCPSession(my_name, remote_name, remote_host, host_type, sess_port, self.__timeout) # Initialize session values (_dialect_data and _dialect_parameters) self.neg_session() # Call login() without any authentication information to # setup a session if the remote server # is in share mode. if (self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SHARE_MASK) == SMB.SECURITY_SHARE_SHARE: self.login('', '') else: self._sess = session self.neg_session(negPacket = negPacket) # Call login() without any authentication information to # setup a session if the remote server # is in share mode. if (self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SHARE_MASK) == SMB.SECURITY_SHARE_SHARE: self.login('', '') @staticmethod def ntlm_supported(): return False def get_remote_name(self): return self.__remote_name def get_remote_host(self): return self.__remote_host def get_flags(self): return self.__flags1, self.__flags2 def set_flags(self, flags1=None, flags2=None): if flags1 is not None: self.__flags1 = flags1 if flags2 is not None: self.__flags2 = flags2 def set_timeout(self, timeout): prev_timeout = self.__timeout self.__timeout = timeout return prev_timeout def get_timeout(self): return self.__timeout @contextmanager def use_timeout(self, timeout): prev_timeout = self.set_timeout(timeout) try: yield finally: self.set_timeout(prev_timeout) def get_session(self): return self._sess def get_tid(self): return self.tid def get_fid(self): return self.fid def isGuestSession(self): return self._action & SMB_SETUP_GUEST def doesSupportNTLMv2(self): return self.__isNTLMv2 def __del__(self): if self._sess: self._sess.close() def recvSMB(self): r = self._sess.recv_packet(self.__timeout) return NewSMBPacket(data = r.get_trailer()) @staticmethod def __decode_trans(params, data): totparamcnt, totdatacnt, _, paramcnt, paramoffset, paramds, datacnt, dataoffset, datads, setupcnt = unpack('<HHHHHHHHHB', params[:19]) if paramcnt + paramds < totparamcnt or datacnt + datads < totdatacnt: has_more = 1 else: has_more = 0 paramoffset = paramoffset - 55 - setupcnt * 2 dataoffset = dataoffset - 55 - setupcnt * 2 return has_more, params[20:20 + setupcnt * 2], data[paramoffset:paramoffset + paramcnt], data[dataoffset:dataoffset + datacnt] # TODO: Move this to NewSMBPacket, it belongs there def signSMB(self, packet, signingSessionKey, signingChallengeResponse): # This logic MUST be applied for messages sent in response to any of the higher-layer actions and in # compliance with the message sequencing rules. # * The client or server that sends the message MUST provide the 32-bit sequence number for this # message, as specified in sections 3.2.4.1 and 3.3.4.1. # * The SMB_FLAGS2_SMB_SECURITY_SIGNATURE flag in the header MUST be set. # * To generate the signature, a 32-bit sequence number is copied into the # least significant 32 bits of the SecuritySignature field and the remaining # 4 bytes are set to 0x00. # * The MD5 algorithm, as specified in [RFC1321], MUST be used to generate a hash of the SMB # message from the start of the SMB Header, which is defined as follows. # CALL MD5Init( md5context ) # CALL MD5Update( md5context, Connection.SigningSessionKey ) # CALL MD5Update( md5context, Connection.SigningChallengeResponse ) # CALL MD5Update( md5context, SMB message ) # CALL MD5Final( digest, md5context ) # SET signature TO the first 8 bytes of the digest # The resulting 8-byte signature MUST be copied into the SecuritySignature field of the SMB Header, # after which the message can be transmitted. #print "seq(%d) signingSessionKey %r, signingChallengeResponse %r" % (self._SignSequenceNumber, signingSessionKey, signingChallengeResponse) packet['SecurityFeatures'] = pack('<q',self._SignSequenceNumber) # Sign with the sequence m = hashlib.md5() m.update( signingSessionKey ) m.update( signingChallengeResponse ) m.update( str(packet) ) # Replace sequence with acual hash packet['SecurityFeatures'] = m.digest()[:8] if self._SignatureVerificationEnabled: self._SignSequenceNumber +=1 else: self._SignSequenceNumber +=2 def checkSignSMB(self, packet, signingSessionKey, signingChallengeResponse): # Let's check signature = packet['SecurityFeatures'] #print "Signature received: %r " % signature self.signSMB(packet, signingSessionKey, signingChallengeResponse) #print "Signature calculated: %r" % packet['SecurityFeatures'] if self._SignatureVerificationEnabled is not True: self._SignSequenceNumber -= 1 return packet['SecurityFeatures'] == signature def sendSMB(self,smb): smb['Uid'] = self._uid #At least on AIX, PIDs can exceed 16 bits, so we mask them out smb['Pid'] = (os.getpid() & 0xFFFF) # set flags smb['Flags1'] |= self.__flags1 smb['Flags2'] |= self.__flags2 if self._SignatureEnabled: smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE self.signSMB(smb, self._SigningSessionKey, self._SigningChallengeResponse) self._sess.send_packet(str(smb)) @staticmethod def isValidAnswer(s, cmd): while 1: if s.rawData(): if s.get_command() == cmd: if s.get_error_class() == 0x00 and s.get_error_code() == 0x00: return 1 else: raise SessionError( "SMB Library Error", s.get_error_class()+ (s.get_reserved() << 8), s.get_error_code() , s.get_flags2() & SMB.FLAGS2_NT_STATUS) else: break return 0 def neg_session(self, extended_security = True, negPacket = None): def parsePacket(smb): if smb.isValidAnswer(SMB.SMB_COM_NEGOTIATE): sessionResponse = SMBCommand(smb['Data'][0]) self._dialects_parameters = SMBNTLMDialect_Parameters(sessionResponse['Parameters']) self._dialects_data = SMBNTLMDialect_Data() self._dialects_data['ChallengeLength'] = self._dialects_parameters['ChallengeLength'] self._dialects_data.fromString(sessionResponse['Data']) if self._dialects_parameters['Capabilities'] & SMB.CAP_EXTENDED_SECURITY: # Whether we choose it or it is enforced by the server, we go for extended security self._dialects_parameters = SMBExtended_Security_Parameters(sessionResponse['Parameters']) self._dialects_data = SMBExtended_Security_Data(sessionResponse['Data']) # Let's setup some variable for later use if self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SIGNATURES_REQUIRED: self._SignatureRequired = True # Interestingly, the security Blob might be missing sometimes. #spnego = SPNEGO_NegTokenInit(self._dialects_data['SecurityBlob']) #for i in spnego['MechTypes']: # print "Mech Found: %s" % MechTypes[i] return 1 # If not, let's try the old way else: if self._dialects_data['ServerName'] is not None: self.__server_name = self._dialects_data['ServerName'] if self._dialects_parameters['DialectIndex'] == 0xffff: raise UnsupportedFeature("Remote server does not know NT LM 0.12") return 1 else: return 0 if negPacket is None: smb = NewSMBPacket() negSession = SMBCommand(SMB.SMB_COM_NEGOTIATE) flags2 = self.get_flags()[1] if extended_security is True: self.set_flags(flags2=flags2|SMB.FLAGS2_EXTENDED_SECURITY) else: self.set_flags(flags2=flags2 & (~SMB.FLAGS2_EXTENDED_SECURITY)) negSession['Data'] = '\x02NT LM 0.12\x00' smb.addCommand(negSession) self.sendSMB(smb) while 1: smb = self.recvSMB() return parsePacket(smb) else: return parsePacket( NewSMBPacket( data = negPacket)) def tree_connect(self, path, password = '', service = SERVICE_ANY): LOG.warning("[MS-CIFS] This is an original Core Protocol command.This command has been deprecated.Client Implementations SHOULD use SMB_COM_TREE_CONNECT_ANDX") # return 0x800 if password: # Password is only encrypted if the server passed us an "encryption" during protocol dialect if self._dialects_parameters['ChallengeLength'] > 0: # this code is untested password = self.get_ntlmv1_response(ntlm.compute_lmhash(password)) if not unicode_support: if unicode_convert: path = str(path) else: raise Exception('SMB: Can\t conver path from unicode!') smb = NewSMBPacket() treeConnect = SMBCommand(SMB.SMB_COM_TREE_CONNECT) treeConnect['Parameters'] = SMBTreeConnect_Parameters() treeConnect['Data'] = SMBTreeConnect_Data() treeConnect['Data']['Path'] = path.upper() treeConnect['Data']['Password'] = password treeConnect['Data']['Service'] = service smb.addCommand(treeConnect) self.sendSMB(smb) while 1: smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_TREE_CONNECT): # XXX Here we are ignoring the rest of the response return smb['Tid'] return smb['Tid'] def get_uid(self): return self._uid def set_uid(self, uid): self._uid = uid def tree_connect_andx(self, path, password = None, service = SERVICE_ANY, smb_packet=None): if password: # Password is only encrypted if the server passed us an "encryption" during protocol dialect if self._dialects_parameters['ChallengeLength'] > 0: # this code is untested password = self.get_ntlmv1_response(ntlm.compute_lmhash(password)) else: password = '\x00' if not unicode_support: if unicode_convert: path = str(path) else: raise Exception('SMB: Can\t convert path from unicode!') if smb_packet is None: smb = NewSMBPacket() else: smb = smb_packet # Just in case this came with the full path ,let's just leave # the sharename, we'll take care of the rest share = path.split('\\')[-1] try: _, _, _, _, sockaddr = socket.getaddrinfo(self.get_remote_host(), 80, 0, 0, socket.IPPROTO_TCP)[0] remote_host = sockaddr[0] except Exception: remote_host = self.get_remote_host() path = '\\\\' + remote_host + '\\' +share path = path.upper().encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path treeConnect = SMBCommand(SMB.SMB_COM_TREE_CONNECT_ANDX) treeConnect['Parameters'] = SMBTreeConnectAndX_Parameters() treeConnect['Data'] = SMBTreeConnectAndX_Data(flags=self.__flags2) treeConnect['Parameters']['PasswordLength'] = len(password) treeConnect['Data']['Password'] = password treeConnect['Data']['Path'] = path treeConnect['Data']['Service'] = service if self.__flags2 & SMB.FLAGS2_UNICODE: treeConnect['Data']['Pad'] = 0x0 smb.addCommand(treeConnect) # filename = "\PIPE\epmapper" # ntCreate = SMBCommand(SMB.SMB_COM_NT_CREATE_ANDX) # ntCreate['Parameters'] = SMBNtCreateAndX_Parameters() # ntCreate['Data'] = SMBNtCreateAndX_Data() # ntCreate['Parameters']['FileNameLength'] = len(filename) # ntCreate['Parameters']['CreateFlags'] = 0 # ntCreate['Parameters']['AccessMask'] = 0x3 # ntCreate['Parameters']['CreateOptions'] = 0x0 # ntCreate['Data']['FileName'] = filename # smb.addCommand(ntCreate) self.sendSMB(smb) while 1: smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_TREE_CONNECT_ANDX): # XXX Here we are ignoring the rest of the response self.tid = smb['Tid'] return self.tid self.tid = smb['Tid'] return self.tid # backwars compatibility connect_tree = tree_connect_andx @staticmethod def getDialect(): return SMB_DIALECT def get_server_name(self): #return self._dialects_data['ServerName'] return self.__server_name def get_session_key(self): return self._SigningSessionKey def set_session_key(self, key): self._SigningSessionKey = key def get_encryption_key(self): if 'Challenge' in self._dialects_data.fields: return self._dialects_data['Challenge'] else: return None def get_server_time(self): timestamp = self._dialects_parameters['HighDateTime'] timestamp <<= 32 timestamp |= self._dialects_parameters['LowDateTime'] timestamp -= 116444736000000000 timestamp /= 10000000 d = datetime.datetime.utcfromtimestamp(timestamp) return d.strftime("%a, %d %b %Y %H:%M:%S GMT") def disconnect_tree(self, tid): smb = NewSMBPacket() smb['Tid'] = tid smb.addCommand(SMBCommand(SMB.SMB_COM_TREE_DISCONNECT)) self.sendSMB(smb) self.recvSMB() def open(self, tid, filename, open_mode, desired_access): filename = string.replace(filename,'/', '\\') filename = filename.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else filename smb = NewSMBPacket() smb['Tid'] = tid openFile = SMBCommand(SMB.SMB_COM_OPEN) openFile['Parameters'] = SMBOpen_Parameters() openFile['Parameters']['DesiredAccess'] = desired_access openFile['Parameters']['OpenMode'] = open_mode openFile['Parameters']['SearchAttributes'] = ATTR_READONLY | ATTR_HIDDEN | ATTR_ARCHIVE openFile['Data'] = SMBOpen_Data(flags=self.__flags2) openFile['Data']['FileName'] = filename if self.__flags2 & SMB.FLAGS2_UNICODE: openFile['Data']['Pad'] = 0x0 smb.addCommand(openFile) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_OPEN): # XXX Here we are ignoring the rest of the response openFileResponse = SMBCommand(smb['Data'][0]) openFileParameters = SMBOpenResponse_Parameters(openFileResponse['Parameters']) return ( openFileParameters['Fid'], openFileParameters['FileAttributes'], openFileParameters['LastWriten'], openFileParameters['FileSize'], openFileParameters['GrantedAccess'], ) def open_andx(self, tid, filename, open_mode, desired_access): filename = string.replace(filename,'/', '\\') filename = filename.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else filename smb = NewSMBPacket() smb['Tid'] = tid openFile = SMBCommand(SMB.SMB_COM_OPEN_ANDX) openFile['Parameters'] = SMBOpenAndX_Parameters() openFile['Parameters']['DesiredAccess'] = desired_access openFile['Parameters']['OpenMode'] = open_mode openFile['Parameters']['SearchAttributes'] = ATTR_READONLY | ATTR_HIDDEN | ATTR_ARCHIVE openFile['Data'] = SMBOpenAndX_Data(flags=self.__flags2) openFile['Data']['FileName'] = filename if self.__flags2 & SMB.FLAGS2_UNICODE: openFile['Data']['Pad'] = 0x0 smb.addCommand(openFile) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_OPEN_ANDX): # XXX Here we are ignoring the rest of the response openFileResponse = SMBCommand(smb['Data'][0]) openFileParameters = SMBOpenAndXResponse_Parameters(openFileResponse['Parameters']) return ( openFileParameters['Fid'], openFileParameters['FileAttributes'], openFileParameters['LastWriten'], openFileParameters['FileSize'], openFileParameters['GrantedAccess'], openFileParameters['FileType'], openFileParameters['IPCState'], openFileParameters['Action'], openFileParameters['ServerFid'], ) def close(self, tid, fid): smb = NewSMBPacket() smb['Tid'] = tid closeFile = SMBCommand(SMB.SMB_COM_CLOSE) closeFile['Parameters'] = SMBClose_Parameters() closeFile['Parameters']['FID'] = fid smb.addCommand(closeFile) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_CLOSE): return 1 return 0 def send_trans(self, tid, setup, name, param, data, noAnswer = 0): smb = NewSMBPacket() smb['Tid'] = tid transCommand = SMBCommand(SMB.SMB_COM_TRANSACTION) transCommand['Parameters'] = SMBTransaction_Parameters() transCommand['Data'] = SMBTransaction_Data() transCommand['Parameters']['Setup'] = setup transCommand['Parameters']['TotalParameterCount'] = len(param) transCommand['Parameters']['TotalDataCount'] = len(data) transCommand['Parameters']['ParameterCount'] = len(param) transCommand['Parameters']['ParameterOffset'] = 32+3+28+len(setup)+len(name) transCommand['Parameters']['DataCount'] = len(data) transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) transCommand['Data']['Name'] = name transCommand['Data']['Trans_Parameters'] = param transCommand['Data']['Trans_Data'] = data if noAnswer: transCommand['Parameters']['Flags'] = TRANS_NO_RESPONSE smb.addCommand(transCommand) self.sendSMB(smb) def send_trans2(self, tid, setup, name, param, data): smb = NewSMBPacket() smb['Tid'] = tid command = pack('<H', setup) transCommand = SMBCommand(SMB.SMB_COM_TRANSACTION2) transCommand['Parameters'] = SMBTransaction2_Parameters() transCommand['Parameters']['MaxDataCount'] = self._dialects_parameters['MaxBufferSize'] transCommand['Data'] = SMBTransaction2_Data() transCommand['Parameters']['Setup'] = command transCommand['Parameters']['TotalParameterCount'] = len(param) transCommand['Parameters']['TotalDataCount'] = len(data) if len(param) > 0: padLen = (4 - (32+2+28 + len(command)) % 4 ) % 4 padBytes = '\xFF' * padLen transCommand['Data']['Pad1'] = padBytes else: transCommand['Data']['Pad1'] = '' padLen = 0 transCommand['Parameters']['ParameterCount'] = len(param) transCommand['Parameters']['ParameterOffset'] = 32+2+28+len(command)+len(name) + padLen if len(data) > 0: pad2Len = (4 - (32+2+28 + len(command) + padLen + len(param)) % 4) % 4 transCommand['Data']['Pad2'] = '\xFF' * pad2Len else: transCommand['Data']['Pad2'] = '' pad2Len = 0 transCommand['Parameters']['DataCount'] = len(data) transCommand['Parameters']['DataOffset'] = transCommand['Parameters']['ParameterOffset'] + len(param) + pad2Len transCommand['Data']['Name'] = name transCommand['Data']['Trans_Parameters'] = param transCommand['Data']['Trans_Data'] = data smb.addCommand(transCommand) self.sendSMB(smb) def query_file_info(self, tid, fid, fileInfoClass = SMB_QUERY_FILE_STANDARD_INFO): self.send_trans2(tid, SMB.TRANS2_QUERY_FILE_INFORMATION, '\x00', pack('<HH', fid, fileInfoClass), '') resp = self.recvSMB() if resp.isValidAnswer(SMB.SMB_COM_TRANSACTION2): trans2Response = SMBCommand(resp['Data'][0]) trans2Parameters = SMBTransaction2Response_Parameters(trans2Response['Parameters']) # Remove Potential Prefix Padding return trans2Response['Data'][-trans2Parameters['TotalDataCount']:] def __nonraw_retr_file(self, tid, fid, offset, datasize, callback): if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_READX) and self._SignatureEnabled is False: max_buf_size = 65000 else: max_buf_size = self._dialects_parameters['MaxBufferSize'] & ~0x3ff # Read in multiple KB blocks read_offset = offset while read_offset < datasize: data = self.read_andx(tid, fid, read_offset, max_buf_size) callback(data) read_offset += len(data) def __nonraw_stor_file(self, tid, fid, offset, datasize, callback): if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_WRITEX) and self._SignatureEnabled is False: max_buf_size = 65000 else: max_buf_size = self._dialects_parameters['MaxBufferSize'] & ~0x3ff # Write in multiple KB blocks write_offset = offset while 1: data = callback(max_buf_size) if not data: break smb = self.write_andx(tid,fid,data, write_offset) writeResponse = SMBCommand(smb['Data'][0]) writeResponseParameters = SMBWriteAndXResponse_Parameters(writeResponse['Parameters']) write_offset += writeResponseParameters['Count'] def get_server_domain(self): return self.__server_domain def get_server_dns_domain_name(self): return self.__server_dns_domain_name def get_server_os(self): return self.__server_os def get_server_os_major(self): return self.__server_os_major def get_server_os_minor(self): return self.__server_os_minor def get_server_os_build(self): return self.__server_os_build def set_server_os(self, os): self.__server_os = os def get_server_lanman(self): return self.__server_lanman def is_login_required(self): # Login is required if share mode is user. # Otherwise only public services or services in share mode # are allowed. return (self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SHARE_MASK) == SMB.SECURITY_SHARE_USER def is_signing_required(self): return self._SignatureRequired def get_ntlmv1_response(self, key): challenge = self._dialects_data['Challenge'] return ntlm.get_ntlmv1_response(key, challenge) def kerberos_login(self, user, password, domain = '', lmhash = '', nthash = '', aesKey = '', kdcHost = '', TGT=None, TGS=None): # Importing down here so pyasn1 is not required if kerberos is not used. from impacket.krb5.asn1 import AP_REQ, Authenticator, TGS_REP, seq_set from impacket.krb5.kerberosv5 import getKerberosTGT, getKerberosTGS from impacket.krb5 import constants from impacket.krb5.types import Principal, KerberosTime, Ticket from pyasn1.codec.der import decoder, encoder import datetime # login feature does not support unicode # disable it if enabled flags2 = self.__flags2 if flags2 & SMB.FLAGS2_UNICODE: self.__flags2 = flags2 & (flags2 ^ SMB.FLAGS2_UNICODE) # If TGT or TGS are specified, they are in the form of: # TGS['KDC_REP'] = the response from the server # TGS['cipher'] = the cipher used # TGS['sessionKey'] = the sessionKey # If we have hashes, normalize them if lmhash != '' or nthash != '': if len(lmhash) % 2: lmhash = '0%s' % lmhash if len(nthash) % 2: nthash = '0%s' % nthash try: # just in case they were converted already lmhash = a2b_hex(lmhash) nthash = a2b_hex(nthash) except: pass self.__userName = user self.__password = password self.__domain = domain self.__lmhash = lmhash self.__nthash = nthash self.__aesKey = aesKey self.__kdc = kdcHost self.__TGT = TGT self.__TGS = TGS # First of all, we need to get a TGT for the user userName = Principal(user, type=constants.PrincipalNameType.NT_PRINCIPAL.value) if TGT is None: if TGS is None: tgt, cipher, oldSessionKey, sessionKey = getKerberosTGT(userName, password, domain, lmhash, nthash, aesKey, kdcHost) else: tgt = TGT['KDC_REP'] cipher = TGT['cipher'] sessionKey = TGT['sessionKey'] # Now that we have the TGT, we should ask for a TGS for cifs if TGS is None: serverName = Principal('cifs/%s' % self.__remote_name, type=constants.PrincipalNameType.NT_SRV_INST.value) tgs, cipher, oldSessionKey, sessionKey = getKerberosTGS(serverName, domain, kdcHost, tgt, cipher, sessionKey) else: tgs = TGS['KDC_REP'] cipher = TGS['cipher'] sessionKey = TGS['sessionKey'] smb = NewSMBPacket() # Are we required to sign SMB? If so we do it, if not we skip it if self._SignatureRequired: smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 61440 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE | SMB.CAP_LARGE_READX | SMB.CAP_LARGE_WRITEX # Let's build a NegTokenInit with the NTLMSSP # TODO: In the future we should be able to choose different providers blob = SPNEGO_NegTokenInit() # Kerberos v5 mech blob['MechTypes'] = [TypesMech['MS KRB5 - Microsoft Kerberos 5']] # Let's extract the ticket from the TGS tgs = decoder.decode(tgs, asn1Spec = TGS_REP())[0] ticket = Ticket() ticket.from_asn1(tgs['ticket']) # Now let's build the AP_REQ apReq = AP_REQ() apReq['pvno'] = 5 apReq['msg-type'] = int(constants.ApplicationTagNumbers.AP_REQ.value) opts = list() apReq['ap-options'] = constants.encodeFlags(opts) seq_set(apReq,'ticket', ticket.to_asn1) authenticator = Authenticator() authenticator['authenticator-vno'] = 5 authenticator['crealm'] = domain seq_set(authenticator, 'cname', userName.components_to_asn1) now = datetime.datetime.utcnow() authenticator['cusec'] = now.microsecond authenticator['ctime'] = KerberosTime.to_asn1(now) encodedAuthenticator = encoder.encode(authenticator) # Key Usage 11 # AP-REQ Authenticator (includes application authenticator # subkey), encrypted with the application session key # (Section 5.5.1) encryptedEncodedAuthenticator = cipher.encrypt(sessionKey, 11, encodedAuthenticator, None) apReq['authenticator'] = None apReq['authenticator']['etype'] = cipher.enctype apReq['authenticator']['cipher'] = encryptedEncodedAuthenticator blob['MechToken'] = encoder.encode(apReq) sessionSetup['Parameters']['SecurityBlobLength'] = len(blob) sessionSetup['Parameters'].getData() sessionSetup['Data']['SecurityBlob'] = blob.getData() # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX): # We will need to use this uid field for all future requests/responses self._uid = smb['Uid'] # Now we have to extract the blob to continue the auth process sessionResponse = SMBCommand(smb['Data'][0]) sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters(sessionResponse['Parameters']) sessionData = SMBSessionSetupAndX_Extended_Response_Data(flags = smb['Flags2']) sessionData['SecurityBlobLength'] = sessionParameters['SecurityBlobLength'] sessionData.fromString(sessionResponse['Data']) self._action = sessionParameters['Action'] # If smb sign required, let's enable it for the rest of the connection if self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SIGNATURES_REQUIRED: self._SigningSessionKey = sessionKey.contents self._SignSequenceNumber = 2 self._SignatureEnabled = True # restore unicode flag if needed if flags2 & SMB.FLAGS2_UNICODE: self.__flags2 |= SMB.FLAGS2_UNICODE return 1 else: raise Exception('Error: Could not login successfully') def login_extended(self, user, password, domain = '', lmhash = '', nthash = '', use_ntlmv2 = True ): # login feature does not support unicode # disable it if enabled flags2 = self.__flags2 if flags2 & SMB.FLAGS2_UNICODE: self.__flags2 = flags2 & (flags2 ^ SMB.FLAGS2_UNICODE) # Once everything's working we should join login methods into a single one smb = NewSMBPacket() # Are we required to sign SMB? If so we do it, if not we skip it if self._SignatureRequired: smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Extended_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Extended_Data() sessionSetup['Parameters']['MaxBufferSize'] = 61440 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VcNumber'] = 1 sessionSetup['Parameters']['SessionKey'] = 0 sessionSetup['Parameters']['Capabilities'] = SMB.CAP_EXTENDED_SECURITY | SMB.CAP_USE_NT_ERRORS | SMB.CAP_UNICODE | SMB.CAP_LARGE_READX | SMB.CAP_LARGE_WRITEX # Let's build a NegTokenInit with the NTLMSSP # TODO: In the future we should be able to choose different providers blob = SPNEGO_NegTokenInit() # NTLMSSP blob['MechTypes'] = [TypesMech['NTLMSSP - Microsoft NTLM Security Support Provider']] auth = ntlm.getNTLMSSPType1('','',self._SignatureRequired, use_ntlmv2 = use_ntlmv2) blob['MechToken'] = str(auth) sessionSetup['Parameters']['SecurityBlobLength'] = len(blob) sessionSetup['Parameters'].getData() sessionSetup['Data']['SecurityBlob'] = blob.getData() # Fake Data here, don't want to get us fingerprinted sessionSetup['Data']['NativeOS'] = 'Unix' sessionSetup['Data']['NativeLanMan'] = 'Samba' smb.addCommand(sessionSetup) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX): # We will need to use this uid field for all future requests/responses self._uid = smb['Uid'] # Now we have to extract the blob to continue the auth process sessionResponse = SMBCommand(smb['Data'][0]) sessionParameters = SMBSessionSetupAndX_Extended_Response_Parameters(sessionResponse['Parameters']) sessionData = SMBSessionSetupAndX_Extended_Response_Data(flags = smb['Flags2']) sessionData['SecurityBlobLength'] = sessionParameters['SecurityBlobLength'] sessionData.fromString(sessionResponse['Data']) respToken = SPNEGO_NegTokenResp(sessionData['SecurityBlob']) # Let's parse some data and keep it to ourselves in case it is asked ntlmChallenge = ntlm.NTLMAuthChallenge(respToken['ResponseToken']) if ntlmChallenge['TargetInfoFields_len'] > 0: av_pairs = ntlm.AV_PAIRS(ntlmChallenge['TargetInfoFields'][:ntlmChallenge['TargetInfoFields_len']]) if av_pairs[ntlm.NTLMSSP_AV_HOSTNAME] is not None: try: self.__server_name = av_pairs[ntlm.NTLMSSP_AV_HOSTNAME][1].decode('utf-16le') except: # For some reason, we couldn't decode Unicode here.. silently discard the operation pass if av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME] is not None: try: if self.__server_name != av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME][1].decode('utf-16le'): self.__server_domain = av_pairs[ntlm.NTLMSSP_AV_DOMAINNAME][1].decode('utf-16le') except: # For some reason, we couldn't decode Unicode here.. silently discard the operation pass if av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME] is not None: try: self.__server_dns_domain_name = av_pairs[ntlm.NTLMSSP_AV_DNS_DOMAINNAME][1].decode('utf-16le') except: # For some reason, we couldn't decode Unicode here.. silently discard the operation pass # Parse Version to know the target Operating system name. Not provided elsewhere anymore if 'Version' in ntlmChallenge.fields: version = ntlmChallenge['Version'] if len(version) >= 4: self.__server_os_major, self.__server_os_minor, self.__server_os_build = unpack('<BBH',version[:4]) type3, exportedSessionKey = ntlm.getNTLMSSPType3(auth, respToken['ResponseToken'], user, password, domain, lmhash, nthash, use_ntlmv2 = use_ntlmv2) if exportedSessionKey is not None: self._SigningSessionKey = exportedSessionKey smb = NewSMBPacket() # Are we required to sign SMB? If so we do it, if not we skip it if self._SignatureRequired: smb['Flags2'] |= SMB.FLAGS2_SMB_SECURITY_SIGNATURE respToken2 = SPNEGO_NegTokenResp() respToken2['ResponseToken'] = str(type3) # Reusing the previous structure sessionSetup['Parameters']['SecurityBlobLength'] = len(respToken2) sessionSetup['Data']['SecurityBlob'] = respToken2.getData() # Storing some info for later use self.__server_os = sessionData['NativeOS'] self.__server_lanman = sessionData['NativeLanMan'] smb.addCommand(sessionSetup) self.sendSMB(smb) smb = self.recvSMB() self._uid = 0 if smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX): self._uid = smb['Uid'] sessionResponse = SMBCommand(smb['Data'][0]) sessionParameters = SMBSessionSetupAndXResponse_Parameters(sessionResponse['Parameters']) self._action = sessionParameters['Action'] # If smb sign required, let's enable it for the rest of the connection if self._dialects_parameters['SecurityMode'] & SMB.SECURITY_SIGNATURES_REQUIRED: self._SignSequenceNumber = 2 self._SignatureEnabled = True # restore unicode flag if needed if flags2 & SMB.FLAGS2_UNICODE: self.__flags2 |= SMB.FLAGS2_UNICODE return 1 else: raise Exception('Error: Could not login successfully') def getCredentials(self): return ( self.__userName, self.__password, self.__domain, self.__lmhash, self.__nthash, self.__aesKey, self.__TGT, self.__TGS) def getIOCapabilities(self): res = dict() if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_READX) and self._SignatureEnabled is False: max_size = 65000 else: max_size = self._dialects_parameters['MaxBufferSize'] # Read in multiple KB blocks res['MaxReadSize'] = max_size res['MaxWriteSize'] = max_size return res def login(self, user, password, domain = '', lmhash = '', nthash = '', ntlm_fallback = True): # If we have hashes, normalize them if lmhash != '' or nthash != '': if len(lmhash) % 2: lmhash = '0%s' % lmhash if len(nthash) % 2: nthash = '0%s' % nthash try: # just in case they were converted already lmhash = a2b_hex(lmhash) nthash = a2b_hex(nthash) except: pass self.__userName = user self.__password = password self.__domain = domain self.__lmhash = lmhash self.__nthash = nthash self.__aesKey = '' self.__TGT = None self.__TGS = None if self._dialects_parameters['Capabilities'] & SMB.CAP_EXTENDED_SECURITY: try: self.login_extended(user, password, domain, lmhash, nthash, use_ntlmv2 = True) except: # If the target OS is Windows 5.0 or Samba, let's try using NTLMv1 if ntlm_fallback and ((self.get_server_lanman().find('Windows 2000') != -1) or (self.get_server_lanman().find('Samba') != -1)): self.login_extended(user, password, domain, lmhash, nthash, use_ntlmv2 = False) self.__isNTLMv2 = False else: raise elif ntlm_fallback: self.login_standard(user, password, domain, lmhash, nthash) self.__isNTLMv2 = False else: raise SessionError('Cannot authenticate against target, enable ntlm_fallback') def login_standard(self, user, password, domain = '', lmhash = '', nthash = ''): # login feature does not support unicode # disable it if enabled flags2 = self.__flags2 if flags2 & SMB.FLAGS2_UNICODE: self.__flags2 = flags2 & (flags2 ^ SMB.FLAGS2_UNICODE) # Only supports NTLMv1 # Password is only encrypted if the server passed us an "encryption key" during protocol dialect negotiation if self._dialects_parameters['ChallengeLength'] > 0: if lmhash != '' or nthash != '': pwd_ansi = self.get_ntlmv1_response(lmhash) pwd_unicode = self.get_ntlmv1_response(nthash) elif password: lmhash = ntlm.compute_lmhash(password) nthash = ntlm.compute_nthash(password) pwd_ansi = self.get_ntlmv1_response(lmhash) pwd_unicode = self.get_ntlmv1_response(nthash) else: # NULL SESSION pwd_ansi = '' pwd_unicode = '' else: pwd_ansi = password pwd_unicode = '' smb = NewSMBPacket() sessionSetup = SMBCommand(SMB.SMB_COM_SESSION_SETUP_ANDX) sessionSetup['Parameters'] = SMBSessionSetupAndX_Parameters() sessionSetup['Data'] = SMBSessionSetupAndX_Data() sessionSetup['Parameters']['MaxBuffer'] = 61440 sessionSetup['Parameters']['MaxMpxCount'] = 2 sessionSetup['Parameters']['VCNumber'] = os.getpid() sessionSetup['Parameters']['SessionKey'] = self._dialects_parameters['SessionKey'] sessionSetup['Parameters']['AnsiPwdLength'] = len(pwd_ansi) sessionSetup['Parameters']['UnicodePwdLength'] = len(pwd_unicode) sessionSetup['Parameters']['Capabilities'] = SMB.CAP_RAW_MODE | SMB.CAP_USE_NT_ERRORS | SMB.CAP_LARGE_READX | SMB.CAP_LARGE_WRITEX sessionSetup['Data']['AnsiPwd'] = pwd_ansi sessionSetup['Data']['UnicodePwd'] = pwd_unicode sessionSetup['Data']['Account'] = str(user) sessionSetup['Data']['PrimaryDomain'] = str(domain) sessionSetup['Data']['NativeOS'] = str(os.name) sessionSetup['Data']['NativeLanMan'] = 'pysmb' smb.addCommand(sessionSetup) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_SESSION_SETUP_ANDX): # We will need to use this uid field for all future requests/responses self._uid = smb['Uid'] sessionResponse = SMBCommand(smb['Data'][0]) sessionParameters = SMBSessionSetupAndXResponse_Parameters(sessionResponse['Parameters']) sessionData = SMBSessionSetupAndXResponse_Data(flags = smb['Flags2'], data = sessionResponse['Data']) self._action = sessionParameters['Action'] # Still gotta figure out how to do this with no EXTENDED_SECURITY if sessionParameters['Action'] & SMB_SETUP_USE_LANMAN_KEY == 0: self._SigningChallengeResponse = sessionSetup['Data']['UnicodePwd'] self._SigningSessionKey = nthash else: self._SigningChallengeResponse = sessionSetup['Data']['AnsiPwd'] self._SigningSessionKey = lmhash #self._SignSequenceNumber = 1 #self.checkSignSMB(smb, self._SigningSessionKey ,self._SigningChallengeResponse) #self._SignatureEnabled = True self.__server_os = sessionData['NativeOS'] self.__server_lanman = sessionData['NativeLanMan'] self.__server_domain = sessionData['PrimaryDomain'] # restore unicode flag if needed if flags2 & SMB.FLAGS2_UNICODE: self.__flags2 |= SMB.FLAGS2_UNICODE return 1 else: raise Exception('Error: Could not login successfully') def waitNamedPipe(self, tid, pipe, timeout = 5, noAnswer = 0): smb = NewSMBPacket() smb['Tid'] = tid transCommand = SMBCommand(SMB.SMB_COM_TRANSACTION) transCommand['Parameters'] = SMBTransaction_Parameters() transCommand['Data'] = SMBTransaction_Data() setup = '\x53\x00\x00\x00' name = '\\PIPE%s\x00' % pipe transCommand['Parameters']['Setup'] = setup transCommand['Parameters']['TotalParameterCount'] = 0 transCommand['Parameters']['TotalDataCount'] = 0 transCommand['Parameters']['MaxParameterCount'] = 0 transCommand['Parameters']['MaxDataCount'] = 0 transCommand['Parameters']['Timeout'] = timeout * 1000 transCommand['Parameters']['ParameterCount'] = 0 transCommand['Parameters']['ParameterOffset'] = 32+3+28+len(setup)+len(name) transCommand['Parameters']['DataCount'] = 0 transCommand['Parameters']['DataOffset'] = 0 transCommand['Data']['Name'] = name transCommand['Data']['Trans_Parameters'] = '' transCommand['Data']['Trans_Data'] = '' if noAnswer: transCommand['Parameters']['Flags'] = TRANS_NO_RESPONSE smb.addCommand(transCommand) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_TRANSACTION): return 1 return 0 def read(self, tid, fid, offset=0, max_size = None, wait_answer=1): if not max_size: max_size = self._dialects_parameters['MaxBufferSize'] # Read in multiple KB blocks # max_size is not working, because although it would, the server returns an error (More data avail) smb = NewSMBPacket() smb['Tid'] = tid read = SMBCommand(SMB.SMB_COM_READ) read['Parameters'] = SMBRead_Parameters() read['Parameters']['Fid'] = fid read['Parameters']['Offset'] = offset read['Parameters']['Count'] = max_size smb.addCommand(read) if wait_answer: while 1: self.sendSMB(smb) ans = self.recvSMB() if ans.isValidAnswer(SMB.SMB_COM_READ): readResponse = SMBCommand(ans['Data'][0]) readData = SMBReadResponse_Data(readResponse['Data']) return readData['Data'] return None def read_andx(self, tid, fid, offset=0, max_size = None, wait_answer=1, smb_packet=None): if not max_size: if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_READX) and self._SignatureEnabled is False: max_size = 65000 else: max_size = self._dialects_parameters['MaxBufferSize'] # Read in multiple KB blocks # max_size is not working, because although it would, the server returns an error (More data avail) if smb_packet is None: smb = NewSMBPacket() smb['Tid'] = tid readAndX = SMBCommand(SMB.SMB_COM_READ_ANDX) readAndX['Parameters'] = SMBReadAndX_Parameters() readAndX['Parameters']['Fid'] = fid readAndX['Parameters']['Offset'] = offset readAndX['Parameters']['MaxCount'] = max_size smb.addCommand(readAndX) else: smb = smb_packet if wait_answer: answer = '' while 1: self.sendSMB(smb) ans = self.recvSMB() if ans.isValidAnswer(SMB.SMB_COM_READ_ANDX): # XXX Here we are only using a few fields from the response readAndXResponse = SMBCommand(ans['Data'][0]) readAndXParameters = SMBReadAndXResponse_Parameters(readAndXResponse['Parameters']) offset = readAndXParameters['DataOffset'] count = readAndXParameters['DataCount']+0x10000*readAndXParameters['DataCount_Hi'] answer += str(ans)[offset:offset+count] if not ans.isMoreData(): return answer max_size = min(max_size, readAndXParameters['Remaining']) readAndX['Parameters']['Offset'] += count # XXX Offset is not important (apparently) else: self.sendSMB(smb) ans = self.recvSMB() try: if ans.isValidAnswer(SMB.SMB_COM_READ_ANDX): return ans else: return None except: return ans return None def read_raw(self, tid, fid, offset=0, max_size = None, wait_answer=1): if not max_size: max_size = self._dialects_parameters['MaxBufferSize'] # Read in multiple KB blocks # max_size is not working, because although it would, the server returns an error (More data avail) smb = NewSMBPacket() smb['Tid'] = tid readRaw = SMBCommand(SMB.SMB_COM_READ_RAW) readRaw['Parameters'] = SMBReadRaw_Parameters() readRaw['Parameters']['Fid'] = fid readRaw['Parameters']['Offset'] = offset readRaw['Parameters']['MaxCount'] = max_size smb.addCommand(readRaw) self.sendSMB(smb) if wait_answer: data = self._sess.recv_packet(self.__timeout).get_trailer() if not data: # If there is no data it means there was an error data = self.read_andx(tid, fid, offset, max_size) return data return None def write(self,tid,fid,data, offset = 0, wait_answer=1): smb = NewSMBPacket() smb['Tid'] = tid write = SMBCommand(SMB.SMB_COM_WRITE) write['Parameters'] = SMBWrite_Parameters() write['Data'] = SMBWrite_Data() write['Parameters']['Fid'] = fid write['Parameters']['Count'] = len(data) write['Parameters']['Offset'] = offset write['Parameters']['Remaining'] = len(data) write['Data']['Data'] = data smb.addCommand(write) self.sendSMB(smb) if wait_answer: smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_WRITE): return smb return None def write_andx(self,tid,fid,data, offset = 0, wait_answer=1, write_pipe_mode = False, smb_packet=None): if smb_packet is None: smb = NewSMBPacket() smb['Tid'] = tid writeAndX = SMBCommand(SMB.SMB_COM_WRITE_ANDX) smb.addCommand(writeAndX) writeAndX['Parameters'] = SMBWriteAndX_Parameters() writeAndX['Parameters']['Fid'] = fid writeAndX['Parameters']['Offset'] = offset writeAndX['Parameters']['WriteMode'] = 8 writeAndX['Parameters']['Remaining'] = len(data) writeAndX['Parameters']['DataLength'] = len(data) writeAndX['Parameters']['DataOffset'] = len(smb) # this length already includes the parameter writeAndX['Data'] = data if write_pipe_mode is True: # First of all we gotta know what the MaxBuffSize is maxBuffSize = self._dialects_parameters['MaxBufferSize'] if len(data) > maxBuffSize: chunks_size = maxBuffSize - 60 writeAndX['Parameters']['WriteMode'] = 0x0c sendData = '\xff\xff' + data totalLen = len(sendData) writeAndX['Parameters']['DataLength'] = chunks_size writeAndX['Parameters']['Remaining'] = totalLen-2 writeAndX['Data'] = sendData[:chunks_size] self.sendSMB(smb) if wait_answer: smbResp = self.recvSMB() smbResp.isValidAnswer(SMB.SMB_COM_WRITE_ANDX) alreadySent = chunks_size sendData = sendData[chunks_size:] while alreadySent < totalLen: writeAndX['Parameters']['WriteMode'] = 0x04 writeAndX['Parameters']['DataLength'] = len(sendData[:chunks_size]) writeAndX['Data'] = sendData[:chunks_size] self.sendSMB(smb) if wait_answer: smbResp = self.recvSMB() smbResp.isValidAnswer(SMB.SMB_COM_WRITE_ANDX) alreadySent += writeAndX['Parameters']['DataLength'] sendData = sendData[chunks_size:] return smbResp else: smb = smb_packet self.sendSMB(smb) if wait_answer: smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_WRITE_ANDX): return smb return None def write_raw(self,tid,fid,data, offset = 0, wait_answer=1): LOG.warning("[MS-CIFS] This command was introduced in the CorePlus dialect, but is often listed as part of the LAN Manager 1.0 dialect.This command has been deprecated.Clients SHOULD use SMB_COM_WRITE_ANDX") smb = NewSMBPacket() smb['Tid'] = tid writeRaw = SMBCommand(SMB.SMB_COM_WRITE_RAW) writeRaw['Parameters'] = SMBWriteRaw_Parameters() writeRaw['Parameters']['Fid'] = fid writeRaw['Parameters']['Offset'] = offset writeRaw['Parameters']['Count'] = len(data) writeRaw['Parameters']['DataLength'] = 0 writeRaw['Parameters']['DataOffset'] = 0 smb.addCommand(writeRaw) self.sendSMB(smb) self._sess.send_packet(data) if wait_answer: smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_WRITE_RAW): return smb return None def TransactNamedPipe(self, tid, fid, data = '', noAnswer = 0, waitAnswer = 1, offset = 0): self.send_trans(tid,pack('<HH', 0x26, fid),'\\PIPE\\\x00','',data, noAnswer = noAnswer) if noAnswer or not waitAnswer: return smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_TRANSACTION): transResponse = SMBCommand(smb['Data'][0]) transParameters = SMBTransactionResponse_Parameters(transResponse['Parameters']) return transResponse['Data'][-transParameters['TotalDataCount']:] # Remove Potential Prefix Padding return None def TransactNamedPipeRecv(self): s = self.recvSMB() if s.isValidAnswer(SMB.SMB_COM_TRANSACTION): transResponse = SMBCommand(s['Data'][0]) transParameters = SMBTransactionResponse_Parameters(transResponse['Parameters']) return transResponse['Data'][-transParameters['TotalDataCount']:] # Remove Potential Prefix Padding return None def nt_create_andx(self,tid,filename, smb_packet=None, cmd = None, shareAccessMode = FILE_SHARE_READ | FILE_SHARE_WRITE, disposition = FILE_OPEN, accessMask = 0x2019f): filename = filename.replace('/', '\\') filename = filename.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else filename if smb_packet is None: smb = NewSMBPacket() smb['Tid'] = tid else: smb = smb_packet if cmd is None: ntCreate = SMBCommand(SMB.SMB_COM_NT_CREATE_ANDX) ntCreate['Parameters'] = SMBNtCreateAndX_Parameters() ntCreate['Data'] = SMBNtCreateAndX_Data(flags=self.__flags2) ntCreate['Parameters']['FileNameLength'] = len(filename) ntCreate['Parameters']['CreateFlags'] = 0x16 ntCreate['Parameters']['AccessMask'] = accessMask ntCreate['Parameters']['CreateOptions'] = 0x40 ntCreate['Parameters']['ShareAccess'] = shareAccessMode ntCreate['Parameters']['Disposition'] = disposition ntCreate['Data']['FileName'] = filename if self.__flags2 & SMB.FLAGS2_UNICODE: ntCreate['Data']['Pad'] = 0x0 else: ntCreate = cmd smb.addCommand(ntCreate) self.sendSMB(smb) while 1: smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_NT_CREATE_ANDX): # XXX Here we are ignoring the rest of the response ntCreateResponse = SMBCommand(smb['Data'][0]) ntCreateParameters = SMBNtCreateAndXResponse_Parameters(ntCreateResponse['Parameters']) self.fid = ntCreateParameters['Fid'] return ntCreateParameters['Fid'] def logoff(self): smb = NewSMBPacket() logOff = SMBCommand(SMB.SMB_COM_LOGOFF_ANDX) logOff['Parameters'] = SMBLogOffAndX() smb.addCommand(logOff) self.sendSMB(smb) self.recvSMB() # Let's clear some fields so you can login again under the same session self._uid = 0 def list_path(self, service, path = '*', password = None): path = path.replace('/', '\\') path = path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: findFirstParameter = SMBFindFirst2_Parameters() findFirstParameter['SearchAttributes'] = SMB_FILE_ATTRIBUTE_DIRECTORY | SMB_FILE_ATTRIBUTE_HIDDEN | \ SMB_FILE_ATTRIBUTE_SYSTEM | SMB_FILE_ATTRIBUTE_READONLY | \ SMB_FILE_ATTRIBUTE_ARCHIVE findFirstParameter['SearchCount'] = 512 findFirstParameter['Flags'] = SMB_FIND_RETURN_RESUME_KEYS | SMB_FIND_CLOSE_AT_EOS findFirstParameter['InformationLevel'] = SMB_FIND_FILE_BOTH_DIRECTORY_INFO findFirstParameter['SearchStorageType'] = 0 findFirstParameter['FileName'] = path + ('\x00\x00' if self.__flags2 & SMB.FLAGS2_UNICODE else '\x00') self.send_trans2(tid, SMB.TRANS2_FIND_FIRST2, '\x00', findFirstParameter, '') files = [ ] totalDataCount = 1 findData = '' findFirst2ParameterBlock = '' while len(findData) < totalDataCount: resp = self.recvSMB() if resp.isValidAnswer(SMB.SMB_COM_TRANSACTION2): trans2Response = SMBCommand(resp['Data'][0]) trans2Parameters = SMBTransaction2Response_Parameters(trans2Response['Parameters']) totalDataCount = trans2Parameters['TotalDataCount'] findFirst2ParameterBlock += trans2Response['Data'][trans2Parameters['ParameterOffset']-55:][:trans2Parameters['ParameterCount']] findData += trans2Response['Data'][trans2Parameters['DataOffset']-55:] findParameterBlock = SMBFindFirst2Response_Parameters(findFirst2ParameterBlock) # Save the SID for resume operations sid = findParameterBlock['SID'] while True: record = SMBFindFileBothDirectoryInfo(data = findData) shortname = record['ShortName'].decode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else record['ShortName'] filename = record['FileName'].decode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else record['FileName'] fileRecord = SharedFile(record['CreationTime'], record['LastAccessTime'], record['LastChangeTime'], record['EndOfFile'], record['AllocationSize'], record['ExtFileAttributes'], shortname, filename) files.append(fileRecord) if record['NextEntryOffset'] > 0 and len(findData[record['NextEntryOffset']:]) > 0: findData = findData[record['NextEntryOffset']:] else: # More data to search? if findParameterBlock['EndOfSearch'] == 0: resume_filename = record['FileName'] findNextParameter = SMBFindNext2_Parameters() findNextParameter['SID'] = sid findNextParameter['SearchCount'] = 1024 findNextParameter['InformationLevel'] = SMB_FIND_FILE_BOTH_DIRECTORY_INFO findNextParameter['ResumeKey'] = 0 findNextParameter['Flags'] = SMB_FIND_RETURN_RESUME_KEYS | SMB_FIND_CLOSE_AT_EOS findNextParameter['FileName'] = resume_filename + ('\x00\x00' if self.__flags2 & SMB.FLAGS2_UNICODE else '\x00') self.send_trans2(tid, SMB.TRANS2_FIND_NEXT2, '\x00', findNextParameter, '') findData = '' findNext2ParameterBlock = '' totalDataCount = 1 while len(findData) < totalDataCount: resp = self.recvSMB() if resp.isValidAnswer(SMB.SMB_COM_TRANSACTION2): trans2Response = SMBCommand(resp['Data'][0]) trans2Parameters = SMBTransaction2Response_Parameters(trans2Response['Parameters']) totalDataCount = trans2Parameters['TotalDataCount'] findNext2ParameterBlock += trans2Response['Data'][trans2Parameters['ParameterOffset']-55:][:trans2Parameters['ParameterCount']] findData += trans2Response['Data'][trans2Parameters['DataOffset']-55:] findParameterBlock = SMBFindNext2Response_Parameters(findNext2ParameterBlock) else: break finally: self.disconnect_tree(tid) return files def retr_file(self, service, filename, callback, mode = FILE_OPEN, offset = 0, password = None, shareAccessMode = SMB_ACCESS_READ): filename = string.replace(filename, '/', '\\') fid = -1 tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: fid = self.nt_create_andx(tid, filename, shareAccessMode = shareAccessMode, accessMask = 0x20089) res = self.query_file_info(tid, fid) datasize = SMBQueryFileStandardInfo(res)['EndOfFile'] self.__nonraw_retr_file(tid, fid, offset, datasize, callback) finally: if fid >= 0: self.close(tid, fid) self.disconnect_tree(tid) def stor_file(self, service, filename, callback, mode = FILE_OVERWRITE_IF, offset = 0, password = None, shareAccessMode = SMB_ACCESS_WRITE): filename = string.replace(filename, '/', '\\') fid = -1 tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: fid = self.nt_create_andx(tid, filename, shareAccessMode = shareAccessMode, disposition = mode ) self.__nonraw_stor_file(tid, fid, offset, 0, callback) finally: if fid >= 0: self.close(tid, fid) self.disconnect_tree(tid) def stor_file_nonraw(self, service, filename, callback, mode = FILE_OVERWRITE_IF, offset = 0, password = None, shareAccessMode = SMB_ACCESS_WRITE ): filename = string.replace(filename, '/', '\\') fid = -1 tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: fid = self.nt_create_andx(tid, filename, shareAccessMode = shareAccessMode, disposition = mode) self.__nonraw_stor_file(tid, fid, offset, 0, callback) finally: if fid >= 0: self.close(tid, fid) self.disconnect_tree(tid) def check_dir(self, service, path, password = None): path = string.replace(path,'/', '\\') tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: smb = NewSMBPacket() smb['Tid'] = tid smb['Mid'] = 0 cmd = SMBCommand(SMB.SMB_COM_CHECK_DIRECTORY) cmd['Parameters'] = '' cmd['Data'] = SMBCheckDirectory_Data(flags = self.__flags2) cmd['Data']['DirectoryName'] = path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path smb.addCommand(cmd) self.sendSMB(smb) while 1: s = self.recvSMB() if s.isValidAnswer(SMB.SMB_COM_CHECK_DIRECTORY): return finally: self.disconnect_tree(tid) def remove(self, service, path, password = None): path = string.replace(path,'/', '\\') # Perform a list to ensure the path exists self.list_path(service, path, password) tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: smb = NewSMBPacket() smb['Tid'] = tid smb['Mid'] = 0 cmd = SMBCommand(SMB.SMB_COM_DELETE) cmd['Parameters'] = SMBDelete_Parameters() cmd['Parameters']['SearchAttributes'] = ATTR_HIDDEN | ATTR_SYSTEM | ATTR_ARCHIVE cmd['Data'] = SMBDelete_Data(flags = self.__flags2) cmd['Data']['FileName'] = (path + '\x00').encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else (path + '\x00') smb.addCommand(cmd) self.sendSMB(smb) while 1: s = self.recvSMB() if s.isValidAnswer(SMB.SMB_COM_DELETE): return finally: self.disconnect_tree(tid) def rmdir(self, service, path, password = None): path = string.replace(path,'/', '\\') # Check that the directory exists self.check_dir(service, path, password) tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: path = path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path smb = NewSMBPacket() smb['Tid'] = tid createDir = SMBCommand(SMB.SMB_COM_DELETE_DIRECTORY) createDir['Data'] = SMBDeleteDirectory_Data(flags=self.__flags2) createDir['Data']['DirectoryName'] = path smb.addCommand(createDir) self.sendSMB(smb) while 1: s = self.recvSMB() if s.isValidAnswer(SMB.SMB_COM_DELETE_DIRECTORY): return finally: self.disconnect_tree(tid) def mkdir(self, service, path, password = None): path = string.replace(path,'/', '\\') tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: path = path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else path smb = NewSMBPacket() smb['Tid'] = tid smb['Mid'] = 0 createDir = SMBCommand(SMB.SMB_COM_CREATE_DIRECTORY) createDir['Data'] = SMBCreateDirectory_Data(flags=self.__flags2) createDir['Data']['DirectoryName'] = path smb.addCommand(createDir) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_CREATE_DIRECTORY): return 1 return 0 finally: self.disconnect_tree(tid) def rename(self, service, old_path, new_path, password = None): old_path = string.replace(old_path,'/', '\\') new_path = string.replace(new_path,'/', '\\') tid = self.tree_connect_andx('\\\\' + self.__remote_name + '\\' + service, password) try: smb = NewSMBPacket() smb['Tid'] = tid smb['Mid'] = 0 renameCmd = SMBCommand(SMB.SMB_COM_RENAME) renameCmd['Parameters'] = SMBRename_Parameters() renameCmd['Parameters']['SearchAttributes'] = ATTR_SYSTEM | ATTR_HIDDEN | ATTR_DIRECTORY renameCmd['Data'] = SMBRename_Data(flags = self.__flags2) renameCmd['Data']['OldFileName'] = old_path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else old_path renameCmd['Data']['NewFileName'] = new_path.encode('utf-16le') if self.__flags2 & SMB.FLAGS2_UNICODE else new_path smb.addCommand(renameCmd) self.sendSMB(smb) smb = self.recvSMB() if smb.isValidAnswer(SMB.SMB_COM_RENAME): return 1 return 0 finally: self.disconnect_tree(tid) def writeFile(self, treeId, fileId, data, offset = 0): if (self._dialects_parameters['Capabilities'] & SMB.CAP_LARGE_WRITEX) and self._SignatureEnabled is False: max_buf_size = 65000 else: max_buf_size = self._dialects_parameters['MaxBufferSize'] & ~0x3ff # Write in multiple KB blocks write_offset = offset while 1: if len(data) == 0: break writeData = data[:max_buf_size] data = data[max_buf_size:] smb = self.write_andx(treeId,fileId,writeData, write_offset) writeResponse = SMBCommand(smb['Data'][0]) writeResponseParameters = SMBWriteAndXResponse_Parameters(writeResponse['Parameters']) write_offset += writeResponseParameters['Count'] def get_socket(self): return self._sess.get_socket() ERRDOS = { 1: 'Invalid function', 2: 'File not found', 3: 'Invalid directory', 4: 'Too many open files', 5: 'Access denied', 6: 'Invalid file handle. Please file a bug report.', 7: 'Memory control blocks destroyed', 8: 'Out of memory', 9: 'Invalid memory block address', 10: 'Invalid environment', 11: 'Invalid format', 12: 'Invalid open mode', 13: 'Invalid data', 15: 'Invalid drive', 16: 'Attempt to remove server\'s current directory', 17: 'Not the same device', 18: 'No files found', 32: 'Sharing mode conflicts detected', 33: 'Lock request conflicts detected', 80: 'File already exists' } ERRSRV = { 1: 'Non-specific error', 2: 'Bad password', 4: 'Access denied', 5: 'Invalid tid. Please file a bug report.', 6: 'Invalid network name', 7: 'Invalid device', 49: 'Print queue full', 50: 'Print queue full', 51: 'EOF on print queue dump', 52: 'Invalid print file handle', 64: 'Command not recognized. Please file a bug report.', 65: 'Internal server error', 67: 'Invalid path', 69: 'Invalid access permissions', 71: 'Invalid attribute mode', 81: 'Server is paused', 82: 'Not receiving messages', 83: 'No room to buffer messages', 87: 'Too many remote user names', 88: 'Operation timeout', 89: 'Out of resources', 91: 'Invalid user handle. Please file a bug report.', 250: 'Temporarily unable to support raw mode for transfer', 251: 'Temporarily unable to support raw mode for transfer', 252: 'Continue in MPX mode', 65535: 'Unsupported function' } ERRHRD = { 19: 'Media is write-protected', 20: 'Unknown unit', 21: 'Drive not ready', 22: 'Unknown command', 23: 'CRC error', 24: 'Bad request', 25: 'Seek error', 26: 'Unknown media type', 27: 'Sector not found', 28: 'Printer out of paper', 29: 'Write fault', 30: 'Read fault', 31: 'General failure', 32: 'Open conflicts with an existing open', 33: 'Invalid lock request', 34: 'Wrong disk in drive', 35: 'FCBs not available', 36: 'Sharing buffer exceeded' }