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/module.rb
Views: 11623
1
# -*- coding: binary -*-
2
3
module Msf
4
5
autoload :OptionContainer, 'msf/core/option_container'
6
7
###
8
#
9
# The module base class is responsible for providing the common interface
10
# that is used to interact with modules at the most basic levels, such as
11
# by inspecting a given module's attributes (name, description, version,
12
# authors, etc) and by managing the module's data store.
13
#
14
###
15
class Module
16
autoload :Alert, 'msf/core/module/alert'
17
autoload :Arch, 'msf/core/module/arch'
18
autoload :Auth, 'msf/core/module/auth'
19
autoload :Author, 'msf/core/module/author'
20
autoload :AuxiliaryAction, 'msf/core/module/auxiliary_action'
21
autoload :Compatibility, 'msf/core/module/compatibility'
22
autoload :DataStore, 'msf/core/module/data_store'
23
autoload :Deprecated, 'msf/core/module/deprecated'
24
autoload :Failure, 'msf/core/module/failure'
25
autoload :FullName, 'msf/core/module/full_name'
26
autoload :HasActions, 'msf/core/module/has_actions'
27
autoload :ModuleInfo, 'msf/core/module/module_info'
28
autoload :ModuleStore, 'msf/core/module/module_store'
29
autoload :Network, 'msf/core/module/network'
30
autoload :Options, 'msf/core/module/options'
31
autoload :Platform, 'msf/core/module/platform'
32
autoload :PlatformList, 'msf/core/module/platform_list'
33
autoload :Privileged, 'msf/core/module/privileged'
34
autoload :Ranking, 'msf/core/module/ranking'
35
autoload :Reference, 'msf/core/module/reference'
36
autoload :SiteReference, 'msf/core/module/reference'
37
autoload :Target, 'msf/core/module/target'
38
autoload :Type, 'msf/core/module/type'
39
autoload :UI, 'msf/core/module/ui'
40
autoload :UUID, 'msf/core/module/uuid'
41
autoload :SideEffects, 'msf/core/module/side_effects'
42
autoload :Stability, 'msf/core/module/stability'
43
autoload :Reliability, 'msf/core/module/reliability'
44
45
include Msf::Module::Alert
46
include Msf::Module::Arch
47
include Msf::Module::Auth
48
include Msf::Module::Author
49
include Msf::Module::Compatibility
50
include Msf::Module::DataStore
51
include Msf::Module::FullName
52
include Msf::Module::ModuleInfo
53
include Msf::Module::ModuleStore
54
include Msf::Module::Network
55
include Msf::Module::Options
56
include Msf::Module::Privileged
57
include Msf::Module::Ranking
58
include Msf::Module::Type
59
include Msf::Module::UI
60
include Msf::Module::UUID
61
include Msf::Module::SideEffects
62
include Msf::Module::Stability
63
include Msf::Module::Reliability
64
65
# The key where a comma-separated list of Ruby module names will live in the
66
# datastore, consumed by #replicant to allow clean override of MSF module methods.
67
REPLICANT_EXTENSION_DS_KEY = 'ReplicantExtensions'
68
69
# Make include public so we can runtime extend
70
public_class_method :include
71
72
class << self
73
include Framework::Offspring
74
75
#
76
# This attribute holds the non-duplicated copy of the module
77
# implementation. This attribute is used for reloading purposes so that
78
# it can be re-duplicated.
79
#
80
attr_accessor :orig_cls
81
82
#
83
# The path from which the module was loaded.
84
#
85
attr_accessor :file_path
86
87
# @return [String, nil] Reference name of the payload being adapted
88
attr_accessor :adapted_refname
89
90
# @return [String, nil] Reference name of the payloads adapter
91
attr_accessor :adapter_refname
92
93
# @return [String, nil] Reference name of the payload stage
94
attr_accessor :stage_refname
95
96
# @return [String, nil] Reference name of the payloads stager
97
attr_accessor :stager_refname
98
99
end
100
101
#
102
# Returns the class reference to the framework
103
#
104
def framework
105
self.class.framework
106
end
107
108
#
109
# Creates an instance of an abstract module using the supplied information
110
# hash.
111
#
112
def initialize(info = {})
113
@module_info_copy = info.dup
114
115
self.module_info = info
116
generate_uuid
117
118
set_defaults
119
120
# Initialize module compatibility hashes
121
init_compat
122
123
# Fixup module fields as needed
124
info_fixups
125
126
# Transform some of the fields to arrays as necessary
127
self.author = Msf::Author.transform(module_info['Author'])
128
self.arch = Rex::Transformer.transform(module_info['Arch'], Array, [ String ], 'Arch')
129
self.platform = PlatformList.transform(module_info['Platform'])
130
self.references = Rex::Transformer.transform(module_info['References'], Array, [ SiteReference, Reference ], 'Ref')
131
132
# Create and initialize the option container for this module
133
self.options = Msf::OptionContainer.new
134
self.options.add_options(info['Options'], self.class)
135
self.options.add_advanced_options(info['AdvancedOptions'], self.class)
136
self.options.add_evasion_options(info['EvasionOptions'], self.class)
137
138
# Create and initialize the data store for this module
139
self.datastore = ModuleDataStore.new(self)
140
141
# Import default options into the datastore
142
import_defaults
143
144
self.privileged = module_info['Privileged'] || false
145
self.license = module_info['License'] || MSF_LICENSE
146
147
# Allow all modules to track their current workspace
148
register_advanced_options(
149
[
150
OptString.new('WORKSPACE', [ false, "Specify the workspace for this module" ]),
151
OptBool.new('VERBOSE', [ false, 'Enable detailed status messages', false ])
152
], Msf::Module)
153
154
end
155
156
def has_check?
157
respond_to?(:check)
158
end
159
160
#
161
# Creates a fresh copy of an instantiated module
162
#
163
def replicant
164
obj = self.clone
165
self.instance_variables.each { |k|
166
old_value = instance_variable_get(k)
167
begin
168
new_value = old_value.is_a?(Rex::Ref) ? old_value.ref : old_value.dup
169
rescue => e
170
elog("#{self.class} replicant failed to dup #{k}", error: e)
171
new_value = old_value
172
end
173
174
obj.instance_variable_set(k, new_value)
175
}
176
177
obj.datastore = self.datastore.copy
178
obj.user_input = self.user_input
179
obj.user_output = self.user_output
180
obj.module_store = self.module_store.clone
181
182
obj.perform_extensions
183
obj
184
end
185
186
# Extends self with the constant list in the datastore
187
# @return [void]
188
def perform_extensions
189
if datastore[REPLICANT_EXTENSION_DS_KEY].present?
190
if datastore[REPLICANT_EXTENSION_DS_KEY].respond_to?(:each)
191
datastore[REPLICANT_EXTENSION_DS_KEY].each do |const|
192
self.extend(const)
193
end
194
else
195
fail "Invalid settings in datastore at key #{REPLICANT_EXTENSION_DS_KEY}"
196
end
197
end
198
end
199
200
# @param rb_modules [Constant] One or more Ruby constants
201
# @return [void]
202
def register_extensions(*rb_modules)
203
datastore[REPLICANT_EXTENSION_DS_KEY] = [] unless datastore[REPLICANT_EXTENSION_DS_KEY].present?
204
rb_modules.each do |rb_mod|
205
datastore[REPLICANT_EXTENSION_DS_KEY] << rb_mod unless datastore[REPLICANT_EXTENSION_DS_KEY].include? rb_mod
206
end
207
end
208
209
#
210
# Returns the unduplicated class associated with this module.
211
#
212
def orig_cls
213
self.class.orig_cls
214
end
215
216
#
217
# The path to the file in which the module can be loaded from.
218
#
219
def file_path
220
self.class.file_path
221
end
222
223
# @return [String, nil] Reference name of the payload being adapted
224
def adapted_refname
225
self.class.adapted_refname
226
end
227
228
# @return [String, nil] Reference name of the payloads adapter
229
def adapter_refname
230
self.class.adapter_refname
231
end
232
233
# @return [String, nil] Reference name of the payload stage
234
def stage_refname
235
self.class.stage_refname
236
end
237
238
# @return [String, nil] Reference name of the payloads stager
239
def stager_refname
240
self.class.stager_refname
241
end
242
243
#
244
# Returns the current workspace
245
#
246
def workspace
247
self.datastore['WORKSPACE'] ||
248
(framework.db and framework.db.active and framework.db.workspace and framework.db.workspace.name)
249
end
250
251
#
252
# Returns the username that instantiated this module, this tries a handful of methods
253
# to determine what actual user ran this module.
254
#
255
def owner
256
# Generic method to configure a module owner
257
username = self.datastore['MODULE_OWNER'].to_s.strip
258
259
# Specific method used by the commercial products
260
if username.empty?
261
username = self.datastore['PROUSER'].to_s.strip
262
end
263
264
# Fallback when neither prior method is available, common for msfconsole
265
if username.empty?
266
username = (ENV['LOGNAME'] || ENV['USERNAME'] || ENV['USER'] || "unknown").to_s.strip
267
end
268
269
username
270
end
271
272
#
273
# Scans the parent module reference to populate additional information. This
274
# is used to inherit common settings (owner, workspace, parent uuid, etc).
275
#
276
def register_parent(ref)
277
self.datastore['WORKSPACE'] = (ref.datastore['WORKSPACE'] ? ref.datastore['WORKSPACE'].dup : nil)
278
self.datastore['PROUSER'] = (ref.datastore['PROUSER'] ? ref.datastore['PROUSER'].dup : nil)
279
self.datastore['MODULE_OWNER'] = ref.owner.dup
280
self.datastore['ParentUUID'] = ref.uuid.dup
281
end
282
283
#
284
# Return a comma separated list of supported platforms, if any.
285
#
286
def platform_to_s
287
platform.all? ? "All" : platform.names.join(", ")
288
end
289
290
#
291
# Checks to see if this module is compatible with the supplied platform
292
#
293
def platform?(what)
294
(platform & what).empty? == false
295
end
296
297
#
298
# Returns true if this module is being debugged.
299
#
300
def debugging?
301
datastore['DEBUG']
302
end
303
304
#
305
# Raises a RuntimeError failure message. This is meant to be used for all non-exploits,
306
# and allows specific classes to override.
307
#
308
# @param reason [String] A reason about the failure.
309
# @param msg [String] (Optional) A message about the failure.
310
# @raise [RuntimeError]
311
# @return [void]
312
# @note If you are writing an exploit, you don't use this API. Instead, please refer to the
313
# API documentation from lib/msf/core/exploit.rb.
314
# @see Msf::Exploit#fail_with
315
# @example
316
# fail_with('No Access', 'Unable to login')
317
#
318
def fail_with(reason, msg=nil)
319
raise RuntimeError, "#{reason.to_s}: #{msg}"
320
end
321
322
323
##
324
#
325
# Just some handy quick checks
326
#
327
##
328
329
#
330
# Returns false since this is the real module
331
#
332
def self.cached?
333
false
334
end
335
336
def default_options
337
self.module_info['DefaultOptions']
338
end
339
340
def required_cred_options
341
@required_cred_options ||= lambda {
342
self.options.select { |name, opt|
343
(
344
opt.type?('string') &&
345
opt.required &&
346
(opt.name.match(/user(name)*$/i) || name.match(/pass(word)*$/i))
347
) ||
348
(
349
opt.type?('bool') &&
350
opt.required &&
351
opt.name.match(/^allow_guest$/i)
352
)
353
}
354
}.call
355
end
356
357
def black_listed_auth_filenames
358
@black_listed_auth_filenames ||= lambda {
359
[
360
'fileformat',
361
'browser'
362
]
363
}.call
364
end
365
366
def post_auth?
367
if self.kind_of?(Msf::Auxiliary::AuthBrute)
368
return true
369
else
370
# Some modules will never be post auth, so let's not waste our time
371
# determining it and create more potential false positives.
372
# If these modules happen to be post auth for some reason, then we it
373
# should manually override the post_auth? method as true.
374
directory_name = self.fullname.split('/')[0..-2]
375
black_listed_auth_filenames.each do |black_listed_name|
376
return false if directory_name.include?(black_listed_name)
377
end
378
379
# Some modules create their own username and password datastore
380
# options, not relying on the AuthBrute mixin. In that case we
381
# just have to go through the options and try to identify them.
382
!required_cred_options.empty?
383
end
384
end
385
386
def default_cred?
387
return false unless post_auth?
388
389
required_cred_options.all? do |name, opt|
390
if opt.type == 'string'
391
if !opt.default.blank?
392
true
393
else
394
false
395
end
396
else
397
true
398
end
399
end
400
401
false
402
end
403
404
#
405
# The array of zero or more platforms.
406
#
407
attr_reader :platform
408
409
#
410
# The reference count for the module.
411
#
412
attr_reader :references
413
414
#
415
# The license under which this module is provided.
416
#
417
attr_reader :license
418
419
#
420
# The job identifier that this module is running as, if any.
421
#
422
attr_accessor :job_id
423
424
#
425
# The last exception to occur using this module
426
#
427
attr_accessor :error
428
429
# An opaque bag of data to attach to a module. This is useful for attaching
430
# some piece of identifying info on to a module before calling
431
# {Msf::Simple::Exploit#exploit_simple} or
432
# {Msf::Simple::Auxiliary#run_simple} for correlating where modules came
433
# from.
434
#
435
attr_accessor :user_data
436
437
protected
438
439
#
440
# Sets the modules unsupplied info fields to their default values.
441
#
442
def set_defaults
443
self.module_info = {
444
'Name' => 'No module name',
445
'Description' => 'No module description',
446
'Version' => '0',
447
'Author' => nil,
448
'Arch' => nil, # No architectures by default.
449
'Platform' => [], # No platforms by default.
450
'Ref' => nil,
451
'Privileged' => false,
452
'License' => MSF_LICENSE,
453
'Notes' => {}
454
}.update(self.module_info)
455
self.module_store = {}
456
end
457
458
attr_writer :platform, :references # :nodoc:
459
attr_writer :privileged # :nodoc:
460
attr_writer :license # :nodoc:
461
462
463
464
end
465
466
end
467
468