class Rex::Post::Meterpreter::Channel
The channel class represents a logical data pipe that exists between the client and the server. The purpose and behavior of the channel depends on which type it is. The three basic types of channels are streams, datagrams, and pools. Streams are basically equivalent to a TCP connection. Bidirectional, connection-oriented streams. Datagrams are basically equivalent to a UDP session. Bidirectional, connectionless. Pools are basically equivalent to a uni-directional connection, like a file handle. Pools denote channels that only have requests flowing in one direction.
Attributes
The unique channel identifier.
The associated meterpreter client instance
The class of channel (stream, datagram, pool).
Any channel-specific flag, like synchronous IO
.
Any channel-specific parameters.
The type of channel.
Public Class Methods
Closes the channel.
# File lib/rex/post/meterpreter/channel.rb, line 270 def self._close(client, cid, addends=nil) if (cid == nil) raise IOError, "Channel has been closed.", caller end request = Packet.create_request('core_channel_close') # Populate the request request.add_tlv(TLV_TYPE_CHANNEL_ID, cid) request.add_tlvs(addends) client.send_request(request, nil) # Disassociate this channel instance client.remove_channel(cid) return true end
Creates a logical channel between the client and the server based on a given type.
# File lib/rex/post/meterpreter/channel.rb, line 95 def Channel.create(client, type = nil, klass = nil, flags = CHANNEL_FLAG_SYNCHRONOUS, addends = nil) request = Packet.create_request('core_channel_open') # Set the type of channel that we're allocating if (type != nil) request.add_tlv(TLV_TYPE_CHANNEL_TYPE, type) end # If no factory class was provided, use the default native class if (klass == nil) klass = self end request.add_tlv(TLV_TYPE_CHANNEL_CLASS, klass.cls) request.add_tlv(TLV_TYPE_FLAGS, flags) request.add_tlvs(addends); # Transmit the request and wait for the response response = client.send_request(request) cid = response.get_tlv(TLV_TYPE_CHANNEL_ID).value # Create the channel instance channel = klass.new(client, cid, type, flags) return channel end
# File lib/rex/post/meterpreter/channel.rb, line 146 def self.finalize(client,cid) proc { self._close(client,cid) } end
Initializes the instance’s attributes, such as client context, class identifier, type, and flags.
# File lib/rex/post/meterpreter/channel.rb, line 133 def initialize(client, cid, type, flags) self.client = client self.cid = cid self.type = type self.flags = flags # Add this instance to the list if (cid and client) client.add_channel(self) end ObjectSpace.define_finalizer( self, self.class.finalize(self.client, self.cid) ) end
Class request handler for all channels that dispatches requests to the appropriate class instance’s DIO handler
# File lib/rex/post/meterpreter/channel.rb, line 55 def request_handler(client, packet) cid = packet.get_tlv_value(TLV_TYPE_CHANNEL_ID) # No channel identifier, then drop it if (cid == nil) return false end channel = client.find_channel(cid) # No valid channel context? The channel may not be registered yet if (channel == nil) return false end dio = channel.dio_map(packet.method) # Supported DIO request? Dump it. if (dio == nil) return true end # Call the channel's dio handler and return success or fail # based on what happens channel.dio_handler(dio, packet) end
Public Instance Methods
# File lib/rex/post/meterpreter/channel.rb, line 289 def _close(addends = nil) self.class._close(self.client, self.cid, addends) self.cid = nil end
Reads data from the remote half of the channel.
# File lib/rex/post/meterpreter/channel.rb, line 166 def _read(length = nil, addends = nil) if (self.cid == nil) raise IOError, "Channel has been closed.", caller end request = Packet.create_request('core_channel_read') if (length == nil) # Default block size to a higher amount for passive dispatcher length = self.client.passive_service ? (1024*1024) : 65536 end request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid) request.add_tlv(TLV_TYPE_LENGTH, length) request.add_tlvs(addends) begin response = self.client.send_request(request) rescue return nil end # If the channel is in synchronous mode, the response should contain # data that was read from the remote side of the channel if (flag?(CHANNEL_FLAG_SYNCHRONOUS)) data = response.get_tlv(TLV_TYPE_CHANNEL_DATA); if (data != nil) return data.value end else raise NotImplementedError, "Asynchronous channel mode is not implemented", caller end return nil end
Writes data to the remote half of the channel.
# File lib/rex/post/meterpreter/channel.rb, line 213 def _write(buf, length = nil, addends = nil) if (self.cid == nil) raise IOError, "Channel has been closed.", caller end request = Packet.create_request('core_channel_write') # Truncation and celebration if ((length != nil) && (buf.length >= length)) buf = buf[0..length] else length = buf.length end # Populate the request request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid) cdata = request.add_tlv(TLV_TYPE_CHANNEL_DATA, buf) if( ( self.flags & CHANNEL_FLAG_COMPRESS ) == CHANNEL_FLAG_COMPRESS ) cdata.compress = true end request.add_tlv(TLV_TYPE_LENGTH, length) request.add_tlvs(addends) response = self.client.send_request(request) written = response.get_tlv(TLV_TYPE_LENGTH) return (written == nil) ? 0 : written.value end
Wrapper around the low-level close.
# File lib/rex/post/meterpreter/channel.rb, line 249 def close(addends = nil) return _close(addends) end
Close the channel for future reads.
# File lib/rex/post/meterpreter/channel.rb, line 263 def close_read return _close end
Close the channel for future writes.
# File lib/rex/post/meterpreter/channel.rb, line 256 def close_write return _close end
Stub close handler.
# File lib/rex/post/meterpreter/channel.rb, line 355 def dio_close_handler(packet) client.remove_channel(self.cid) # Trap IOErrors as parts of the channel may have already been closed begin self.cleanup rescue IOError end # No more channel action, foo. self.cid = nil return true end
Handles dispatching I/O requests based on the request packet. The default implementation does nothing with direct I/O requests.
# File lib/rex/post/meterpreter/channel.rb, line 323 def dio_handler(dio, packet) if (dio == CHANNEL_DIO_READ) length = packet.get_tlv_value(TLV_TYPE_LENGTH) return dio_read_handler(packet, length) elsif (dio == CHANNEL_DIO_WRITE) data = packet.get_tlv_value(TLV_TYPE_CHANNEL_DATA) return dio_write_handler(packet, data) elsif (dio == CHANNEL_DIO_CLOSE) return dio_close_handler(packet) end return false; end
Maps packet request methods to DIO request identifiers on a per-instance basis as other instances may add custom dio handlers.
# File lib/rex/post/meterpreter/channel.rb, line 375 def dio_map(method) if (method == 'core_channel_read') return CHANNEL_DIO_READ elsif (method == 'core_channel_write') return CHANNEL_DIO_WRITE elsif (method == 'core_channel_close') return CHANNEL_DIO_CLOSE end return nil end
Stub read handler.
# File lib/rex/post/meterpreter/channel.rb, line 341 def dio_read_handler(packet, length) return true end
Stub write handler.
# File lib/rex/post/meterpreter/channel.rb, line 348 def dio_write_handler(packet, data) return true end
Checks to see if a flag is set on the instance’s flags attribute.
# File lib/rex/post/meterpreter/channel.rb, line 396 def flag?(flag) return ((self.flags & flag) == flag) end
Enables or disables interactive mode.
# File lib/rex/post/meterpreter/channel.rb, line 296 def interactive(tf = true, addends = nil) if (self.cid == nil) raise IOError, "Channel has been closed.", caller end request = Packet.create_request('core_channel_interact') # Populate the request request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid) request.add_tlv(TLV_TYPE_BOOL, tf) request.add_tlvs(addends) self.client.send_request(request) return true end
Wrapper around the low-level channel read operation.
# File lib/rex/post/meterpreter/channel.rb, line 159 def read(length = nil, addends = nil) return _read(length, addends) end
Returns whether or not the channel is operating synchronously.
# File lib/rex/post/meterpreter/channel.rb, line 403 def synchronous? return (self.flags & CHANNEL_FLAG_SYNCHRONOUS) end
Wrapper around the low-level write.
# File lib/rex/post/meterpreter/channel.rb, line 206 def write(buf, length = nil, addends = nil) return _write(buf, length, addends) end
Protected Instance Methods
Cleans up any lingering resources
# File lib/rex/post/meterpreter/channel.rb, line 439 def cleanup end