class Rex::Post::Meterpreter::Tlv

Base TLV (Type-Length-Value) class

Attributes

compress[RW]
type[RW]
value[RW]

Public Class Methods

new(type, value = nil, compress=false) click to toggle source

Returns an instance of a TLV.

# File lib/rex/post/meterpreter/packet.rb, line 133
def initialize(type, value = nil, compress=false)
  @type     = type
  @compress = compress

  if (value != nil)
    if (type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
      if (value.kind_of?(Fixnum))
        @value = value.to_s
      else
        @value = value.dup
      end
    else
      @value = value
    end
  end
end

Public Instance Methods

from_r(raw) click to toggle source

Translates the raw format of the TLV into a sanitize version.

# File lib/rex/post/meterpreter/packet.rb, line 317
def from_r(raw)
  self.value  = nil

  length, self.type = raw.unpack("NN");

  # check if the tlv value has been compressed...
  if( self.type & TLV_META_TYPE_COMPRESSED == TLV_META_TYPE_COMPRESSED )
    # set this TLV as using compression
    @compress = true
    # remove the TLV_META_TYPE_COMPRESSED flag from the tlv type to restore the
    # tlv type to its origional, allowing for transparent data compression.
    self.type = self.type ^ TLV_META_TYPE_COMPRESSED
    # decompress the compressed data (skipping the length and type DWORD's)
    raw_decompressed = Rex::Text.zlib_inflate( raw[8..length-1] )
    # update the length to reflect the decompressed data length (+8 for the length and type DWORD's)
    length = raw_decompressed.length + 8
    # update the raw buffer with the new length, decompressed data and updated type.
    raw = [length, self.type].pack("NN") + raw_decompressed
  end

  if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
    if (raw.length > 0)
      self.value = raw[8..length-2]
    else
      self.value = nil
    end
  elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
    self.value = raw.unpack("NNN")[2]
  elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
    self.value = raw.unpack("NNQ<")[2]
    self.value = self.ntohq( self.value )
  elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
    self.value = raw.unpack("NNc")[2]

    if (self.value == 1)
      self.value = true
    else
      self.value = false
    end
  else
    self.value = raw[8..length-1]
  end

  return length;
end
inspect() click to toggle source
# File lib/rex/post/meterpreter/packet.rb, line 150
def inspect
  utype = type ^ TLV_META_TYPE_COMPRESSED
  group = false
  meta = case (utype & TLV_META_MASK)
    when TLV_META_TYPE_STRING; "STRING"
    when TLV_META_TYPE_UINT; "INT"
    when TLV_META_TYPE_RAW; "RAW"
    when TLV_META_TYPE_BOOL; "BOOL"
    when TLV_META_TYPE_QWORD; "QWORD"
    when TLV_META_TYPE_GROUP; group=true; "GROUP"
    when TLV_META_TYPE_COMPLEX; "COMPLEX"
    else; 'unknown-meta-type'
    end
  stype = case type
    when PACKET_TYPE_REQUEST; "Request"
    when PACKET_TYPE_RESPONSE; "Response"
    when TLV_TYPE_REQUEST_ID; "REQUEST-ID"
    when TLV_TYPE_METHOD; "METHOD"
    when TLV_TYPE_RESULT; "RESULT"
    when TLV_TYPE_EXCEPTION; "EXCEPTION"
    when TLV_TYPE_STRING; "STRING"
    when TLV_TYPE_UINT; "UINT"
    when TLV_TYPE_BOOL; "BOOL"

    when TLV_TYPE_LENGTH; "LENGTH"
    when TLV_TYPE_DATA; "DATA"
    when TLV_TYPE_FLAGS; "FLAGS"

    when TLV_TYPE_CHANNEL_ID; "CHANNEL-ID"
    when TLV_TYPE_CHANNEL_TYPE; "CHANNEL-TYPE"
    when TLV_TYPE_CHANNEL_DATA; "CHANNEL-DATA"
    when TLV_TYPE_CHANNEL_DATA_GROUP; "CHANNEL-DATA-GROUP"
    when TLV_TYPE_CHANNEL_CLASS; "CHANNEL-CLASS"
    when TLV_TYPE_CHANNEL_PARENTID; "CHANNEL-PARENTID"

    when TLV_TYPE_SEEK_WHENCE; "SEEK-WHENCE"
    when TLV_TYPE_SEEK_OFFSET; "SEEK-OFFSET"
    when TLV_TYPE_SEEK_POS; "SEEK-POS"

    when TLV_TYPE_EXCEPTION_CODE; "EXCEPTION-CODE"
    when TLV_TYPE_EXCEPTION_STRING; "EXCEPTION-STRING"

    when TLV_TYPE_LIBRARY_PATH; "LIBRARY-PATH"
    when TLV_TYPE_TARGET_PATH; "TARGET-PATH"
    when TLV_TYPE_MIGRATE_PID; "MIGRATE-PID"
    when TLV_TYPE_MIGRATE_LEN; "MIGRATE-LEN"
    when TLV_TYPE_MIGRATE_PAYLOAD; "MIGRATE-PAYLOAD"
    when TLV_TYPE_MIGRATE_ARCH; "MIGRATE-ARCH"
    when TLV_TYPE_TRANS_TYPE; "TRANS-TYPE"
    when TLV_TYPE_TRANS_URL; "TRANS-URL"
    when TLV_TYPE_TRANS_COMM_TIMEOUT; "TRANS-COMM-TIMEOUT"
    when TLV_TYPE_TRANS_SESSION_EXP; "TRANS-SESSION-EXP"
    when TLV_TYPE_TRANS_CERT_HASH; "TRANS-CERT-HASH"
    when TLV_TYPE_TRANS_PROXY_HOST; "TRANS-PROXY-HOST"
    when TLV_TYPE_TRANS_PROXY_USER; "TRANS-PROXY-USER"
    when TLV_TYPE_TRANS_PROXY_PASS; "TRANS-PROXY-PASS"
    when TLV_TYPE_TRANS_RETRY_TOTAL; "TRANS-RETRY-TOTAL"
    when TLV_TYPE_TRANS_RETRY_WAIT; "TRANS-RETRY-WAIT"
    when TLV_TYPE_MACHINE_ID; "MACHINE-ID"
    when TLV_TYPE_UUID; "UUID"

    #when Extensions::Stdapi::TLV_TYPE_NETWORK_INTERFACE; 'network-interface'
    #when Extensions::Stdapi::TLV_TYPE_IP; 'ip-address'
    #when Extensions::Stdapi::TLV_TYPE_NETMASK; 'netmask'
    #when Extensions::Stdapi::TLV_TYPE_MAC_ADDRESS; 'mac-address'
    #when Extensions::Stdapi::TLV_TYPE_MAC_NAME; 'interface-name'
    #when Extensions::Stdapi::TLV_TYPE_IP6_SCOPE; 'address-scope'
    #when Extensions::Stdapi::TLV_TYPE_INTERFACE_MTU; 'interface-mtu'
    #when Extensions::Stdapi::TLV_TYPE_INTERFACE_FLAGS; 'interface-flags'
    #when Extensions::Stdapi::TLV_TYPE_INTERFACE_INDEX; 'interface-index'

    else; "unknown-#{type}"
    end
  val = value.inspect
  if val.length > 50
    val = val[0,50] + ' ..."'
  end
  group ||= (self.class.to_s =~ /Packet/)
  if group
    tlvs_inspect = "tlvs=[\n"
    @tlvs.each { |t|
      tlvs_inspect << "  #{t.inspect}\n"
    }
    tlvs_inspect << "]"
  else
    tlvs_inspect = "meta=#{meta.ljust 10} value=#{val}"
  end
  "#<#{self.class} type=#{stype.ljust 15} #{tlvs_inspect}>"
end
meta_type?(meta) click to toggle source

Checks to see if a TLVs meta type is equivalent to the meta type passed.

# File lib/rex/post/meterpreter/packet.rb, line 249
def meta_type?(meta)
  return (self.type & meta == meta)
end
to_r() click to toggle source

Converts the TLV to raw.

# File lib/rex/post/meterpreter/packet.rb, line 276
def to_r
  # Forcibly convert to ASCII-8BIT encoding
  raw = value.to_s.unpack("C*").pack("C*")

  if (self.type & TLV_META_TYPE_STRING == TLV_META_TYPE_STRING)
    raw += "\x00"
  elsif (self.type & TLV_META_TYPE_UINT == TLV_META_TYPE_UINT)
    raw = [value].pack("N")
  elsif (self.type & TLV_META_TYPE_QWORD == TLV_META_TYPE_QWORD)
    raw = [ self.htonq( value.to_i ) ].pack("Q<")
  elsif (self.type & TLV_META_TYPE_BOOL == TLV_META_TYPE_BOOL)
    if (value == true)
      raw = [1].pack("c")
    else
      raw = [0].pack("c")
    end
  end

  # check if the tlv is to be compressed...
  if( @compress )
    raw_uncompressed = raw
    # compress the raw data
    raw_compressed = Rex::Text.zlib_deflate( raw_uncompressed )
    # check we have actually made the raw data smaller...
    # (small blobs often compress slightly larger then the origional)
    # if the compressed data is not smaller, we dont use the compressed data
    if( raw_compressed.length < raw_uncompressed.length )
      # if so, set the TLV's type to indicate compression is used
      self.type = self.type | TLV_META_TYPE_COMPRESSED
      # update the raw data with the uncompressed data length + compressed data
      # (we include the uncompressed data length as the C side will need to know this for decompression)
      raw = [ raw_uncompressed.length ].pack("N") + raw_compressed
    end
  end

  return [raw.length + 8, self.type].pack("NN") + raw
end
type?(type) click to toggle source

Checks to see if the TLVs type is equivalent to the type passed.

# File lib/rex/post/meterpreter/packet.rb, line 256
def type?(type)
  return self.type == type
end
value?(value) click to toggle source

Checks to see if the TLVs value is equivalent to the value passed.

# File lib/rex/post/meterpreter/packet.rb, line 263
def value?(value)
  return self.value == value
end

Protected Instance Methods

htonq( value ) click to toggle source
# File lib/rex/post/meterpreter/packet.rb, line 365
def htonq( value )
  if( [1].pack( 's' ) == [1].pack( 'n' ) )
    return value
  end
  return [ value ].pack( 'Q<' ).reverse.unpack( 'Q<' ).first
end
ntohq( value ) click to toggle source
# File lib/rex/post/meterpreter/packet.rb, line 372
def ntohq( value )
  return htonq( value )
end