Skip to content

Commit 04541ac

Browse files
committed
Parse msfconsole options before initializing Rails
MSP-10905
1 parent 8e7dd1b commit 04541ac

File tree

8 files changed

+485
-160
lines changed

8 files changed

+485
-160
lines changed

config/application.rb

Lines changed: 1 addition & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,7 @@
11
require 'rails'
22
require File.expand_path('../boot', __FILE__)
33

4-
# only the parts of 'rails/all' that metasploit-framework actually uses
5-
begin
6-
require 'active_record/railtie'
7-
rescue LoadError
8-
warn "activerecord not in the bundle, so database support will be disabled."
9-
warn "Bundle installed '--without #{Bundler.settings.without.join(' ')}'"
10-
warn "To clear the without option do `bundle install --without ''` " \
11-
"(the --without flag with an empty string) or " \
12-
"`rm -rf .bundle` to remove the .bundle/config manually and " \
13-
"then `bundle install`"
14-
end
15-
16-
all_environments = [
17-
:development,
18-
:production,
19-
:test
20-
]
21-
22-
Bundler.require(
23-
*Rails.groups(
24-
db: all_environments,
25-
pcap: all_environments
26-
)
27-
)
4+
Bundler.require(*Rails.groups)
285

296
#
307
# Project

lib/metasploit/framework/command.rb

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
#
2+
# Gems
3+
#
4+
5+
# have to be exact so minimum is loaded prior to parsing arguments which could influence loading.
6+
require 'active_support/dependencies/autoload'
7+
8+
# @note Must use the nested declaration of the {Metasploit::Framework::Command} namespace because commands need to be
9+
# able to be required directly without any other part of metasploit-framework besides config/boot so that the commands
10+
# can parse arguments, setup RAILS_ENV, and load config/application.rb correctly.
11+
module Metasploit
12+
module Framework
13+
module Command
14+
# Namespace for commands for metasploit-framework. There are corresponding classes in the
15+
# {Metasploit::Framework::ParsedOptions} namespace, which handle for parsing the options for each command.
16+
extend ActiveSupport::Autoload
17+
18+
autoload :Base
19+
autoload :Console
20+
end
21+
end
22+
end
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
#
2+
# Gems
3+
#
4+
5+
require 'active_support/core_ext/module/introspection'
6+
7+
#
8+
# Project
9+
#
10+
11+
require 'metasploit/framework/command'
12+
require 'metasploit/framework/parsed_options'
13+
14+
# Based on pattern used for lib/rails/commands in the railties gem.
15+
class Metasploit::Framework::Command::Base
16+
#
17+
# Attributes
18+
#
19+
20+
# @!attribute [r] application
21+
# The Rails application for metasploit-framework.
22+
#
23+
# @return [Metasploit::Framework::Application]
24+
attr_reader :application
25+
26+
# @!attribute [r] parsed_options
27+
# The parsed options from the command line.
28+
#
29+
# @return (see parsed_options)
30+
attr_reader :parsed_options
31+
32+
#
33+
# Class Methods
34+
#
35+
36+
# @note {require_environment!} should be called to load `config/application.rb` to so that the RAILS_ENV can be set
37+
# from the command line options in `ARGV` prior to `Rails.env` being set.
38+
# @note After returning, `Rails.application` will be defined and configured.
39+
#
40+
# Parses `ARGV` for command line arguments to configure the `Rails.application`.
41+
#
42+
# @return (see parsed_options)
43+
def self.require_environment!
44+
parsed_options = self.parsed_options
45+
# RAILS_ENV must be set before requiring 'config/application.rb'
46+
parsed_options.environment!
47+
ARGV.replace(parsed_options.positional)
48+
49+
# @see https://github.com/rails/rails/blob/v3.2.17/railties/lib/rails/commands.rb#L39-L40
50+
require Pathname.new(__FILE__).parent.parent.parent.parent.parent.join('config', 'application')
51+
52+
# have to configure before requiring environment because config/environment.rb calls initialize! and the initializers
53+
# will use the configuration from the parsed options.
54+
parsed_options.configure(Rails.application)
55+
56+
# support disabling the database
57+
unless parsed_options.options.database.disable
58+
begin
59+
require 'active_record/railtie'
60+
rescue LoadError
61+
warn "activerecord not in the bundle, so database support will be disabled."
62+
warn "Bundle installed '--without #{Bundler.settings.without.join(' ')}'"
63+
warn "To clear the without option do `bundle install --without ''` " \
64+
"(the --without flag with an empty string) or " \
65+
"`rm -rf .bundle` to remove the .bundle/config manually and " \
66+
"then `bundle install`"
67+
end
68+
69+
ENV['RAILS_GROUP'] = 'db,pcap'
70+
end
71+
72+
Rails.application.require_environment!
73+
74+
parsed_options
75+
end
76+
77+
def self.parsed_options
78+
parsed_options_class.new
79+
end
80+
81+
def self.parsed_options_class
82+
@parsed_options_class ||= parsed_options_class_name.constantize
83+
end
84+
85+
def self.parsed_options_class_name
86+
@parsed_options_class_name ||= "#{parent.parent}::ParsedOptions::#{name.demodulize}"
87+
end
88+
89+
def self.start
90+
parsed_options = require_environment!
91+
new(application: Rails.application, parsed_options: parsed_options).start
92+
end
93+
94+
#
95+
# Instance Methods
96+
#
97+
98+
# @param attributes [Hash{Symbol => ActiveSupport::OrderedOptions,Rails::Application}]
99+
# @option attributes [Rails::Application] :application
100+
# @option attributes [ActiveSupport::OrderedOptions] :parsed_options
101+
# @raise [KeyError] if :application is not given
102+
# @raise [KeyError] if :parsed_options is not given
103+
def initialize(attributes={})
104+
@application = attributes.fetch(:application)
105+
@parsed_options = attributes.fetch(:parsed_options)
106+
end
107+
108+
# @abstract Use {#application} to start this command.
109+
#
110+
# Starts this command.
111+
#
112+
# @return [void]
113+
# @raise [NotImplementedError]
114+
def start
115+
raise NotImplementedError
116+
end
117+
end
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#
2+
# Project
3+
#
4+
5+
require 'metasploit/framework/command'
6+
require 'metasploit/framework/command/base'
7+
8+
# Based on pattern used for lib/rails/commands in the railties gem.
9+
class Metasploit::Framework::Command::Console < Metasploit::Framework::Command::Base
10+
def start
11+
driver.run
12+
end
13+
14+
private
15+
16+
# The console UI driver.
17+
#
18+
# @return [Msf::Ui::Console::Driver]
19+
def driver
20+
unless @driver
21+
# require here so minimum loading is done before {start} is called.
22+
require 'msf/ui'
23+
24+
@driver = Msf::Ui::Console::Driver.new(
25+
Msf::Ui::Console::Driver::DefaultPrompt,
26+
Msf::Ui::Console::Driver::DefaultPromptChar,
27+
driver_options
28+
)
29+
end
30+
31+
@driver
32+
end
33+
34+
def driver_options
35+
unless @driver_options
36+
options = parsed_options.options
37+
38+
driver_options = {}
39+
driver_options['Config'] = options.framework.config
40+
driver_options['DatabaseEnv'] = options.environment
41+
driver_options['DatabaseMigrationPaths'] = options.database.migrations_paths
42+
driver_options['DatabaseYAML'] = options.database.config
43+
driver_options['Defanged'] = options.console.defanged
44+
driver_options['DisableBanner'] = options.console.quiet
45+
driver_options['DisableDatabase'] = options.database.disable
46+
driver_options['LocalOutput'] = options.console.local_output
47+
driver_options['ModulePath'] = options.modules.path
48+
driver_options['Plugins'] = options.console.plugins
49+
driver_options['RealReadline'] = options.console.real_readline
50+
driver_options['Resource'] = options.console.resource
51+
driver_options['XCommands'] = options.console.commands
52+
53+
@driver_options = driver_options
54+
end
55+
56+
@driver_options
57+
end
58+
end
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
#
2+
# Gems
3+
#
4+
5+
require 'active_support/dependencies/autoload'
6+
7+
# # @note Must use the nested declaration of the {Metasploit::Framework::ParsedOptions} namespace because commands,
8+
# which use parsed options, need to be able to be required directly without any other part of metasploit-framework
9+
# besides config/boot so that the commands can parse arguments, setup RAILS_ENV, and load config/application.rb
10+
# correctly.
11+
module Metasploit
12+
module Framework
13+
# Namespace for parsed options for {Metasploit::Framework::Command commands}. The names of `Class`es in this
14+
# namespace correspond to the name of the `Class` in the {Metasploit::Framework::Command} namespace for which this
15+
# namespace's `Class` parses options.
16+
module ParsedOptions
17+
extend ActiveSupport::Autoload
18+
19+
autoload :Base
20+
autoload :Console
21+
end
22+
end
23+
end
24+

0 commit comments

Comments
 (0)