internal void TrySendCommand(SMB2Command request) { TrySendCommand(request, m_encryptSessionData); }
private void ProcessPacket(SessionPacket packet, ref ConnectionState state) { if (packet is SessionRequestPacket && m_transport == SMBTransportType.NetBiosOverTCP) { PositiveSessionResponsePacket response = new PositiveSessionResponsePacket(); state.SendQueue.Enqueue(response); } else if (packet is SessionKeepAlivePacket && m_transport == SMBTransportType.NetBiosOverTCP) { // [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer } else if (packet is SessionMessagePacket) { // Note: To be compatible with SMB2 specifications, we must accept SMB_COM_NEGOTIATE. // We will disconnect the connection if m_enableSMB1 == false and the client does not support SMB2. bool acceptSMB1 = (state.Dialect == SMBDialect.NotSet || state.Dialect == SMBDialect.NTLM012); bool acceptSMB2 = (m_enableSMB2 && (state.Dialect == SMBDialect.NotSet || state.Dialect == SMBDialect.SMB202 || state.Dialect == SMBDialect.SMB210)); if (SMB1Header.IsValidSMB1Header(packet.Trailer)) { if (!acceptSMB1) { state.LogToServer(Severity.Verbose, "Rejected SMB1 message"); state.ClientSocket.Close(); return; } SMB1Message message = null; try { message = SMB1Message.GetSMB1Message(packet.Trailer); } catch (Exception ex) { state.LogToServer(Severity.Warning, "Invalid SMB1 message: " + ex.Message); state.ClientSocket.Close(); return; } state.LogToServer(Severity.Verbose, "SMB1 message received: {0} requests, First request: {1}, Packet length: {2}", message.Commands.Count, message.Commands[0].CommandName.ToString(), packet.Length); if (state.Dialect == SMBDialect.NotSet && m_enableSMB2) { // Check if the client supports SMB 2 List <string> smb2Dialects = SMB2.NegotiateHelper.FindSMB2Dialects(message); if (smb2Dialects.Count > 0) { SMB2Command response = SMB2.NegotiateHelper.GetNegotiateResponse(smb2Dialects, m_securityProvider, state, m_serverGuid, m_serverStartTime); if (state.Dialect != SMBDialect.NotSet) { state = new SMB2ConnectionState(state); m_connectionManager.AddConnection(state); } EnqueueResponse(state, response); return; } } if (m_enableSMB1) { ProcessSMB1Message(message, ref state); } else { // [MS-SMB2] 3.3.5.3.2 If the string is not present in the dialect list and the server does not implement SMB, // the server MUST disconnect the connection [..] without sending a response. state.LogToServer(Severity.Verbose, "Rejected SMB1 message"); state.ClientSocket.Close(); } } else if (SMB2Header.IsValidSMB2Header(packet.Trailer)) { if (!acceptSMB2) { state.LogToServer(Severity.Verbose, "Rejected SMB2 message"); state.ClientSocket.Close(); return; } List <SMB2Command> requestChain; try { requestChain = SMB2Command.ReadRequestChain(packet.Trailer, 0); } catch (Exception ex) { state.LogToServer(Severity.Warning, "Invalid SMB2 request chain: " + ex.Message); state.ClientSocket.Close(); return; } state.LogToServer(Severity.Verbose, "SMB2 request chain received: {0} requests, First request: {1}, Packet length: {2}", requestChain.Count, requestChain[0].CommandName.ToString(), packet.Length); ProcessSMB2RequestChain(requestChain, ref state); } else { state.LogToServer(Severity.Warning, "Invalid SMB message"); state.ClientSocket.Close(); } } else { state.LogToServer(Severity.Warning, "Invalid NetBIOS packet"); state.ClientSocket.Close(); return; } }
private void ProcessPacket(SessionPacket packet, ConnectionState state) { if (packet is SessionMessagePacket) { byte[] messageBytes; if (m_dialect == SMB2Dialect.SMB300 && SMB2TransformHeader.IsTransformHeader(packet.Trailer, 0)) { SMB2TransformHeader transformHeader = new SMB2TransformHeader(packet.Trailer, 0); byte[] encryptedMessage = ByteReader.ReadBytes(packet.Trailer, SMB2TransformHeader.Length, (int)transformHeader.OriginalMessageSize); messageBytes = SMB2Cryptography.DecryptMessage(m_decryptionKey, transformHeader, encryptedMessage); } else { messageBytes = packet.Trailer; } SMB2Command command; try { command = SMB2Command.ReadResponse(messageBytes, 0); } catch (Exception ex) { Log("Invalid SMB2 response: " + ex.Message); state.ClientSocket.Close(); m_isConnected = false; return; } m_availableCredits += command.Header.Credits; if (m_transport == SMBTransportType.DirectTCPTransport && command is NegotiateResponse) { NegotiateResponse negotiateResponse = (NegotiateResponse)command; if ((negotiateResponse.Capabilities & Capabilities.LargeMTU) > 0) { // [MS-SMB2] 3.2.5.1 Receiving Any Message - If the message size received exceeds Connection.MaxTransactSize, the client MUST disconnect the connection. // Note: Windows clients do not enforce the MaxTransactSize value, we add 256 bytes. int maxPacketSize = SessionPacket.HeaderLength + (int)Math.Min(negotiateResponse.MaxTransactSize, ClientMaxTransactSize) + 256; if (maxPacketSize > state.ReceiveBuffer.Buffer.Length) { state.ReceiveBuffer.IncreaseBufferSize(maxPacketSize); } } } // [MS-SMB2] 3.2.5.1.2 - If the MessageId is 0xFFFFFFFFFFFFFFFF, this is not a reply to a previous request, // and the client MUST NOT attempt to locate the request, but instead process it as follows: // If the command field in the SMB2 header is SMB2 OPLOCK_BREAK, it MUST be processed as specified in 3.2.5.19. // Otherwise, the response MUST be discarded as invalid. if (command.Header.MessageID != 0xFFFFFFFFFFFFFFFF || command.Header.Command == SMB2CommandName.OplockBreak) { lock (m_incomingQueueLock) { m_incomingQueue.Add(command); m_incomingQueueEventHandle.Set(); } } } else if ((packet is PositiveSessionResponsePacket || packet is NegativeSessionResponsePacket) && m_transport == SMBTransportType.NetBiosOverTCP) { m_sessionResponsePacket = packet; m_sessionResponseEventHandle.Set(); } else if (packet is SessionKeepAlivePacket && m_transport == SMBTransportType.NetBiosOverTCP) { // [RFC 1001] NetBIOS session keep alives do not require a response from the NetBIOS peer } else { Log("Inappropriate NetBIOS session packet"); state.ClientSocket.Close(); } }
private void TrySendCommand(SMB2Command request) { request.Header.TreeID = m_treeID; m_client.TrySendCommand(request, m_encryptShareData); }