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/msf/core/framework.rb
Views: 11780
1
# -*- coding: binary -*-
2
3
#
4
# Standard Library
5
#
6
7
require 'monitor'
8
9
#
10
# Project
11
#
12
13
require 'metasploit/framework/version'
14
require 'rex/socket/ssl'
15
require 'metasploit/framework/thread_factory_provider'
16
module Msf
17
18
###
19
#
20
# This class is the primary context that modules, scripts, and user
21
# interfaces interact with. It ties everything together.
22
#
23
###
24
class Framework
25
include MonitorMixin
26
27
#
28
# Versioning information
29
#
30
31
Major = Metasploit::Framework::Version::MAJOR
32
Minor = Metasploit::Framework::Version::MINOR
33
Point = Metasploit::Framework::Version::PATCH
34
Release = "-#{Metasploit::Framework::Version::PRERELEASE}"
35
Version = Metasploit::Framework::VERSION
36
37
Revision = "$Revision$"
38
39
#
40
# Mixin meant to be included into all classes that can have instances that
41
# should be tied to the framework, such as modules.
42
#
43
module Offspring
44
45
#
46
# A reference to the framework instance from which this offspring was
47
# derived.
48
#
49
attr_accessor :framework
50
end
51
52
require 'metasploit/framework/data_service/proxy/core'
53
54
#
55
# Creates an instance of the framework context.
56
#
57
def initialize(options={})
58
self.options = options
59
# call super to initialize MonitorMixin. #synchronize won't work without this.
60
super()
61
62
# Allow specific module types to be loaded
63
types = options[:module_types] || Msf::MODULE_TYPES
64
65
self.history_manager = Rex::Ui::Text::Shell::HistoryManager.new
66
67
self.features = FeatureManager.instance
68
self.features.load_config
69
70
self.events = EventDispatcher.new(self)
71
self.modules = ModuleManager.new(self,types)
72
self.datastore = DataStore.new
73
self.jobs = Rex::JobContainer.new
74
self.analyze = Analyze.new(self)
75
self.plugins = PluginManager.new(self)
76
self.browser_profiles = Hash.new
77
78
# Configure the thread factory
79
Rex::ThreadFactory.provider = Metasploit::Framework::ThreadFactoryProvider.new(framework: self)
80
81
# Configure the SSL certificate generator
82
require 'msf/core/cert_provider'
83
Rex::Socket::Ssl.cert_provider = Msf::Ssl::CertProvider
84
85
if options.include?('CustomDnsResolver') && Msf::FeatureManager.instance.enabled?(Msf::FeatureManager::DNS)
86
self.dns_resolver = options['CustomDnsResolver']
87
self.dns_resolver.set_framework(self)
88
Rex::Socket._install_global_resolver(self.dns_resolver)
89
end
90
91
subscriber = FrameworkEventSubscriber.new(self)
92
events.add_exploit_subscriber(subscriber)
93
events.add_session_subscriber(subscriber)
94
events.add_general_subscriber(subscriber)
95
events.add_db_subscriber(subscriber)
96
events.add_ui_subscriber(subscriber)
97
end
98
99
def inspect
100
"#<Framework (#{sessions.length} sessions, #{jobs.length} jobs, #{plugins.length} plugins#{db.active ? ", #{db.driver} database active" : ""})>"
101
end
102
103
#
104
# Returns the module set for encoders.
105
#
106
def encoders
107
return modules.encoders
108
end
109
110
#
111
# Returns the module set for exploits.
112
#
113
def exploits
114
return modules.exploits
115
end
116
117
#
118
# Returns the module set for nops
119
#
120
def nops
121
return modules.nops
122
end
123
124
#
125
# Returns the module set for payloads
126
#
127
def payloads
128
return modules.payloads
129
end
130
131
#
132
# Returns the module set for auxiliary modules
133
#
134
def auxiliary
135
return modules.auxiliary
136
end
137
138
#
139
# Returns the module set for post modules
140
#
141
def post
142
return modules.post
143
end
144
145
def evasion
146
return modules.evasion
147
end
148
149
#
150
# Returns the framework version in Major.Minor format.
151
#
152
def version
153
Version
154
end
155
156
#
157
# DNS resolver for the framework
158
#
159
attr_reader :dns_resolver
160
#
161
# Event management interface for registering event handler subscribers and
162
# for interacting with the correlation engine.
163
#
164
attr_reader :events
165
#
166
# Module manager that contains information about all loaded modules,
167
# regardless of type.
168
#
169
attr_reader :modules
170
#
171
# The global framework datastore that can be used by modules.
172
#
173
attr_reader :datastore
174
#
175
# The framework instance's aux manager. The aux manager is responsible
176
# for collecting and cataloging all aux information that comes in from
177
# aux modules.
178
#
179
attr_reader :auxmgr
180
#
181
# Background job management specific to things spawned from this instance
182
# of the framework.
183
#
184
attr_reader :jobs
185
#
186
# The framework instance's plugin manager. The plugin manager is
187
# responsible for exposing an interface that allows for the loading and
188
# unloading of plugins.
189
#
190
attr_reader :plugins
191
#
192
# The framework instance's browser profile store. These profiles are
193
# generated by client-side modules and need to be shared across
194
# different contexts.
195
#
196
attr_reader :browser_profiles
197
#
198
# The framework instance's analysis utility. Provide method to analyze
199
# framework objects to offer related objects/actions available.
200
#
201
attr_reader :analyze
202
#
203
# The framework instance's feature manager. The feature manager is responsible
204
# for configuring feature flags that can change characteristics of framework.
205
# @return [Msf::FeatureManager]
206
attr_reader :features
207
208
# The framework instance's history manager, responsible for managing command history
209
# in different contexts
210
# @return [Rex::Ui::Text::Shell::HistoryManager]
211
attr_reader :history_manager
212
213
#
214
# The framework instance's data service proxy
215
#
216
# @return [Metasploit::Framework::DataService::DataProxy]
217
def db
218
return @db if @db
219
220
synchronize {
221
@db ||= get_db
222
}
223
end
224
225
# Session manager that tracks sessions associated with this framework
226
# instance over the course of their lifetime.
227
#
228
# @return [Msf::SessionManager]
229
def sessions
230
return @sessions if @sessions
231
232
synchronize {
233
@sessions ||= Msf::SessionManager.new(self)
234
}
235
end
236
237
# The framework instance's thread manager. The thread manager
238
# provides a cleaner way to manage spawned threads
239
#
240
# @return [Msf::ThreadManager]
241
def threads
242
return @threads if @threads
243
244
synchronize {
245
@threads ||= Msf::ThreadManager.new(self)
246
}
247
end
248
249
# Whether {#threads} has been initialized
250
#
251
# @return [true] if {#threads} has been initialized
252
# @return [false] otherwise
253
def threads?
254
synchronize {
255
instance_variable_defined? :@threads
256
}
257
end
258
259
def search(search_string)
260
search_params = Msf::Modules::Metadata::Search.parse_search_string(search_string)
261
Msf::Modules::Metadata::Cache.instance.find(search_params)
262
end
263
264
#
265
# EICAR Canary
266
# @return [Boolean] Should return true if the EICAR file has been corrupted
267
def eicar_corrupted?
268
path = ::File.expand_path(::File.join(
269
::File.dirname(__FILE__),"..", "..", "..", "data", "eicar.com")
270
)
271
return true unless ::File.exist?(path)
272
273
data = ::File.read(path, mode: 'rb')
274
return true unless Digest::SHA1.hexdigest(data) == "3395856ce81f2b7382dee72602f798b642f14140"
275
276
false
277
278
# If anything goes wrong assume AV got us
279
rescue ::Exception
280
true
281
end
282
283
protected
284
285
# @!attribute options
286
# Options passed to {#initialize}
287
#
288
# @return [Hash]
289
attr_accessor :options
290
291
attr_writer :dns_resolver #:nodoc:
292
attr_writer :events # :nodoc:
293
attr_writer :modules # :nodoc:
294
attr_writer :datastore # :nodoc:
295
attr_writer :auxmgr # :nodoc:
296
attr_writer :jobs # :nodoc:
297
attr_writer :plugins # :nodoc:
298
attr_writer :db # :nodoc:
299
attr_writer :browser_profiles # :nodoc:
300
attr_writer :analyze # :nodoc:
301
attr_writer :features # :nodoc:
302
attr_writer :history_manager # :nodoc:
303
304
private
305
306
def get_db
307
unless options['DisableDatabase']
308
db_manager = Msf::DBManager.new(self)
309
options[:db_manager] = db_manager
310
unless options['SkipDatabaseInit']
311
db_manager.init_db(options)
312
end
313
end
314
315
Metasploit::Framework::DataService::DataProxy.new(options)
316
end
317
318
end
319
320
class FrameworkEventSubscriber
321
include Framework::Offspring
322
def initialize(framework)
323
self.framework = framework
324
end
325
326
def report_event(data)
327
if framework.db.active
328
framework.db.report_event(data)
329
end
330
end
331
332
include Msf::GeneralEventSubscriber
333
334
#
335
# Generic handler for module events
336
#
337
def module_event(name, instance, opts={})
338
if framework.db.active
339
event = {
340
:workspace => framework.db.find_workspace(instance.workspace),
341
:name => name,
342
:username => instance.owner,
343
:info => {
344
:module_name => instance.fullname,
345
:module_uuid => instance.uuid
346
}.merge(opts)
347
}
348
349
report_event(event)
350
end
351
end
352
353
##
354
# :category: ::Msf::GeneralEventSubscriber implementors
355
def on_module_run(instance)
356
opts = { :datastore => instance.datastore.to_h }
357
module_event('module_run', instance, opts)
358
end
359
360
##
361
# :category: ::Msf::GeneralEventSubscriber implementors
362
def on_module_complete(instance)
363
module_event('module_complete', instance)
364
end
365
366
##
367
# :category: ::Msf::GeneralEventSubscriber implementors
368
def on_module_error(instance, exception=nil)
369
module_event('module_error', instance, :exception => exception.to_s)
370
end
371
372
include ::Msf::UiEventSubscriber
373
##
374
# :category: ::Msf::UiEventSubscriber implementors
375
def on_ui_command(command)
376
if (framework.db and framework.db.active)
377
report_event(:name => "ui_command", :info => {:command => command})
378
end
379
end
380
381
##
382
# :category: ::Msf::UiEventSubscriber implementors
383
def on_ui_stop()
384
if (framework.db and framework.db.active)
385
report_event(:name => "ui_stop")
386
end
387
end
388
389
##
390
# :category: ::Msf::UiEventSubscriber implementors
391
def on_ui_start(rev)
392
#
393
# The database is not active at startup time unless msfconsole was
394
# started with a database.yml, so this event won't always be saved to
395
# the db. Not great, but best we can do.
396
#
397
info = { :revision => rev }
398
report_event(:name => "ui_start", :info => info)
399
end
400
401
402
include ::Msf::SessionEvent
403
404
#
405
# Generic handler for session events
406
#
407
def session_event(name, session, opts={})
408
address = session.session_host
409
410
if not (address and address.length > 0)
411
elog("Session with no session_host/target_host/tunnel_peer. Session Info: #{session.inspect}")
412
return
413
end
414
415
if framework.db.active
416
ws = framework.db.find_workspace(session.workspace)
417
opts.each_key do |attr|
418
opts[attr].force_encoding('UTF-8') if opts[attr].is_a?(String)
419
end
420
421
event = {
422
:workspace => ws,
423
:username => session.username,
424
:name => name,
425
:host => address,
426
:info => {
427
:session_id => session.sid,
428
:session_info => session.info,
429
:session_uuid => session.uuid,
430
:session_type => session.type,
431
:username => session.username,
432
:target_host => address,
433
:via_exploit => session.via_exploit,
434
:via_payload => session.via_payload,
435
:tunnel_peer => session.tunnel_peer,
436
:exploit_uuid => session.exploit_uuid
437
}.merge(opts)
438
}
439
report_event(event)
440
end
441
end
442
443
444
##
445
# :category: ::Msf::SessionEvent implementors
446
def on_session_open(session)
447
opts = { :datastore => session.exploit_datastore.to_h, :critical => true }
448
session_event('session_open', session, opts)
449
framework.db.report_session(:session => session)
450
end
451
452
##
453
# :category: ::Msf::SessionEvent implementors
454
def on_session_upload(session, lpath, rpath)
455
session_event('session_upload', session, :local_path => lpath, :remote_path => rpath)
456
framework.db.report_session_event({
457
:etype => 'upload',
458
:session => session,
459
:local_path => lpath,
460
:remote_path => rpath
461
})
462
end
463
##
464
# :category: ::Msf::SessionEvent implementors
465
def on_session_download(session, rpath, lpath)
466
session_event('session_download', session, :local_path => lpath, :remote_path => rpath)
467
framework.db.report_session_event({
468
:etype => 'download',
469
:session => session,
470
:local_path => lpath,
471
:remote_path => rpath
472
})
473
end
474
475
##
476
# :category: ::Msf::SessionEvent implementors
477
def on_session_close(session, reason='')
478
session_event('session_close', session)
479
if session.db_record
480
# Don't bother saving here, the session's cleanup method will take
481
# care of that later.
482
session.db_record.close_reason = reason
483
session.db_record.closed_at = Time.now.utc
484
end
485
end
486
487
#def on_session_interact(session)
488
# $stdout.puts('session_interact', session.inspect)
489
#end
490
491
##
492
# :category: ::Msf::SessionEvent implementors
493
def on_session_command(session, command)
494
session_event('session_command', session, :command => command)
495
framework.db.report_session_event({
496
:etype => 'command',
497
:session => session,
498
:command => command
499
})
500
end
501
502
##
503
# :category: ::Msf::SessionEvent implementors
504
def on_session_output(session, output)
505
# Break up the output into chunks that will fit into the database.
506
buff = output.dup
507
chunks = []
508
if buff.length > 1024
509
while buff.length > 0
510
chunks << buff.slice!(0,1024)
511
end
512
else
513
chunks << buff
514
end
515
chunks.each { |chunk|
516
session_event('session_output', session, :output => chunk)
517
framework.db.report_session_event({
518
:etype => 'output',
519
:session => session,
520
:output => chunk
521
})
522
}
523
end
524
525
##
526
# :category: ::Msf::SessionEvent implementors
527
def on_session_route(session, route)
528
framework.db.report_session_route({session: session, route: route})
529
end
530
531
##
532
# :category: ::Msf::SessionEvent implementors
533
def on_session_route_remove(session, route)
534
framework.db.report_session_route_remove({session: session, route: route})
535
end
536
537
##
538
# :category: ::Msf::SessionEvent implementors
539
def on_session_script_run(session, script)
540
framework.db.report_session_event({
541
:etype => 'script_run',
542
:session => session,
543
:local_path => script
544
})
545
end
546
547
##
548
# :category: ::Msf::SessionEvent implementors
549
def on_session_module_run(session, mod)
550
framework.db.report_session_event({
551
:etype => 'module_run',
552
:session => session,
553
:local_path => mod.fullname
554
})
555
end
556
557
#
558
# This is covered by on_module_run and on_session_open, so don't bother
559
#
560
#include ExploitEvent
561
#def on_exploit_success(exploit, session)
562
#end
563
564
end
565
end
566
567