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.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/app/models/mdm/host.rb +42 -33
  3. data/app/models/mdm/loot.rb +9 -0
  4. data/app/models/mdm/module/detail.rb +28 -7
  5. data/app/models/mdm/module/ref.rb +4 -4
  6. data/app/models/mdm/ref.rb +5 -5
  7. data/app/models/mdm/session.rb +18 -1
  8. data/app/models/mdm/user.rb +13 -0
  9. data/app/models/mdm/vuln.rb +16 -7
  10. data/app/models/mdm/workspace.rb +16 -8
  11. data/app/models/metasploit_data_models/automatic_exploitation.rb +5 -0
  12. data/app/models/metasploit_data_models/automatic_exploitation/match.rb +42 -0
  13. data/app/models/metasploit_data_models/automatic_exploitation/match_result.rb +40 -0
  14. data/app/models/metasploit_data_models/automatic_exploitation/match_set.rb +30 -0
  15. data/app/models/metasploit_data_models/automatic_exploitation/run.rb +27 -0
  16. data/app/models/metasploit_data_models/module_run.rb +213 -0
  17. data/app/validators/password_is_strong_validator.rb +5 -5
  18. data/db/migrate/20131002004641_create_automatic_exploitation_matches.rb +13 -0
  19. data/db/migrate/20131002164449_create_automatic_exploitation_match_sets.rb +12 -0
  20. data/db/migrate/20131008213344_create_automatic_exploitation_runs.rb +11 -0
  21. data/db/migrate/20131011184338_module_detail_on_automatic_exploitation_match.rb +10 -0
  22. data/db/migrate/20131017150735_create_automatic_exploitation_match_results.rb +11 -0
  23. data/db/migrate/20131021185657_make_match_polymorphic.rb +11 -0
  24. data/db/migrate/20150219173821_create_module_runs.rb +23 -0
  25. data/db/migrate/20150219215039_add_module_run_to_session.rb +8 -0
  26. data/db/migrate/20150226151459_add_module_run_fk_to_loot.rb +8 -0
  27. data/db/migrate/20150312155312_add_module_full_name_to_match.rb +6 -0
  28. data/db/migrate/20150326183742_add_missing_ae_indices.rb +13 -0
  29. data/lib/metasploit_data_models/version.rb +1 -1
  30. data/spec/app/models/mdm/host_spec.rb +28 -27
  31. data/spec/app/models/mdm/loot_spec.rb +1 -0
  32. data/spec/app/models/mdm/module/detail_spec.rb +2 -2
  33. data/spec/app/models/mdm/session_spec.rb +21 -18
  34. data/spec/app/models/mdm/vuln_spec.rb +9 -10
  35. data/spec/app/models/metasploit_data_models/automatic_exploitation/match_result_spec.rb +88 -0
  36. data/spec/app/models/metasploit_data_models/automatic_exploitation/match_set_spec.rb +48 -0
  37. data/spec/app/models/metasploit_data_models/automatic_exploitation/match_spec.rb +25 -0
  38. data/spec/app/models/metasploit_data_models/automatic_exploitation/run_spec.rb +40 -0
  39. data/spec/app/models/metasploit_data_models/module_run_spec.rb +136 -0
  40. data/spec/dummy/db/structure.sql +369 -2
  41. data/spec/factories/mdm/module/details.rb +21 -21
  42. data/spec/factories/metasploit_data_models/automatic_exploitation/match_results.rb +7 -0
  43. data/spec/factories/metasploit_data_models/automatic_exploitation/match_sets.rb +8 -0
  44. data/spec/factories/metasploit_data_models/automatic_exploitation/matches.rb +6 -0
  45. data/spec/factories/metasploit_data_models/automatic_exploitation/runs.rb +6 -0
  46. data/spec/factories/module_runs.rb +40 -0
  47. 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,11 @@
1
+ class CreateAutomaticExploitationRuns < ActiveRecord::Migration
2
+ def change
3
+ create_table :automatic_exploitation_runs do |t|
4
+ t.integer :workspace_id
5
+ t.integer :user_id
6
+ t.integer :match_set_id
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ 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 CreateAutomaticExploitationMatchResults < ActiveRecord::Migration
2
+ def change
3
+ create_table :automatic_exploitation_match_results do |t|
4
+ t.integer :match_id
5
+ t.integer :run_id
6
+ t.string :state, null: false
7
+
8
+ t.timestamps
9
+ end
10
+ end
11
+ 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,8 @@
1
+ class AddModuleRunToSession < ActiveRecord::Migration
2
+ def change
3
+ change_table :sessions do |t|
4
+ t.integer :module_run_id
5
+ end
6
+ add_index :sessions, :module_run_id
7
+ end
8
+ end
@@ -0,0 +1,8 @@
1
+ class AddModuleRunFkToLoot < ActiveRecord::Migration
2
+ def change
3
+ change_table(:loots) do |t|
4
+ t.integer :module_run_id
5
+ t.index :module_run_id
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ class AddModuleFullNameToMatch < ActiveRecord::Migration
2
+ def change
3
+ add_column :automatic_exploitation_matches, :module_fullname, :text
4
+ add_index :automatic_exploitation_matches, :module_fullname
5
+ end
6
+ 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 = 1
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
- context 'associations' do
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
- end
212
+ end
212
213
 
213
- context 'CONSTANTS' do
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
- context 'SEARCH_FIELDS' do
289
- subject(:search_fields) do
290
- described_class::SEARCH_FIELDS
291
- end
292
-
293
- it 'should be an Array<String>' do
294
- search_fields.should be_an Array
295
-
296
- search_fields.each { |search_field|
297
- search_field.should be_a String
298
- }
299
- end
300
-
301
- it 'should cast address to text' do
302
- search_fields.should include('address::text')
303
- end
304
-
305
- it { should include('comments') }
306
- it { should include('mac') }
307
- it { should include('name') }
308
- it { should include('os_flavor') }
309
- it { should include('os_name') }
310
- it { should include('os_sp') }
311
- it { should include('purpose') }
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
@@ -430,5 +430,5 @@ describe Mdm::Module::Detail do
430
430
  its(:name) { should == name }
431
431
  end
432
432
  end
433
- end
434
- end
433
+ end
434
+ end
@@ -25,31 +25,34 @@ describe Mdm::Session do
25
25
  context 'database' do
26
26
 
27
27
  context 'timestamps'do
28
- it { should have_db_column(:opened_at).of_type(:datetime).with_options(:null => false) }
29
- it { should have_db_column(:closed_at).of_type(:datetime) }
30
- it { should have_db_column(:last_seen).of_type(:datetime) }
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 { should have_db_column(:host_id).of_type(:integer) }
35
- it { should have_db_column(:stype).of_type(:string) }
36
- it { should have_db_column(:via_exploit).of_type(:string) }
37
- it { should have_db_column(:via_payload).of_type(:string) }
38
- it { should have_db_column(:desc).of_type(:string) }
39
- it { should have_db_column(:port).of_type(:integer) }
40
- it { should have_db_column(:platform).of_type(:string) }
41
- it { should have_db_column(:datastore).of_type(:text) }
42
- it { should have_db_column(:local_id).of_type(:integer) }
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 { should belong_to(:host).class_name('Mdm::Host') }
48
- it { should have_many(:events).class_name('Mdm::SessionEvent').dependent(:delete_all) }
49
- it { should have_many(:routes).class_name('Mdm::Route').dependent(:delete_all) }
50
- it { should have_one(:workspace).class_name('Mdm::Workspace').through(:host) }
51
- it { should have_many(:task_sessions).class_name('Mdm::TaskSession').dependent(:destroy)}
52
- it { should have_many(:tasks).class_name('Mdm::Task').through(:task_sessions)}
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 { should belong_to(:host).class_name('Mdm::Host') }
37
- it { should belong_to(:service).class_name('Mdm::Service') }
38
- it { should have_many(:module_refs).class_name('Mdm::Module::Ref').through(:refs) }
39
- # @todo https://www.pivotaltracker.com/story/show/49004623
40
- it { should have_many(:refs).class_name('Mdm::Ref').through(:vulns_refs) }
41
- it { should have_many(:vuln_attempts).class_name('Mdm::VulnAttempt').dependent(:destroy) }
42
- it { should have_many(:vuln_details).class_name('Mdm::VulnDetail').dependent(:destroy) }
43
- # @todo https://www.pivotaltracker.com/story/show/49004623
44
- it { should have_many(:vulns_refs).class_name('Mdm::VulnRef').dependent(:destroy) }
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