#!/usr/bin/ruby require 'rex/post/meterpreter/inbound_packet_handler' module Rex module Post module Meterpreter # # The various types of channels # CHANNEL_CLASS_STREAM = 1 CHANNEL_CLASS_DATAGRAM = 2 CHANNEL_CLASS_POOL = 3 # # The various flags that can affect how the channel operates # # CHANNEL_FLAG_SYNCHRONOUS # Specifies that I/O requests on the channel are blocking. # CHANNEL_FLAG_SYNCHRONOUS = (1 << 0) # # The core types of direct I/O requests # CHANNEL_DIO_READ = 'read' CHANNEL_DIO_WRITE = 'write' CHANNEL_DIO_CLOSE = 'close' class Channel # Class modifications to support global channel message # dispatching without having to register a per-instance handler class <= length)) buf = buf[0..length] else length = buf.length end # Populate the request request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid) request.add_tlv(TLV_TYPE_CHANNEL_DATA, buf) 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 def close(addends = nil) return _close(addends) end # Close the channel for future writes def close_write return _close end # Close the channel for future reads def close_read return _close end # Closes the channel def _close(addends = nil) if (self.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, self.cid) request.add_tlvs(addends) self.client.send_request(request) # Disassociate this channel instance self.client.remove_channel(self.cid) self.cid = nil return true end # # Enables or disables interactive mode # 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 ## # # Direct I/O # ## # Handles dispatching I/O requests based on the request packet. # The default implementation does nothing with direct I/O requests. 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 # Stub read handler def dio_read_handler(packet, length) return false end # Stub write handler def dio_write_handler(packet, data) return false end # Stub close handler def dio_close_handler(packet) client.remove_channel(self) # 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 false end # Maps packet request methods to DIO request identifiers on a # per-instance basis as other instances may add custom dio # handlers. 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 ## # # Conditionals # ## # Checks to see if a flag is set on the instance's flags attribute def flag?(flag) return ((self.flags & flag) == flag) end # Returns whether or not the channel is operating synchronously def synchronous? return (self.flags & CHANNEL_FLAG_SYNCHRONOUS) end attr_reader :cid, :type, :cls, :flags protected attr_accessor :client attr_writer :cid, :type, :cls, :flags # # Cleans up any lingering resources # def cleanup end end end; end; end