CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
rapid7

Real-time collaboration for Jupyter Notebooks, Linux Terminals, LaTeX, VS Code, R IDE, and more,
all in one place.

GitHub Repository: rapid7/metasploit-framework
Path: blob/master/lib/rex/post/meterpreter/client.rb
Views: 11784
1
# -*- coding: binary -*-
2
3
require 'socket'
4
require 'openssl'
5
6
require 'rex/post/channel'
7
require 'rex/post/meterpreter/extension_mapper'
8
require 'rex/post/meterpreter/client_core'
9
require 'rex/post/meterpreter/channel'
10
require 'rex/post/meterpreter/dependencies'
11
require 'rex/post/meterpreter/object_aliases'
12
require 'rex/post/meterpreter/packet'
13
require 'rex/post/meterpreter/packet_parser'
14
require 'rex/post/meterpreter/packet_dispatcher'
15
require 'rex/post/meterpreter/pivot'
16
require 'rex/post/meterpreter/pivot_container'
17
18
module Rex
19
module Post
20
module Meterpreter
21
22
#
23
# Just to get it in there...
24
#
25
module Extensions
26
end
27
28
###
29
#
30
# This class represents a logical meterpreter client class. This class
31
# provides an interface that is compatible with the Rex post-exploitation
32
# interface in terms of the feature set that it attempts to expose. This
33
# class is meant to drive a single meterpreter client session.
34
#
35
###
36
class Client
37
38
include Rex::Post::Channel::Container
39
include Rex::Post::Meterpreter::PacketDispatcher
40
include Rex::Post::Meterpreter::PivotContainer
41
42
#
43
# Extension name to class hash.
44
#
45
@@ext_hash = {}
46
47
#
48
# Cached auto-generated SSL certificate
49
#
50
@@ssl_cached_cert = nil
51
52
#
53
# Mutex to synchronize class-wide operations
54
#
55
@@ssl_mutex = ::Mutex.new
56
57
#
58
# Lookup the error that occurred
59
#
60
def self.lookup_error(code)
61
code
62
end
63
64
#
65
# Checks the extension hash to see if a class has already been associated
66
# with the supplied extension name.
67
#
68
def self.check_ext_hash(name)
69
@@ext_hash[name]
70
end
71
72
#
73
# Stores the name to class association for the supplied extension name.
74
#
75
def self.set_ext_hash(name, klass)
76
@@ext_hash[name] = klass
77
end
78
79
#
80
# Initializes the client context with the supplied socket through
81
# which communication with the server will be performed.
82
#
83
def initialize(sock, opts={})
84
init_meterpreter(sock, opts)
85
end
86
87
#
88
# Cleans up the meterpreter instance, terminating the dispatcher thread.
89
#
90
def cleanup_meterpreter
91
if self.pivot_session
92
self.pivot_session.remove_pivot_session(self.session_guid)
93
end
94
95
self.pivot_sessions.keys.each do |k|
96
pivot = self.pivot_sessions[k]
97
pivot.pivoted_session.kill('Pivot closed')
98
pivot.pivoted_session.shutdown_passive_dispatcher
99
end
100
101
unless self.skip_cleanup
102
ext.aliases.each_value do | extension |
103
extension.cleanup if extension.respond_to?( 'cleanup' )
104
end
105
end
106
107
dispatcher_thread.kill if dispatcher_thread
108
109
unless self.skip_cleanup
110
core.shutdown rescue nil
111
end
112
113
shutdown_passive_dispatcher
114
115
shutdown_tlv_logging
116
end
117
118
#
119
# Initializes the meterpreter client instance
120
#
121
def init_meterpreter(sock,opts={})
122
self.sock = sock
123
self.parser = PacketParser.new
124
self.ext = ObjectAliases.new
125
self.ext_aliases = ObjectAliases.new
126
self.alive = true
127
self.target_id = opts[:target_id]
128
self.capabilities = opts[:capabilities] || {}
129
self.commands = []
130
self.last_checkin = ::Time.now
131
132
self.conn_id = opts[:conn_id]
133
self.url = opts[:url]
134
self.ssl = opts[:ssl]
135
136
self.pivot_session = opts[:pivot_session]
137
if self.pivot_session
138
self.expiration = self.pivot_session.expiration
139
self.comm_timeout = self.pivot_session.comm_timeout
140
self.retry_total = self.pivot_session.retry_total
141
self.retry_wait = self.pivot_session.retry_wait
142
else
143
self.expiration = opts[:expiration]
144
self.comm_timeout = opts[:comm_timeout]
145
self.retry_total = opts[:retry_total]
146
self.retry_wait = opts[:retry_wait]
147
self.passive_dispatcher = opts[:passive_dispatcher]
148
end
149
150
self.response_timeout = opts[:timeout] || self.class.default_timeout
151
self.send_keepalives = true
152
153
# TODO: Clarify why we don't allow unicode to be set in initial options
154
# self.encode_unicode = opts.has_key?(:encode_unicode) ? opts[:encode_unicode] : true
155
self.encode_unicode = false
156
157
self.aes_key = nil
158
self.session_guid = opts[:session_guid] || "\x00" * 16
159
160
# The SSL certificate is being passed down as a file path
161
if opts[:ssl_cert]
162
if ! ::File.exist? opts[:ssl_cert]
163
elog("SSL certificate at #{opts[:ssl_cert]} does not exist and will be ignored")
164
else
165
# Load the certificate the same way that SslTcpServer does it
166
self.ssl_cert = ::File.read(opts[:ssl_cert])
167
end
168
end
169
# Use the debug build if specified
170
self.debug_build = opts[:debug_build]
171
172
173
# Protocol specific dispatch mixins go here, this may be neater with explicit Client classes
174
opts[:dispatch_ext].each {|dx| self.extend(dx)} if opts[:dispatch_ext]
175
initialize_passive_dispatcher if opts[:passive_dispatcher]
176
177
register_extension_alias('core', ClientCore.new(self))
178
179
initialize_inbound_handlers
180
initialize_channels
181
initialize_pivots
182
183
# Register the channel and pivot inbound packet handlers
184
register_inbound_handler(Rex::Post::Meterpreter::Channel)
185
register_inbound_handler(Rex::Post::Meterpreter::Pivot)
186
187
monitor_socket
188
end
189
190
def swap_sock_plain_to_ssl
191
# Create a new SSL session on the existing socket
192
ctx = generate_ssl_context()
193
ssl = OpenSSL::SSL::SSLSocket.new(sock, ctx)
194
195
# Use non-blocking OpenSSL operations on Windows
196
if !( ssl.respond_to?(:accept_nonblock) and Rex::Compat.is_windows )
197
ssl.accept
198
else
199
begin
200
ssl.accept_nonblock
201
202
# Ruby 1.8.7 and 1.9.0/1.9.1 uses a standard Errno
203
rescue ::Errno::EAGAIN, ::Errno::EWOULDBLOCK
204
IO::select(nil, nil, nil, 0.10)
205
retry
206
207
# Ruby 1.9.2+ uses IO::WaitReadable/IO::WaitWritable
208
rescue ::Exception => e
209
if ::IO.const_defined?('WaitReadable') and e.kind_of?(::IO::WaitReadable)
210
IO::select( [ ssl ], nil, nil, 0.10 )
211
retry
212
end
213
214
if ::IO.const_defined?('WaitWritable') and e.kind_of?(::IO::WaitWritable)
215
IO::select( nil, [ ssl ], nil, 0.10 )
216
retry
217
end
218
219
raise e
220
end
221
end
222
223
self.sock.extend(Rex::Socket::SslTcp)
224
self.sock.sslsock = ssl
225
self.sock.sslctx = ctx
226
self.sock.sslhash = Rex::Text.sha1_raw(ctx.cert.to_der)
227
228
tag = self.sock.get_once(-1, 30)
229
if(not tag or tag !~ /^GET \//)
230
raise RuntimeError, "Could not read the HTTP hello token"
231
end
232
end
233
234
def swap_sock_ssl_to_plain
235
# Remove references to the SSLSocket and Context
236
self.sock.sslsock.close
237
self.sock.sslsock = nil
238
self.sock.sslctx = nil
239
self.sock.sslhash = nil
240
self.sock = self.sock.fd
241
self.sock.extend(::Rex::Socket::Tcp)
242
end
243
244
def generate_ssl_context
245
246
ctx = nil
247
ssl_cert_info = nil
248
249
loop do
250
251
# Load a custom SSL certificate if one has been specified
252
if self.ssl_cert
253
wlog("Loading custom SSL certificate for Meterpreter session")
254
ssl_cert_info = Rex::Socket::SslTcpServer.ssl_parse_pem(self.ssl_cert)
255
wlog("Loaded custom SSL certificate for Meterpreter session")
256
break
257
end
258
259
# Generate a certificate if necessary and cache it
260
if ! @@ssl_cached_cert
261
@@ssl_mutex.synchronize do
262
wlog("Generating SSL certificate for Meterpreter sessions")
263
@@ssl_cached_cert = Rex::Socket::SslTcpServer.ssl_generate_certificate
264
wlog("Generated SSL certificate for Meterpreter sessions")
265
end
266
end
267
268
# Use the cached certificate
269
ssl_cert_info = @@ssl_cached_cert
270
break
271
end
272
273
# Create a new context for each session
274
ctx = OpenSSL::SSL::SSLContext.new()
275
ctx.key = ssl_cert_info[0]
276
ctx.cert = ssl_cert_info[1]
277
ctx.extra_chain_cert = ssl_cert_info[2]
278
ctx.options = 0
279
ctx.session_id_context = Rex::Text.rand_text(16)
280
281
ctx
282
end
283
284
##
285
#
286
# Accessors
287
#
288
##
289
290
#
291
# Returns the default timeout that request packets will use when
292
# waiting for a response.
293
#
294
def Client.default_timeout
295
return 300
296
end
297
298
##
299
#
300
# Alias processor
301
#
302
##
303
304
#
305
# Translates unhandled methods into registered extension aliases
306
# if a matching extension alias exists for the supplied symbol.
307
#
308
def method_missing(symbol, *args)
309
#$stdout.puts("method_missing: #{symbol}")
310
self.ext_aliases.aliases[symbol.to_s]
311
end
312
313
##
314
#
315
# Extension registration
316
#
317
##
318
319
#
320
# Loads the client half of the supplied extension and initializes it as a
321
# registered extension that can be reached through client.ext.[extension].
322
#
323
def add_extension(name, commands=[])
324
self.commands.concat(commands)
325
326
# Check to see if this extension has already been loaded.
327
if ((klass = self.class.check_ext_hash(name.downcase)) == nil)
328
klass = Rex::Post::Meterpreter::ExtensionMapper.get_extension_klass(name)
329
# Save the module name to class association now that the code is
330
# loaded.
331
self.class.set_ext_hash(name.downcase, klass)
332
end
333
334
# Create a new instance of the extension
335
inst = klass.new(self)
336
337
self.ext.aliases[inst.name] = inst
338
339
return true
340
end
341
342
#
343
# Deregisters an extension alias of the supplied name.
344
#
345
def deregister_extension(name)
346
self.ext.aliases.delete(name)
347
end
348
349
#
350
# Enumerates all of the loaded extensions.
351
#
352
def each_extension(&block)
353
self.ext.aliases.each(block)
354
end
355
356
#
357
# Registers an aliased extension that can be referenced through
358
# client.name.
359
#
360
def register_extension_alias(name, ext)
361
self.ext_aliases.aliases[name] = ext
362
# Whee! Syntactic sugar, where art thou?
363
#
364
# Create an instance method on this object called +name+ that returns
365
# +ext+. We have to do it this way instead of simply
366
# self.class.class_eval so that other meterpreter sessions don't get
367
# extension methods when this one does
368
(class << self; self; end).class_eval do
369
define_method(name.to_sym) do
370
ext
371
end
372
end
373
ext
374
end
375
376
#
377
# Registers zero or more aliases that are provided in an array.
378
#
379
def register_extension_aliases(aliases)
380
aliases.each { |a|
381
register_extension_alias(a['name'], a['ext'])
382
}
383
end
384
385
#
386
# Deregisters a previously registered extension alias.
387
#
388
def deregister_extension_alias(name)
389
self.ext_aliases.aliases.delete(name)
390
end
391
392
#
393
# Dumps the extension tree.
394
#
395
def dump_extension_tree()
396
items = []
397
items.concat(self.ext.dump_alias_tree('client.ext'))
398
items.concat(self.ext_aliases.dump_alias_tree('client'))
399
400
return items.sort
401
end
402
403
#
404
# Encodes (or not) a UTF-8 string
405
#
406
def unicode_filter_encode(str)
407
self.encode_unicode ? Rex::Text.unicode_filter_encode(str) : str
408
end
409
410
#
411
# Decodes (or not) a UTF-8 string
412
#
413
def unicode_filter_decode(str)
414
self.encode_unicode ? Rex::Text.unicode_filter_decode(str) : str
415
end
416
417
#
418
# The extension alias under which all extensions can be accessed by name.
419
# For example:
420
#
421
# client.ext.stdapi
422
#
423
#
424
attr_reader :ext
425
#
426
# The socket the client is communicating over.
427
#
428
attr_reader :sock
429
#
430
# The timeout value to use when waiting for responses.
431
#
432
attr_accessor :response_timeout
433
#
434
# Whether to send pings every so often to determine liveness.
435
#
436
attr_accessor :send_keepalives
437
#
438
# Whether this session is alive. If the socket is disconnected or broken,
439
# this will be false
440
#
441
attr_accessor :alive
442
#
443
# The unique target identifier for this payload
444
#
445
attr_accessor :target_id
446
#
447
# The libraries available to this meterpreter server
448
#
449
attr_accessor :capabilities
450
#
451
# The Connection ID
452
#
453
attr_accessor :conn_id
454
#
455
# The Connect URL
456
#
457
attr_accessor :url
458
#
459
# Use SSL (HTTPS)
460
#
461
attr_accessor :ssl
462
#
463
# Use this SSL Certificate (unified PEM)
464
#
465
attr_accessor :ssl_cert
466
#
467
# The Session Expiration Timeout
468
#
469
attr_accessor :expiration
470
#
471
# The Communication Timeout
472
#
473
attr_accessor :comm_timeout
474
#
475
# The total time for retrying connections
476
#
477
attr_accessor :retry_total
478
#
479
# The time to wait between retry attempts
480
#
481
attr_accessor :retry_wait
482
#
483
# The Passive Dispatcher
484
#
485
attr_accessor :passive_dispatcher
486
#
487
# Reference to a session to pivot through
488
#
489
attr_accessor :pivot_session
490
#
491
# Flag indicating whether to hex-encode UTF-8 file names and other strings
492
#
493
attr_accessor :encode_unicode
494
#
495
# A list of the commands
496
#
497
attr_reader :commands
498
#
499
# The timestamp of the last received response
500
#
501
attr_accessor :last_checkin
502
#
503
# Whether or not to use a debug build for loaded extensions
504
#
505
attr_accessor :debug_build
506
507
protected
508
attr_accessor :parser, :ext_aliases # :nodoc:
509
attr_writer :ext, :sock # :nodoc:
510
attr_writer :commands # :nodoc:
511
end
512
513
end; end; end
514
515