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