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/base/config.rb
Views: 11780
1
# -*- coding: binary -*-
2
3
#
4
# Standard Library
5
#
6
7
require 'fileutils'
8
9
#
10
# Project
11
#
12
13
require 'metasploit/framework/version'
14
require 'rex/compat'
15
16
module Msf
17
18
# This class wraps interaction with global configuration that can be used as a
19
# persistent storage point for configuration, logs, and other such fun things.
20
class Config < Hash
21
22
# The installation's root directory for the distribution
23
InstallRoot = File.expand_path(File.join(File.dirname(__FILE__), '..', '..', '..'))
24
25
# Determines the base configuration directory. This method should be considered `private`.
26
#
27
# @return [String] the base configuration directory
28
def self.get_config_root
29
30
# Use MSF_CFGROOT_CONFIG environment variable first.
31
val = Rex::Compat.getenv('MSF_CFGROOT_CONFIG')
32
if (val and File.directory?(val))
33
return val
34
end
35
36
# XXX Update this when there is a need to break compatibility
37
config_dir_major = 4
38
config_dir = ".msf#{config_dir_major}"
39
40
# Windows-specific environment variables
41
['HOME', 'LOCALAPPDATA', 'APPDATA', 'USERPROFILE'].each do |dir|
42
val = Rex::Compat.getenv(dir)
43
if (val and File.directory?(val))
44
return File.join(val, config_dir)
45
end
46
end
47
48
begin
49
# First we try $HOME/.msfx
50
File.expand_path("~#{FileSep}#{config_dir}")
51
rescue ::ArgumentError
52
# Give up and install root + ".msfx"
53
InstallRoot + config_dir
54
end
55
end
56
57
#
58
# Default values
59
#
60
61
# Default system file separator.
62
FileSep = File::SEPARATOR
63
64
# Default configuration locations.
65
Defaults =
66
{
67
'ConfigDirectory' => get_config_root,
68
'ConfigFile' => "config",
69
'ModuleDirectory' => "modules",
70
'ScriptDirectory' => "scripts",
71
'LogDirectory' => "logs",
72
'LogosDirectory' => "logos",
73
'SessionLogDirectory' => "logs/sessions",
74
'PluginDirectory' => "plugins",
75
'DataDirectory' => "data",
76
'LootDirectory' => "loot",
77
'LocalDirectory' => "local",
78
'HistoriesDirectory' => "histories"
79
}
80
81
##
82
#
83
# Class methods
84
#
85
##
86
87
# Returns the framework installation root.
88
#
89
# @return [String] the framework installation root {InstallRoot}.
90
def self.install_root
91
InstallRoot
92
end
93
94
# Returns the configuration directory default.
95
#
96
# @return [String] the root configuration directory.
97
def self.config_directory
98
self.new.config_directory
99
end
100
101
# Returns the histories directory default.
102
#
103
# @return [String] the SQL session histories directory.
104
def self.histories_directory
105
self.new.histories_directory
106
end
107
108
# Return the directory that logo files should be loaded from.
109
#
110
# @return [String] path to the logos directory.
111
def self.logos_directory
112
self.new.logos_directory
113
end
114
115
# Returns the global module directory.
116
#
117
# @return [String] path to global module directory.
118
def self.module_directory
119
self.new.module_directory
120
end
121
122
# Returns the path that scripts can be loaded from.
123
#
124
# @return [String] path to script directory.
125
def self.script_directory
126
self.new.script_directory
127
end
128
129
# Returns the directory that log files should be stored in.
130
#
131
# @return [String] path to log directory.
132
def self.log_directory
133
self.new.log_directory
134
end
135
136
# Returns the directory that plugins are stored in.
137
#
138
# @return [String] path to plugin directory.
139
def self.plugin_directory
140
self.new.plugin_directory
141
end
142
143
# Returns the user-specific plugin base path
144
#
145
# @return [String] path to user-specific plugin directory.
146
def self.user_plugin_directory
147
self.new.user_plugin_directory
148
end
149
150
# Returns the directory in which session log files are to reside.
151
#
152
# @return [String] path to session log directory.
153
def self.session_log_directory
154
self.new.session_log_directory
155
end
156
157
# Returns the directory in which captured data will reside.
158
#
159
# @return [String] path to loot directory.
160
def self.loot_directory
161
self.new.loot_directory
162
end
163
164
# Returns the directory in which locally-generated data will reside.
165
#
166
# @return [String] path to locally-generated data directory.
167
def self.local_directory
168
self.new.local_directory
169
end
170
171
# Return the user-specific directory that logo files should be loaded from.
172
#
173
# @return [String] path to the logos directory.
174
def self.user_logos_directory
175
self.new.user_logos_directory
176
end
177
178
# Returns the user-specific module base path
179
#
180
# @return [String] path to user-specific modules directory.
181
def self.user_module_directory
182
self.new.user_module_directory
183
end
184
185
# Returns the user-specific script base path
186
#
187
# @return [String] path to user-specific script directory.
188
def self.user_script_directory
189
self.new.user_script_directory
190
end
191
192
# @return [String] path to user-specific data directory.
193
def self.user_data_directory
194
self.new.user_data_directory
195
end
196
197
# Returns the data directory
198
#
199
# @return [String] path to data directory.
200
def self.data_directory
201
self.new.data_directory
202
end
203
204
# Returns the full path to the configuration file.
205
#
206
# @return [String] path to the configuration file.
207
def self.config_file
208
self.new.config_file
209
end
210
211
# Returns the full path to the history file.
212
#
213
# @return [String] path to the history file.
214
def self.history_file
215
self.new.history_file
216
end
217
218
# Returns the full path to the meterpreter history file.
219
#
220
# @return [String] path to the history file.
221
def self.meterpreter_history
222
self.new.meterpreter_history
223
end
224
225
# Returns the full path to the smb session history file.
226
#
227
# @return [String] path to the history file.
228
def self.smb_session_history
229
self.new.smb_session_history
230
end
231
232
# Returns the full path to the ldap session history file.
233
#
234
# @return [String] path to the history file.
235
def self.ldap_session_history
236
self.new.ldap_session_history
237
end
238
239
# Returns the full path to the MySQL interactive query history file
240
#
241
# @return [String] path to the interactive query history file.
242
def self.history_file_for_session_type(opts)
243
self.new.history_file_for_session_type(opts)
244
end
245
246
def self.pry_history
247
self.new.pry_history
248
end
249
# Returns the full path to the fav_modules file.
250
#
251
# @return [String] path to the fav_modules file.
252
def self.fav_modules_file
253
self.new.fav_modules_file
254
end
255
256
# Returns the full path to the handler file.
257
#
258
# @return [String] path to the handler file.
259
def self.persist_file
260
self.new.persist_file
261
end
262
263
# Initializes configuration, creating directories as necessary.
264
#
265
# @return [void]
266
def self.init
267
self.new.init
268
end
269
270
# Loads configuration from the supplied file path, or the default one if
271
# none is specified.
272
#
273
# @param path [String] the path to the configuration file.
274
# @return [Rex::Parser::Ini] INI file parser.
275
def self.load(path = nil)
276
self.new.load(path)
277
end
278
279
# Saves configuration to the path specified in the ConfigFile hash key or
280
# the default path if one isn't specified. The options should be group
281
# references that have named value pairs.
282
#
283
# @param opts [Hash] Hash containing configuration options.
284
# @option opts 'ConfigFile' [Hash] configuration file these options apply
285
# to.
286
# @return [void]
287
# @example Save 'Cat' => 'Foo' in group 'ExampleGroup'
288
# save(
289
# 'ExampleGroup' =>
290
# {
291
# 'Foo' => 'Cat'
292
# })
293
def self.save(opts)
294
self.new.save(opts)
295
end
296
297
# Deletes the specified config group from the ini file
298
#
299
# @param group [String] The name of the group to remove
300
# @return [void]
301
def self.delete_group(group)
302
self.new.delete_group(group)
303
end
304
305
# Updates the config class' self with the default hash.
306
#
307
# @return [Hash] the updated Hash.
308
def initialize
309
update(Defaults)
310
end
311
312
# Returns the installation root directory
313
#
314
# @return [String] the installation root directory {InstallRoot}.
315
def install_root
316
InstallRoot
317
end
318
319
# Return the directory that logo files should be loaded from.
320
#
321
# @return [String] path to the logos directory.
322
def logos_directory
323
data_directory + FileSep + self['LogosDirectory']
324
end
325
326
# Returns the configuration directory default.
327
#
328
# @return [String] the root configuration directory.
329
def config_directory
330
self['ConfigDirectory']
331
end
332
333
# Returns the histories directory default.
334
#
335
# @return [String] the SQL session histories directory.
336
def histories_directory
337
config_directory + FileSep + self['HistoriesDirectory']
338
end
339
340
# Returns the full path to the configuration file.
341
#
342
# @return [String] path to the configuration file.
343
def config_file
344
config_directory + FileSep + self['ConfigFile']
345
end
346
347
# Returns the full path to the history file.
348
#
349
# @return [String] path the history file.
350
def history_file
351
config_directory + FileSep + "history"
352
end
353
354
def meterpreter_history
355
config_directory + FileSep + "meterpreter_history"
356
end
357
358
def smb_session_history
359
config_directory + FileSep + "smb_session_history"
360
end
361
362
def ldap_session_history
363
config_directory + FileSep + "ldap_session_history"
364
end
365
366
def history_options_valid?(opts)
367
return false if (opts[:session_type].nil? || opts[:interactive].nil?)
368
369
true
370
end
371
372
def interactive_to_string_map(interactive)
373
# Check for true explicitly rather than just a value that is truthy.
374
interactive == true ? '_interactive' : ''
375
end
376
377
def history_file_for_session_type(opts)
378
return nil unless history_options_valid?(opts)
379
380
session_type_name = opts[:session_type]
381
interactive = interactive_to_string_map(opts[:interactive])
382
383
histories_directory + FileSep + "#{session_type_name}_session#{interactive}_history"
384
end
385
386
def pry_history
387
config_directory + FileSep + "pry_history"
388
end
389
390
# Returns the full path to the fav_modules file.
391
#
392
# @return [String] path the fav_modules file.
393
def fav_modules_file
394
config_directory + FileSep + "fav_modules"
395
end
396
397
# Returns the full path to the handler file.
398
#
399
# @return [String] path the handler file.
400
def persist_file
401
config_directory + FileSep + "persist"
402
end
403
404
# Returns the global module directory.
405
#
406
# @return [String] path to global module directory.
407
def module_directory
408
install_root + FileSep + self['ModuleDirectory']
409
end
410
411
# Returns the path that scripts can be loaded from.
412
#
413
# @return [String] path to script directory.
414
def script_directory
415
install_root + FileSep + self['ScriptDirectory']
416
end
417
418
# Returns the directory that log files should be stored in.
419
#
420
# @return [String] path to log directory.
421
def log_directory
422
config_directory + FileSep + self['LogDirectory']
423
end
424
425
# Returns the directory that plugins are stored in.
426
#
427
# @return [String] path to plugin directory.
428
def plugin_directory
429
install_root + FileSep + self['PluginDirectory']
430
end
431
432
# Returns the directory in which session log files are to reside.
433
#
434
# @return [String] path to session log directory.
435
def session_log_directory
436
config_directory + FileSep + self['SessionLogDirectory']
437
end
438
439
# Returns the directory in which captured data will reside.
440
#
441
# @return [String] path to loot directory.
442
def loot_directory
443
config_directory + FileSep + self['LootDirectory']
444
end
445
446
# Returns the directory in which locally-generated data will reside.
447
#
448
# @return [String] path to locally-generated data directory.
449
def local_directory
450
config_directory + FileSep + self['LocalDirectory']
451
end
452
453
# Return the user-specific directory that logo files should be loaded from.
454
#
455
# @return [String] path to the logos directory.
456
def user_logos_directory
457
config_directory + FileSep + self['LogosDirectory']
458
end
459
460
# Returns the user-specific module base path
461
#
462
# @return [String] path to user-specific modules directory.
463
def user_module_directory
464
config_directory + FileSep + "modules"
465
end
466
467
# Returns the user-specific plugin base path
468
#
469
# @return [String] path to user-specific plugin directory.
470
def user_plugin_directory
471
config_directory + FileSep + "plugins"
472
end
473
474
# Returns the user-specific script base path
475
#
476
# @return [String] path to user-specific script directory.
477
def user_script_directory
478
config_directory + FileSep + "scripts"
479
end
480
481
# @return [String] path to user-specific data directory.
482
def user_data_directory
483
config_directory + FileSep + self['DataDirectory']
484
end
485
486
# Returns the data directory
487
#
488
# @return [String] path to data directory.
489
def data_directory
490
install_root + FileSep + self['DataDirectory']
491
end
492
493
# Initializes configuration, creating directories as necessary.
494
#
495
# @return [void]
496
def init
497
FileUtils.mkdir_p(module_directory)
498
FileUtils.mkdir_p(config_directory)
499
FileUtils.mkdir_p(log_directory)
500
FileUtils.mkdir_p(session_log_directory)
501
FileUtils.mkdir_p(loot_directory)
502
FileUtils.mkdir_p(local_directory)
503
FileUtils.mkdir_p(user_logos_directory)
504
FileUtils.mkdir_p(user_module_directory)
505
FileUtils.mkdir_p(user_plugin_directory)
506
FileUtils.mkdir_p(user_data_directory)
507
FileUtils.mkdir_p(histories_directory)
508
end
509
510
# Loads configuration from the supplied file path, or the default one if
511
# none is specified.
512
#
513
# @param path [String] the path to the configuration file.
514
# @return [Rex::Parser::Ini] INI file parser.
515
def load(path = nil)
516
path = config_file if (!path)
517
518
return Rex::Parser::Ini.new(path)
519
end
520
521
# Saves configuration to the path specified in the ConfigFile hash key or
522
# the default path if one isn't specified. The options should be group
523
# references that have named value pairs.
524
#
525
# @param opts [Hash] Hash containing configuration options.
526
# @option opts 'ConfigFile' [Hash] configuration file these options apply
527
# to.
528
# @return [void]
529
# @example Save 'Cat' => 'Foo' in group 'ExampleGroup'
530
# save(
531
# 'ExampleGroup' =>
532
# {
533
# 'Foo' => 'Cat'
534
# })
535
def save(opts)
536
ini = Rex::Parser::Ini.new(opts['ConfigFile'] || config_file)
537
538
ini.update(opts)
539
540
ini.to_file
541
end
542
543
# Deletes the specified config group from the ini file
544
#
545
# @param group [String] The name of the group to remove
546
# @return [void]
547
def delete_group(group)
548
ini = Rex::Parser::Ini.new(config_file)
549
550
ini.delete(group)
551
552
ini.to_file
553
end
554
end
555
556
end
557
558