Class: Rex::Post::Meterpreter::Extensions::Stdapi::Net::SocketSubsystem::UdpChannel

Inherits:
Channel
  • Object
show all
Includes:
Socket::Udp
Defined in:
lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb

Constant Summary

Constants included from Socket

Socket::MATCH_IPV4, Socket::MATCH_IPV4_PRIVATE, Socket::MATCH_IPV6

Instance Attribute Summary

Attributes included from Socket

#context, #ipv, #localhost, #localport, #peerhost, #peerport

Attributes inherited from Channel

#cid, #client, #cls, #flags, #params, #type

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Socket::Udp

create, create_param, #def_read_timeout, #get, #read, #sendto, #type?, #write

Methods included from Socket

addr_atoc, addr_atoi, addr_atoi_list, addr_aton, addr_ctoa, addr_itoa, addr_iton, addr_ntoa, addr_ntoi, bit2netmask, cidr_crack, compress_address, create, create_ip, create_param, create_tcp, create_tcp_server, create_udp, dotted_ip?, eth_aton, eth_ntoa, #fd, from_sockaddr, getaddress, getaddresses, gethostbyname, #getlocalname, #getpeername, #getsockname, #initsock, ipv6_link_address, ipv6_mac, is_internal?, is_ipv4?, is_ipv6?, net2bitmask, portlist_to_portspec, portspec_crack, portspec_to_portlist, resolv_nbo, resolv_nbo_i, resolv_nbo_i_list, resolv_nbo_list, resolv_to_dotted, source_address, support_ipv6?, tcp_socket_pair, to_sockaddr, #type?, udp_socket_pair

Methods inherited from Channel

_close, #_close, #_read, #close, #close_read, #close_write, create, #dio_close_handler, #dio_handler, #dio_map, #dio_read_handler, finalize, #flag?, #interactive, #read, request_handler, #synchronous?, #write

Methods included from InboundPacketHandler

#request_handler, #response_handler

Constructor Details

#initialize(client, cid, type, flags) ⇒ UdpChannel

Simply initialize this instance.


67
68
69
70
71
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 67

def initialize(client, cid, type, flags)
  super(client, cid, type, flags)
  # the instance variable that holds all incoming datagrams.
  @datagrams = []
end

Class Method Details

.clsObject


28
29
30
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 28

def cls
  return CHANNEL_CLASS_DATAGRAM
end

.open(client, params) ⇒ Object

Open a new UDP channel on the remote end. The local host/port are optional, if none are specified the remote end will bind to INADDR_ANY with a random port number. The peer host/port are also optional, if specified all default send(), write() call will sendto the specified peer. If no peer host/port is specified you must use sendto() and specify the remote peer you wish to send to. This effectivly lets us create bound/unbound and connected/unconnected UDP sockets with ease.


40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 40

def UdpChannel.open(client, params)
  c = Channel.create(client, 'stdapi_net_udp_client', self, CHANNEL_FLAG_SYNCHRONOUS,
  [
    {
      'type'  => TLV_TYPE_LOCAL_HOST,
      'value' => params.localhost
    },
    {
      'type'  => TLV_TYPE_LOCAL_PORT,
      'value' => params.localport
    },
    {
      'type'  => TLV_TYPE_PEER_HOST,
      'value' => params.peerhost
    },
    {
      'type'  => TLV_TYPE_PEER_PORT,
      'value' => params.peerport
    }
  ] )
  c.params = params
  c
end

Instance Method Details

#_write(*args) ⇒ Object

Wrap the _write() call in order to catch some common, but harmless Windows exceptions


194
195
196
197
198
199
200
201
202
203
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 194

def _write(*args)
  begin
    super(*args)
  rescue ::Rex::Post::Meterpreter::RequestError => e
    case e.code
    when 10000 .. 10100
      raise ::Rex::ConnectionError.new
    end
  end
end

#dio_write_handler(packet, data) ⇒ Object

The channels direct io write handler for any incoming data from the remote end of the channel. We extract the data and peer host/port, and save this to a queue of incoming datagrams which are passed out via calls to self.recvfrom()


178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 178

def dio_write_handler( packet, data )

  peerhost = packet.get_tlv_value( TLV_TYPE_PEER_HOST )
  peerport = packet.get_tlv_value( TLV_TYPE_PEER_PORT )

  if( peerhost and peerport )
    @datagrams << [ data, peerhost, peerport ]
    return true
  end

  return false
end

#recvfrom(length = 65535, timeout = def_read_timeout) ⇒ Object

We overwrite Rex::Socket::Udp.recvfrom in order to correctly hand out the datagrams which the remote end of this channel has received and are in the queue.


103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 103

def recvfrom( length=65535, timeout=def_read_timeout )
  result = nil
  # force a timeout on the wait for an incoming datagram
  begin
    Timeout.timeout( timeout ) {
      while( true )
        # wait untill we have at least one datagram in the queue
        if( @datagrams.empty? )
          Rex::ThreadSafe.sleep( 0.2 )
          next
        end
        # grab the oldest datagram we have received...
        result = @datagrams.shift
        # break as we have a result...
        break
      end
    }
  rescue Timeout::Error
    result = nil
  end
  # if no result return nothing
  if( result == nil )
    return [ '', nil, nil ]
  end
  # get the data from this datagram
  data = result[0]
  # if its only a partial read of this datagram, slice it, loosing the remainder.
  result[0] = data[0,length-1] if data.length > length
  # return the result in the form [ data, host, port ]
  return result
end

#send(buf, flags, saddr) ⇒ Object

This function is called by Rex::Socket::Udp.sendto and writes data to a specified remote peer host/port via the remote end of the channel.


156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 156

def send( buf, flags, saddr )
  af, peerhost, peerport = Rex::Socket.from_sockaddr( saddr )

  addends = [
    {
      'type'  => TLV_TYPE_PEER_HOST,
      'value' => peerhost
    },
    {
      'type'  => TLV_TYPE_PEER_PORT,
      'value' => peerport
    }
  ]

  return _write( buf, buf.length, addends )
end

#sysread(length) ⇒ Object

Overwrite the low level sysread to read data off our datagram queue. Calls to read() will end up calling this.


139
140
141
142
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 139

def sysread( length )
  result = self.recvfrom( length )
  return result[0]
end

#syswrite(buf) ⇒ Object

Overwrite the low level syswrite to write data to the remote end of the channel. Calls to write() will end up calling this.


148
149
150
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 148

def syswrite( buf )
  return _write( buf )
end

#timed_read(length = 65535, timeout = def_read_timeout) ⇒ Object

We overwrite Rex::Socket::Udp.timed_read in order to avoid the call to Kernel.select which wont be of use as we are not a natively backed ::Socket or ::IO instance.


77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/rex/post/meterpreter/extensions/stdapi/net/socket_subsystem/udp_channel.rb', line 77

def timed_read( length=65535, timeout=def_read_timeout )
  result = ''

  begin
    Timeout.timeout( timeout ) {
      while( true )
        if( @datagrams.empty? )
          Rex::ThreadSafe.sleep( 0.2 )
          next
        end
        result = self.read( length )
        break
      end
    }
  rescue Timeout::Error
    result = ''
  end

  return result
end