CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/post/meterpreter/channel.rb
Views: 1904
1
# -*- coding: binary -*-
2
3
require 'rex/post/meterpreter/inbound_packet_handler'
4
5
module Rex
6
module Post
7
module Meterpreter
8
9
#
10
# The various types of channels
11
#
12
CHANNEL_CLASS_STREAM = 1
13
CHANNEL_CLASS_DATAGRAM = 2
14
CHANNEL_CLASS_POOL = 3
15
16
#
17
# The various flags that can affect how the channel operates
18
#
19
# CHANNEL_FLAG_SYNCHRONOUS
20
# Specifies that I/O requests on the channel are blocking.
21
#
22
# CHANNEL_FLAG_COMPRESS
23
# Specifies that I/O requests on the channel have their data zlib compressed.
24
#
25
CHANNEL_FLAG_SYNCHRONOUS = (1 << 0)
26
CHANNEL_FLAG_COMPRESS = (1 << 1)
27
28
#
29
# The core types of direct I/O requests
30
#
31
CHANNEL_DIO_READ = 'read'
32
CHANNEL_DIO_WRITE = 'write'
33
CHANNEL_DIO_CLOSE = 'close'
34
35
###
36
#
37
# The channel class represents a logical data pipe that exists between the
38
# client and the server. The purpose and behavior of the channel depends on
39
# which type it is. The three basic types of channels are streams, datagrams,
40
# and pools. Streams are basically equivalent to a TCP connection.
41
# Bidirectional, connection-oriented streams. Datagrams are basically
42
# equivalent to a UDP session. Bidirectional, connectionless. Pools are
43
# basically equivalent to a uni-directional connection, like a file handle.
44
# Pools denote channels that only have requests flowing in one direction.
45
#
46
###
47
class Channel
48
# Class modifications to support global channel message
49
# dispatching without having to register a per-instance handler
50
class << self
51
include Rex::Post::Meterpreter::InboundPacketHandler
52
53
# Class request handler for all channels that dispatches requests
54
# to the appropriate class instance's DIO handler
55
def request_handler(client, packet)
56
cid = packet.get_tlv_value(TLV_TYPE_CHANNEL_ID)
57
58
# No channel identifier, then drop it
59
if cid.nil?
60
return false
61
end
62
63
channel = client.find_channel(cid)
64
65
# No valid channel context? The channel may not be registered yet
66
if channel.nil?
67
return false
68
end
69
70
71
dio = channel.dio_map(packet.method)
72
73
# Supported DIO request? Dump it.
74
if dio.nil?
75
return true
76
end
77
78
79
# Call the channel's dio handler and return success or fail
80
# based on what happens
81
channel.dio_handler(dio, packet)
82
end
83
end
84
85
##
86
#
87
# Factory
88
#
89
##
90
91
#
92
# Creates a logical channel between the client and the server
93
# based on a given type.
94
#
95
def Channel.create(client, type = nil, klass = nil,
96
flags = CHANNEL_FLAG_SYNCHRONOUS, addends = nil, **klass_kwargs)
97
request = Packet.create_request(COMMAND_ID_CORE_CHANNEL_OPEN)
98
99
# Set the type of channel that we're allocating
100
if !type.nil?
101
request.add_tlv(TLV_TYPE_CHANNEL_TYPE, type)
102
end
103
104
# If no factory class was provided, use the default native class
105
if klass.nil?
106
klass = self
107
end
108
109
request.add_tlv(TLV_TYPE_CHANNEL_CLASS, klass.cls)
110
request.add_tlv(TLV_TYPE_FLAGS, flags)
111
request.add_tlvs(addends)
112
113
# Transmit the request and wait for the response
114
cid = nil
115
begin
116
response = client.send_request(request)
117
cid = response.get_tlv_value(TLV_TYPE_CHANNEL_ID)
118
if cid.nil?
119
raise Rex::Post::Meterpreter::RequestError
120
end
121
end
122
123
# Create the channel instance
124
klass.new(client, cid, type, flags, response, **klass_kwargs)
125
end
126
127
##
128
#
129
# Constructor
130
#
131
##
132
133
#
134
# Initializes the instance's attributes, such as client context,
135
# class identifier, type, and flags.
136
#
137
def initialize(client, cid, type, flags, packet, **_)
138
self.client = client
139
self.cid = cid
140
self.type = type
141
self.flags = flags
142
@mutex = Mutex.new
143
144
# Add this instance to the list
145
if (cid and client)
146
client.add_channel(self)
147
end
148
149
# Ensure the remote object is closed when all references are removed
150
ObjectSpace.define_finalizer(self, self.class.finalize(client, cid))
151
end
152
153
def self.finalize(client, cid)
154
proc {
155
unless cid.nil?
156
deferred_close_proc = proc do
157
begin
158
self._close(client, cid)
159
rescue => e
160
elog("finalize method for Channel failed", error: e)
161
end
162
end
163
164
# Schedule the finalizing logic out-of-band; as this logic might be called in the context of a Signal.trap, which can't synchronize mutexes
165
client.framework.sessions.schedule(deferred_close_proc)
166
end
167
}
168
end
169
170
171
##
172
#
173
# Channel interaction
174
#
175
##
176
177
#
178
# Wrapper around the low-level channel read operation.
179
#
180
def read(length = nil, addends = nil)
181
return _read(length, addends)
182
end
183
184
#
185
# Reads data from the remote half of the channel.
186
#
187
def _read(length = nil, addends = nil)
188
if self.cid.nil?
189
raise IOError, "Channel has been closed.", caller
190
end
191
192
request = Packet.create_request(COMMAND_ID_CORE_CHANNEL_READ)
193
194
if length.nil?
195
# Default block size to a higher amount for passive dispatcher
196
length = self.client.passive_service ? (1024*1024) : 65536
197
end
198
199
request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid)
200
request.add_tlv(TLV_TYPE_LENGTH, length)
201
request.add_tlvs(addends)
202
203
begin
204
response = self.client.send_request(request)
205
rescue
206
return nil
207
end
208
209
# If the channel is in synchronous mode, the response should contain
210
# data that was read from the remote side of the channel
211
if (flag?(CHANNEL_FLAG_SYNCHRONOUS))
212
data = response.get_tlv(TLV_TYPE_CHANNEL_DATA);
213
214
if (data != nil)
215
return data.value
216
end
217
else
218
raise NotImplementedError, "Asynchronous channel mode is not implemented", caller
219
end
220
221
return nil
222
end
223
224
#
225
# Wrapper around the low-level write.
226
#
227
def write(buf, length = nil, addends = nil)
228
return _write(buf, length, addends)
229
end
230
231
#
232
# Writes data to the remote half of the channel.
233
#
234
def _write(buf, length = nil, addends = nil)
235
if self.cid.nil?
236
raise IOError, "Channel has been closed.", caller
237
end
238
239
request = Packet.create_request(COMMAND_ID_CORE_CHANNEL_WRITE)
240
241
# Truncation and celebration
242
if ((length != nil) &&
243
(buf.length >= length))
244
buf = buf[0..length]
245
else
246
length = buf.length
247
end
248
249
# Populate the request
250
request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid)
251
252
cdata = request.add_tlv(TLV_TYPE_CHANNEL_DATA, buf)
253
if( ( self.flags & CHANNEL_FLAG_COMPRESS ) == CHANNEL_FLAG_COMPRESS )
254
cdata.compress = true
255
end
256
257
request.add_tlv(TLV_TYPE_LENGTH, length)
258
request.add_tlvs(addends)
259
260
response = self.client.send_request(request)
261
written = response.get_tlv(TLV_TYPE_LENGTH)
262
263
written.nil? ? 0 : written.value
264
end
265
266
#
267
# Wrapper around check for self.cid
268
#
269
def closed?
270
self.cid.nil?
271
end
272
273
#
274
# Wrapper around the low-level close.
275
#
276
def close(addends = nil)
277
return _close(addends)
278
end
279
280
#
281
# Close the channel for future writes.
282
#
283
def close_write
284
return _close
285
end
286
287
#
288
# Close the channel for future reads.
289
#
290
def close_read
291
return _close
292
end
293
294
#
295
# Closes the channel.
296
#
297
def self._close(client, cid, addends=nil)
298
if cid.nil?
299
raise IOError, "Channel has been closed.", caller
300
end
301
302
request = Packet.create_request(COMMAND_ID_CORE_CHANNEL_CLOSE)
303
304
# Populate the request
305
request.add_tlv(TLV_TYPE_CHANNEL_ID, cid)
306
request.add_tlvs(addends)
307
308
client.send_request(request, nil)
309
310
# Disassociate this channel instance
311
client.remove_channel(cid)
312
313
return true
314
end
315
316
def _close(addends = nil)
317
# let the finalizer do the work behind the scenes
318
@mutex.synchronize {
319
unless self.cid.nil?
320
ObjectSpace.undefine_finalizer(self)
321
self.class._close(self.client, self.cid, addends)
322
self.cid = nil
323
end
324
}
325
end
326
#
327
# Enables or disables interactive mode.
328
#
329
def interactive(tf = true, addends = nil)
330
if self.cid.nil?
331
raise IOError, "Channel has been closed.", caller
332
end
333
334
request = Packet.create_request(COMMAND_ID_CORE_CHANNEL_INTERACT)
335
336
# Populate the request
337
request.add_tlv(TLV_TYPE_CHANNEL_ID, self.cid)
338
request.add_tlv(TLV_TYPE_BOOL, tf)
339
request.add_tlvs(addends)
340
341
self.client.send_request(request)
342
343
return true
344
end
345
346
##
347
#
348
# Direct I/O
349
#
350
##
351
352
#
353
# Handles dispatching I/O requests based on the request packet.
354
# The default implementation does nothing with direct I/O requests.
355
#
356
def dio_handler(dio, packet)
357
if (dio == CHANNEL_DIO_READ)
358
length = packet.get_tlv_value(TLV_TYPE_LENGTH)
359
360
return dio_read_handler(packet, length)
361
elsif (dio == CHANNEL_DIO_WRITE)
362
data = packet.get_tlv_value(TLV_TYPE_CHANNEL_DATA)
363
364
return dio_write_handler(packet, data)
365
elsif (dio == CHANNEL_DIO_CLOSE)
366
return dio_close_handler(packet)
367
end
368
return false;
369
end
370
371
#
372
# Stub read handler.
373
#
374
def dio_read_handler(packet, length)
375
return true
376
end
377
378
#
379
# Stub write handler.
380
#
381
def dio_write_handler(packet, data)
382
return true
383
end
384
385
#
386
# Stub close handler.
387
#
388
def dio_close_handler(packet)
389
temp_cid = nil
390
@mutex.synchronize {
391
temp_cid = self.cid
392
self.cid = nil
393
}
394
client.remove_channel(temp_cid)
395
396
# Trap IOErrors as parts of the channel may have already been closed
397
begin
398
self.cleanup
399
rescue IOError
400
end
401
402
return true
403
end
404
405
#
406
# Maps packet request methods to DIO request identifiers on a
407
# per-instance basis as other instances may add custom dio
408
# handlers.
409
#
410
def dio_map(command_id)
411
if command_id == COMMAND_ID_CORE_CHANNEL_READ
412
return CHANNEL_DIO_READ
413
elsif command_id == COMMAND_ID_CORE_CHANNEL_WRITE
414
return CHANNEL_DIO_WRITE
415
elsif command_id == COMMAND_ID_CORE_CHANNEL_CLOSE
416
return CHANNEL_DIO_CLOSE
417
end
418
419
return nil
420
end
421
422
##
423
#
424
# Conditionals
425
#
426
##
427
428
#
429
# Checks to see if a flag is set on the instance's flags attribute.
430
#
431
def flag?(flag)
432
return ((self.flags & flag) == flag)
433
end
434
435
#
436
# Returns whether or not the channel is operating synchronously.
437
#
438
def synchronous?
439
return (self.flags & CHANNEL_FLAG_SYNCHRONOUS)
440
end
441
442
#
443
# The unique channel identifier.
444
#
445
attr_reader :cid
446
#
447
# The type of channel.
448
#
449
attr_reader :type
450
#
451
# The class of channel (stream, datagram, pool).
452
#
453
attr_reader :cls
454
#
455
# Any channel-specific flag, like synchronous IO.
456
#
457
attr_reader :flags
458
#
459
# Any channel-specific parameters.
460
#
461
attr_accessor :params
462
#
463
# The associated meterpreter client instance
464
#
465
attr_accessor :client
466
protected
467
468
469
attr_writer :cid, :type, :cls, :flags # :nodoc:
470
471
#
472
# Cleans up any lingering resources
473
#
474
def cleanup
475
end
476
477
end
478
479
end; end; end
480
481