metasploit_data_models 0.15.2 → 0.16.0

Sign up to get free protection for your applications and to get access to all the features.
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