Skip to content
Permalink
Branch: master
Find file Copy path
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
4246 lines (3653 sloc) 154 KB
# SECUREAUTH LABS. Copyright 2018 SecureAuth Corporation. All rights reserved.
#
# 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 overlapping 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
from __future__ import division
from __future__ import print_function
import os
import socket
from binascii import a2b_hex
import datetime
from struct import pack, unpack
from contextlib import contextmanager
from pyasn1.type.univ import noValue
from impacket import nmb, ntlm, nt_errors, LOG
from impacket.structure import Structure
from impacket.spnego import SPNEGO_NegTokenInit, TypesMech, SPNEGO_NegTokenResp, ASN1_OID, asn1encode, ASN1_AID
from impacket.krb5.gssapi import KRB5_AP_REQ
# For signing
import hashlib
unicode_support = 0
unicode_convert = 1
# 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 occurred 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, packet=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
self.packet = packet
def get_error_class( self ):
return self.error_class
def get_error_code( self ):
return self.error_code
def get_error_packet(self):
return self.packet
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:
if isinstance(shortname,bytes):
self.__shortname = shortname[:shortname.index(b'\0')]
else:
self.__shortname = shortname[:shortname.index('\0')]
except (ValueError, TypeError):
self.__shortname = shortname
try:
if isinstance(shortname,bytes):
self.__longname = longname[:longname.index(b'\0')]
else:
self.__longname = longname[:longname.index('\0')]
except (ValueError, TypeError):
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, self)
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, overridden 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',':'),
('PadLen','_-Pad','1 if (len(self["SecurityBlob"]) % 2 == 0) else 0'),
('Pad',':=""'),
('NativeOS','u=""'),
('NativeLanMan','u=""'),
)
def getData(self):
if self.structure == self.UnicodeStructure:
if len(str(self['SecurityBlob'])) % 2 == 0:
self['Pad'] = '\x00'
return AsciiOrUnicodeStructure.getData(self)
############# 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'),
('ParameterDisplacement','<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','u'),
)
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.__client_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 = remote_name.upper()
self.__remote_host = remote_host
self.__isNTLMv2 = True
self._dialects_parameters = None
self._dialects_data = None
self._doKerberos = False
# Credentials
self.__userName = b''
self.__password = b''
self.__domain = b''
self.__lmhash = b''
self.__nthash = b''
self.__aesKey = b''
self.__kdc = b''
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 = b''
self._SigningChallengeResponse = b''
self._SignatureEnabled = False
self._SignatureVerificationEnabled = False
self._SignatureRequired = False
# Base flags (default flags, can be overridden 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
# This is on purpose. I'm still not convinced to do a socket.gethostname() if not specified
if my_name is None:
self.__client_name = b''
else:
self.__client_name = my_name
if session is None:
if not my_name:
# If destination port is 139 yes, there's some client disclosure
my_name = socket.gethostname()
i = my_name.find('.')
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 getKerberos(self):
return self._doKerberos
def get_remote_name(self):
return self.__remote_name
def set_remote_name(self, name):
self.__remote_name = name
return True
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 close_session(self):
if self._sess:
self._sess.close()
self._sess = None
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( packet.getData() )
# 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(smb.getData())
@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 server speaks Unicode, let's set that flag from now on
if smb['Flags2'] & SMB.FLAGS2_UNICODE:
self.__flags2 |= SMB.FLAGS2_UNICODE
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'] = b'\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_client_name(self):
return self.__client_name
def get_session_key(self):
return self._SigningSessionKey
def set_session_key(self, key):
self._SignatureEnabled = True
self._SignSequenceNumber = 2
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 = filename.replace('/', '\\')
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
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 = filename.replace('/', '\\')
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
self._doKerberos= True
# 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