metasploit_data_models 0.23.1 → 0.23.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/models/mdm/host.rb +42 -33
- data/app/models/mdm/loot.rb +9 -0
- data/app/models/mdm/module/detail.rb +28 -7
- data/app/models/mdm/module/ref.rb +4 -4
- data/app/models/mdm/ref.rb +5 -5
- data/app/models/mdm/session.rb +18 -1
- data/app/models/mdm/user.rb +13 -0
- data/app/models/mdm/vuln.rb +16 -7
- data/app/models/mdm/workspace.rb +16 -8
- data/app/models/metasploit_data_models/automatic_exploitation.rb +5 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match.rb +42 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match_result.rb +40 -0
- data/app/models/metasploit_data_models/automatic_exploitation/match_set.rb +30 -0
- data/app/models/metasploit_data_models/automatic_exploitation/run.rb +27 -0
- data/app/models/metasploit_data_models/module_run.rb +213 -0
- data/app/validators/password_is_strong_validator.rb +5 -5
- data/db/migrate/20131002004641_create_automatic_exploitation_matches.rb +13 -0
- data/db/migrate/20131002164449_create_automatic_exploitation_match_sets.rb +12 -0
- data/db/migrate/20131008213344_create_automatic_exploitation_runs.rb +11 -0
- data/db/migrate/20131011184338_module_detail_on_automatic_exploitation_match.rb +10 -0
- data/db/migrate/20131017150735_create_automatic_exploitation_match_results.rb +11 -0
- data/db/migrate/20131021185657_make_match_polymorphic.rb +11 -0
- data/db/migrate/20150219173821_create_module_runs.rb +23 -0
- data/db/migrate/20150219215039_add_module_run_to_session.rb +8 -0
- data/db/migrate/20150226151459_add_module_run_fk_to_loot.rb +8 -0
- data/db/migrate/20150312155312_add_module_full_name_to_match.rb +6 -0
- data/db/migrate/20150326183742_add_missing_ae_indices.rb +13 -0
- data/lib/metasploit_data_models/version.rb +1 -1
- data/spec/app/models/mdm/host_spec.rb +28 -27
- data/spec/app/models/mdm/loot_spec.rb +1 -0
- data/spec/app/models/mdm/module/detail_spec.rb +2 -2
- data/spec/app/models/mdm/session_spec.rb +21 -18
- data/spec/app/models/mdm/vuln_spec.rb +9 -10
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_result_spec.rb +88 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_set_spec.rb +48 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_spec.rb +25 -0
- data/spec/app/models/metasploit_data_models/automatic_exploitation/run_spec.rb +40 -0
- data/spec/app/models/metasploit_data_models/module_run_spec.rb +136 -0
- data/spec/dummy/db/structure.sql +369 -2
- data/spec/factories/mdm/module/details.rb +21 -21
- data/spec/factories/metasploit_data_models/automatic_exploitation/match_results.rb +7 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/match_sets.rb +8 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/matches.rb +6 -0
- data/spec/factories/metasploit_data_models/automatic_exploitation/runs.rb +6 -0
- data/spec/factories/module_runs.rb +40 -0
- metadata +30 -172
@@ -0,0 +1,12 @@
|
|
1
|
+
class CreateAutomaticExploitationMatchSets < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :automatic_exploitation_match_sets do |t|
|
4
|
+
t.integer :workspace_id
|
5
|
+
t.integer :user_id
|
6
|
+
|
7
|
+
t.timestamps
|
8
|
+
end
|
9
|
+
add_index :automatic_exploitation_match_sets, :user_id
|
10
|
+
add_index :automatic_exploitation_match_sets, :workspace_id
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
class ModuleDetailOnAutomaticExploitationMatch < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
rename_column :automatic_exploitation_matches, :ref_id, :module_detail_id
|
4
|
+
add_column :automatic_exploitation_matches, :match_set_id, :integer
|
5
|
+
end
|
6
|
+
|
7
|
+
def down
|
8
|
+
rename_column :automatic_exploitation_matches, :module_detail_id, :ref_id
|
9
|
+
end
|
10
|
+
end
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class MakeMatchPolymorphic < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
add_column :automatic_exploitation_matches, :matchable_type, :string
|
4
|
+
add_column :automatic_exploitation_matches, :matchable_id, :integer
|
5
|
+
end
|
6
|
+
|
7
|
+
def down
|
8
|
+
remove_column :automatic_exploitation_matches, :matchable_type
|
9
|
+
remove_column :automatic_exploitation_matches, :matchable_id
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
class CreateModuleRuns < ActiveRecord::Migration
|
2
|
+
def change
|
3
|
+
create_table :module_runs do |t|
|
4
|
+
t.datetime :attempted_at
|
5
|
+
t.text :fail_detail
|
6
|
+
t.string :fail_reason
|
7
|
+
t.text :module_fullname
|
8
|
+
t.integer :port
|
9
|
+
t.string :proto
|
10
|
+
t.integer :session_id
|
11
|
+
t.string :status
|
12
|
+
t.integer :trackable_id
|
13
|
+
t.string :trackable_type
|
14
|
+
t.integer :user_id
|
15
|
+
t.string :username
|
16
|
+
|
17
|
+
t.timestamps
|
18
|
+
end
|
19
|
+
|
20
|
+
add_index :module_runs, :session_id
|
21
|
+
add_index :module_runs, :user_id
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,13 @@
|
|
1
|
+
class AddMissingAeIndices < ActiveRecord::Migration
|
2
|
+
def up
|
3
|
+
add_index :automatic_exploitation_match_results, :match_id
|
4
|
+
add_index :automatic_exploitation_match_results, :run_id
|
5
|
+
|
6
|
+
add_index :automatic_exploitation_runs, :match_set_id
|
7
|
+
add_index :automatic_exploitation_runs, :user_id
|
8
|
+
add_index :automatic_exploitation_runs, :workspace_id
|
9
|
+
end
|
10
|
+
|
11
|
+
def down
|
12
|
+
end
|
13
|
+
end
|
@@ -6,7 +6,7 @@ module MetasploitDataModels
|
|
6
6
|
# The minor version number, scoped to the {MAJOR} version number.
|
7
7
|
MINOR = 23
|
8
8
|
# The patch number, scoped to the {MAJOR} and {MINOR} version numbers.
|
9
|
-
PATCH =
|
9
|
+
PATCH = 2
|
10
10
|
|
11
11
|
# The full version string, including the {MAJOR}, {MINOR}, {PATCH}, and optionally, the `PRERELEASE` in the
|
12
12
|
# {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0} format.
|
@@ -102,7 +102,7 @@ describe Mdm::Host do
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
-
|
105
|
+
context 'associations' do
|
106
106
|
it { should have_many(:creds).class_name('Mdm::Cred').through(:services) }
|
107
107
|
it { should have_many(:clients).class_name('Mdm::Client').dependent(:destroy) }
|
108
108
|
it { should have_many(:exploit_attempts).class_name('Mdm::ExploitAttempt').dependent(:destroy) }
|
@@ -110,6 +110,7 @@ describe Mdm::Host do
|
|
110
110
|
it { should have_many(:host_details).class_name('Mdm::HostDetail').dependent(:destroy) }
|
111
111
|
it { should have_many(:hosts_tags).class_name('Mdm::HostTag') }
|
112
112
|
it { should have_many(:loots).class_name('Mdm::Loot').dependent(:destroy).order('loots.created_at DESC') }
|
113
|
+
it { should have_many(:module_runs).class_name('MetasploitDataModels::ModuleRun') }
|
113
114
|
it { should have_many(:task_hosts).class_name('Mdm::TaskHost').dependent(:destroy) }
|
114
115
|
it { should have_many(:tasks).class_name('Mdm::Task').through(:task_hosts) }
|
115
116
|
|
@@ -208,9 +209,9 @@ describe Mdm::Host do
|
|
208
209
|
it { should have_many(:vuln_refs).class_name('Mdm::VulnRef') }
|
209
210
|
it { should have_many(:web_sites).class_name('Mdm::WebSite').through(:services) }
|
210
211
|
it { should belong_to(:workspace).class_name('Mdm::Workspace') }
|
211
|
-
|
212
|
+
end
|
212
213
|
|
213
|
-
|
214
|
+
context 'CONSTANTS' do
|
214
215
|
context 'ARCHITECTURES' do
|
215
216
|
subject(:architectures) do
|
216
217
|
described_class::ARCHITECTURES
|
@@ -285,30 +286,30 @@ describe Mdm::Host do
|
|
285
286
|
|
286
287
|
end
|
287
288
|
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
289
|
+
context 'SEARCH_FIELDS' do
|
290
|
+
subject(:search_fields) do
|
291
|
+
described_class::SEARCH_FIELDS
|
292
|
+
end
|
293
|
+
|
294
|
+
it 'should be an Array<String>' do
|
295
|
+
search_fields.should be_an Array
|
296
|
+
|
297
|
+
search_fields.each { |search_field|
|
298
|
+
search_field.should be_a String
|
299
|
+
}
|
300
|
+
end
|
301
|
+
|
302
|
+
it 'should cast address to text' do
|
303
|
+
search_fields.should include('address::text')
|
304
|
+
end
|
305
|
+
|
306
|
+
it { should include('comments') }
|
307
|
+
it { should include('mac') }
|
308
|
+
it { should include('name') }
|
309
|
+
it { should include('os_flavor') }
|
310
|
+
it { should include('os_name') }
|
311
|
+
it { should include('os_sp') }
|
312
|
+
it { should include('purpose') }
|
312
313
|
end
|
313
314
|
|
314
315
|
it 'should define STATES in any order' do
|
@@ -7,6 +7,7 @@ describe Mdm::Loot do
|
|
7
7
|
it { should belong_to(:workspace).class_name('Mdm::Workspace') }
|
8
8
|
it { should belong_to(:service).class_name('Mdm::Service') }
|
9
9
|
it { should belong_to(:host).class_name('Mdm::Host') }
|
10
|
+
it { should belong_to(:module_run).class_name('MetasploitDataModels::ModuleRun') }
|
10
11
|
end
|
11
12
|
|
12
13
|
context 'database' do
|
@@ -25,31 +25,34 @@ describe Mdm::Session do
|
|
25
25
|
context 'database' do
|
26
26
|
|
27
27
|
context 'timestamps'do
|
28
|
-
it {
|
29
|
-
it {
|
30
|
-
it {
|
28
|
+
it { is_expected.to have_db_column(:closed_at).of_type(:datetime) }
|
29
|
+
it { is_expected.to have_db_column(:last_seen).of_type(:datetime) }
|
30
|
+
it { is_expected.to have_db_column(:opened_at).of_type(:datetime).with_options(:null => false) }
|
31
31
|
end
|
32
32
|
|
33
33
|
context 'columns' do
|
34
|
-
it {
|
35
|
-
it {
|
36
|
-
it {
|
37
|
-
it {
|
38
|
-
it {
|
39
|
-
it {
|
40
|
-
it {
|
41
|
-
it {
|
42
|
-
it {
|
34
|
+
it { is_expected.to have_db_column(:datastore).of_type(:text) }
|
35
|
+
it { is_expected.to have_db_column(:desc).of_type(:string) }
|
36
|
+
it { is_expected.to have_db_column(:host_id).of_type(:integer) }
|
37
|
+
it { is_expected.to have_db_column(:local_id).of_type(:integer) }
|
38
|
+
it { is_expected.to have_db_column(:module_run_id).of_type(:integer) }
|
39
|
+
it { is_expected.to have_db_column(:platform).of_type(:string) }
|
40
|
+
it { is_expected.to have_db_column(:port).of_type(:integer) }
|
41
|
+
it { is_expected.to have_db_column(:stype).of_type(:string) }
|
42
|
+
it { is_expected.to have_db_column(:via_exploit).of_type(:string) }
|
43
|
+
it { is_expected.to have_db_column(:via_payload).of_type(:string) }
|
43
44
|
end
|
44
45
|
end
|
45
46
|
|
46
47
|
context 'associations' do
|
47
|
-
it {
|
48
|
-
it {
|
49
|
-
it {
|
50
|
-
it {
|
51
|
-
it {
|
52
|
-
it {
|
48
|
+
it { is_expected.to have_many(:events).class_name('Mdm::SessionEvent').dependent(:delete_all) }
|
49
|
+
it { is_expected.to belong_to(:host).class_name('Mdm::Host') }
|
50
|
+
it { is_expected.to belong_to(:originating_module_run).class_name('MetasploitDataModels::ModuleRun') }
|
51
|
+
it { is_expected.to have_many(:routes).class_name('Mdm::Route').dependent(:delete_all) }
|
52
|
+
it { is_expected.to have_many(:target_module_runs).class_name('MetasploitDataModels::ModuleRun') }
|
53
|
+
it { is_expected.to have_many(:tasks).class_name('Mdm::Task').through(:task_sessions)}
|
54
|
+
it { is_expected.to have_many(:task_sessions).class_name('Mdm::TaskSession').dependent(:destroy) }
|
55
|
+
it { is_expected.to have_one(:workspace).class_name('Mdm::Workspace').through(:host) }
|
53
56
|
end
|
54
57
|
|
55
58
|
context 'scopes' do
|
@@ -33,16 +33,15 @@ describe Mdm::Vuln do
|
|
33
33
|
|
34
34
|
|
35
35
|
context 'associations' do
|
36
|
-
it {
|
37
|
-
it {
|
38
|
-
it {
|
39
|
-
|
40
|
-
it {
|
41
|
-
it {
|
42
|
-
it {
|
43
|
-
|
44
|
-
it {
|
45
|
-
it { should have_many(:notes).class_name('Mdm::Note').dependent(:delete_all).order('notes.created_at') }
|
36
|
+
it { is_expected.to belong_to(:host).class_name('Mdm::Host') }
|
37
|
+
it { is_expected.to belong_to(:service).class_name('Mdm::Service') }
|
38
|
+
it { is_expected.to have_many(:module_refs).class_name('Mdm::Module::Ref').through(:refs) }
|
39
|
+
it { is_expected.to have_many(:module_runs).class_name('MetasploitDataModels::ModuleRun') }
|
40
|
+
it { is_expected.to have_many(:refs).class_name('Mdm::Ref').through(:vulns_refs) }
|
41
|
+
it { is_expected.to have_many(:vuln_attempts).class_name('Mdm::VulnAttempt').dependent(:destroy) }
|
42
|
+
it { is_expected.to have_many(:vuln_details).class_name('Mdm::VulnDetail').dependent(:destroy) }
|
43
|
+
it { is_expected.to have_many(:vulns_refs).class_name('Mdm::VulnRef').dependent(:destroy) }
|
44
|
+
it { is_expected.to have_many(:notes).class_name('Mdm::Note').dependent(:delete_all).order('notes.created_at') }
|
46
45
|
|
47
46
|
context 'module_details' do
|
48
47
|
it { should have_many(:module_details).class_name('Mdm::Module::Detail').through(:module_refs) }
|
@@ -0,0 +1,88 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MetasploitDataModels::AutomaticExploitation::MatchResult do
|
4
|
+
it_should_behave_like 'Metasploit::Concern.run'
|
5
|
+
|
6
|
+
context "database" do
|
7
|
+
it { is_expected.to have_db_column(:match_id).of_type(:integer) }
|
8
|
+
it { is_expected.to have_db_index(:match_id) }
|
9
|
+
it { is_expected.to have_db_column(:run_id).of_type(:integer) }
|
10
|
+
it { is_expected.to have_db_index(:run_id) }
|
11
|
+
end
|
12
|
+
|
13
|
+
context 'associations' do
|
14
|
+
it { should belong_to(:match).class_name('MetasploitDataModels::AutomaticExploitation::Match') }
|
15
|
+
it { should belong_to(:run).class_name('MetasploitDataModels::AutomaticExploitation::Run') }
|
16
|
+
end
|
17
|
+
|
18
|
+
context 'scopes' do
|
19
|
+
before do
|
20
|
+
match_failed = FactoryGirl.create(:automatic_exploitation_match)
|
21
|
+
match_succeeded = FactoryGirl.create(:automatic_exploitation_match)
|
22
|
+
run = FactoryGirl.create(:automatic_exploitation_run)
|
23
|
+
|
24
|
+
described_class.create do |match_result|
|
25
|
+
match_result.match = match_failed
|
26
|
+
match_result.run = run
|
27
|
+
match_result.state = MetasploitDataModels::AutomaticExploitation::MatchResult::SUCCEEDED
|
28
|
+
end
|
29
|
+
|
30
|
+
described_class.create do |match_result|
|
31
|
+
match_result.match = match_succeeded
|
32
|
+
match_result.run = run
|
33
|
+
match_result.state = MetasploitDataModels::AutomaticExploitation::MatchResult::FAILED
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'succeeded' do
|
38
|
+
subject(:succeeded) do
|
39
|
+
described_class.succeeded
|
40
|
+
end
|
41
|
+
|
42
|
+
specify 'returns only successful results' do
|
43
|
+
expect(succeeded.count).to eq(1)
|
44
|
+
expect(succeeded.first.state).to eq(MetasploitDataModels::AutomaticExploitation::MatchResult::SUCCEEDED)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'failed' do
|
49
|
+
subject(:failed) do
|
50
|
+
described_class.failed
|
51
|
+
end
|
52
|
+
|
53
|
+
specify 'returns only failed results' do
|
54
|
+
expect(failed.count).to eq(1)
|
55
|
+
expect(failed.first.state).to eq(MetasploitDataModels::AutomaticExploitation::MatchResult::FAILED)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'validations' do
|
61
|
+
context 'state' do
|
62
|
+
subject(:match_result) do
|
63
|
+
FactoryGirl.build(:automatic_exploitation_match_result, state: state)
|
64
|
+
end
|
65
|
+
context 'with nil' do
|
66
|
+
let(:state) { nil }
|
67
|
+
specify do
|
68
|
+
expect(match_result).not_to be_valid
|
69
|
+
expect(match_result.errors[:state]).to include("can't be blank")
|
70
|
+
end
|
71
|
+
end
|
72
|
+
context 'with "asdf"' do
|
73
|
+
let(:state) { "asdf" }
|
74
|
+
specify do
|
75
|
+
expect(match_result).not_to be_valid
|
76
|
+
expect(match_result.errors[:state]).to include("is not included in the list")
|
77
|
+
end
|
78
|
+
end
|
79
|
+
context 'with "succeeded"' do
|
80
|
+
let(:state) { MetasploitDataModels::AutomaticExploitation::MatchResult::SUCCEEDED }
|
81
|
+
specify do
|
82
|
+
expect(match_result).to be_valid
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe MetasploitDataModels::AutomaticExploitation::MatchSet do
|
4
|
+
describe "database" do
|
5
|
+
describe "foreign_keys" do
|
6
|
+
it { should have_db_column(:workspace_id).of_type(:integer) }
|
7
|
+
it { should have_db_column(:user_id).of_type(:integer) }
|
8
|
+
end
|
9
|
+
|
10
|
+
describe "indices" do
|
11
|
+
it { should have_db_index(:user_id) }
|
12
|
+
it { should have_db_index(:workspace_id) }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
describe "associations" do
|
17
|
+
it { should have_many(:matches).class_name('MetasploitDataModels::AutomaticExploitation::Match') }
|
18
|
+
it { should have_many(:matches).inverse_of(:match_set) }
|
19
|
+
it { should have_many(:runs).class_name('MetasploitDataModels::AutomaticExploitation::Run') }
|
20
|
+
it { should have_many(:runs).inverse_of(:match_set) }
|
21
|
+
it { should belong_to(:user).class_name('Mdm::User') }
|
22
|
+
it { should belong_to(:user).inverse_of(:automatic_exploitation_match_sets) }
|
23
|
+
it { should belong_to(:workspace).class_name('Mdm::Workspace') }
|
24
|
+
it { should belong_to(:workspace).inverse_of(:automatic_exploitation_match_sets) }
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "validations" do
|
28
|
+
subject(:match_set){ FactoryGirl.build(:automatic_exploitation_match_set)}
|
29
|
+
|
30
|
+
describe "missing user" do
|
31
|
+
before(:each) do
|
32
|
+
match_set.user = nil
|
33
|
+
end
|
34
|
+
|
35
|
+
it{ is_expected.to be_invalid }
|
36
|
+
end
|
37
|
+
|
38
|
+
describe "missing workspace" do
|
39
|
+
before(:each) do
|
40
|
+
match_set.workspace = nil
|
41
|
+
end
|
42
|
+
|
43
|
+
it{ is_expected.to be_invalid }
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|