Merge pull request #17 from rapid7/feature/MSP-9606/metasploit-credential

Run migrations from Metasploit::Credential and initialize its concerns which patch Mdm
bug/bundler_fix
dmaloney-r7 2014-05-14 11:15:07 -05:00
commit acaf713229
40 changed files with 415 additions and 633 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

37
Gemfile
View File

@ -10,28 +10,28 @@ gem 'json'
gem 'msgpack'
# Needed by anemone crawler
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'
# Needed by db.rb and Msf::Exploit::Capture
gem 'packetfu', '1.1.9'
# required for Time::TZInfo in ActiveSupport
gem 'tzinfo'
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
group :pcap do
gem 'network_interface', '~> 0.0.1'
# For sniffer and raw socket modules
gem 'pcaprub'
end
group :development do
# Markdown formatting for yard
gem 'redcarpet'
@ -44,19 +44,26 @@ 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
gem 'network_interface', '~> 0.0.1'
# For sniffer and raw socket modules
gem 'pcaprub'
end
group :test do
# Removes records from database created during tests. Can't use rspec-rails'
# 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)
@ -15,15 +35,22 @@ GEM
arel (3.0.3)
bcrypt (3.1.7)
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 +62,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 +90,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)
@ -64,23 +123,27 @@ DEPENDENCIES
activerecord (>= 3.0.0, < 4.0.0)
activesupport (>= 3.0.0, < 4.0.0)
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
tzinfo
yard

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

42
config/application.rb Normal file
View File

@ -0,0 +1,42 @@
require 'rails'
require File.expand_path('../boot', __FILE__)
# only the parts of 'rails/all' that metasploit-framework actually uses
begin
require 'active_record/railtie'
rescue LoadError
warn "activerecord not in the bundle, so database support will be disabled."
warn "Bundle installed '--without #{Bundler.settings.without.join(' ')}'"
warn "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
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

@ -378,6 +378,10 @@ module Kernel #:nodoc:all
# This method handles the loading of FASTLIB archives
#
def fastlib_require(name)
if name.respond_to? :to_path
name = name.to_path
end
name = name + ".rb" if not name =~ /\.rb$/
return false if fastlib_already_loaded?(name)
return false if fastlib_already_tried?(name)

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

@ -1,6 +1,18 @@
# -*- coding: binary -*-
#
# Standard Library
#
require 'fileutils'
#
# Project
#
require 'msf/core'
require 'rex/compat'
module Msf
# This class wraps interaction with global configuration that can be used as a

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
@ -43,7 +50,10 @@ class DBManager
attr_accessor :usable
# Returns the list of usable database drivers
attr_accessor :drivers
def drivers
@drivers ||= []
end
attr_writer :drivers
# Returns the active driver
attr_accessor :driver
@ -86,9 +96,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 +106,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 +122,48 @@ class DBManager
#
# Scan through available drivers
#
def initialize_drivers
self.drivers = []
tdrivers = %W{ postgresql }
tdrivers.each do |driver|
def initialize_adapter
ActiveRecord::Base.default_timezone = :utc
if ActiveRecord::Base.connected? && ActiveRecord::Base.connection_config[:adapter] == ADAPTER
dlog("Already connected to #{ADAPTER}, so reusing active connection.")
else
begin
ActiveRecord::Base.default_timezone = :utc
ActiveRecord::Base.establish_connection(:adapter => driver)
if(self.respond_to?("driver_check_#{driver}"))
self.send("driver_check_#{driver}")
end
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"
def add_rails_engine_migration_paths
unless defined? ActiveRecord
fail "Bundle installed '--without #{Bundler.settings.without.join(' ')}'. 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_data_model_migrations_pathname = MetasploitDataModels.root.join(
'db',
'migrate'
)
metasploit_data_model_migrations_path = metasploit_data_model_migrations_pathname.to_s
Rails.application.railties.engines.each do |engine|
migrations_paths = engine.paths['db/migrate'].existent_directories
# 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_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
migrations_paths.each do |migrations_path|
# Since ActiveRecord::Migrator.migrations_paths can persist between
# instances of Msf::DBManager, such as in specs,
# 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? migrations_path
ActiveRecord::Migrator.migrations_paths << migrations_path
end
end
end
end
@ -259,7 +253,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

@ -186,7 +186,7 @@ class Driver < Msf::Ui::Driver
if (dbfile and File.exists? dbfile)
if File.readable?(dbfile)
dbinfo = YAML.load(File.read(dbfile))
dbenv = opts['DatabaseEnv'] || "production"
dbenv = opts['DatabaseEnv'] || Rails.env
db = dbinfo[dbenv]
else
print_error("Warning, #{dbfile} is not readable. Try running as root or chmod.")

View File

@ -2,11 +2,12 @@
# 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
# Override the normal rails default, so that msfconsole will come up in production mode instead of development mode
# unless the `--environment` flag is passed.
ENV['RAILS_ENV'] ||= 'production'
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)
# -*- coding: binary -*-
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
end
# 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

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'))

View File

@ -1 +0,0 @@
#

View File

@ -1,18 +0,0 @@
#This feature contains scenarios that test the various encoders within the metasploit framework
@announce-stdout
Feature: As a Metasploit Framework user
I want to user encoders
So that I can encode various payloads I might use for attacks
Scenario: Create a windows tcp bind payload using the x86/unicode mixed encoder
When I run msfvenom to encode for windows using the "x86/unicode_mixed" encoder with "-i 1" options and a buffer register
#When I run `./msfvenom -p windows/shell/bind_tcp -e x86/unicode_mixed -i 1 BufferRegister=eax` interactively
Then the output should contain "x86/unicode_mixed succeeded with size"
Scenario: Create a windows tcp bind payload encoded with x86 alpha mixed
When I run msfvenom to encode for windows using the "x86/alpha_mixed" encoder with "-b '\x00' -i 1" options
#When I run `./msfvenom -p windows/shell/bind_tcp -e x86/alpha_mixed -b '\x00' -i 1` interactively
Then the output should contain "x86/alpha_mixed succeeded with size"

View File

@ -1,19 +0,0 @@
#This feature contains scenarios that test different handlers within the metasploit framework
@announce
Feature: As a MS Framework User
I want to launch various handlers
So the framework can properly handle input and output from exploits
Scenario: Launching the exploit multi handler in Check mode
When I run `./msfcli exploit/multi/handler C`
Then the output should contain "module tree"
Then the output should contain "This exploit does not support check."
Scenario: Launching the generic multi handler in Check mode
When I run `./msfcli multi/handler C`
Then the output should contain "module tree"
Then the output should contain "This exploit does not support check."

View File

@ -1,24 +0,0 @@
#This feature contains scenarios to test the ability to run/access payloads from the metasploit framework
Feature: I want access to Metasploit payloads
So that I can define payload options for exploits
Scenario: Verify the windows shell reverse tcp payload option in ruby
When I run msfpayload to generate a "windows/shell_reverse_tcp" on the local host
Then the output should contain "# windows/shell_reverse_tcp"
Then the output should contain "# http://www.metasploit.com"
Scenario: Verify the windows x64 shell reverse tcp payload option in ruby
When I run msfpayload to generate a "windows/x64/shell_reverse_tcp" on the local host
Then the output should contain "# windows/x64/shell_reverse_tcp"
Then the output should contain "# http://www.metasploit.com"
Scenario: Verify the linux x86 shell reverse tcp payload option in ruby
When I run msfpayload to generate a "linux/x86/shell_reverse_tcp" on the local host
Then the output should contain "# linux/x86/shell_reverse_tcp"
Then the output should contain "# http://www.metasploit.com"
Scenario: Verify the windows meterpreter reverse tcp payload can output its contents in ruby
When I run msfpayload to generate a "windows/meterpreter/reverse_tcp" on the local host
Then the output should contain "# windows/meterpreter/reverse_tcp - 290 bytes (stage 1)"
Then the output should contain "# http://www.metasploit.com"

View File

@ -1,31 +0,0 @@
#This is the step definition file for common framework testing steps or meta steps
When /^I run the "([^"]*)" exploit with standard target options$/ do |exploit|
steps %Q{
When I run `#{exploit} RHOST=#{TestConfig.instance.rhost} SMBPass=#{TestConfig.instance.smbpass} SMBUser=#{TestConfig.instance.smbuser} E` interactively
}
end
When /^I run the "([^"]*)" exploit with standard target options in check mode$/ do |exploit|
steps %Q{
When I run `#{exploit} RHOST=#{TestConfig.instance.rhost} SMBPass=#{TestConfig.instance.smbpass} SMBUser=#{TestConfig.instance.smbuser} C` interactively
}
end
When /^I run msfvenom to encode for windows using the "([^"]*)" encoder with "(.*)" options$/ do |encoder, options|
steps %Q{
When I run `./msfvenom ./msfvenom -p windows/shell/bind_tcp -e #{encoder} #{options}` interactively
}
end
When /^I run msfvenom to encode for windows using the "([^"]*)" encoder with "(.*)" options and a buffer register$/ do |encoder, options|
steps %Q{
When I run `./msfvenom ./msfvenom -p windows/shell/bind_tcp -e #{encoder} #{options} BufferRegister=eax` interactively
}
end
When /^I run msfpayload to generate a "([^"]*)" on the local host$/ do |payload|
steps %Q{
When I run `./msfpayload #{payload} LHOST=127.0.0.1 y`
}
end

View File

@ -1,23 +0,0 @@
#This is the step definition file for cucumber features relating to the framework handler feature
Given /^I launch the exploit multi handler$/ do
steps %Q{
When I run `./msfcli exploit/multi/handler E`
Then the output should contain "Please wait while we load the module tree..."
Then the output should contain "Started reverse handler on"
Then the output should contain "Starting the payload handler..."
}
end
Given /^I launch the generic multi handler$/ do
steps %Q{
When I run `./msfcli multi/handler E`
Then the output should contain "Please wait while we load the module tree..."
Then the output should contain "Started reverse handler on"
Then the output should contain "Starting the payload handler..."
}
end

View File

@ -1,3 +0,0 @@
# These files are to be excluded from git #
test_config.yml

View File

@ -1,25 +0,0 @@
#Cucumber automation environment setup class for MSF Testing
require 'cucumber'
require 'aruba/cucumber'
require_relative 'test_config'
Before do
# Automatically find the framework path
default_path = File.join(File.expand_path(File.dirname(__FILE__)), '../../../')
# Add more paths manually if needed. For example:
# "/Users/gary/rapid7/framework"
@dirs = [default_path]
@aruba_timeout_seconds = 150
end
Before('@slow_process') do
@aruba_io_wait_seconds = 150
end
@After
#after automation execution methods go here

View File

@ -1,44 +0,0 @@
#Test config class provides public methods or varables to use for ever test
#Includes housing data such as default web site to test, time out varaibels, etc
require 'singleton'
class TestConfig
include Singleton
def initialize(*args)
yml_path = File.join(File.dirname(__FILE__),'test_config.yml')
if File.exists?(yml_path)
@yaml_options = YAML::load(File.open(yml_path))
else
@yaml_options = {}
end
@options = {
"rhost" => "localhost",
"smbuser" => "user",
"smbpass" => "password"
}
end
def run_server
@options[:define_site].nil?
end
def method_missing(method)
if @options.has_key? method.to_s
return @options[method.to_s]
else
super
end
end
def respond_to?(method_sym, include_private = false)
if @options.include? method_s
true
else
super
end
end
end

View File

@ -1,31 +0,0 @@
#This feature contains scenarios that test running exploits related to microsft windows platforms
@announce-stdout
Feature: I want to launch Windows based exploits
So that I can hack Windows targets
So that I can prove how totally unsecured Windows can be
Scenario: Launch Psexec against a Windows Host
When I run the "./msfcli windows/smb/psexec" exploit with standard target options
Then the output should contain "445|WORKGROUP as user"
Then the output should contain "module tree"
Scenario: Launch PSexec in Internal Check Mode
When I run the "./msfcli windows/smb/psexec" exploit with standard target options in check mode
Then the output should contain "module tree"
Then the output should contain "This exploit does not support check."
Scenario: Launch ms08-067 in Internal Check Mode
When I run the "./msfcli windows/smb/ms08_067_netapi" exploit with standard target options in check mode
#When I run `./msfcli windows/smb/ms08_067_netapi RHOST=10.6.0.194 C` interactively
Then the output should contain "module tree"
Then the output should not contain "Check failed:"
Scenario: Launch ms08-067 against a windows remote host
When I run the "./msfcli windows/smb/ms08_067_netapi" exploit with standard target options
Then the output should contain "module tree"
Then the output should contain "Started reverse handler"