Allow use of rake db tasks

[#46224565]

The following rake tasks are added and work similar to how they work in
rails apps:
* db:create
* db:drop
* db:migrate
* db:migrate:status
* db:rollback
* db:schema:dump
* db:schema:load
* db:seed (but no db seeds defined at this time)
* db:setup
* db:version

The hidden task db:test:prepare is also available, which means `rake
spec` can depend on it so that the test database is dropped and
recreated from the development database when running specs (Although
there are yet to be database tests, this branch is in preparation for
that work that will be split between multiple developers.)
This commit is contained in:
Luke Imhoff 2013-03-14 15:46:18 -05:00
parent d8f46e3df4
commit 2604fad164
7 changed files with 800 additions and 2 deletions

2
.gitignore vendored
View File

@ -6,6 +6,8 @@
.yardoc
# Mac OS X files
.DS_Store
# database config for testing
config/database.yml
# simplecov coverage data
coverage
data/meterpreter/ext_server_pivot.dll

View File

@ -2,6 +2,18 @@ require 'bundler/setup'
require 'metasploit_data_models'
#
# load rake files like a rails engine
#
pathname = Pathname.new(__FILE__)
root = pathname.parent
rakefile_glob = root.join('lib', 'tasks', '**', '*.rake').to_path
Dir.glob(rakefile_glob) do |rakefile|
load rakefile
end
print_without = false
begin
@ -12,7 +24,7 @@ rescue LoadError
print_without = true
else
RSpec::Core::RakeTask.new(:spec)
RSpec::Core::RakeTask.new(:spec => 'db:test:prepare')
task :default => :spec
end

View File

@ -0,0 +1,21 @@
# Please only use postgresql bound to a TCP port.
development: &pgsql
adapter: postgresql
database: metasploit_framework_development
username: metasploit_framework_development
password: __________________________________
host: localhost
port: 5432
pool: 5
timeout: 5
# Warning: The database defined as "test" will be erased and
# re-generated from your development database when you run "rake".
# Do not set this db to the same as development or production.
#
# Note also, sqlite3 is totally unsupported by Metasploit now.
test:
<<: *pgsql
database: metasploit_framework_test
username: metasploit_framework_test
password: ___________________________

638
db/schema.rb Normal file
View File

@ -0,0 +1,638 @@
# encoding: UTF-8
# This file is auto-generated from the current state of the database. Instead
# of editing this file, please use the migrations feature of Active Record to
# incrementally modify your database, and then regenerate this schema definition.
#
# Note that this schema.rb definition is the authoritative source for your
# database schema. If you need to create the application database on another
# system, you should be using db:schema:load, not running all the migrations
# from scratch. The latter is a flawed and unsustainable approach (the more migrations
# you'll amass, the slower it'll run and the greater likelihood for issues).
#
# It's strongly recommended to check this file into your version control system.
ActiveRecord::Schema.define(:version => 20130228214900) do
create_table "api_keys", :force => true do |t|
t.text "token"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "attachments", :force => true do |t|
t.string "name", :limit => 512
t.binary "data"
t.string "content_type", :limit => 512
t.boolean "inline", :default => true, :null => false
t.boolean "zip", :default => false, :null => false
t.integer "campaign_id"
end
create_table "attachments_email_templates", :id => false, :force => true do |t|
t.integer "attachment_id"
t.integer "email_template_id"
end
create_table "campaigns", :force => true do |t|
t.integer "workspace_id", :null => false
t.string "name", :limit => 512
t.text "prefs"
t.integer "status", :default => 0
t.datetime "started_at"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "clients", :force => true do |t|
t.integer "host_id"
t.datetime "created_at"
t.string "ua_string", :limit => 1024, :null => false
t.string "ua_name", :limit => 64
t.string "ua_ver", :limit => 32
t.datetime "updated_at"
t.integer "campaign_id"
end
create_table "creds", :force => true do |t|
t.integer "service_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "user", :limit => 2048
t.string "pass", :limit => 4096
t.boolean "active", :default => true
t.string "proof", :limit => 4096
t.string "ptype", :limit => 256
t.integer "source_id"
t.string "source_type"
end
create_table "email_addresses", :force => true do |t|
t.integer "campaign_id", :null => false
t.string "first_name", :limit => 512
t.string "last_name", :limit => 512
t.string "address", :limit => 512
t.boolean "sent", :default => false, :null => false
t.datetime "clicked_at"
end
create_table "email_templates", :force => true do |t|
t.string "name", :limit => 512
t.string "subject", :limit => 1024
t.text "body"
t.integer "parent_id"
t.integer "campaign_id"
t.text "prefs"
end
create_table "events", :force => true do |t|
t.integer "workspace_id"
t.integer "host_id"
t.datetime "created_at"
t.string "name"
t.datetime "updated_at"
t.boolean "critical"
t.boolean "seen"
t.string "username"
t.text "info"
end
create_table "exploit_attempts", :force => true do |t|
t.integer "host_id"
t.integer "service_id"
t.integer "vuln_id"
t.datetime "attempted_at"
t.boolean "exploited"
t.string "fail_reason"
t.string "username"
t.text "module"
t.integer "session_id"
t.integer "loot_id"
t.integer "port"
t.string "proto"
t.text "fail_detail"
end
create_table "exploited_hosts", :force => true do |t|
t.integer "host_id", :null => false
t.integer "service_id"
t.string "session_uuid", :limit => 8
t.string "name", :limit => 2048
t.string "payload", :limit => 2048
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "host_details", :force => true do |t|
t.integer "host_id"
t.integer "nx_console_id"
t.integer "nx_device_id"
t.string "src"
t.string "nx_site_name"
t.string "nx_site_importance"
t.string "nx_scan_template"
t.float "nx_risk_score"
end
create_table "hosts", :force => true do |t|
t.datetime "created_at"
t.string "address", :limit => nil
t.string "mac"
t.string "comm"
t.string "name"
t.string "state"
t.string "os_name"
t.string "os_flavor"
t.string "os_sp"
t.string "os_lang"
t.string "arch"
t.integer "workspace_id"
t.datetime "updated_at"
t.text "purpose"
t.string "info", :limit => 65536
t.text "comments"
t.text "scope"
t.text "virtual_host"
t.integer "note_count", :default => 0
t.integer "vuln_count", :default => 0
t.integer "service_count", :default => 0
t.integer "host_detail_count", :default => 0
t.integer "exploit_attempt_count", :default => 0
end
add_index "hosts", ["address"], :name => "index_hosts_on_address"
add_index "hosts", ["name"], :name => "index_hosts_on_name"
add_index "hosts", ["os_flavor"], :name => "index_hosts_on_os_flavor"
add_index "hosts", ["os_name"], :name => "index_hosts_on_os_name"
add_index "hosts", ["purpose"], :name => "index_hosts_on_purpose"
add_index "hosts", ["state"], :name => "index_hosts_on_state"
create_table "hosts_tags", :id => false, :force => true do |t|
t.integer "host_id"
t.integer "tag_id"
end
create_table "imported_creds", :force => true do |t|
t.integer "workspace_id", :default => 1, :null => false
t.string "user", :limit => 512
t.string "pass", :limit => 512
t.string "ptype", :limit => 16, :default => "password"
end
create_table "listeners", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.integer "workspace_id", :default => 1, :null => false
t.integer "task_id"
t.boolean "enabled", :default => true
t.text "owner"
t.text "payload"
t.text "address"
t.integer "port"
t.binary "options"
t.text "macro"
end
create_table "loots", :force => true do |t|
t.integer "workspace_id", :default => 1, :null => false
t.integer "host_id"
t.integer "service_id"
t.string "ltype", :limit => 512
t.string "path", :limit => 1024
t.text "data"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "content_type"
t.text "name"
t.text "info"
end
create_table "macros", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.text "owner"
t.text "name"
t.text "description"
t.binary "actions"
t.binary "prefs"
end
create_table "mod_refs", :force => true do |t|
t.string "module", :limit => 1024
t.string "mtype", :limit => 128
t.text "ref"
end
create_table "module_actions", :force => true do |t|
t.integer "module_detail_id"
t.text "name"
end
add_index "module_actions", ["module_detail_id"], :name => "index_module_actions_on_module_detail_id"
create_table "module_archs", :force => true do |t|
t.integer "module_detail_id"
t.text "name"
end
add_index "module_archs", ["module_detail_id"], :name => "index_module_archs_on_module_detail_id"
create_table "module_authors", :force => true do |t|
t.integer "module_detail_id"
t.text "name"
t.text "email"
end
add_index "module_authors", ["module_detail_id"], :name => "index_module_authors_on_module_detail_id"
create_table "module_details", :force => true do |t|
t.datetime "mtime"
t.text "file"
t.string "mtype"
t.text "refname"
t.text "fullname"
t.text "name"
t.integer "rank"
t.text "description"
t.string "license"
t.boolean "privileged"
t.datetime "disclosure_date"
t.integer "default_target"
t.text "default_action"
t.string "stance"
t.boolean "ready"
end
add_index "module_details", ["description"], :name => "index_module_details_on_description"
add_index "module_details", ["mtype"], :name => "index_module_details_on_mtype"
add_index "module_details", ["name"], :name => "index_module_details_on_name"
add_index "module_details", ["refname"], :name => "index_module_details_on_refname"
create_table "module_mixins", :force => true do |t|
t.integer "module_detail_id"
t.text "name"
end
add_index "module_mixins", ["module_detail_id"], :name => "index_module_mixins_on_module_detail_id"
create_table "module_platforms", :force => true do |t|
t.integer "module_detail_id"
t.text "name"
end
add_index "module_platforms", ["module_detail_id"], :name => "index_module_platforms_on_module_detail_id"
create_table "module_refs", :force => true do |t|
t.integer "module_detail_id"
t.text "name"
end
add_index "module_refs", ["module_detail_id"], :name => "index_module_refs_on_module_detail_id"
add_index "module_refs", ["name"], :name => "index_module_refs_on_name"
create_table "module_targets", :force => true do |t|
t.integer "module_detail_id"
t.integer "index"
t.text "name"
end
add_index "module_targets", ["module_detail_id"], :name => "index_module_targets_on_module_detail_id"
create_table "nexpose_consoles", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.boolean "enabled", :default => true
t.text "owner"
t.text "address"
t.integer "port", :default => 3780
t.text "username"
t.text "password"
t.text "status"
t.text "version"
t.text "cert"
t.binary "cached_sites"
t.text "name"
end
create_table "notes", :force => true do |t|
t.datetime "created_at"
t.string "ntype", :limit => 512
t.integer "workspace_id", :default => 1, :null => false
t.integer "service_id"
t.integer "host_id"
t.datetime "updated_at"
t.boolean "critical"
t.boolean "seen"
t.text "data"
end
add_index "notes", ["ntype"], :name => "index_notes_on_ntype"
create_table "profiles", :force => true do |t|
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.boolean "active", :default => true
t.text "name"
t.text "owner"
t.binary "settings"
end
create_table "refs", :force => true do |t|
t.integer "ref_id"
t.datetime "created_at"
t.string "name", :limit => 512
t.datetime "updated_at"
end
add_index "refs", ["name"], :name => "index_refs_on_name"
create_table "report_templates", :force => true do |t|
t.integer "workspace_id", :default => 1, :null => false
t.string "created_by"
t.string "path", :limit => 1024
t.text "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "reports", :force => true do |t|
t.integer "workspace_id", :default => 1, :null => false
t.string "created_by"
t.string "rtype"
t.string "path", :limit => 1024
t.text "options"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.datetime "downloaded_at"
t.integer "task_id"
t.string "name", :limit => 63
end
create_table "routes", :force => true do |t|
t.integer "session_id"
t.string "subnet"
t.string "netmask"
end
create_table "services", :force => true do |t|
t.integer "host_id"
t.datetime "created_at"
t.integer "port", :null => false
t.string "proto", :limit => 16, :null => false
t.string "state"
t.string "name"
t.datetime "updated_at"
t.text "info"
end
add_index "services", ["name"], :name => "index_services_on_name"
add_index "services", ["port"], :name => "index_services_on_port"
add_index "services", ["proto"], :name => "index_services_on_proto"
add_index "services", ["state"], :name => "index_services_on_state"
create_table "session_events", :force => true do |t|
t.integer "session_id"
t.string "etype"
t.binary "command"
t.binary "output"
t.string "remote_path"
t.string "local_path"
t.datetime "created_at"
end
create_table "sessions", :force => true do |t|
t.integer "host_id"
t.string "stype"
t.string "via_exploit"
t.string "via_payload"
t.string "desc"
t.integer "port"
t.string "platform"
t.text "datastore"
t.datetime "opened_at", :null => false
t.datetime "closed_at"
t.string "close_reason"
t.integer "local_id"
t.datetime "last_seen"
end
create_table "tags", :force => true do |t|
t.integer "user_id"
t.string "name", :limit => 1024
t.text "desc"
t.boolean "report_summary", :default => false, :null => false
t.boolean "report_detail", :default => false, :null => false
t.boolean "critical", :default => false, :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
end
create_table "tasks", :force => true do |t|
t.integer "workspace_id", :default => 1, :null => false
t.string "created_by"
t.string "module"
t.datetime "completed_at"
t.string "path", :limit => 1024
t.string "info"
t.string "description"
t.integer "progress"
t.text "options"
t.text "error"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.text "result"
t.string "module_uuid", :limit => 8
t.binary "settings"
end
create_table "users", :force => true do |t|
t.string "username"
t.string "crypted_password"
t.string "password_salt"
t.string "persistence_token"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "fullname"
t.string "email"
t.string "phone"
t.string "company"
t.string "prefs", :limit => 524288
t.boolean "admin", :default => true, :null => false
end
create_table "vuln_attempts", :force => true do |t|
t.integer "vuln_id"
t.datetime "attempted_at"
t.boolean "exploited"
t.string "fail_reason"
t.string "username"
t.text "module"
t.integer "session_id"
t.integer "loot_id"
t.text "fail_detail"
end
create_table "vuln_details", :force => true do |t|
t.integer "vuln_id"
t.float "cvss_score"
t.string "cvss_vector"
t.string "title"
t.text "description"
t.text "solution"
t.binary "proof"
t.integer "nx_console_id"
t.integer "nx_device_id"
t.string "nx_vuln_id"
t.float "nx_severity"
t.float "nx_pci_severity"
t.datetime "nx_published"
t.datetime "nx_added"
t.datetime "nx_modified"
t.text "nx_tags"
t.text "nx_vuln_status"
t.text "nx_proof_key"
t.string "src"
t.integer "nx_scan_id"
t.datetime "nx_vulnerable_since"
t.string "nx_pci_compliance_status"
end
create_table "vulns", :force => true do |t|
t.integer "host_id"
t.integer "service_id"
t.datetime "created_at"
t.string "name"
t.datetime "updated_at"
t.string "info", :limit => 65536
t.datetime "exploited_at"
t.integer "vuln_detail_count", :default => 0
t.integer "vuln_attempt_count", :default => 0
end
add_index "vulns", ["name"], :name => "index_vulns_on_name"
create_table "vulns_refs", :id => false, :force => true do |t|
t.integer "ref_id"
t.integer "vuln_id"
end
create_table "web_forms", :force => true do |t|
t.integer "web_site_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.text "path"
t.string "method", :limit => 1024
t.text "params"
t.text "query"
end
add_index "web_forms", ["path"], :name => "index_web_forms_on_path"
create_table "web_pages", :force => true do |t|
t.integer "web_site_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.text "path"
t.text "query"
t.integer "code", :null => false
t.text "cookie"
t.text "auth"
t.text "ctype"
t.datetime "mtime"
t.text "location"
t.text "headers"
t.binary "body"
t.binary "request"
end
add_index "web_pages", ["path"], :name => "index_web_pages_on_path"
add_index "web_pages", ["query"], :name => "index_web_pages_on_query"
create_table "web_sites", :force => true do |t|
t.integer "service_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "vhost", :limit => 2048
t.text "comments"
t.text "options"
end
add_index "web_sites", ["comments"], :name => "index_web_sites_on_comments"
add_index "web_sites", ["options"], :name => "index_web_sites_on_options"
add_index "web_sites", ["vhost"], :name => "index_web_sites_on_vhost"
create_table "web_templates", :force => true do |t|
t.string "name", :limit => 512
t.string "title", :limit => 512
t.string "body", :limit => 524288
t.integer "campaign_id"
t.text "prefs"
end
create_table "web_vulns", :force => true do |t|
t.integer "web_site_id", :null => false
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.text "path", :null => false
t.string "method", :limit => 1024, :null => false
t.text "params", :null => false
t.text "pname", :null => false
t.integer "risk", :null => false
t.string "name", :limit => 1024, :null => false
t.text "query"
t.text "category", :null => false
t.text "confidence", :null => false
t.text "description"
t.text "blame"
t.binary "request"
t.binary "proof", :null => false
t.string "owner"
t.text "payload"
end
add_index "web_vulns", ["method"], :name => "index_web_vulns_on_method"
add_index "web_vulns", ["name"], :name => "index_web_vulns_on_name"
add_index "web_vulns", ["path"], :name => "index_web_vulns_on_path"
create_table "wmap_requests", :force => true do |t|
t.string "host"
t.string "address", :limit => nil
t.integer "port"
t.integer "ssl"
t.string "meth", :limit => 32
t.text "path"
t.text "headers"
t.text "query"
t.text "body"
t.string "respcode", :limit => 16
t.text "resphead"
t.text "response"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "wmap_targets", :force => true do |t|
t.string "host"
t.string "address", :limit => nil
t.integer "port"
t.integer "ssl"
t.integer "selected"
t.datetime "created_at"
t.datetime "updated_at"
end
create_table "workspace_members", :id => false, :force => true do |t|
t.integer "workspace_id", :null => false
t.integer "user_id", :null => false
end
create_table "workspaces", :force => true do |t|
t.string "name"
t.datetime "created_at", :null => false
t.datetime "updated_at", :null => false
t.string "boundary", :limit => 4096
t.string "description", :limit => 4096
t.integer "owner_id"
t.boolean "limit_to_network", :default => false, :null => false
end
end

103
lib/tasks/database.rake Normal file
View File

@ -0,0 +1,103 @@
load 'active_record/railties/databases.rake'
module Metasploit
module Framework
def self.env
unless instance_variable_defined? :@env
name = ENV['METASPLOIT_FRAMEWORK_ENV']
name ||= 'development'
@env = ActiveSupport::StringInquirer.new(name)
end
@env
end
def self.root
unless instance_variable_defined? :@root
pathname = Pathname.new(__FILE__)
@root = pathname.parent.parent.parent
end
@root
end
end
end
# 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
# This would normally use Rails.application.config.database_configuration
def database_configurations
YAML.load_file(database_configurations_pathname)
end
def database_configurations_pathname
Metasploit::Framework.root.join('config', 'database.yml')
end
# emulate initializer "active_record.initialize_database" from active_record/railtie
ActiveSupport.on_load(:active_record) do
self.configurations = database_configurations
puts "Connecting to database specified by #{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 = 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

21
lib/tasks/rails.rake Normal file
View File

@ -0,0 +1,21 @@
# 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

View File

@ -1,6 +1,6 @@
require 'rubygems'
require 'bundler'
Bundler.setup(:default, :test)
Bundler.require(:default, :test)
# add project lib directory to load path
spec_pathname = Pathname.new(__FILE__).dirname
@ -12,6 +12,7 @@ $LOAD_PATH.unshift(lib_pathname.to_s)
# 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 'rspec/core'
# Requires supporting ruby files with custom matchers and macros, etc,