metasploit_data_models 0.15.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/Gemfile +2 -0
  2. data/app/models/mdm/client.rb +0 -1
  3. data/app/models/mdm/cred.rb +1 -1
  4. data/app/models/mdm/exploited_host.rb +0 -1
  5. data/app/models/mdm/listener.rb +2 -1
  6. data/app/models/mdm/nexpose_console.rb +2 -2
  7. data/app/models/mdm/session.rb +5 -1
  8. data/app/models/mdm/workspace.rb +0 -1
  9. data/db/migrate/20130525015035_remove_campaign_id_from_clients.rb +9 -0
  10. data/db/migrate/20130525212420_drop_table_imported_creds.rb +14 -0
  11. data/db/migrate/20130531144949_making_host_tags_a_real_ar_model.rb +6 -0
  12. data/lib/mdm/host/operating_system_normalization.rb +4 -4
  13. data/lib/metasploit_data_models/version.rb +1 -1
  14. data/spec/app/models/mdm/client_spec.rb +43 -0
  15. data/spec/app/models/mdm/cred_spec.rb +211 -0
  16. data/spec/app/models/mdm/events_spec.rb +85 -0
  17. data/spec/app/models/mdm/exploit_attempt_spec.rb +60 -0
  18. data/spec/app/models/mdm/exploited_host_spec.rb +44 -0
  19. data/spec/app/models/mdm/host_detail_spec.rb +49 -0
  20. data/spec/app/models/mdm/host_spec.rb +468 -0
  21. data/spec/app/models/mdm/host_tag_spec.rb +26 -0
  22. data/spec/app/models/mdm/listener_spec.rb +108 -0
  23. data/spec/app/models/mdm/loot_spec.rb +77 -0
  24. data/spec/app/models/mdm/nexpose_console_spec.rb +128 -0
  25. data/spec/app/models/mdm/note_spec.rb +84 -0
  26. data/spec/app/models/mdm/ref_spec.rb +13 -0
  27. data/spec/app/models/mdm/report_spec.rb +104 -0
  28. data/spec/app/models/mdm/report_template_spec.rb +52 -0
  29. data/spec/app/models/mdm/route_spec.rb +36 -0
  30. data/spec/app/models/mdm/service_spec.rb +70 -15
  31. data/spec/app/models/mdm/session_event_spec.rb +42 -0
  32. data/spec/app/models/mdm/session_spec.rb +114 -0
  33. data/spec/app/models/mdm/tag_spec.rb +104 -0
  34. data/spec/app/models/mdm/task_creds_spec.rb +32 -0
  35. data/spec/app/models/mdm/task_host_spec.rb +33 -0
  36. data/spec/app/models/mdm/task_service_spec.rb +33 -0
  37. data/spec/app/models/mdm/task_spec.rb +59 -5
  38. data/spec/app/models/mdm/user_spec.rb +51 -0
  39. data/spec/app/models/mdm/vuln_attempt_spec.rb +54 -0
  40. data/spec/app/models/mdm/vuln_details_spec.rb +66 -0
  41. data/spec/app/models/mdm/vuln_ref_spec.rb +24 -0
  42. data/spec/app/models/mdm/vuln_spec.rb +25 -0
  43. data/spec/app/models/mdm/web_form_spec.rb +47 -0
  44. data/spec/app/models/mdm/web_page_spec.rb +55 -0
  45. data/spec/app/models/mdm/web_site_spec.rb +86 -0
  46. data/spec/app/models/mdm/web_vuln_spec.rb +12 -0
  47. data/spec/app/models/mdm/workspace_spec.rb +567 -0
  48. data/spec/dummy/db/schema.rb +5 -13
  49. data/spec/factories/mdm/addresses.rb +5 -0
  50. data/spec/factories/mdm/clients.rb +8 -0
  51. data/spec/factories/mdm/events.rb +15 -0
  52. data/spec/factories/mdm/exploit_attempts.rb +8 -0
  53. data/spec/factories/mdm/exploited_hosts.rb +7 -0
  54. data/spec/factories/mdm/fingerprints/nessus_fingerprints.rb +6 -0
  55. data/spec/factories/mdm/fingerprints/nexpose_fingerprints.rb +6 -0
  56. data/spec/factories/mdm/fingerprints/nmap_fingerprints.rb +6 -0
  57. data/spec/factories/mdm/fingerprints/retina_fingerprints.rb +6 -0
  58. data/spec/factories/mdm/fingerprints/session_fingerprints.rb +6 -0
  59. data/spec/factories/mdm/host_details.rb +8 -0
  60. data/spec/factories/mdm/listeners.rb +12 -0
  61. data/spec/factories/mdm/loots.rb +11 -0
  62. data/spec/factories/mdm/nexpose_consoles.rb +15 -0
  63. data/spec/factories/mdm/notes.rb +12 -0
  64. data/spec/factories/mdm/report_templates.rb +8 -0
  65. data/spec/factories/mdm/reports.rb +13 -0
  66. data/spec/factories/mdm/routes.rb +36 -0
  67. data/spec/factories/mdm/session_events.rb +8 -0
  68. data/spec/factories/mdm/sessions.rb +13 -0
  69. data/spec/factories/mdm/vuln_attempts.rb +8 -0
  70. data/spec/factories/mdm/vuln_details.rb +8 -0
  71. data/spec/factories/mdm/web_forms.rb +33 -0
  72. data/spec/factories/mdm/web_pages.rb +64 -0
  73. metadata +95 -5
  74. data/app/models/mdm/imported_cred.rb +0 -10
@@ -0,0 +1,104 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::Report do
4
+
5
+ context 'associations' do
6
+ it { should belong_to(:workspace).class_name('Mdm::Workspace') }
7
+ it { should belong_to(:task).class_name('Mdm::Task') }
8
+ end
9
+
10
+ context 'validations' do
11
+ context 'name' do
12
+ it 'may be blank' do
13
+ blank_name = FactoryGirl.build(:mdm_report, :name => '')
14
+ blank_name.should be_valid
15
+ end
16
+
17
+ it 'may contain A-Z, 0-9, space, dot, underscore, or dash' do
18
+ named_report = FactoryGirl.build(:mdm_report, :name => 'A1 B2.C_3-D')
19
+ named_report.should be_valid
20
+ end
21
+
22
+ it 'may not contain other characters' do
23
+ invalid_name = FactoryGirl.build(:mdm_report, :name => 'A/1')
24
+ invalid_name.should_not be_valid
25
+ invalid_name.errors[:name].should include('name must consist of A-Z, 0-9, space, dot, underscore, or dash')
26
+ invalid_name = FactoryGirl.build(:mdm_report, :name => '#A1')
27
+ invalid_name.should_not be_valid
28
+ invalid_name.errors[:name].should include('name must consist of A-Z, 0-9, space, dot, underscore, or dash')
29
+ invalid_name = FactoryGirl.build(:mdm_report, :name => 'A,1')
30
+ invalid_name.should_not be_valid
31
+ invalid_name.errors[:name].should include('name must consist of A-Z, 0-9, space, dot, underscore, or dash')
32
+ invalid_name = FactoryGirl.build(:mdm_report, :name => 'A;1')
33
+ invalid_name.should_not be_valid
34
+ invalid_name.errors[:name].should include('name must consist of A-Z, 0-9, space, dot, underscore, or dash')
35
+ invalid_name = FactoryGirl.build(:mdm_report, :name => "A' or '1'='1'")
36
+ invalid_name.should_not be_valid
37
+ invalid_name.errors[:name].should include('name must consist of A-Z, 0-9, space, dot, underscore, or dash')
38
+ end
39
+ end
40
+ end
41
+
42
+ context 'scopes' do
43
+ context 'flagged' do
44
+ it 'should return un-downlaoded reports' do
45
+ flagged_report = FactoryGirl.create(:mdm_report)
46
+ Mdm::Report.flagged.should include(flagged_report)
47
+ end
48
+
49
+ it 'should not return reports that have been downloaded' do
50
+ downlaoded_report = FactoryGirl.create(:mdm_report, :downloaded_at => Time.now)
51
+ Mdm::Report.flagged.should_not include(downlaoded_report)
52
+ end
53
+ end
54
+ end
55
+
56
+ context 'callbacks' do
57
+ context 'before_destroy' do
58
+ it 'should call #delete_file' do
59
+ myreport = FactoryGirl.create(:mdm_report)
60
+ myreport.should_receive(:delete_file)
61
+ myreport.destroy
62
+ end
63
+ end
64
+ end
65
+
66
+ context 'factory' do
67
+ it 'should be valid' do
68
+ report = FactoryGirl.build(:mdm_report)
69
+ report.should be_valid
70
+ end
71
+ end
72
+
73
+ context '#destroy' do
74
+ it 'should successfully destroy the object' do
75
+ report = FactoryGirl.create(:mdm_report)
76
+ expect {
77
+ report.destroy
78
+ }.to_not raise_error
79
+ expect {
80
+ report.reload
81
+ }.to raise_error(ActiveRecord::RecordNotFound)
82
+ end
83
+ end
84
+
85
+ context 'database' do
86
+
87
+ context 'timestamps'do
88
+ it { should have_db_column(:created_at).of_type(:datetime).with_options(:null => false) }
89
+ it { should have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) }
90
+ it { should have_db_column(:downloaded_at).of_type(:datetime) }
91
+ end
92
+
93
+ context 'columns' do
94
+ it { should have_db_column(:workspace_id).of_type(:integer).with_options(:null => false, :default =>1) }
95
+ it { should have_db_column(:created_by).of_type(:string) }
96
+ it { should have_db_column(:rtype).of_type(:string) }
97
+ it { should have_db_column(:path).of_type(:string) }
98
+ it { should have_db_column(:options).of_type(:text) }
99
+ it { should have_db_column(:name).of_type(:string) }
100
+
101
+ end
102
+ end
103
+
104
+ end
@@ -0,0 +1,52 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::ReportTemplate do
4
+
5
+ context 'associations' do
6
+ it { should belong_to(:workspace).class_name('Mdm::Workspace') }
7
+ end
8
+
9
+ context 'callbacks' do
10
+ context 'before_destroy' do
11
+ it 'should call #delete_file' do
12
+ report_template = FactoryGirl.create(:mdm_report_template)
13
+ report_template.should_receive(:delete_file)
14
+ report_template.destroy
15
+ end
16
+ end
17
+ end
18
+
19
+ context 'factory' do
20
+ it 'should be valid' do
21
+ report_template = FactoryGirl.build(:mdm_report_template)
22
+ report_template.should be_valid
23
+ end
24
+ end
25
+
26
+ context '#destroy' do
27
+ it 'should successfully destroy the object' do
28
+ report_template = FactoryGirl.create(:mdm_report_template)
29
+ expect {
30
+ report_template.destroy
31
+ }.to_not raise_error
32
+ expect {
33
+ report_template.reload
34
+ }.to raise_error(ActiveRecord::RecordNotFound)
35
+ end
36
+ end
37
+
38
+ context 'database' do
39
+
40
+ context 'timestamps'do
41
+ it { should have_db_column(:created_at).of_type(:datetime).with_options(:null => false) }
42
+ it { should have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) }
43
+ end
44
+
45
+ context 'columns' do
46
+ it { should have_db_column(:workspace_id).of_type(:integer).with_options(:null => false, :default =>1) }
47
+ it { should have_db_column(:created_by).of_type(:string) }
48
+ it { should have_db_column(:path).of_type(:string) }
49
+ it { should have_db_column(:name).of_type(:text) }
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,36 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::Route do
4
+
5
+ context 'associations' do
6
+ it { should belong_to(:session).class_name('Mdm::Session') }
7
+ end
8
+
9
+ context 'factory' do
10
+ it 'should be valid' do
11
+ route = FactoryGirl.build(:mdm_route)
12
+ route.should be_valid
13
+ end
14
+ end
15
+
16
+ context '#destroy' do
17
+ it 'should successfully destroy the object' do
18
+ route = FactoryGirl.create(:mdm_route)
19
+ expect {
20
+ route.destroy
21
+ }.to_not raise_error
22
+ expect {
23
+ route.reload
24
+ }.to raise_error(ActiveRecord::RecordNotFound)
25
+ end
26
+ end
27
+
28
+ context 'database' do
29
+ context 'columns' do
30
+ it { should have_db_column(:session_id).of_type(:integer) }
31
+ it { should have_db_column(:subnet).of_type(:string) }
32
+ it { should have_db_column(:netmask).of_type(:string) }
33
+ end
34
+ end
35
+
36
+ end
@@ -17,27 +17,82 @@ describe Mdm::Service do
17
17
  it { should belong_to(:host).class_name('Mdm::Host') }
18
18
  end
19
19
 
20
- context "inactive" do
21
- it "should exclude open services" do
22
- open_service = FactoryGirl.create(:mdm_service, :state => 'open')
23
- Mdm::Service.inactive.should_not include(open_service)
20
+ context 'scopes' do
21
+ context "inactive" do
22
+ it "should exclude open services" do
23
+ open_service = FactoryGirl.create(:mdm_service, :state => 'open')
24
+ Mdm::Service.inactive.should_not include(open_service)
25
+ end
26
+ end
27
+
28
+ context "with_state open" do
29
+ it "should exclude closed services" do
30
+ closed_service = FactoryGirl.create(:mdm_service, :state => 'closed')
31
+ Mdm::Service.with_state('open').should_not include(closed_service)
32
+ end
33
+ end
34
+
35
+ context "search for 'snmp'" do
36
+ it "should find only services that match" do
37
+ snmp_service = FactoryGirl.create(:mdm_service)
38
+ ftp_service = FactoryGirl.create(:mdm_service, :proto => 'ftp')
39
+ search_results = Mdm::Service.search('snmp')
40
+ search_results.should include(snmp_service)
41
+ search_results.should_not include(ftp_service)
42
+ end
24
43
  end
25
44
  end
26
45
 
27
- context "with_state open" do
28
- it "should exclude closed services" do
29
- closed_service = FactoryGirl.create(:mdm_service, :state => 'closed')
30
- Mdm::Service.with_state('open').should_not include(closed_service)
46
+ context 'callbacks' do
47
+ context 'after_save' do
48
+ it 'should call #normalize_host_os' do
49
+ svc = FactoryGirl.create(:mdm_service)
50
+ svc.should_receive(:normalize_host_os)
51
+ svc.run_callbacks(:save)
52
+ end
31
53
  end
32
54
  end
33
55
 
34
- context "search for 'snmp'" do
35
- it "should find only services that match" do
36
- snmp_service = FactoryGirl.create(:mdm_service)
37
- ftp_service = FactoryGirl.create(:mdm_service, :proto => 'ftp')
38
- search_results = Mdm::Service.search('snmp')
39
- search_results.should include(snmp_service)
40
- search_results.should_not include(ftp_service)
56
+ context 'factory' do
57
+ it 'should be valid' do
58
+ service = FactoryGirl.build(:mdm_service)
59
+ service.should be_valid
60
+ end
61
+ end
62
+
63
+ context '#destroy' do
64
+ it 'should successfully destroy the object' do
65
+ service = FactoryGirl.create(:mdm_service)
66
+ expect {
67
+ service.destroy
68
+ }.to_not raise_error
69
+ expect {
70
+ service.reload
71
+ }.to raise_error(ActiveRecord::RecordNotFound)
72
+ end
73
+ end
74
+
75
+ context 'database' do
76
+
77
+ context 'timestamps'do
78
+ it { should have_db_column(:created_at).of_type(:datetime) }
79
+ it { should have_db_column(:updated_at).of_type(:datetime) }
80
+ end
81
+
82
+ context 'columns' do
83
+ it { should have_db_column(:host_id).of_type(:integer) }
84
+ it { should have_db_column(:port).of_type(:integer).with_options(:null => false) }
85
+ it { should have_db_column(:proto).of_type(:string).with_options(:null => false) }
86
+ it { should have_db_column(:state).of_type(:string) }
87
+ it { should have_db_column(:name).of_type(:string) }
88
+ it { should have_db_column(:info).of_type(:text) }
89
+ end
90
+
91
+ context 'indices' do
92
+ it { should have_db_index(:name) }
93
+ it { should have_db_index(:port) }
94
+ it { should have_db_index(:proto) }
95
+ it { should have_db_index(:state) }
41
96
  end
42
97
  end
43
98
 
@@ -0,0 +1,42 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::SessionEvent do
4
+ context 'associations' do
5
+ it { should belong_to(:session).class_name('Mdm::Session') }
6
+ end
7
+
8
+ context 'factory' do
9
+ it 'should be valid' do
10
+ session_event = FactoryGirl.build(:mdm_session_event)
11
+ session_event.should be_valid
12
+ end
13
+ end
14
+
15
+ context '#destroy' do
16
+ it 'should successfully destroy the object' do
17
+ session_event = FactoryGirl.create(:mdm_session_event)
18
+ expect {
19
+ session_event.destroy
20
+ }.to_not raise_error
21
+ expect {
22
+ session_event.reload
23
+ }.to raise_error(ActiveRecord::RecordNotFound)
24
+ end
25
+ end
26
+
27
+ context 'database' do
28
+ context 'timestamps'do
29
+ it { should have_db_column(:created_at).of_type(:datetime) }
30
+ end
31
+
32
+ context 'columns' do
33
+ it { should have_db_column(:session_id).of_type(:integer) }
34
+ it { should have_db_column(:etype).of_type(:string) }
35
+ it { should have_db_column(:command).of_type(:binary) }
36
+ it { should have_db_column(:output).of_type(:binary) }
37
+ it { should have_db_column(:remote_path).of_type(:string) }
38
+ it { should have_db_column(:local_path).of_type(:string) }
39
+ end
40
+ end
41
+
42
+ end
@@ -0,0 +1,114 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::Session do
4
+
5
+ context 'factory' do
6
+ it 'should be valid' do
7
+ session = FactoryGirl.build(:mdm_session)
8
+ session.should be_valid
9
+ end
10
+ end
11
+
12
+ context '#destroy' do
13
+ it 'should successfully destroy the object' do
14
+ session = FactoryGirl.create(:mdm_session)
15
+ expect {
16
+ session.destroy
17
+ }.to_not raise_error
18
+ expect {
19
+ session.reload
20
+ }.to raise_error(ActiveRecord::RecordNotFound)
21
+ end
22
+ end
23
+
24
+ context 'database' do
25
+
26
+ context 'timestamps'do
27
+ it { should have_db_column(:opened_at).of_type(:datetime).with_options(:null => false) }
28
+ it { should have_db_column(:closed_at).of_type(:datetime) }
29
+ it { should have_db_column(:last_seen).of_type(:datetime) }
30
+ end
31
+
32
+ context 'columns' do
33
+ it { should have_db_column(:host_id).of_type(:integer) }
34
+ it { should have_db_column(:stype).of_type(:string) }
35
+ it { should have_db_column(:via_exploit).of_type(:string) }
36
+ it { should have_db_column(:via_payload).of_type(:string) }
37
+ it { should have_db_column(:desc).of_type(:string) }
38
+ it { should have_db_column(:port).of_type(:integer) }
39
+ it { should have_db_column(:platform).of_type(:string) }
40
+ it { should have_db_column(:datastore).of_type(:text) }
41
+ it { should have_db_column(:local_id).of_type(:integer) }
42
+ end
43
+ end
44
+
45
+ context 'asscoiations' do
46
+ it { should belong_to(:host).class_name('Mdm::Host') }
47
+ it { should have_many(:events).class_name('Mdm::SessionEvent').dependent(:delete_all) }
48
+ it { should have_many(:routes).class_name('Mdm::Route').dependent(:delete_all) }
49
+ it { should have_one(:workspace).class_name('Mdm::Workspace').through(:host) }
50
+ end
51
+
52
+ context 'scopes' do
53
+ context 'alive' do
54
+ it 'should return sessions that have not been closed' do
55
+ alive_session = FactoryGirl.create(:mdm_session)
56
+ dead_session = FactoryGirl.create(:mdm_session, :closed_at => Time.now)
57
+ alive_set = Mdm::Session.alive
58
+ alive_set.should include(alive_session)
59
+ alive_set.should_not include(dead_session)
60
+ end
61
+ end
62
+
63
+ context 'dead' do
64
+ it 'should return sessions that have been closed' do
65
+ alive_session = FactoryGirl.create(:mdm_session)
66
+ dead_session = FactoryGirl.create(:mdm_session, :closed_at => Time.now)
67
+ dead_set = Mdm::Session.dead
68
+ dead_set.should_not include(alive_session)
69
+ dead_set.should include(dead_session)
70
+ end
71
+ end
72
+
73
+ context 'upgradeable' do
74
+ it 'should return sessions that can be upgraded to meterpreter' do
75
+ win_shell = FactoryGirl.create(:mdm_session, :stype => 'shell', :platform => 'Windows')
76
+ linux_shell = FactoryGirl.create(:mdm_session, :stype => 'shell', :platform => 'Linux')
77
+ win_meterp = FactoryGirl.create(:mdm_session, :stype => 'meterpreter', :platform => 'Windows')
78
+ upgrade_set = Mdm::Session.upgradeable
79
+ upgrade_set.should include(win_shell)
80
+ upgrade_set.should_not include(linux_shell)
81
+ upgrade_set.should_not include(win_meterp)
82
+ end
83
+ end
84
+ end
85
+
86
+ context 'callbacks' do
87
+ context 'before_destroy' do
88
+ it 'should call #stop' do
89
+ mysession = FactoryGirl.create(:mdm_session)
90
+ mysession.should_receive(:stop)
91
+ mysession.destroy
92
+ end
93
+ end
94
+ end
95
+
96
+ context 'methods' do
97
+ context '#upgradeable?' do
98
+ it 'should return true for windows shells' do
99
+ win_shell = FactoryGirl.create(:mdm_session, :stype => 'shell', :platform => 'Windows')
100
+ win_shell.upgradeable?.should == true
101
+ end
102
+
103
+ it 'should return false for non-windows shells' do
104
+ linux_shell = FactoryGirl.create(:mdm_session, :stype => 'shell', :platform => 'Linux')
105
+ linux_shell.upgradeable?.should == false
106
+ end
107
+
108
+ it 'should return false for Windows Meterpreter Sessions' do
109
+ win_meterp = FactoryGirl.create(:mdm_session, :stype => 'meterpreter', :platform => 'Windows')
110
+ win_meterp.upgradeable?.should == false
111
+ end
112
+ end
113
+ end
114
+ end