def listShareResultsCB(result_message, **kwargs): messages_history.append(result_message) if result_message.status == 0: # The payload.data_bytes will contain the results of the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC. data_bytes = result_message.payload.out_data if data_bytes[3] & 0x02 == 0: sendReadRequest(result_message.tid, kwargs['fid'], data_bytes) else: decodeResults(result_message.tid, kwargs['fid'], data_bytes) elif result_message.status == 0x0103: # STATUS_PENDING self.pending_requests[result_message.mid] = _PendingRequest( result_message.mid, expiry_time, listShareResultsCB, errback, fid=kwargs['fid']) else: closeFid(result_message.tid, kwargs['fid']) errback( OperationFailure( 'Failed to list shares: Unable to retrieve shared device list', messages_history))
def connectSrvSvcCB(create_message, **kwargs): messages_history.append(create_message) if create_message.status == 0: call_id = self._getNextRPCCallID() # The data_bytes are binding call to Server Service RPC using DCE v1.1 RPC over SMB. See [MS-SRVS] and [C706] # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream data_bytes = \ binascii.unhexlify(b"""05 00 0b 03 10 00 00 00 74 00 00 00""".replace(b' ', b'')) + \ struct.pack('<I', call_id) + \ binascii.unhexlify(b""" b8 10 b8 10 00 00 00 00 02 00 00 00 00 00 01 00 c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00 2b 10 48 60 02 00 00 00 01 00 01 00 c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00 2c 1c b7 6c 12 98 40 45 03 00 00 00 00 00 00 00 01 00 00 00 """.replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message(SMB2WriteRequest(create_message.payload.fid, data_bytes, 0)) m.tid = create_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcBindCB, errback, fid = create_message.payload.fid) messages_history.append(m) else: errback(OperationFailure('Failed to list shares: Unable to locate Server Service RPC endpoint', messages_history))
def connectSrvSvcCB(create_message, **kwargs): messages_history.append(create_message) if create_message.status == 0: call_id = self._getNextRPCCallID() # The data_bytes are binding call to Server Service RPC using DCE v1.1 RPC over SMB. See [MS-SRVS] and [C706] # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream data_bytes = \ binascii.unhexlify(b"""05 00 0b 03 10 00 00 00 74 00 00 00""".replace(b' ', b'')) + \ struct.pack('<I', call_id) + \ binascii.unhexlify(b""" b8 10 b8 10 00 00 00 00 02 00 00 00 00 00 01 00 c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00 2b 10 48 60 02 00 00 00 01 00 01 00 c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00 2c 1c b7 6c 12 98 40 45 03 00 00 00 00 00 00 00 01 00 00 00 """.replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message( SMB2WriteRequest(create_message.payload.fid, data_bytes, 0)) m.tid = create_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest( m.mid, expiry_time, rpcBindCB, errback, fid=create_message.payload.fid) messages_history.append(m) else: errback( OperationFailure( 'Failed to list shares: Unable to locate Server Service RPC endpoint', messages_history))
def sendReadRequest(tid, fid, data_bytes): read_count = min(4280, self.max_read_size) m = SMB2Message(SMB2ReadRequest(fid, 0, read_count)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, fid = fid, data_bytes = data_bytes)
def rpcReadCB(read_message, **kwargs): messages_history.append(read_message) if read_message.status == 0: call_id = self._getNextRPCCallID() padding = b'' remote_name = '\\\\' + self.remote_name server_len = len(remote_name) + 1 server_bytes_len = server_len * 2 if server_len % 2 != 0: padding = b'\0\0' server_bytes_len += 2 # The data bytes are the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC. # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream data_bytes = \ binascii.unhexlify(b"""05 00 00 03 10 00 00 00""".replace(b' ', b'')) + \ struct.pack('<HHI', 72+server_bytes_len, 0, call_id) + \ binascii.unhexlify(b"""4c 00 00 00 00 00 0f 00 00 00 02 00""".replace(b' ', b'')) + \ struct.pack('<III', server_len, 0, server_len) + \ (remote_name + '\0').encode('UTF-16LE') + padding + \ binascii.unhexlify(b""" 02 00 00 00 02 00 00 00 04 00 02 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 """.replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message(SMB2IoctlRequest(kwargs['fid'], 0x0011C017, flags = 0x01, max_out_size = 8196, in_data = data_bytes)) m.tid = read_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, listShareResultsCB, errback, fid = kwargs['fid']) messages_history.append(m) else: closeFid(read_message.tid, kwargs['fid'], error = 'Failed to list shares: Unable to bind to Server Service RPC endpoint')
def sendCreate(tid): if overwrite: OVERWRITE = FILE_OVERWRITE_IF else: OVERWRITE = FILE_OPEN_IF create_context_data = binascii.unhexlify( b"28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00" b"44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00" b"00 00 00 00 00 00 00 00 20 00 00 00 10 00 04 00" b"00 00 18 00 08 00 00 00 41 6c 53 69 00 00 00 00" b"85 62 00 00 00 00 00 00 18 00 00 00 10 00 04 00" b"00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00" b"00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00" b"51 46 69 64 00 00 00 00".replace(b' ', b'').replace(b'\n', b'') ) m = SMB2Message(SMB2CreateRequest(path, file_attributes = ATTR_ARCHIVE, access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_EA | WRITE_DAC | READ_CONTROL | SYNCHRONIZE, share_access = 0, oplock = SMB2_OPLOCK_LEVEL_NONE, impersonation = SEC_IMPERSONATE, create_options = FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE, create_disp = OVERWRITE, create_context_data = create_context_data)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback, tid = tid) messages_history.append(m)
def rpcReadCB(read_message, **kwargs): messages_history.append(read_message) if read_message.status == 0: call_id = self._getNextRPCCallID() padding = b'' remote_name = '\\\\' + self.remote_name server_len = len(remote_name) + 1 server_bytes_len = server_len * 2 if server_len % 2 != 0: padding = b'\0\0' server_bytes_len += 2 # The data bytes are the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC. # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream data_bytes = \ binascii.unhexlify(b"""05 00 00 03 10 00 00 00""".replace(b' ', b'')) + \ struct.pack('<HHI', 72+server_bytes_len, 0, call_id) + \ binascii.unhexlify(b"""4c 00 00 00 00 00 0f 00 00 00 02 00""".replace(b' ', b'')) + \ struct.pack('<III', server_len, 0, server_len) + \ (remote_name + '\0').encode('UTF-16LE') + padding + \ binascii.unhexlify(b""" 02 00 00 00 02 00 00 00 04 00 02 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 """.replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message(SMB2IoctlRequest(kwargs['fid'], 0x0011C017, flags = 0x01, max_out_size = 8196, in_data = data_bytes)) m.tid = read_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, listShareResultsCB, errback, fid = kwargs['fid']) messages_history.append(m) else: closeFid(read_message.tid, kwargs['fid'], error = 'Failed to list shares: Unable to bind to Server Service RPC endpoint')
def sendReadRequest(tid, fid, data_bytes): read_count = min(4280, self.max_read_size) m = SMB2Message(SMB2ReadRequest(fid, 0, read_count)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, fid = fid, data_bytes = data_bytes)
def sendQuery(tid, fid, data_buf): m = SMB2Message(SMB2QueryDirectoryRequest(fid, pattern, info_class = 0x03, # FileBothDirectoryInformation flags = 0, output_buf_len = conn.max_transact_size)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, queryCB, errback, fid = fid, data_buf = data_buf) messages_history.append(m)
def rpcBindCB(trans_message, **kwargs): messages_history.append(trans_message) if trans_message.status == 0: m = SMB2Message(SMB2ReadRequest(kwargs['fid'], read_len = 1024, read_offset = 0)) m.tid = trans_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcReadCB, errback, fid = kwargs['fid']) messages_history.append(m) else: closeFid(trans_message.tid, kwargs['fid'], error = 'Failed to list shares: Unable to read from Server Service RPC endpoint')
def sendOpen(tid): m = SMBMessage(ComOpenAndxRequest(filename = path, access_mode = 0x0040, # Sharing mode: Deny nothing to others open_mode = 0x0001, # Failed if file does not exist search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM, timeout = timeout * 1000)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, openCB, errback) messages_history.append(m)
def sendRead(tid, fid, offset, file_attributes, read_len, remaining_len): read_count = self.max_raw_size - 2 m = SMBMessage(ComReadAndxRequest(fid = fid, offset = offset, max_return_bytes_count = read_count, min_return_bytes_count = min(0xFFFF, read_count))) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, fid = fid, offset = offset, file_attributes = file_attributes, read_len = read_len, remaining_len = remaining_len)
def sendOpen(tid): m = SMBMessage(ComOpenAndxRequest(filename = path, access_mode = 0x0040, # Sharing mode: Deny nothing to others open_mode = 0x0001, # Failed if file does not exist search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM, timeout = timeout * 1000)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, openCB, errback) messages_history.append(m)
def rpcBindCB(trans_message, **kwargs): messages_history.append(trans_message) if trans_message.status == 0: m = SMB2Message(SMB2ReadRequest(kwargs['fid'], read_len = 1024, read_offset = 0)) m.tid = trans_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcReadCB, errback, fid = kwargs['fid']) messages_history.append(m) else: closeFid(trans_message.tid, kwargs['fid'], error = 'Failed to list shares: Unable to read from Server Service RPC endpoint')
def sendOpen(tid): m = SMBMessage(ComOpenAndxRequest(filename = path, access_mode = 0x0041, # Sharing mode: Deny nothing to others + Open for writing open_mode = 0x0011, # Create file if file does not exist. Overwrite if exists. search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM, timeout = timeout * 1000)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, openCB, errback) messages_history.append(m)
def sendRead(tid, fid, offset, file_attributes, read_len, remaining_len): read_count = self.max_raw_size - 2 m = SMBMessage(ComReadAndxRequest(fid = fid, offset = offset, max_return_bytes_count = read_count, min_return_bytes_count = min(0xFFFF, read_count))) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, fid = fid, offset = offset, file_attributes = file_attributes, read_len = read_len, remaining_len = remaining_len)
def sendGetDfsReferral(tid): params_bytes = struct.pack('<H', 4) + path.encode('UTF-16LE') + '\x00' m = SMBMessage(ComTransaction2Request(max_params_count = 0, max_data_count = 4096, max_setup_count = 0, setup_bytes = '\x10\x00', params_bytes = params_bytes,)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, enumSnapshotsCB, errback, tid = tid, fid = '') messages_history.append(m)
def sendWrite(tid, fid, offset): write_count = conn.max_write_size data = file_obj.read(write_count) data_len = len(data) if data_len > 0: m = SMB2Message(SMB2WriteRequest(fid, data, offset)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, writeCB, errback, fid = fid, offset = offset+data_len) else: closeFid(tid, fid, offset = offset)
def closeFid(tid, fid, results=None, error=None): m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results=results, error=error) messages_history.append(m)
def sendGetDfsReferral(tid): data_bytes = struct.pack('<H', 4) + path.encode('UTF-16LE') + '\x00' fid = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' m = SMB2Message(SMB2IoctlRequest(fid, ctlcode = 0x00060194, # FSCTL_GET_DFS_REFERREALS flags = 0x0001, in_data = data_bytes)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, enumSnapshotsCB, errback, tid = tid, fid = '') messages_history.append(m)
def connectSrvSvc(tid): m = SMB2Message(SMB2CreateRequest('srvsvc', file_attributes = 0, access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, oplock = SMB2_OPLOCK_LEVEL_NONE, impersonation = SEC_IMPERSONATE, create_options = FILE_NON_DIRECTORY_FILE | FILE_OPEN_NO_RECALL, create_disp = FILE_OPEN)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectSrvSvcCB, errback) messages_history.append(m)
def sendWrite(tid, fid, offset): # For message signing, the total SMB message size must be not exceed the max_buffer_size. Non-message signing does not have this limitation write_count = min((conn.is_signing_active and (conn.max_buffer_size-64)) or conn.max_raw_size, 0xFFFF-1) # Need to minus 1 byte from 0xFFFF because of the first NULL byte in the ComWriteAndxRequest message data data_bytes = file_obj.read(write_count) data_len = len(data_bytes) if data_len > 0: m = SMBMessage(ComWriteAndxRequest(fid = fid, offset = offset, data_bytes = data_bytes)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, writeCB, errback, fid = fid, offset = offset+data_len) else: closeFid(tid, fid) callback(( file_obj, offset )) # Note that this is a tuple of 2-elements
def connectSrvSvc(tid): m = SMB2Message(SMB2CreateRequest('srvsvc', file_attributes = 0, access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, oplock = SMB2_OPLOCK_LEVEL_NONE, impersonation = SEC_IMPERSONATE, create_options = FILE_NON_DIRECTORY_FILE | FILE_OPEN_NO_RECALL, create_disp = FILE_OPEN)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectSrvSvcCB, errback) messages_history.append(m)
def listShareResultsCB(result_message, **kwargs): messages_history.append(result_message) if result_message.status == 0: # The payload.data_bytes will contain the results of the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC. data_bytes = result_message.payload.out_data if data_bytes[3] & 0x02 == 0: sendReadRequest(result_message.tid, kwargs['fid'], data_bytes) else: decodeResults(result_message.tid, kwargs['fid'], data_bytes) elif result_message.status == 0x0103: # STATUS_PENDING self.pending_requests[result_message.mid] = _PendingRequest(result_message.mid, expiry_time, listShareResultsCB, errback, fid = kwargs['fid']) else: closeFid(result_message.tid, kwargs['fid']) errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list', messages_history))
def _getDfsReferral_SMB1(conn, service_name, path, callback, errback, timeout = 30): if not conn.has_authenticated: raise NotReadyError('SMB connection not authenticated') expiry_time = time.time() + timeout ipc_path = 'IPC$' messages_history = [ ] def sendGetDfsReferral(tid): params_bytes = struct.pack('<H', 4) + path.encode('UTF-16LE') + '\x00' m = SMBMessage(ComTransaction2Request(max_params_count = 0, max_data_count = 4096, max_setup_count = 0, setup_bytes = '\x10\x00', params_bytes = params_bytes,)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, enumSnapshotsCB, errback, tid = tid, fid = '') messages_history.append(m) def enumSnapshotsCB(enum_message, **kwargs): messages_history.append(enum_message) results = [] if not enum_message.status.hasError: results = ref_data(enum_message.payload.data_bytes) else: errback(OperationFailure('Failed to list shares: Unable to locate Server Service RPC endpoint', messages_history)) closeFid(kwargs['tid'], kwargs['fid']) callback(results) def closeFid(tid, fid): m = SMBMessage(ComCloseRequest(fid)) m.tid = tid conn._sendSMBMessage(m) messages_history.append(m) def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if not connect_message.status.hasError: conn.connected_trees[path] = connect_message.tid sendGetDfsReferral(connect_message.tid) else: errback(OperationFailure('Failed to list shares: Unable to connect to IPC$', messages_history)) m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( conn.remote_name.upper(), ipc_path ), SERVICE_ANY, '')) conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = ipc_path) messages_history.append(m)
def sendFindNext(tid, sid, resume_key): setup_bytes = struct.pack('<H', 0x0002) # TRANS2_FIND_NEXT2 sub-command. See [MS-CIFS]: 2.2.6.3.1 params_bytes = \ struct.pack('<HHHIH', sid, # SID 100, # SearchCount 0x0104, # InfoLevel: SMB_FIND_FILE_BOTH_DIRECTORY_INFO resume_key, # ResumeKey 0x000a) # Flags: SMB_FIND_RETURN_RESUME_KEYS | SMB_FIND_CLOSE_AT_EOS | SMB_FIND_RETURN_RESUME_KEYS params_bytes += pattern.encode('UTF-16LE') m = SMBMessage(ComTransaction2Request(max_params_count = 10, max_data_count = 16644, max_setup_count = 0, params_bytes = params_bytes, setup_bytes = setup_bytes)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, findNextCB, errback, sid = sid) messages_history.append(m)
def sendFindFirst(tid): setup_bytes = struct.pack('<H', 0x0001) # TRANS2_FIND_FIRST2 sub-command. See [MS-CIFS]: 2.2.6.2.1 params_bytes = \ struct.pack('<HHHHI', search, # SearchAttributes 100, # SearchCount 0x0006, # Flags: SMB_FIND_CLOSE_AT_EOS | SMB_FIND_RETURN_RESUME_KEYS 0x0104, # InfoLevel: SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x0000) # SearchStorageType params_bytes += (path + pattern).encode('UTF-16LE') m = SMBMessage(ComTransaction2Request(max_params_count = 10, max_data_count = 16644, max_setup_count = 0, params_bytes = params_bytes, setup_bytes = setup_bytes)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, findFirstCB, errback) messages_history.append(m)
def sendCreate(tid): create_context_data = binascii.unhexlify( b"28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 " b"44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 " b"00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 " b"00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 " b"00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 " b"51 46 69 64 00 00 00 00".replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, oplock = SMB2_OPLOCK_LEVEL_NONE, impersonation = SEC_IMPERSONATE, create_options = FILE_DIRECTORY_FILE, create_disp = FILE_OPEN, create_context_data = create_context_data)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, createCB, errback) messages_history.append(m)
def findNextCB(find_message, **kwargs): messages_history.append(find_message) if not find_message.status.hasError: if 'total_count' not in kwargs: # TRANS2_FIND_NEXT2 response. [MS-CIFS]: 2.2.6.3.2 search_count, end_of_search, _, last_name_offset = struct.unpack('<HHHH', find_message.payload.params_bytes[:8]) kwargs.update({ 'end_of_search': end_of_search, 'last_name_offset': last_name_offset, 'data_buf': b'' }) else: end_of_search, last_name_offset = kwargs['end_of_search'], kwargs['last_name_offset'] send_next = True if find_message.payload.data_bytes: d = decodeFindStruct(kwargs['data_buf'] + find_message.payload.data_bytes) if d is False: send_next = True end_of_search = True elif 'data_count' not in kwargs: if len(find_message.payload.data_bytes) != find_message.payload.total_data_count: kwargs.update({ 'data_count': len(find_message.payload.data_bytes), 'total_count': find_message.payload.total_data_count, 'data_buf': d, }) send_next = False else: kwargs['data_count'] += len(find_message.payload.data_bytes) kwargs['total_count'] = min(find_message.payload.total_data_count, kwargs['total_count']) kwargs['data_buf'] = d if kwargs['data_count'] != kwargs['total_count']: send_next = False if not send_next: self.pending_requests[find_message.mid] = _PendingRequest(find_message.mid, expiry_time, findNextCB, errback, **kwargs) elif end_of_search: callback(results) else: sendFindNext(find_message.tid, kwargs['sid'], last_name_offset) else: errback(OperationFailure('Failed to list %s on %s: Unable to retrieve file list' % ( path, service_name ), messages_history))
def _retrieveFileFromOffset_SMB1Unix(self, service_name, path, file_obj, callback, errback, starting_offset, max_length, timeout=30): if not self.has_authenticated: raise NotReadyError('SMB connection not authenticated') messages_history = [] def sendOpen(tid): m = SMBMessage( ComOpenAndxRequest( filename=path, access_mode=0x0040, # Sharing mode: Deny nothing to others open_mode=0x0001, # Failed if file does not exist search_attributes=SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM, timeout=timeout * 1000)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest( m.mid, int(time.time()) + timeout, openCB, errback) messages_history.append(m) def openCB(open_message, **kwargs): messages_history.append(open_message) if not open_message.status.hasError: if max_length == 0: closeFid(open_message.tid, open_message.payload.fid) callback( (file_obj, open_message.payload.file_attributes, 0)) else: sendRead(open_message.tid, open_message.payload.fid, starting_offset, open_message.payload.file_attributes, 0, max_length) else: errback( OperationFailure( 'Failed to retrieve %s on %s: Unable to open file' % (path, service_name), messages_history)) def sendRead(tid, fid, offset, file_attributes, read_len, remaining_len): read_count = self.max_raw_size - 2 m = SMBMessage( ComReadAndxRequest(fid=fid, offset=offset, max_return_bytes_count=read_count, min_return_bytes_count=min( 0xFFFF, read_count))) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest( m.mid, int(time.time()) + timeout, readCB, errback, fid=fid, offset=offset, file_attributes=file_attributes, read_len=read_len, remaining_len=remaining_len) def readCB(read_message, **kwargs): # To avoid crazy memory usage when retrieving large files, we do not save every read_message in messages_history. if not read_message.status.hasError: read_len = kwargs['read_len'] remaining_len = kwargs['remaining_len'] data_len = read_message.payload.data_length if max_length > 0: if data_len > remaining_len: file_obj.write( read_message.payload.data[:remaining_len]) read_len += remaining_len remaining_len = 0 else: file_obj.write(read_message.payload.data) remaining_len -= data_len read_len += data_len else: file_obj.write(read_message.payload.data) read_len += data_len if (max_length > 0 and remaining_len <= 0 ) or data_len < (self.max_raw_size - 2): closeFid(read_message.tid, kwargs['fid']) callback( (file_obj, kwargs['file_attributes'], read_len)) # Note that this is a tuple of 3-elements else: sendRead(read_message.tid, kwargs['fid'], kwargs['offset'] + data_len, kwargs['file_attributes'], read_len, remaining_len) else: messages_history.append(read_message) closeFid(read_message.tid, kwargs['fid']) errback( OperationFailure( 'Failed to retrieve %s on %s: Read failed' % (path, service_name), messages_history)) def closeFid(tid, fid): m = SMBMessage(ComCloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) messages_history.append(m) if service_name not in self.connected_trees: def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if not connect_message.status.hasError: self.connected_trees[service_name] = connect_message.tid sendOpen(connect_message.tid) else: errback( OperationFailure( 'Failed to retrieve %s on %s: Unable to connect to shared device' % (path, service_name), messages_history)) m = SMBMessage( ComTreeConnectAndxRequest( r'\\%s\%s' % (self.remote_name.upper(), service_name), SERVICE_ANY, '')) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path=service_name) messages_history.append(m) else: sendOpen(self.connected_trees[service_name])
def listSharesEx(self, callback, errback, timeout=30): if not self.has_authenticated: raise NotReadyError('SMB connection not authenticated') expiry_time = time.time() + timeout path = 'IPC$' messages_history = [] def connectSrvSvc(tid): m = SMB2Message( SMB2CreateRequest( 'srvsvc', file_attributes=0, access_mask=FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, share_access=FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, oplock=SMB2_OPLOCK_LEVEL_NONE, impersonation=SEC_IMPERSONATE, create_options=FILE_NON_DIRECTORY_FILE | FILE_OPEN_NO_RECALL, create_disp=FILE_OPEN)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest( m.mid, expiry_time, connectSrvSvcCB, errback) messages_history.append(m) def connectSrvSvcCB(create_message, **kwargs): messages_history.append(create_message) if create_message.status == 0: call_id = self._getNextRPCCallID() # The data_bytes are binding call to Server Service RPC using DCE v1.1 RPC over SMB. See [MS-SRVS] and [C706] # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream data_bytes = \ binascii.unhexlify(b"""05 00 0b 03 10 00 00 00 74 00 00 00""".replace(b' ', b'')) + \ struct.pack('<I', call_id) + \ binascii.unhexlify(b""" b8 10 b8 10 00 00 00 00 02 00 00 00 00 00 01 00 c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00 2b 10 48 60 02 00 00 00 01 00 01 00 c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00 2c 1c b7 6c 12 98 40 45 03 00 00 00 00 00 00 00 01 00 00 00 """.replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message( SMB2WriteRequest(create_message.payload.fid, data_bytes, 0)) m.tid = create_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest( m.mid, expiry_time, rpcBindCB, errback, fid=create_message.payload.fid) messages_history.append(m) else: errback( OperationFailure( 'Failed to list shares: Unable to locate Server Service RPC endpoint', messages_history)) def rpcBindCB(trans_message, **kwargs): messages_history.append(trans_message) if trans_message.status == 0: m = SMB2Message( SMB2ReadRequest(kwargs['fid'], read_len=1024, read_offset=0)) m.tid = trans_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest( m.mid, expiry_time, rpcReadCB, errback, fid=kwargs['fid']) messages_history.append(m) else: closeFid( trans_message.tid, kwargs['fid'], error= 'Failed to list shares: Unable to read from Server Service RPC endpoint' ) def rpcReadCB(read_message, **kwargs): messages_history.append(read_message) if read_message.status == 0: call_id = self._getNextRPCCallID() padding = b'' remote_name = '\\\\' + self.remote_name server_len = len(remote_name) + 1 server_bytes_len = server_len * 2 if server_len % 2 != 0: padding = b'\0\0' server_bytes_len += 2 # The data bytes are the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC. # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream data_bytes = \ binascii.unhexlify(b"""05 00 00 03 10 00 00 00""".replace(b' ', b'')) + \ struct.pack('<HHI', 72+server_bytes_len, 0, call_id) + \ binascii.unhexlify(b"""4c 00 00 00 00 00 0f 00 00 00 02 00""".replace(b' ', b'')) + \ struct.pack('<III', server_len, 0, server_len) + \ (remote_name + '\0').encode('UTF-16LE') + padding + \ binascii.unhexlify(b""" 02 00 00 00 02 00 00 00 04 00 02 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 """.replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message( SMB2IoctlRequest(kwargs['fid'], 0x0011C017, flags=0x01, max_out_size=8196, in_data=data_bytes)) m.tid = read_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest( m.mid, expiry_time, listShareResultsCB, errback, fid=kwargs['fid']) messages_history.append(m) else: closeFid( read_message.tid, kwargs['fid'], error= 'Failed to list shares: Unable to bind to Server Service RPC endpoint' ) def listShareResultsCB(result_message, **kwargs): messages_history.append(result_message) if result_message.status == 0: # The payload.data_bytes will contain the results of the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC. data_bytes = result_message.payload.out_data if data_bytes[3] & 0x02 == 0: sendReadRequest(result_message.tid, kwargs['fid'], data_bytes) else: decodeResults(result_message.tid, kwargs['fid'], data_bytes) elif result_message.status == 0x0103: # STATUS_PENDING self.pending_requests[result_message.mid] = _PendingRequest( result_message.mid, expiry_time, listShareResultsCB, errback, fid=kwargs['fid']) else: closeFid(result_message.tid, kwargs['fid']) errback( OperationFailure( 'Failed to list shares: Unable to retrieve shared device list', messages_history)) def decodeResults(tid, fid, data_bytes): shares_count = struct.unpack('<I', data_bytes[36:40])[0] results = [] # A list of SharedDevice2 instances offset = 36 + 52 # You need to study the byte stream to understand the meaning of these constants for i in range(0, shares_count): results.append( SharedDevice( struct.unpack('<I', data_bytes[offset + 4:offset + 8])[0], None, None)) offset += 12 for i in range(0, shares_count): max_length, _, length = struct.unpack( '<III', data_bytes[offset:offset + 12]) offset += 12 results[i].name = data_bytes[offset:offset + length * 2 - 2].decode('UTF-16LE') if length % 2 != 0: offset += (length * 2 + 2) else: offset += (length * 2) max_length, _, length = struct.unpack( '<III', data_bytes[offset:offset + 12]) offset += 12 results[i].comments = data_bytes[offset:offset + length * 2 - 2].decode('UTF-16LE') if length % 2 != 0: offset += (length * 2 + 2) else: offset += (length * 2) max_length, _, length = struct.unpack( '<III', data_bytes[offset:offset + 12]) offset += 12 results[i].path = data_bytes[offset:offset + length * 2 - 2].decode('UTF-16LE') if length % 2 != 0: offset += (length * 2 + 2) else: offset += (length * 2) max_length, _, length = struct.unpack( '<III', data_bytes[offset:offset + 12]) offset += 12 results[i].password = data_bytes[offset:offset + length * 2 - 2].decode('UTF-16LE') if length % 2 != 0: offset += (length * 2 + 2) else: offset += (length * 2) closeFid(tid, fid) callback(results) def sendReadRequest(tid, fid, data_bytes): read_count = min(4280, self.max_read_size) m = SMB2Message(SMB2ReadRequest(fid, 0, read_count)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest( m.mid, int(time.time()) + timeout, readCB, errback, fid=fid, data_bytes=data_bytes) def readCB(read_message, **kwargs): messages_history.append(read_message) if read_message.status == 0: data_len = read_message.payload.data_length data_bytes = read_message.payload.data if data_bytes[3] & 0x02 == 0: sendReadRequest( read_message.tid, kwargs['fid'], kwargs['data_bytes'] + data_bytes[24:data_len - 24]) else: decodeResults( read_message.tid, kwargs['fid'], kwargs['data_bytes'] + data_bytes[24:data_len - 24]) else: closeFid(read_message.tid, kwargs['fid']) errback( OperationFailure( 'Failed to list shares: Unable to retrieve shared device list', messages_history)) def closeFid(tid, fid, results=None, error=None): m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results=results, error=error) messages_history.append(m) def closeCB(close_message, **kwargs): if kwargs['results'] is not None: callback(kwargs['results']) elif kwargs['error'] is not None: errback(OperationFailure(kwargs['error'], messages_history)) if path not in self.connected_trees: def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if connect_message.status == 0: self.connected_trees[path] = connect_message.tid connectSrvSvc(connect_message.tid) else: errback( OperationFailure( 'Failed to list shares: Unable to connect to IPC$', messages_history)) m = SMB2Message( SMB2TreeConnectRequest(r'\\%s\%s' % (self.remote_name.upper(), path))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path=path) messages_history.append(m) else: connectSrvSvc(self.connected_trees[path])
def _getDfsReferral_SMB2(conn, service_name, path, callback, errback, timeout = 30): if not conn.has_authenticated: raise NotReadyError('SMB connection not authenticated') expiry_time = time.time() + timeout path = path.replace('/', '\\') if path.startswith('\\'): path = path[1:] if path.endswith('\\'): path = path[:-1] messages_history = [ ] def sendGetDfsReferral(tid): data_bytes = struct.pack('<H', 4) + path.encode('UTF-16LE') + '\x00' fid = '\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff' m = SMB2Message(SMB2IoctlRequest(fid, ctlcode = 0x00060194, # FSCTL_GET_DFS_REFERREALS flags = 0x0001, in_data = data_bytes)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, enumSnapshotsCB, errback, tid = tid, fid = '') messages_history.append(m) def closeFid(tid, fid, ret = None, error = None): m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, ret = ret, error = error) messages_history.append(m) def closeCB(close_message, **kwargs): if kwargs['ret'] is not None: callback(kwargs['ret']) elif kwargs['error'] is not None: errback(OperationFailure('Failed to retrieve %s on %s: Read failed' % ( path, service_name ), messages_history)) def enumSnapshotsCB(enum_message, **kwargs): messages_history.append(enum_message) if enum_message.status == 0: results = ref_data(enum_message.payload.out_data) closeFid(kwargs['tid'], kwargs['fid'], ret = results) else: closeFid(kwargs['tid'], kwargs['fid'], error = enum_message.status) if not conn.connected_trees.has_key(path): def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if connect_message.status == 0: conn.connected_trees[path] = connect_message.tid sendGetDfsReferral(connect_message.tid) else: errback(OperationFailure('Failed to list shares: Unable to connect to IPC$', messages_history)) m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( conn.remote_name.upper(), 'IPC$' ))) conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = path) messages_history.append(m) else: sendGetDfsReferral(conn.connected_trees[path])
def listSharesEx(self, callback, errback, timeout = 30): if not self.has_authenticated: raise NotReadyError('SMB connection not authenticated') expiry_time = time.time() + timeout path = 'IPC$' messages_history = [ ] def connectSrvSvc(tid): m = SMB2Message(SMB2CreateRequest('srvsvc', file_attributes = 0, access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_EA | FILE_WRITE_EA | READ_CONTROL | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, oplock = SMB2_OPLOCK_LEVEL_NONE, impersonation = SEC_IMPERSONATE, create_options = FILE_NON_DIRECTORY_FILE | FILE_OPEN_NO_RECALL, create_disp = FILE_OPEN)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectSrvSvcCB, errback) messages_history.append(m) def connectSrvSvcCB(create_message, **kwargs): messages_history.append(create_message) if create_message.status == 0: call_id = self._getNextRPCCallID() # The data_bytes are binding call to Server Service RPC using DCE v1.1 RPC over SMB. See [MS-SRVS] and [C706] # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream data_bytes = \ binascii.unhexlify(b"""05 00 0b 03 10 00 00 00 74 00 00 00""".replace(b' ', b'')) + \ struct.pack('<I', call_id) + \ binascii.unhexlify(b""" b8 10 b8 10 00 00 00 00 02 00 00 00 00 00 01 00 c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00 04 5d 88 8a eb 1c c9 11 9f e8 08 00 2b 10 48 60 02 00 00 00 01 00 01 00 c8 4f 32 4b 70 16 d3 01 12 78 5a 47 bf 6e e1 88 03 00 00 00 2c 1c b7 6c 12 98 40 45 03 00 00 00 00 00 00 00 01 00 00 00 """.replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message(SMB2WriteRequest(create_message.payload.fid, data_bytes, 0)) m.tid = create_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcBindCB, errback, fid = create_message.payload.fid) messages_history.append(m) else: errback(OperationFailure('Failed to list shares: Unable to locate Server Service RPC endpoint', messages_history)) def rpcBindCB(trans_message, **kwargs): messages_history.append(trans_message) if trans_message.status == 0: m = SMB2Message(SMB2ReadRequest(kwargs['fid'], read_len = 1024, read_offset = 0)) m.tid = trans_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, rpcReadCB, errback, fid = kwargs['fid']) messages_history.append(m) else: closeFid(trans_message.tid, kwargs['fid'], error = 'Failed to list shares: Unable to read from Server Service RPC endpoint') def rpcReadCB(read_message, **kwargs): messages_history.append(read_message) if read_message.status == 0: call_id = self._getNextRPCCallID() padding = b'' remote_name = '\\\\' + self.remote_name server_len = len(remote_name) + 1 server_bytes_len = server_len * 2 if server_len % 2 != 0: padding = b'\0\0' server_bytes_len += 2 # The data bytes are the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC. # If you wish to understand the meanings of the byte stream, I would suggest you use a recent version of WireShark to packet capture the stream data_bytes = \ binascii.unhexlify(b"""05 00 00 03 10 00 00 00""".replace(b' ', b'')) + \ struct.pack('<HHI', 72+server_bytes_len, 0, call_id) + \ binascii.unhexlify(b"""4c 00 00 00 00 00 0f 00 00 00 02 00""".replace(b' ', b'')) + \ struct.pack('<III', server_len, 0, server_len) + \ (remote_name + '\0').encode('UTF-16LE') + padding + \ binascii.unhexlify(b""" 02 00 00 00 02 00 00 00 04 00 02 00 00 00 00 00 00 00 00 00 ff ff ff ff 00 00 00 00 00 00 00 00 """.replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message(SMB2IoctlRequest(kwargs['fid'], 0x0011C017, flags = 0x01, max_out_size = 8196, in_data = data_bytes)) m.tid = read_message.tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, listShareResultsCB, errback, fid = kwargs['fid']) messages_history.append(m) else: closeFid(read_message.tid, kwargs['fid'], error = 'Failed to list shares: Unable to bind to Server Service RPC endpoint') def listShareResultsCB(result_message, **kwargs): messages_history.append(result_message) if result_message.status == 0: # The payload.data_bytes will contain the results of the RPC call to NetrShareEnum (Opnum 15) at Server Service RPC. data_bytes = result_message.payload.out_data if data_bytes[3] & 0x02 == 0: sendReadRequest(result_message.tid, kwargs['fid'], data_bytes) else: decodeResults(result_message.tid, kwargs['fid'], data_bytes) elif result_message.status == 0x0103: # STATUS_PENDING self.pending_requests[result_message.mid] = _PendingRequest(result_message.mid, expiry_time, listShareResultsCB, errback, fid = kwargs['fid']) else: closeFid(result_message.tid, kwargs['fid']) errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list', messages_history)) def decodeResults(tid, fid, data_bytes): shares_count = struct.unpack('<I', data_bytes[36:40])[0] results = [ ] # A list of SharedDevice2 instances offset = 36 + 52 # You need to study the byte stream to understand the meaning of these constants for i in range(0, shares_count): results.append(SharedDevice(struct.unpack('<I', data_bytes[offset+4:offset+8])[0], None, None)) offset += 12 for i in range(0, shares_count): max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12]) offset += 12 results[i].name = data_bytes[offset:offset+length*2-2].decode('UTF-16LE') if length % 2 != 0: offset += (length * 2 + 2) else: offset += (length * 2) max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12]) offset += 12 results[i].comments = data_bytes[offset:offset+length*2-2].decode('UTF-16LE') if length % 2 != 0: offset += (length * 2 + 2) else: offset += (length * 2) max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12]) offset += 12 results[i].path = data_bytes[offset:offset+length*2-2].decode('UTF-16LE') if length % 2 != 0: offset += (length * 2 + 2) else: offset += (length * 2) max_length, _, length = struct.unpack('<III', data_bytes[offset:offset+12]) offset += 12 results[i].password = data_bytes[offset:offset+length*2-2].decode('UTF-16LE') if length % 2 != 0: offset += (length * 2 + 2) else: offset += (length * 2) closeFid(tid, fid) callback(results) def sendReadRequest(tid, fid, data_bytes): read_count = min(4280, self.max_read_size) m = SMB2Message(SMB2ReadRequest(fid, 0, read_count)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, fid = fid, data_bytes = data_bytes) def readCB(read_message, **kwargs): messages_history.append(read_message) if read_message.status == 0: data_len = read_message.payload.data_length data_bytes = read_message.payload.data if data_bytes[3] & 0x02 == 0: sendReadRequest(read_message.tid, kwargs['fid'], kwargs['data_bytes'] + data_bytes[24:data_len-24]) else: decodeResults(read_message.tid, kwargs['fid'], kwargs['data_bytes'] + data_bytes[24:data_len-24]) else: closeFid(read_message.tid, kwargs['fid']) errback(OperationFailure('Failed to list shares: Unable to retrieve shared device list', messages_history)) def closeFid(tid, fid, results = None, error = None): m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results = results, error = error) messages_history.append(m) def closeCB(close_message, **kwargs): if kwargs['results'] is not None: callback(kwargs['results']) elif kwargs['error'] is not None: errback(OperationFailure(kwargs['error'], messages_history)) if path not in self.connected_trees: def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if connect_message.status == 0: self.connected_trees[path] = connect_message.tid connectSrvSvc(connect_message.tid) else: errback(OperationFailure('Failed to list shares: Unable to connect to IPC$', messages_history)) m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( self.remote_name.upper(), path ))) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = path) messages_history.append(m) else: connectSrvSvc(self.connected_trees[path])
def _listPath_SMB2( conn, service_name, path, callback, errback, search, pattern, timeout=30, limit=0, begin_at=0, ignore=None ): if not conn.has_authenticated: raise NotReadyError('SMB connection not authenticated') expiry_time = time.time() + timeout path = path.replace('/', '\\') if path.startswith('\\'): path = path[1:] if path.endswith('\\'): path = path[:-1] messages_history = [ ] results = Results() if not ignore: ignore = [] def sendCreate(tid): create_context_data = binascii.unhexlify( b"28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00 " b"44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00 " b"00 00 00 00 00 00 00 00 18 00 00 00 10 00 04 00 " b"00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00 " b"00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00 " b"51 46 69 64 00 00 00 00".replace(b' ', b'').replace(b'\n', b'')) m = SMB2Message(SMB2CreateRequest(path, file_attributes = 0, access_mask = FILE_READ_DATA | FILE_READ_EA | FILE_READ_ATTRIBUTES | SYNCHRONIZE, share_access = FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, oplock = SMB2_OPLOCK_LEVEL_NONE, impersonation = SEC_IMPERSONATE, create_options = FILE_DIRECTORY_FILE, create_disp = FILE_OPEN, create_context_data = create_context_data)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, createCB, errback) messages_history.append(m) def createCB(create_message, **kwargs): messages_history.append(create_message) if create_message.status == 0: sendQuery(create_message.tid, create_message.payload.fid, '') else: errback(OperationFailure('Failed to list %s on %s: Unable to open directory' % ( path, service_name ), messages_history)) def sendQuery(tid, fid, data_buf): m = SMB2Message(SMB2QueryDirectoryRequest(fid, pattern, info_class = 0x03, # FileBothDirectoryInformation flags = 0, output_buf_len = conn.max_transact_size)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, queryCB, errback, fid = fid, data_buf = data_buf) messages_history.append(m) def queryCB(query_message, **kwargs): messages_history.append(query_message) if query_message.status == 0: data_buf = decodeQueryStruct( kwargs['data_buf'].encode('utf-8') + query_message.payload.data, query_message.tid, kwargs['fid'] ) if data_buf is False: closeFid(query_message.tid, kwargs['fid'], results = results) else: sendQuery(query_message.tid, kwargs['fid'], data_buf) elif query_message.status == 0x80000006: # STATUS_NO_MORE_FILES closeFid(query_message.tid, kwargs['fid'], results = results) else: closeFid(query_message.tid, kwargs['fid'], error = query_message.status) def decodeQueryStruct(data_bytes, tid, fid): # SMB_FIND_FILE_BOTH_DIRECTORY_INFO structure. See [MS-CIFS]: 2.2.8.1.7 and [MS-SMB]: 2.2.8.1.1 info_format = '<IIQQQQQQIIIBB24s' info_size = struct.calcsize(info_format) data_length = len(data_bytes) offset = 0 while offset < data_length: if offset + info_size > data_length: return data_bytes[offset:] next_offset, _, \ create_time, last_access_time, last_write_time, last_attr_change_time, \ file_size, alloc_size, file_attributes, filename_length, ea_size, \ short_name_length, _, short_name = struct.unpack(info_format, data_bytes[offset:offset+info_size]) offset2 = offset + info_size if offset2 + filename_length > data_length: return data_bytes[offset:] filename = data_bytes[offset2:offset2+filename_length].decode('UTF-16LE') if filename in ignore: if next_offset: offset += next_offset continue else: break short_name = short_name.decode('UTF-16LE') if results.at >= begin_at: results.append(SharedFile(convertFILETIMEtoEpoch(create_time), convertFILETIMEtoEpoch(last_access_time), convertFILETIMEtoEpoch(last_write_time), convertFILETIMEtoEpoch(last_attr_change_time), file_size, alloc_size, file_attributes, short_name, filename)) if limit != 0 and len(results) >= limit: return False results.at += 1 if next_offset: offset += next_offset else: break return '' def closeFid(tid, fid, results = None, error = None): m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results = results, error = error) messages_history.append(m) def closeCB(close_message, **kwargs): if kwargs['results'] is not None: callback(kwargs['results']) elif kwargs['error'] is not None: errback(OperationFailure('Failed to list %s on %s: Query failed with errorcode 0x%08x' % ( path, service_name, kwargs['error'] ), messages_history)) if service_name not in conn.connected_trees: def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if connect_message.status == 0: conn.connected_trees[service_name] = connect_message.tid sendCreate(connect_message.tid) else: errback(OperationFailure('Failed to list %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( conn.remote_name.upper(), service_name ))) conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) else: sendCreate(conn.connected_trees[service_name])
def _retrieveFileFromOffset_SMB1Unix(self, service_name, path, file_obj, callback, errback, starting_offset, max_length, timeout = 30): if not self.has_authenticated: raise NotReadyError('SMB connection not authenticated') messages_history = [ ] def sendOpen(tid): m = SMBMessage(ComOpenAndxRequest(filename = path, access_mode = 0x0040, # Sharing mode: Deny nothing to others open_mode = 0x0001, # Failed if file does not exist search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM, timeout = timeout * 1000)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, openCB, errback) messages_history.append(m) def openCB(open_message, **kwargs): messages_history.append(open_message) if not open_message.status.hasError: if max_length == 0: closeFid(open_message.tid, open_message.payload.fid) callback(( file_obj, open_message.payload.file_attributes, 0 )) else: sendRead(open_message.tid, open_message.payload.fid, starting_offset, open_message.payload.file_attributes, 0, max_length) else: errback(OperationFailure('Failed to retrieve %s on %s: Unable to open file' % ( path, service_name ), messages_history)) def sendRead(tid, fid, offset, file_attributes, read_len, remaining_len): read_count = self.max_raw_size - 2 m = SMBMessage(ComReadAndxRequest(fid = fid, offset = offset, max_return_bytes_count = read_count, min_return_bytes_count = min(0xFFFF, read_count))) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, readCB, errback, fid = fid, offset = offset, file_attributes = file_attributes, read_len = read_len, remaining_len = remaining_len) def readCB(read_message, **kwargs): # To avoid crazy memory usage when retrieving large files, we do not save every read_message in messages_history. if not read_message.status.hasError: read_len = kwargs['read_len'] remaining_len = kwargs['remaining_len'] data_len = read_message.payload.data_length if max_length > 0: if data_len > remaining_len: file_obj.write(read_message.payload.data[:remaining_len]) read_len += remaining_len remaining_len = 0 else: file_obj.write(read_message.payload.data) remaining_len -= data_len read_len += data_len else: file_obj.write(read_message.payload.data) read_len += data_len if (max_length > 0 and remaining_len <= 0) or data_len < (self.max_raw_size - 2): closeFid(read_message.tid, kwargs['fid']) callback(( file_obj, kwargs['file_attributes'], read_len )) # Note that this is a tuple of 3-elements else: sendRead(read_message.tid, kwargs['fid'], kwargs['offset']+data_len, kwargs['file_attributes'], read_len, remaining_len) else: messages_history.append(read_message) closeFid(read_message.tid, kwargs['fid']) errback(OperationFailure('Failed to retrieve %s on %s: Read failed' % ( path, service_name ), messages_history)) def closeFid(tid, fid): m = SMBMessage(ComCloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) messages_history.append(m) if service_name not in self.connected_trees: def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if not connect_message.status.hasError: self.connected_trees[service_name] = connect_message.tid sendOpen(connect_message.tid) else: errback(OperationFailure('Failed to retrieve %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) messages_history.append(m) else: sendOpen(self.connected_trees[service_name])
def _storeFileFromOffset_SMB1(conn, service_name, path, file_obj, callback, errback, starting_offset, timeout = 30, **kwargs): if not conn.has_authenticated: raise NotReadyError('SMB connection not authenticated') path = path.replace('/', '\\') messages_history = [ ] def sendOpen(tid): m = SMBMessage(ComOpenAndxRequest(filename = path, access_mode = 0x0041, # Sharing mode: Deny nothing to others + Open for writing open_mode = 0x0011, # Create file if file does not exist. Overwrite if exists. search_attributes = SMB_FILE_ATTRIBUTE_HIDDEN | SMB_FILE_ATTRIBUTE_SYSTEM, timeout = timeout * 1000)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, openCB, errback) messages_history.append(m) def openCB(open_message, **kwargs): messages_history.append(open_message) if not open_message.status.hasError: sendWrite(open_message.tid, open_message.payload.fid, starting_offset) else: errback(OperationFailure('Failed to store %s on %s: Unable to open file' % ( path, service_name ), messages_history)) def sendWrite(tid, fid, offset): # For message signing, the total SMB message size must be not exceed the max_buffer_size. Non-message signing does not have this limitation write_count = min((conn.is_signing_active and (conn.max_buffer_size-64)) or conn.max_raw_size, 0xFFFF-1) # Need to minus 1 byte from 0xFFFF because of the first NULL byte in the ComWriteAndxRequest message data data_bytes = file_obj.read(write_count) data_len = len(data_bytes) if data_len > 0: m = SMBMessage(ComWriteAndxRequest(fid = fid, offset = offset, data_bytes = data_bytes)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, writeCB, errback, fid = fid, offset = offset+data_len) else: closeFid(tid, fid) callback(( file_obj, offset )) # Note that this is a tuple of 2-elements def writeCB(write_message, **kwargs): # To avoid crazy memory usage when saving large files, we do not save every write_message in messages_history. if not write_message.status.hasError: sendWrite(write_message.tid, kwargs['fid'], kwargs['offset']) else: messages_history.append(write_message) closeFid(write_message.tid, kwargs['fid']) errback(OperationFailure('Failed to store %s on %s: Write failed' % ( path, service_name ), messages_history)) def closeFid(tid, fid): m = SMBMessage(ComCloseRequest(fid)) m.tid = tid conn._sendSMBMessage(m) messages_history.append(m) if service_name not in conn.connected_trees: def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if not connect_message.status.hasError: conn.connected_trees[service_name] = connect_message.tid sendOpen(connect_message.tid) else: errback(OperationFailure('Failed to store %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( conn.remote_name.upper(), service_name ), SERVICE_ANY, '')) conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) messages_history.append(m) else: sendOpen(conn.connected_trees[service_name])
def closeFid(tid, fid, error = None, offset = None): m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback, fid = fid, offset = offset, error = error) messages_history.append(m)
def closeFid(tid, fid, results = None, error = None): m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, closeCB, errback, results = results, error = error) messages_history.append(m)
def _listPath_SMB1( self, service_name, path, callback, errback, search, pattern, timeout = 30, limit=0, begin_at=0, ignore=None ): if not self.has_authenticated: raise NotReadyError('SMB connection not authenticated') expiry_time = time.time() + timeout path = path.replace('/', '\\') if not path.endswith('\\'): path += '\\' messages_history = [ ] results = Results() if not ignore: ignore = [] def sendFindFirst(tid): setup_bytes = struct.pack('<H', 0x0001) # TRANS2_FIND_FIRST2 sub-command. See [MS-CIFS]: 2.2.6.2.1 params_bytes = \ struct.pack('<HHHHI', search, # SearchAttributes 100, # SearchCount 0x0006, # Flags: SMB_FIND_CLOSE_AT_EOS | SMB_FIND_RETURN_RESUME_KEYS 0x0104, # InfoLevel: SMB_FIND_FILE_BOTH_DIRECTORY_INFO 0x0000) # SearchStorageType params_bytes += (path + pattern).encode('UTF-16LE') m = SMBMessage(ComTransaction2Request(max_params_count = 10, max_data_count = 16644, max_setup_count = 0, params_bytes = params_bytes, setup_bytes = setup_bytes)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, findFirstCB, errback) messages_history.append(m) def decodeFindStruct(data_bytes): # SMB_FIND_FILE_BOTH_DIRECTORY_INFO structure. See [MS-CIFS]: 2.2.8.1.7 and [MS-SMB]: 2.2.8.1.1 info_format = '<IIQQQQQQIIIBB24s' info_size = struct.calcsize(info_format) data_length = len(data_bytes) offset = 0 while offset < data_length: if offset + info_size > data_length: return data_bytes[offset:] next_offset, _, \ create_time, last_access_time, last_write_time, last_attr_change_time, \ file_size, alloc_size, file_attributes, filename_length, ea_size, \ short_name_length, _, short_name = struct.unpack(info_format, data_bytes[offset:offset+info_size]) offset2 = offset + info_size if offset2 + filename_length > data_length: return data_bytes[offset:] filename = data_bytes[offset2:offset2+filename_length].decode('UTF-16LE') if filename in ignore: if next_offset: offset += next_offset continue else: break short_name = short_name.decode('UTF-16LE') shared_file = SharedFile(convertFILETIMEtoEpoch(create_time), convertFILETIMEtoEpoch(last_access_time), convertFILETIMEtoEpoch(last_write_time), convertFILETIMEtoEpoch(last_attr_change_time), file_size, alloc_size, file_attributes, short_name, filename) if results.at >= begin_at: results.append(shared_file) if limit > 0 and len(results) >= limit: return False results.at += 1 if next_offset: offset += next_offset else: break return '' def findFirstCB(find_message, **kwargs): messages_history.append(find_message) if not find_message.status.hasError: if 'total_count' not in kwargs: # TRANS2_FIND_FIRST2 response. [MS-CIFS]: 2.2.6.2.2 sid, search_count, end_of_search, _, last_name_offset = struct.unpack('<HHHHH', find_message.payload.params_bytes[:10]) kwargs.update({ 'sid': sid, 'end_of_search': end_of_search, 'last_name_offset': last_name_offset, 'data_buf': b'' }) else: sid, end_of_search, last_name_offset = kwargs['sid'], kwargs['end_of_search'], kwargs['last_name_offset'] send_next = True if find_message.payload.data_bytes: d = decodeFindStruct(kwargs['data_buf'] + find_message.payload.data_bytes) if d is False: send_next = True end_of_search = True elif 'data_count' not in kwargs: if len(find_message.payload.data_bytes) != find_message.payload.total_data_count: kwargs.update({ 'data_count': len(find_message.payload.data_bytes), 'total_count': find_message.payload.total_data_count, 'data_buf': d, }) send_next = False else: kwargs['data_count'] += len(find_message.payload.data_bytes) kwargs['total_count'] = min(find_message.payload.total_data_count, kwargs['total_count']) kwargs['data_buf'] = d if kwargs['data_count'] != kwargs['total_count']: send_next = False if not send_next: self.pending_requests[find_message.mid] = _PendingRequest(find_message.mid, expiry_time, findFirstCB, errback, **kwargs) elif end_of_search: callback(results) else: sendFindNext(find_message.tid, sid, last_name_offset) else: errback(OperationFailure('Failed to list %s on %s: Unable to retrieve file list' % ( path, service_name ), messages_history)) def sendFindNext(tid, sid, resume_key): setup_bytes = struct.pack('<H', 0x0002) # TRANS2_FIND_NEXT2 sub-command. See [MS-CIFS]: 2.2.6.3.1 params_bytes = \ struct.pack('<HHHIH', sid, # SID 100, # SearchCount 0x0104, # InfoLevel: SMB_FIND_FILE_BOTH_DIRECTORY_INFO resume_key, # ResumeKey 0x000a) # Flags: SMB_FIND_RETURN_RESUME_KEYS | SMB_FIND_CLOSE_AT_EOS | SMB_FIND_RETURN_RESUME_KEYS params_bytes += pattern.encode('UTF-16LE') m = SMBMessage(ComTransaction2Request(max_params_count = 10, max_data_count = 16644, max_setup_count = 0, params_bytes = params_bytes, setup_bytes = setup_bytes)) m.tid = tid self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, findNextCB, errback, sid = sid) messages_history.append(m) def findNextCB(find_message, **kwargs): messages_history.append(find_message) if not find_message.status.hasError: if 'total_count' not in kwargs: # TRANS2_FIND_NEXT2 response. [MS-CIFS]: 2.2.6.3.2 search_count, end_of_search, _, last_name_offset = struct.unpack('<HHHH', find_message.payload.params_bytes[:8]) kwargs.update({ 'end_of_search': end_of_search, 'last_name_offset': last_name_offset, 'data_buf': b'' }) else: end_of_search, last_name_offset = kwargs['end_of_search'], kwargs['last_name_offset'] send_next = True if find_message.payload.data_bytes: d = decodeFindStruct(kwargs['data_buf'] + find_message.payload.data_bytes) if d is False: send_next = True end_of_search = True elif 'data_count' not in kwargs: if len(find_message.payload.data_bytes) != find_message.payload.total_data_count: kwargs.update({ 'data_count': len(find_message.payload.data_bytes), 'total_count': find_message.payload.total_data_count, 'data_buf': d, }) send_next = False else: kwargs['data_count'] += len(find_message.payload.data_bytes) kwargs['total_count'] = min(find_message.payload.total_data_count, kwargs['total_count']) kwargs['data_buf'] = d if kwargs['data_count'] != kwargs['total_count']: send_next = False if not send_next: self.pending_requests[find_message.mid] = _PendingRequest(find_message.mid, expiry_time, findNextCB, errback, **kwargs) elif end_of_search: callback(results) else: sendFindNext(find_message.tid, kwargs['sid'], last_name_offset) else: errback(OperationFailure('Failed to list %s on %s: Unable to retrieve file list' % ( path, service_name ), messages_history)) if service_name not in self.connected_trees: def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if not connect_message.status.hasError: self.connected_trees[service_name] = connect_message.tid sendFindFirst(connect_message.tid) else: errback(OperationFailure('Failed to list %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) m = SMBMessage(ComTreeConnectAndxRequest(r'\\%s\%s' % ( self.remote_name.upper(), service_name ), SERVICE_ANY, '')) self._sendSMBMessage(m) self.pending_requests[m.mid] = _PendingRequest(m.mid, expiry_time, connectCB, errback, path = service_name) messages_history.append(m) else: sendFindFirst(self.connected_trees[service_name])
def _storeFileFromOffset_SMB2(conn, service_name, path, file_obj, callback, errback, starting_offset, timeout = 30, overwrite = False): if not conn.has_authenticated: raise NotReadyError('SMB connection not authenticated') path = path.replace('/', '\\') if path.startswith('\\'): path = path[1:] if path.endswith('\\'): path = path[:-1] messages_history = [ ] def sendCreate(tid): if overwrite: OVERWRITE = FILE_OVERWRITE_IF else: OVERWRITE = FILE_OPEN_IF create_context_data = binascii.unhexlify( b"28 00 00 00 10 00 04 00 00 00 18 00 10 00 00 00" b"44 48 6e 51 00 00 00 00 00 00 00 00 00 00 00 00" b"00 00 00 00 00 00 00 00 20 00 00 00 10 00 04 00" b"00 00 18 00 08 00 00 00 41 6c 53 69 00 00 00 00" b"85 62 00 00 00 00 00 00 18 00 00 00 10 00 04 00" b"00 00 18 00 00 00 00 00 4d 78 41 63 00 00 00 00" b"00 00 00 00 10 00 04 00 00 00 18 00 00 00 00 00" b"51 46 69 64 00 00 00 00".replace(b' ', b'').replace(b'\n', b'') ) m = SMB2Message(SMB2CreateRequest(path, file_attributes = ATTR_ARCHIVE, access_mask = FILE_READ_DATA | FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_READ_ATTRIBUTES | FILE_WRITE_ATTRIBUTES | FILE_READ_EA | FILE_WRITE_EA | WRITE_DAC | READ_CONTROL | SYNCHRONIZE, share_access = 0, oplock = SMB2_OPLOCK_LEVEL_NONE, impersonation = SEC_IMPERSONATE, create_options = FILE_SEQUENTIAL_ONLY | FILE_NON_DIRECTORY_FILE, create_disp = OVERWRITE, create_context_data = create_context_data)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, createCB, errback, tid = tid) messages_history.append(m) def createCB(create_message, **kwargs): messages_history.append(create_message) if create_message.status == 0: sendWrite(create_message.tid, create_message.payload.fid, starting_offset) else: errback(OperationFailure('Failed to store %s on %s: Unable to open file' % ( path, service_name ), messages_history)) def sendWrite(tid, fid, offset): write_count = conn.max_write_size data = file_obj.read(write_count) data_len = len(data) if data_len > 0: m = SMB2Message(SMB2WriteRequest(fid, data, offset)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, writeCB, errback, fid = fid, offset = offset+data_len) else: closeFid(tid, fid, offset = offset) def writeCB(write_message, **kwargs): # To avoid crazy memory usage when saving large files, we do not save every write_message in messages_history. if write_message.status == 0: sendWrite(write_message.tid, kwargs['fid'], kwargs['offset']) else: messages_history.append(write_message) closeFid(write_message.tid, kwargs['fid']) errback(OperationFailure('Failed to store %s on %s: Write failed' % ( path, service_name ), messages_history)) def closeFid(tid, fid, error = None, offset = None): m = SMB2Message(SMB2CloseRequest(fid)) m.tid = tid conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, closeCB, errback, fid = fid, offset = offset, error = error) messages_history.append(m) def closeCB(close_message, **kwargs): if kwargs['offset'] is not None: callback(( file_obj, kwargs['offset'] )) # Note that this is a tuple of 2-elements elif kwargs['error'] is not None: errback(OperationFailure('Failed to store %s on %s: Write failed' % ( path, service_name ), messages_history)) if service_name not in conn.connected_trees: def connectCB(connect_message, **kwargs): messages_history.append(connect_message) if connect_message.status == 0: conn.connected_trees[service_name] = connect_message.tid sendCreate(connect_message.tid) else: errback(OperationFailure('Failed to store %s on %s: Unable to connect to shared device' % ( path, service_name ), messages_history)) m = SMB2Message(SMB2TreeConnectRequest(r'\\%s\%s' % ( conn.remote_name.upper(), service_name ))) conn._sendSMBMessage(m) conn.pending_requests[m.mid] = _PendingRequest(m.mid, int(time.time()) + timeout, connectCB, errback, path = service_name) messages_history.append(m) else: sendCreate(conn.connected_trees[service_name])