Use railties to load Metasploit::Credential correctly

MSP-9606

In order to support Metasploit::Credential correctly,
metasploit-framework needs to support Metasploit::Concern, which does
all its magic using a Rails::Engine initializer, so the easiest path is
to make metasploit-framework be able to use Rails::Engines.  To make
Rails::Engine use Rails::Engine, make a dummy Rails::Application
subclass so that all the initializers will be run when anything requires
msfenv.
bug/bundler_fix
Luke Imhoff 2014-05-12 15:03:51 -05:00
parent c70ef2afbd
commit 3370465d84
No known key found for this signature in database
GPG Key ID: 5B1FB01FB33356F8
27 changed files with 366 additions and 399 deletions

3
.gitignore vendored
View File

@ -50,6 +50,9 @@ tags
*.opensdf
*.user
# Rails log directory
/log
# ignore release/debug folders for exploits
external/source/exploits/**/Debug
external/source/exploits/**/Release

16
Gemfile
View File

@ -12,16 +12,21 @@ gem 'msgpack'
gem 'nokogiri'
# Needed by db.rb and Msf::Exploit::Capture
gem 'packetfu', '1.1.9'
# Run initializers for metasploit-concern, metasploit-credential, metasploit_data_models Rails::Engines
gem 'railties'
# Needed by JSObfu
gem 'rkelly-remix', '0.0.6'
# Needed by anemone crawler
gem 'robots'
group :db do
# Needed for Msf::DbManager
gem 'activerecord', '>= 3.0.0', '< 4.0.0'
# Metasploit::Creential database models
gem 'metasploit-credential', git: 'github-metasploit-credential:rapid7/metasploit-credential.git', tag: 'v0.1.2-metasploit-credential'
# Database models shared between framework and Pro.
gem 'metasploit_data_models', '~> 0.17.0'
gem 'metasploit_data_models', '~> 0.17.1'
# Needed for module caching in Mdm::ModuleDetails
gem 'pg', '>= 0.11'
end
@ -38,10 +43,17 @@ group :development, :test do
# Version 4.1.0 or newer is needed to support generate calls without the
# 'FactoryGirl.' in factory definitions syntax.
gem 'factory_girl', '>= 4.1.0'
# automatically include factories from spec/factories
gem 'factory_girl_rails'
# Make rspec output shorter and more useful
gem 'fivemat', '1.2.1'
# running documentation generation tasks and rspec tasks
gem 'rake', '>= 10.0.0'
# testing framework
gem 'rspec', '>= 2.12'
# Define `rake spec`. Must be in development AND test so that its available by default as a rake test when the
# environment is development
gem 'rspec-rails'
end
group :pcap do
@ -55,8 +67,6 @@ group :test do
# transactional fixtures because multiple connections are in use so
# transactions won't work.
gem 'database_cleaner'
# testing framework
gem 'rspec', '>= 2.12'
gem 'shoulda-matchers'
# code coverage for tests
# any version newer than 0.5.4 gives an Encoding error when trying to read the source files.

View File

@ -1,6 +1,26 @@
GIT
remote: github-metasploit-credential:rapid7/metasploit-credential.git
revision: 2f8384cd5f7d0124e276a6e4b7fa8193dd96f56c
tag: v0.1.2-metasploit-credential
specs:
metasploit-credential (0.1.2.pre.metasploit.pre.credential)
metasploit-concern (~> 0.0.4)
metasploit_data_models (~> 0.17.0)
rubyntlm
GEM
remote: https://rubygems.org/
specs:
actionpack (3.2.17)
activemodel (= 3.2.17)
activesupport (= 3.2.17)
builder (~> 3.0.0)
erubis (~> 2.7.0)
journey (~> 1.0.4)
rack (~> 1.4.5)
rack-cache (~> 1.2)
rack-test (~> 0.6.1)
sprockets (~> 2.2.1)
activemodel (3.2.17)
activesupport (= 3.2.17)
builder (~> 3.0.0)
@ -17,13 +37,21 @@ GEM
builder (3.0.4)
database_cleaner (1.2.0)
diff-lcs (1.2.5)
erubis (2.7.0)
factory_girl (4.4.0)
activesupport (>= 3.0.0)
factory_girl_rails (4.4.1)
factory_girl (~> 4.4.0)
railties (>= 3.0.0)
fivemat (1.2.1)
hike (1.2.3)
i18n (0.6.9)
journey (1.0.4)
json (1.8.1)
metasploit_data_models (0.17.0)
activerecord (>= 3.2.13)
metasploit-concern (0.0.4)
activesupport (~> 3.0, >= 3.0.0)
metasploit_data_models (0.17.1)
activerecord (>= 3.2.13, < 4.0.0)
activesupport
pg
mini_portile (0.5.3)
@ -35,7 +63,23 @@ GEM
packetfu (1.1.9)
pcaprub (0.11.3)
pg (0.17.1)
rack (1.4.5)
rack-cache (1.2)
rack (>= 0.4)
rack-ssl (1.3.4)
rack
rack-test (0.6.2)
rack (>= 1.0)
railties (3.2.17)
actionpack (= 3.2.17)
activesupport (= 3.2.17)
rack-ssl (~> 1.3.2)
rake (>= 0.8.7)
rdoc (~> 3.4)
thor (>= 0.14.6, < 2.0)
rake (10.3.1)
rdoc (3.12.2)
json (~> 1.4)
redcarpet (3.1.1)
rkelly-remix (0.0.6)
robots (0.10.1)
@ -47,12 +91,28 @@ GEM
rspec-expectations (2.14.5)
diff-lcs (>= 1.1.3, < 2.0)
rspec-mocks (2.14.6)
rspec-rails (2.14.2)
actionpack (>= 3.0)
activemodel (>= 3.0)
activesupport (>= 3.0)
railties (>= 3.0)
rspec-core (~> 2.14.0)
rspec-expectations (~> 2.14.0)
rspec-mocks (~> 2.14.0)
rubyntlm (0.4.0)
shoulda-matchers (2.6.0)
activesupport (>= 3.0.0)
simplecov (0.5.4)
multi_json (~> 1.0.3)
simplecov-html (~> 0.5.3)
simplecov-html (0.5.3)
sprockets (2.2.2)
hike (~> 1.2)
multi_json (~> 1.0)
rack (~> 1.0)
tilt (~> 1.1, != 1.3.0)
thor (0.19.1)
tilt (1.4.1)
timecop (0.7.1)
tzinfo (0.3.39)
yard (0.8.7.4)
@ -66,20 +126,24 @@ DEPENDENCIES
bcrypt
database_cleaner
factory_girl (>= 4.1.0)
factory_girl_rails
fivemat (= 1.2.1)
json
metasploit_data_models (~> 0.17.0)
metasploit-credential!
metasploit_data_models (~> 0.17.1)
msgpack
network_interface (~> 0.0.1)
nokogiri
packetfu (= 1.1.9)
pcaprub
pg (>= 0.11)
railties
rake (>= 10.0.0)
redcarpet
rkelly-remix (= 0.0.6)
robots
rspec (>= 2.12)
rspec-rails
shoulda-matchers
simplecov (= 0.5.4)
timecop

View File

@ -1,81 +1,4 @@
require 'bundler/setup'
#!/usr/bin/env rake
require File.expand_path('../config/application', __FILE__)
pathname = Pathname.new(__FILE__)
root = pathname.parent
# add metasploit-framework/lib to load paths so rake files can just require
# files normally without having to use __FILE__ and recalculating root and the
# path to lib
lib_pathname = root.join('lib')
$LOAD_PATH.unshift(lib_pathname.to_s)
#
# load rake files like a rails engine
#
rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path
Dir.glob(rakefile_glob) do |rakefile|
# Skip database tasks, will load them later if MDM is present
next if rakefile =~ /database\.rake$/
load rakefile
end
print_without = false
begin
require 'rspec/core/rake_task'
rescue LoadError
puts "rspec not in bundle, so can't set up spec tasks. " \
"To run specs ensure to install the development and test groups."
print_without = true
else
RSpec::Core::RakeTask.new(:spec => 'db:test:prepare')
task :default => :spec
end
# Require yard before loading metasploit_data_models rake tasks as the yard tasks won't be defined if
# YARD is not defined when yard.rake is loaded.
begin
require 'yard'
rescue LoadError
puts "yard not in bundle, so can't set up yard tasks. " \
"To generate documentation ensure to install the development group."
print_without = true
end
begin
require 'metasploit_data_models'
rescue LoadError
puts "metasploit_data_models not in bundle, so can't set up db tasks. " \
"To run database tasks, ensure to install the db bundler group."
print_without = true
else
load 'lib/tasks/database.rake'
metasploit_data_models_task_glob = MetasploitDataModels.root.join(
'lib',
'tasks',
'**',
'*.rake'
).to_s
# include tasks from metasplioit_data_models, such as `rake yard`.
# metasploit-framework specific yard options are in .yardopts
Dir.glob(metasploit_data_models_task_glob) do |path|
load path
end
end
if print_without
puts "Bundle currently installed " \
"'--without #{Bundler.settings.without.join(' ')}'."
puts "To clear the without option do `bundle install --without ''` " \
"(the --without flag with an empty string) or " \
"`rm -rf .bundle` to remove the .bundle/config manually and " \
"then `bundle install`"
end
Metasploit::Framework::Application.load_tasks

33
config/application.rb Normal file
View File

@ -0,0 +1,33 @@
require 'rails'
require File.expand_path('../boot', __FILE__)
# only the parts of 'rails/all' that metasploit-framework actually uses
require 'active_record/railtie'
all_environments = [
:development,
:production,
:test
]
Bundler.require(
*Rails.groups(
db: all_environments,
pcap: all_environments
)
)
require 'msf/base/config'
module Metasploit
module Framework
class Application < Rails::Application
user_config_root = Pathname.new(Msf::Config.get_config_root)
user_database_yaml = user_config_root.join('database.yml')
if user_database_yaml.exist?
config.paths['config/database'] = [user_database_yaml.to_path]
end
end
end
end

33
config/boot.rb Normal file
View File

@ -0,0 +1,33 @@
require 'pathname'
require 'rubygems'
bundle_gemfile = ENV['BUNDLE_GEMFILE']
config_pathname = Pathname.new(__FILE__).expand_path.parent
root = config_pathname.parent
if bundle_gemfile
bundle_gemfile = Pathname.new(bundle_gemfile)
else
bundle_gemfile = root.join('Gemfile')
end
if bundle_gemfile.exist?
ENV['BUNDLE_GEMFILE'] = bundle_gemfile.to_path
begin
require 'bundler'
rescue LoadError
$stderr.puts "[*] Metasploit requires the Bundler gem to be installed"
$stderr.puts " $ gem install bundler"
exit(0)
end
end
Bundler.setup
lib_path = root.join('lib').to_path
unless $LOAD_PATH.include? lib_path
$LOAD_PATH.unshift lib_path
end

5
config/environment.rb Normal file
View File

@ -0,0 +1,5 @@
# Load the rails application
require File.expand_path('../application', __FILE__)
# Initialize the rails application
Metasploit::Framework::Application.initialize!

0
db/migrate/.git-keep Normal file
View File

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130717150737) do
ActiveRecord::Schema.define(:version => 20140417140933) do
create_table "api_keys", :force => true do |t|
t.text "token"
@ -167,6 +167,97 @@ ActiveRecord::Schema.define(:version => 20130717150737) do
t.binary "prefs"
end
create_table "metasploit_credential_cores", :force => true do |t|
t.integer "origin_id", :null => false
t.string "origin_type", :null => false
t.integer "private_id"
t.integer "public_id"
t.integer "realm_id"
t.integer "workspace_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_cores", ["origin_type", "origin_id"], :name => "index_metasploit_credential_cores_on_origin_type_and_origin_id"
add_index "metasploit_credential_cores", ["private_id"], :name => "index_metasploit_credential_cores_on_private_id"
add_index "metasploit_credential_cores", ["public_id"], :name => "index_metasploit_credential_cores_on_public_id"
add_index "metasploit_credential_cores", ["realm_id"], :name => "index_metasploit_credential_cores_on_realm_id"
add_index "metasploit_credential_cores", ["workspace_id"], :name => "index_metasploit_credential_cores_on_workspace_id"
create_table "metasploit_credential_logins", :force => true do |t|
t.integer "core_id", :null => false
t.integer "service_id", :null => false
t.string "access_level"
t.string "status", :null => false
t.datetime "last_attempted_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_logins", ["core_id", "service_id"], :name => "index_metasploit_credential_logins_on_core_id_and_service_id", :unique => true
add_index "metasploit_credential_logins", ["service_id", "core_id"], :name => "index_metasploit_credential_logins_on_service_id_and_core_id", :unique => true
create_table "metasploit_credential_origin_imports", :force => true do |t|
t.text "filename", :null => false
t.integer "task_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_origin_imports", ["task_id"], :name => "index_metasploit_credential_origin_imports_on_task_id"
create_table "metasploit_credential_origin_manuals", :force => true do |t|
t.integer "user_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_origin_manuals", ["user_id"], :name => "index_metasploit_credential_origin_manuals_on_user_id"
create_table "metasploit_credential_origin_services", :force => true do |t|
t.integer "service_id", :null => false
t.text "module_full_name", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_origin_services", ["service_id", "module_full_name"], :name => "unique_metasploit_credential_origin_services", :unique => true
create_table "metasploit_credential_origin_sessions", :force => true do |t|
t.text "post_reference_name", :null => false
t.integer "session_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_origin_sessions", ["session_id", "post_reference_name"], :name => "unique_metasploit_credential_origin_sessions", :unique => true
create_table "metasploit_credential_privates", :force => true do |t|
t.string "type", :null => false
t.text "data", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_privates", ["type", "data"], :name => "index_metasploit_credential_privates_on_type_and_data", :unique => true
create_table "metasploit_credential_publics", :force => true do |t|
t.string "username", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_publics", ["username"], :name => "index_metasploit_credential_publics_on_username", :unique => true
create_table "metasploit_credential_realms", :force => true do |t|
t.string "key", :null => false
t.string "value", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
add_index "metasploit_credential_realms", ["key", "value"], :name => "index_metasploit_credential_realms_on_key_and_value", :unique => true
create_table "mod_refs", :force => true do |t|
t.string "module", :limit => 1024
t.string "mtype", :limit => 128

View File

@ -5,30 +5,6 @@ module Metasploit
# works in compatible manner with activerecord's rake tasks and other
# railties.
module Framework
# Returns the environment for {Metasploit::Framework}. Checks
# `METASPLOIT_FRAMEWORK_ENV` environment variable for value. Defaults to
# `'development'` if `METASPLOIT_FRAMEWORK_ENV` is not set in the
# environment variables.
#
# {env} is a ActiveSupport::StringInquirer like `Rails.env` so it can be
# queried for its value.
#
# @example check if environment is development
# if Metasploit::Framework.env.development?
# # runs only when in development
# end
#
# @return [ActiveSupport::StringInquirer] the environment name
def self.env
unless instance_variable_defined? :@env
name = ENV['METASPLOIT_FRAMEWORK_ENV']
name ||= 'development'
@env = ActiveSupport::StringInquirer.new(name)
end
@env
end
# Returns the root of the metasploit-framework project. Use in place of
# `Rails.root`.
#

View File

@ -8,7 +8,7 @@ module Metasploit
end
def self.configurations_pathname
Metasploit::Framework.root.join('config', 'database.yml')
Metasploit::Framework::Application.paths['config/database'].first
end
end
end

View File

@ -22,6 +22,13 @@ class DBManager
include Msf::DBManager::Migration
include Msf::Framework::Offspring
#
# CONSTANTS
#
# The adapter to use to establish database connection.
ADAPTER = 'postgresql'
# Mainly, it's Ruby 1.9.1 that cause a lot of problems now, along with Ruby 1.8.6.
# Ruby 1.8.7 actually seems okay, but why tempt fate? Let's say 1.9.3 and beyond.
def warn_about_rubies
@ -86,9 +93,7 @@ class DBManager
# Database drivers can reset our KCODE, do not let them
$KCODE = 'NONE' if RUBY_VERSION =~ /^1\.8\./
require "active_record"
initialize_metasploit_data_models
add_rails_engine_migration_paths
@usable = true
@ -98,22 +103,10 @@ class DBManager
return false
end
# Only include Mdm if we're not using Metasploit commercial versions
# If Mdm::Host is defined, the dynamically created classes
# are already in the object space
begin
unless defined? Mdm::Host
MetasploitDataModels.require_models
end
rescue NameError => e
warn_about_rubies
raise e
end
#
# Determine what drivers are available
#
initialize_drivers
initialize_adapter
#
# Instantiate the database sink
@ -126,50 +119,42 @@ class DBManager
#
# Scan through available drivers
#
def initialize_drivers
self.drivers = []
tdrivers = %W{ postgresql }
tdrivers.each do |driver|
begin
def initialize_adapter
ActiveRecord::Base.default_timezone = :utc
ActiveRecord::Base.establish_connection(:adapter => driver)
if(self.respond_to?("driver_check_#{driver}"))
self.send("driver_check_#{driver}")
end
if ActiveRecord::Base.connected? && ActiveRecord::Base.connection_config[:adapter] == ADAPTER
dlog("Already connected to #{ADAPTER}, so reusing active connection.")
else
begin
ActiveRecord::Base.establish_connection(adapter: ADAPTER)
ActiveRecord::Base.remove_connection
self.drivers << driver
rescue ::Exception
rescue Exception => error
@adapter_error = error
else
# @deprecated Use in RPC_Db, but only postgresql is supported, so useless otherwise
self.drivers << ADAPTER
self.driver = ADAPTER
end
end
if(not self.drivers.empty?)
self.driver = self.drivers[0]
end
# Database drivers can reset our KCODE, do not let them
$KCODE = 'NONE' if RUBY_VERSION =~ /^1\.8\./
end
# Loads Metasploit Data Models and adds its migrations to migrations paths.
#
# @return [void]
def initialize_metasploit_data_models
# Provide access to ActiveRecord models shared w/ commercial versions
require "metasploit_data_models"
metasploit_data_model_migrations_pathname = MetasploitDataModels.root.join(
'db',
'migrate'
)
metasploit_data_model_migrations_path = metasploit_data_model_migrations_pathname.to_s
def add_rails_engine_migration_paths
Rails.application.railties.engines.each do |engine|
migrations_paths = engine.paths['db/migrate'].existent_directories
migrations_paths.each do |migrations_path|
# Since ActiveRecord::Migrator.migrations_paths can persist between
# instances of Msf::DBManager, such as in specs,
# metasploit_data_models_migrations_path may already be part of
# migrations_path may already be part of
# migrations_paths, in which case it should not be added or multiple
# migrations with the same version number errors will occur.
unless ActiveRecord::Migrator.migrations_paths.include? metasploit_data_model_migrations_path
ActiveRecord::Migrator.migrations_paths << metasploit_data_model_migrations_path
unless ActiveRecord::Migrator.migrations_paths.include? migrations_path
ActiveRecord::Migrator.migrations_paths << migrations_path
end
end
end
end
@ -259,7 +244,13 @@ class DBManager
errstr = e.to_s
if errstr =~ /does not exist/i or errstr =~ /Unknown database/
ilog("Database doesn't exist \"#{opts['database']}\", attempting to create it.")
ActiveRecord::Base.establish_connection(opts.merge('database' => nil))
ActiveRecord::Base.establish_connection(
opts.merge(
'database' => 'postgres',
'schema_search_path' => 'public'
)
)
ActiveRecord::Base.connection.create_database(opts['database'])
else
ilog("Trying to continue despite failed database creation: #{e}")

View File

@ -2,11 +2,8 @@
# Use bundler to load dependencies
#
ENV['BUNDLE_GEMFILE'] ||= ::File.expand_path(::File.join(::File.dirname(__FILE__), "..", "Gemfile"))
begin
require 'bundler/setup'
rescue ::LoadError
$stderr.puts "[*] Metasploit requires the Bundler gem to be installed"
$stderr.puts " $ gem install bundler"
exit(0)
end
require 'pathname'
root = Pathname.new(__FILE__).expand_path.parent.parent
config = root.join('config')
require config.join('boot')
require config.join('environment')

View File

@ -1,73 +0,0 @@
load 'active_record/railties/databases.rake'
require 'metasploit/framework'
require 'metasploit/framework/database'
# A modification to remove dependency on Rails.env
#
# @see https://github.com/rails/rails/blob/ddce29bfa12462fde2342a0c2bd0eefd420c0eab/activerecord/lib/active_record/railties/databases.rake#L550
def configs_for_environment
environments = [Metasploit::Framework.env]
if Metasploit::Framework.env.development?
environments << 'test'
end
environment_configurations = ActiveRecord::Base.configurations.values_at(*environments)
present_environment_configurations = environment_configurations.compact
valid_environment_configurations = present_environment_configurations.reject { |config|
config['database'].blank?
}
valid_environment_configurations
end
# emulate initializer "active_record.initialize_database" from active_record/railtie
ActiveSupport.on_load(:active_record) do
self.configurations = Metasploit::Framework::Database.configurations
puts "Connecting to database specified by #{Metasploit::Framework::Database.configurations_pathname}"
spec = configurations[Metasploit::Framework.env]
establish_connection(spec)
end
#
# Remove tasks that aren't supported
#
Rake::TaskManager.class_eval do
def remove_task(task_name)
@tasks.delete(task_name.to_s)
end
end
Rake.application.remove_task('db:fixtures:load')
# completely replace db:load_config and db:seed as they will attempt to use
# Rails.application, which does not exist
Rake::Task['db:load_config'].clear
Rake::Task['db:seed'].clear
db_namespace = namespace :db do
task :load_config do
ActiveRecord::Base.configurations = Metasploit::Framework::Database.configurations
ActiveRecord::Migrator.migrations_paths = [
# rails isn't in Gemfile, so can't use the more appropriate
# Metasploit::Engine.instance.paths['db/migrate'].to_a since using
# Metasploit::Engine requires rails.
MetasploitDataModels.root.join('db', 'migrate').to_s
]
end
desc 'Load the seed data from db/seeds.rb'
task :seed do
db_namespace['abort_if_pending_migrations'].invoke
seeds_pathname = Metasploit::Framework.root.join('db', 'seeds.rb')
if seeds_pathname.exist?
load(seeds_pathname)
end
end
end

7
lib/tasks/databases.rake Normal file
View File

@ -0,0 +1,7 @@
namespace :db do
# Add onto the task so that after adding Rails.application.paths['db/migrate']
task :load_config do
# It's important to call to_a or the paths will just be relative and not realpaths
ActiveRecord::Migrator.migrations_paths += Metasploit::Credential::Engine.instance.paths['db/migrate'].to_a
end
end

View File

@ -1,21 +0,0 @@
# Rake tasks added for compatibility with rake tasks that depend on a Rails
# environment, such as those in activerecord
# Would normally load config/environment.rb of the rails application.
#
# @see https://github.com/rails/rails/blob/e2908356672d4459ada0064f773efd820efda822/railties/lib/rails/application.rb#L190
task :environment do
# ensures that Mdm models are available for migrations which use the models
MetasploitDataModels.require_models
# avoids the need for Rails.root in db:schema:dump
schema_pathname = Metasploit::Framework.root.join('db', 'schema.rb')
ENV['SCHEMA'] = schema_pathname.to_s
end
# This would normally default RAILS_ENV to development if ENV['RAILS_ENV'] is
# not set
#
# @see https://github.com/rails/rails/blob/1a275730b290c1f06d4e8df680d22ae1b41ab585/railties/lib/rails/tasks/misc.rake#L3
task :rails_env do
end

6
script/rails Normal file
View File

@ -0,0 +1,6 @@
#!/usr/bin/env ruby
# This command will automatically be run when you run "rails" with Rails 3 gems installed from the root of your application.
APP_PATH = File.expand_path('../../config/application', __FILE__)
require File.expand_path('../../config/boot', __FILE__)
require 'rails/commands'

View File

@ -8,12 +8,15 @@ require 'metasploit/framework'
MetasploitDataModels.require_models
describe ActiveRecord::ConnectionAdapters::ConnectionPool do
self.use_transactional_fixtures = false
def database_configurations
YAML.load_file(database_configurations_pathname)
end
def database_configurations_pathname
Metasploit::Framework.root.join('config', 'database.yml')
# paths are always Array<String>, but there should only be on 'config/database' entry
Rails.application.config.paths['config/database'].first
end
subject(:connection_pool) do
@ -24,7 +27,7 @@ describe ActiveRecord::ConnectionAdapters::ConnectionPool do
# used, so have to manually establish connection.
before(:each) do
ActiveRecord::Base.configurations = database_configurations
spec = ActiveRecord::Base.configurations[Metasploit::Framework.env]
spec = ActiveRecord::Base.configurations[Rails.env]
ActiveRecord::Base.establish_connection(spec)
end

View File

@ -1177,10 +1177,22 @@ describe Msf::Modules::Loader::Base do
end
context 'with namespace_module nil' do
#
# lets
#
let(:namespace_module) do
nil
end
#
# Callbacks
#
before(:each) do
parent_module.const_set(relative_name, Module.new)
end
it 'should remove relative_name' do
parent_module.should_receive(:remove_const).with(relative_name)

View File

@ -79,7 +79,7 @@ describe Msf::DBManager::Export do
it 'should have Mdm::Module::Detail#disclosure_date from disclosure-date content' do
node = module_detail_node.at_xpath('disclosure-date')
Date.parse(node.content).should == module_detail.disclosure_date
DateTime.parse(node.content).should == module_detail.disclosure_date
end
end

View File

@ -21,16 +21,16 @@ describe Msf::DBManager do
it_should_behave_like 'Msf::DBManager::Migration'
it_should_behave_like 'Msf::DBManager::ImportMsfXml'
context '#initialize_metasploit_data_models' do
def initialize_metasploit_data_models
db_manager.initialize_metasploit_data_models
context '#add_rails_engine_migration_paths' do
def add_rails_engine_migration_paths
db_manager.add_rails_engine_migration_paths
end
it 'should not add duplicate paths to ActiveRecord::Migrator.migrations_paths' do
initialize_metasploit_data_models
add_rails_engine_migration_paths
expect {
initialize_metasploit_data_models
add_rails_engine_migration_paths
}.to_not change {
ActiveRecord::Migrator.migrations_paths.length
}
@ -92,7 +92,7 @@ describe Msf::DBManager do
it 'should create a connection' do
# in purge_all_module_details
# in after(:each)
ActiveRecord::Base.connection_pool.should_receive(:with_connection).twice.and_call_original
ActiveRecord::Base.connection_pool.should_receive(:with_connection).and_call_original
purge_all_module_details
end
@ -129,9 +129,7 @@ describe Msf::DBManager do
end
it 'should create connection' do
# 1st time from with_established_connection
# 2nd time from report_session
ActiveRecord::Base.connection_pool.should_receive(:with_connection).exactly(2).times
ActiveRecord::Base.connection_pool.should_receive(:with_connection)
report_session
end
@ -754,8 +752,7 @@ describe Msf::DBManager do
it { should be_nil }
it 'should not create a connection' do
# 1st time for with_established_connection
ActiveRecord::Base.connection_pool.should_receive(:with_connection).once
ActiveRecord::Base.connection_pool.should_not_receive(:with_connection)
report_session
end
@ -1274,7 +1271,7 @@ describe Msf::DBManager do
end
it 'should create a connection' do
ActiveRecord::Base.connection_pool.should_receive(:with_connection).twice.and_call_original
ActiveRecord::Base.connection_pool.should_receive(:with_connection).and_call_original
update_all_module_details
end
@ -1285,8 +1282,6 @@ describe Msf::DBManager do
framework.should_receive(:cache_thread=).with(nil).ordered
update_all_module_details
ActiveRecord::Base.connection_pool.should_receive(:with_connection).ordered.and_call_original
end
it 'should set modules_cached to false and then true around connection' do
@ -1295,8 +1290,6 @@ describe Msf::DBManager do
db_manager.should_receive(:modules_cached=).with(true).ordered
update_all_module_details
ActiveRecord::Base.connection_pool.should_receive(:with_connection).ordered.and_call_original
end
it 'should set modules_caching to true and then false around connection' do
@ -1305,8 +1298,6 @@ describe Msf::DBManager do
db_manager.should_receive(:modules_caching=).with(false).ordered
update_all_module_details
ActiveRecord::Base.connection_pool.should_receive(:with_connection).ordered.and_call_original
end
context 'with Mdm::Module::Details' do
@ -1483,7 +1474,6 @@ describe Msf::DBManager do
it 'should create connection' do
ActiveRecord::Base.connection_pool.should_receive(:with_connection)
ActiveRecord::Base.connection_pool.should_receive(:with_connection).and_call_original
update_module_details
end

View File

@ -1,49 +1,38 @@
# -*- coding: binary -*-
require 'rubygems'
require 'bundler'
Bundler.require(:default, :test, :db)
ENV['RAILS_ENV'] = 'test'
FILE_FIXTURES_PATH = File.expand_path(File.dirname(__FILE__)) + "/file_fixtures/"
# add project lib directory to load path
spec_pathname = Pathname.new(__FILE__).dirname
root_pathname = spec_pathname.join('..').expand_path
lib_pathname = root_pathname.join('lib')
$LOAD_PATH.unshift(lib_pathname.to_s)
# must be first require and started before any other requires so that it can measure coverage of all following required
# code. It is after the rubygems and bundler only because Bundler.setup supplies the LOAD_PATH to simplecov.
require 'simplecov'
# now that simplecov is loaded, load everything else
require File.expand_path('../../config/environment', __FILE__)
# Don't `require 'rspec/rails'` as it includes support for pieces of rails that metasploit-framework doesn't use
require 'rspec/core'
require 'rails/version'
require 'rspec/rails/adapters'
require 'rspec/rails/extensions'
require 'rspec/rails/fixture_support'
require 'rspec/rails/matchers'
require 'rspec/rails/mocks'
FILE_FIXTURES_PATH = File.expand_path(File.dirname(__FILE__)) + '/file_fixtures/'
# Requires supporting ruby files with custom matchers and macros, etc,
# in spec/support/ and its subdirectories.
support_glob = root_pathname.join('spec', 'support', '**', '*.rb')
Dir.glob(support_glob) do |path|
require path
Dir[Rails.root.join('spec', 'support', '**', '*.rb')].each do |f|
require f
end
RSpec.configure do |config|
config.mock_with :rspec
# Can't use factory_girl_rails since not using rails, so emulate
# factory_girl.set_factory_paths initializer and after_initialize for
# FactoryGirl::Railtie
config.before(:suite) do
# Need to load Mdm models first so factories can use them
MetasploitDataModels.require_models
# Run specs in random order to surface order dependencies. If you find an
# order dependency and want to debug it, you can fix the order by providing
# the seed, which is printed after each run.
# --seed 1234
config.order = 'random'
FactoryGirl.definition_file_paths = [
MetasploitDataModels.root.join('spec', 'factories'),
# Have metasploit-framework's definition file path last so it can
# modify gem factories.
Metasploit::Framework.root.join('spec', 'factories')
]
FactoryGirl.find_definitions
# If you're not using ActiveRecord, or you'd prefer not to run each of your
# examples within a transaction, remove the following line or assign false
# instead of true.
config.use_transactional_fixtures = true
end
end

View File

@ -1,37 +0,0 @@
# -*- coding:binary -*-
require 'metasploit/framework/database'
shared_context 'DatabaseCleaner' do
def with_established_connection
begin
ActiveRecord::Base.connection_pool.with_connection do
yield
end
rescue ActiveRecord::ConnectionNotEstablished
# if there isn't a connection established, then established one and try
# again
ActiveRecord::Base.configurations = Metasploit::Framework::Database.configurations
spec = ActiveRecord::Base.configurations[Metasploit::Framework.env]
ActiveRecord::Base.establish_connection(spec)
retry
end
end
# clean before all in case last test run was interrupted before
# after(:each) could clean up
before(:all) do
with_established_connection do
DatabaseCleaner.clean_with(:truncation)
end
end
# Clean up after each test
after(:each) do
with_established_connection do
# Testing using both :truncation and :deletion; :truncation took long
# for testing.
DatabaseCleaner.clean_with(:deletion)
end
end
end

View File

@ -1,5 +1,4 @@
shared_context 'Msf::DBManager' do
include_context 'DatabaseCleaner'
include_context 'Msf::Simple::Framework'
let(:active) do
@ -11,13 +10,8 @@ shared_context 'Msf::DBManager' do
end
before(:each) do
configurations = Metasploit::Framework::Database.configurations
spec = configurations[Metasploit::Framework.env]
# Need to connect or ActiveRecord::Base.connection_pool will raise an
# error.
db_manager.connect(spec)
# already connected due to use_transactional_fixtures, but need some of the side-effects of #connect
framework.db.workspace = framework.db.default_workspace
db_manager.stub(:active => active)
end
end

View File

@ -273,8 +273,6 @@ shared_examples_for 'Msf::DBManager::ImportMsfXml' do
end
context 'with :type' do
include_context 'DatabaseCleaner'
let(:source) do
xml.tag!("web_#{type}") do
web_site = web_vuln.web_site
@ -618,8 +616,6 @@ shared_examples_for 'Msf::DBManager::ImportMsfXml' do
end
context 'with required attributes' do
include_context 'DatabaseCleaner'
let(:element) do
document.root
end
@ -775,8 +771,6 @@ shared_examples_for 'Msf::DBManager::ImportMsfXml' do
end
context 'with required attributes' do
include_context 'DatabaseCleaner'
let(:element) do
document.root
end
@ -952,8 +946,6 @@ shared_examples_for 'Msf::DBManager::ImportMsfXml' do
end
context 'with required attributes' do
include_context 'DatabaseCleaner'
let(:element) do
document.root
end
@ -1030,8 +1022,6 @@ shared_examples_for 'Msf::DBManager::ImportMsfXml' do
end
context 'with web_forms/web_form elements' do
include_context 'DatabaseCleaner'
let(:data) do
xml.tag!('MetasploitV4') do
xml.web_forms do
@ -1071,8 +1061,6 @@ shared_examples_for 'Msf::DBManager::ImportMsfXml' do
end
context 'with web_pages/web_page elements' do
include_context 'DatabaseCleaner'
let(:data) do
xml.tag!('MetasploitV4') do
xml.web_pages do
@ -1124,8 +1112,6 @@ shared_examples_for 'Msf::DBManager::ImportMsfXml' do
end
context 'with web_vulns/web_vuln elements' do
include_context 'DatabaseCleaner'
let(:data) do
xml.tag!('MetasploitV4') do
xml.web_vulns do

View File

@ -7,7 +7,7 @@ shared_examples_for 'Msf::DBManager::Migration' do
end
it 'should create a connection' do
ActiveRecord::Base.connection_pool.should_receive(:with_connection).twice
ActiveRecord::Base.connection_pool.should_receive(:with_connection).once
migrate
end

View File

@ -358,25 +358,12 @@ shared_examples_for 'Msf::ModuleManager::Cache' do
end
context 'with framework migrated' do
include_context 'DatabaseCleaner'
let(:framework_migrated?) do
true
end
before(:each) do
configurations = Metasploit::Framework::Database.configurations
spec = configurations[Metasploit::Framework.env]
# Need to connect or ActiveRecord::Base.connection_pool will raise an
# error.
framework.db.connect(spec)
end
it 'should call ActiveRecord::Base.connection_pool.with_connection' do
# 1st is from with_established_connection
# 2nd is from module_info_by_path_from_database!
ActiveRecord::Base.connection_pool.should_receive(:with_connection).at_least(2).times
ActiveRecord::Base.connection_pool.should_receive(:with_connection)
module_info_by_path_from_database!
end
@ -408,7 +395,7 @@ shared_examples_for 'Msf::ModuleManager::Cache' do
end
it 'should use Msf::Modules::Loader::Base.typed_path to derive parent_path' do
Msf::Modules::Loader::Base.should_receive(:typed_path).with(type, reference_name).and_call_original
Msf::Modules::Loader::Base.should_receive(:typed_path).with(type, reference_name).at_least(:once).and_call_original
module_info_by_path_from_database!
end
@ -465,8 +452,6 @@ shared_examples_for 'Msf::ModuleManager::Cache' do
false
end
it { should_not query_the_database.when_calling(:module_info_by_path_from_database!) }
it 'should reset #module_info_by_path' do
# pre-fill module_info_by_path so change can be detected
module_manager.send(:module_info_by_path=, double('In-memory Cache'))