async def __handle_smb_in(self): """ Waits from SMB messages from the NetBIOSTransport in_queue, and fills the connection table. This function started automatically when calling connect. """ while not self.shutdown_evt.is_set(): msg = await self.netbios_transport.in_queue.get() logger.log( 1, '__handle_smb_in got new message with Id %s' % msg.header.MessageId) if isinstance(msg, SMB2Transform): #message is encrypted #this point we should decrypt it and only store the decrypted part in the OutstandingResponses table #but for now we just thropw exception bc encryption is not implemented raise Exception( 'Encrypted SMBv2 message recieved, but encryption is not yet supported!' ) self.OutstandingResponses[msg.header.MessageId] = msg if msg.header.MessageId in self.OutstandingResponsesEvent: self.OutstandingResponsesEvent[msg.header.MessageId].set() else: #here we are loosing messages, the functionality for "PENDING" and "SHARING_VIOLATION" should be written continue
async def __handle_smb_in(self): """ Waits from SMB messages from the NetBIOSTransport in_queue, and fills the connection table. This function started automatically when calling connect. """ try: while True: msg, err = await self.netbios_transport.in_queue.get() self.activity_at = datetime.datetime.utcnow() if err is not None: logger.error( '__handle_smb_in got error from transport layer %s' % err) #setting all outstanding events to finished for mid in self.OutstandingResponsesEvent: self.OutstandingResponses[mid] = None self.OutstandingResponsesEvent[mid].set() await self.terminate() return logger.log( 1, '__handle_smb_in got new message with Id %s' % msg.header.MessageId) if isinstance(msg, SMB2Transform): #message is encrypted #this point we should decrypt it and only store the decrypted part in the OutstandingResponses table #but for now we just thropw exception bc encryption is not implemented raise Exception( 'Encrypted SMBv2 message recieved, but encryption is not yet supported!' ) if msg.header.Status == NTStatus.PENDING: self.pending_table[msg.header.MessageId] = SMBPendingMsg( msg.header.MessageId, self.OutstandingResponses, self.OutstandingResponsesEvent) await self.pending_table[msg.header.MessageId].run() continue if msg.header.MessageId in self.pending_table: await self.pending_table[msg.header.MessageId].stop() del self.pending_table[msg.header.MessageId] self.OutstandingResponses[msg.header.MessageId] = msg if msg.header.MessageId in self.OutstandingResponsesEvent: self.OutstandingResponsesEvent[msg.header.MessageId].set() else: #here we are loosing messages, the functionality for "PENDING" and "SHARING_VIOLATION" should be implemented continue except asyncio.CancelledError: #the SMB connection is terminating return except: logger.exception('__handle_smb_in')
async def recvSMB(self, message_id): """ Returns an SMB message from the outstandingresponse dict, OR waits until the expected message_id appears. """ if message_id not in self.OutstandingResponses: logger.log(1, 'Waiting on messageID : %s' % message_id) await self.OutstandingResponsesEvent[message_id].wait() msg = self.OutstandingResponses.pop(message_id) if msg.header.Status != NTStatus.PENDING: if message_id in self.OutstandingResponsesEvent: del self.OutstandingResponsesEvent[message_id] else: self.OutstandingResponsesEvent[message_id].clear() return msg
async def negotiate(self): """ Initiates protocol negotiation. First we send an SMB_COM_NEGOTIATE_REQ with our supported dialects """ #let's construct an SMBv1 SMB_COM_NEGOTIATE_REQ packet header = SMBHeader() header.Command = SMBCommand.SMB_COM_NEGOTIATE header.Status = NTStatus.SUCCESS header.Flags = 0 header.Flags2 = SMBHeaderFlags2Enum.SMB_FLAGS2_UNICODE command = SMB_COM_NEGOTIATE_REQ() command.Dialects = ['SMB 2.???'] msg = SMBMessage(header, command) message_id = await self.sendSMB(msg) #recieveing reply, should be version2, because currently we dont support v1 :( rply = await self.recvSMB(message_id) #negotiate MessageId should be 1 if rply.header.Status == NTStatus.SUCCESS: if isinstance(rply, SMB2Message): if rply.command.DialectRevision == NegotiateDialects.WILDCARD: command = NEGOTIATE_REQ() command.SecurityMode = NegotiateSecurityMode.SMB2_NEGOTIATE_SIGNING_ENABLED | NegotiateSecurityMode.SMB2_NEGOTIATE_SIGNING_REQUIRED command.Capabilities = 0 command.ClientGuid = self.ClientGUID command.Dialects = self.dialects header = SMB2Header_SYNC() header.Command = SMB2Command.NEGOTIATE header.CreditReq = 0 msg = SMB2Message(header, command) message_id = await self.sendSMB(msg) rply = await self.recvSMB( message_id) #negotiate MessageId should be 1 if rply.header.Status != NTStatus.SUCCESS: print('session got reply!') print(rply) raise Exception( 'session_setup_1 (authentication probably failed) reply: %s' % rply.header.Status) if rply.command.DialectRevision not in self.supported_dialects: raise SMBUnsupportedDialectSelected() self.selected_dialect = rply.command.DialectRevision self.signing_required = NegotiateSecurityMode.SMB2_NEGOTIATE_SIGNING_ENABLED in rply.command.SecurityMode logger.log( 1, 'Server selected dialect: %s' % self.selected_dialect) self.MaxTransactSize = min(0x100000, rply.command.MaxTransactSize) self.MaxReadSize = min(0x100000, rply.command.MaxReadSize) self.MaxWriteSize = min(0x100000, rply.command.MaxWriteSize) self.ServerGuid = rply.command.ServerGuid self.SupportsMultiChannel = NegotiateCapabilities.MULTI_CHANNEL in rply.command.Capabilities else: logger.error( 'Server choose SMB v1 which is not supported currently') raise SMBUnsupportedSMBVersion() else: print('session got reply!') print(rply) raise Exception( 'session_setup_1 (authentication probably failed) reply: %s' % rply.header.Status) self.status = SMBConnectionStatus.SESSIONSETUP