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
@@ -1,6 +1,19 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Mdm::HostTag do
4
+
5
+ context 'associations' do
6
+ it { should belong_to(:host).class_name('Mdm::Host') }
7
+ it { should belong_to(:tag).class_name('Mdm::Tag') }
8
+ end
9
+
10
+ context 'database' do
11
+ context 'columns' do
12
+ it { should have_db_column(:host_id).of_type(:integer) }
13
+ it { should have_db_column(:tag_id).of_type(:integer) }
14
+ end
15
+ end
16
+
4
17
  context 'factories' do
5
18
  context 'mdm_host_tag' do
6
19
  subject(:mdm_host_tag) do
@@ -10,4 +23,17 @@ describe Mdm::HostTag do
10
23
  it { should be_valid }
11
24
  end
12
25
  end
26
+
27
+ context '#destroy' do
28
+ it 'should successfully destroy the object' do
29
+ host_tag = FactoryGirl.create(:mdm_host_tag)
30
+ expect {
31
+ host_tag.destroy
32
+ }.to_not raise_error
33
+ expect {
34
+ host_tag.reload
35
+ }.to raise_error(ActiveRecord::RecordNotFound)
36
+ end
37
+ end
38
+
13
39
  end
@@ -0,0 +1,108 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::Listener 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 'database' do
11
+
12
+ context 'timestamps'do
13
+ it { should have_db_column(:created_at).of_type(:datetime).with_options(:null => false) }
14
+ it { should have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) }
15
+ end
16
+
17
+ context 'columns' do
18
+ it { should have_db_column(:workspace_id).of_type(:integer).with_options(:null => false, :default =>1) }
19
+ it { should have_db_column(:task_id).of_type(:integer) }
20
+ it { should have_db_column(:enabled).of_type(:boolean).with_options(:default => true) }
21
+ it { should have_db_column(:owner).of_type(:text) }
22
+ it { should have_db_column(:payload).of_type(:text) }
23
+ it { should have_db_column(:address).of_type(:text) }
24
+ it { should have_db_column(:port).of_type(:integer) }
25
+ it { should have_db_column(:options).of_type(:binary) }
26
+ it { should have_db_column(:macro).of_type(:text) }
27
+ end
28
+ end
29
+
30
+ context 'factory' do
31
+ it 'should be valid' do
32
+ listener = FactoryGirl.build(:mdm_listener)
33
+ listener.should be_valid
34
+ end
35
+ end
36
+
37
+ context '#destroy' do
38
+ it 'should successfully destroy the object' do
39
+ listener = FactoryGirl.create(:mdm_listener)
40
+ expect {
41
+ listener.destroy
42
+ }.to_not raise_error
43
+ expect {
44
+ listener.reload
45
+ }.to raise_error(ActiveRecord::RecordNotFound)
46
+ end
47
+ end
48
+
49
+ context 'validations' do
50
+ context 'port' do
51
+ it 'should require a port' do
52
+ portless_listener = FactoryGirl.build(:mdm_listener, :port => nil)
53
+ portless_listener.should_not be_valid
54
+ portless_listener.errors[:port].should include("can't be blank")
55
+ end
56
+
57
+ it 'should not be valid for out-of-range numbers' do
58
+ out_of_range = FactoryGirl.build(:mdm_listener, :port => 70000)
59
+ out_of_range.should_not be_valid
60
+ out_of_range.errors[:port].should include("is not included in the list")
61
+ end
62
+
63
+ it 'should not be valid for port 0' do
64
+ out_of_range = FactoryGirl.build(:mdm_listener, :port => 0)
65
+ out_of_range.should_not be_valid
66
+ out_of_range.errors[:port].should include("is not included in the list")
67
+ end
68
+
69
+ it 'should not be valid for decimal numbers' do
70
+ out_of_range = FactoryGirl.build(:mdm_listener, :port => 5.67)
71
+ out_of_range.should_not be_valid
72
+ out_of_range.errors[:port].should include("must be an integer")
73
+ end
74
+
75
+ it 'should not be valid for a negative number' do
76
+ out_of_range = FactoryGirl.build(:mdm_listener, :port => -8)
77
+ out_of_range.should_not be_valid
78
+ out_of_range.errors[:port].should include("is not included in the list")
79
+ end
80
+ end
81
+
82
+ context 'address' do
83
+ it 'should require an address' do
84
+ addressless_listener = FactoryGirl.build(:mdm_listener, :address => nil)
85
+ addressless_listener.should_not be_valid
86
+ addressless_listener.errors[:address].should include("can't be blank")
87
+ end
88
+
89
+ it 'should be valid for IPv4 format' do
90
+ ipv4_listener = FactoryGirl.build(:mdm_listener, :address => '192.168.1.120')
91
+ ipv4_listener.should be_valid
92
+ end
93
+
94
+ it 'should be valid for IPv6 format' do
95
+ ipv6_listener = FactoryGirl.build(:mdm_listener, :address => '2001:0db8:85a3:0000:0000:8a2e:0370:7334')
96
+ ipv6_listener.should be_valid
97
+ end
98
+
99
+ it 'should not be valid for strings not conforming to IPv4 or IPv6' do
100
+ invalid_listener = FactoryGirl.build(:mdm_listener, :address => '1234-fark')
101
+ invalid_listener.should_not be_valid
102
+ end
103
+
104
+ end
105
+ end
106
+
107
+
108
+ end
@@ -0,0 +1,77 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::Loot do
4
+ context 'associations' do
5
+ it { should belong_to(:workspace).class_name('Mdm::Workspace') }
6
+ it { should belong_to(:service).class_name('Mdm::Service') }
7
+ it { should belong_to(:host).class_name('Mdm::Host') }
8
+ end
9
+
10
+ context 'database' do
11
+
12
+ context 'timestamps'do
13
+ it { should have_db_column(:created_at).of_type(:datetime).with_options(:null => false) }
14
+ it { should have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) }
15
+ end
16
+
17
+ context 'columns' do
18
+ it { should have_db_column(:workspace_id).of_type(:integer).with_options(:null => false, :default =>1) }
19
+ it { should have_db_column(:host_id).of_type(:integer) }
20
+ it { should have_db_column(:service_id).of_type(:integer) }
21
+ it { should have_db_column(:ltype).of_type(:string) }
22
+ it { should have_db_column(:path).of_type(:string) }
23
+ it { should have_db_column(:data).of_type(:text) }
24
+ it { should have_db_column(:content_type).of_type(:string) }
25
+ it { should have_db_column(:name).of_type(:text) }
26
+ it { should have_db_column(:info).of_type(:text) }
27
+ end
28
+ end
29
+
30
+ context 'factory' do
31
+ it 'should be valid' do
32
+ loot = FactoryGirl.build(:mdm_loot)
33
+ loot.should be_valid
34
+ end
35
+ end
36
+
37
+ context '#destroy' do
38
+ it 'should successfully destroy the object' do
39
+ loot = FactoryGirl.create(:mdm_loot)
40
+ expect {
41
+ loot.destroy
42
+ }.to_not raise_error
43
+ expect {
44
+ loot.reload
45
+ }.to raise_error(ActiveRecord::RecordNotFound)
46
+ end
47
+ end
48
+
49
+ context 'scopes' do
50
+ context 'search' do
51
+ it 'should match on ltype' do
52
+ myloot = FactoryGirl.create(:mdm_loot, :ltype => 'find.this.ltype')
53
+ Mdm::Loot.search('find.this.ltype').should include(myloot)
54
+ end
55
+
56
+ it 'should match on name' do
57
+ myloot = FactoryGirl.create(:mdm_loot, :name => 'Find This')
58
+ Mdm::Loot.search('Find This').should include(myloot)
59
+ end
60
+
61
+ it 'should match on info' do
62
+ myloot = FactoryGirl.create(:mdm_loot, :info => 'Find This')
63
+ Mdm::Loot.search('Find This').should include(myloot)
64
+ end
65
+ end
66
+ end
67
+
68
+ context 'callbacks' do
69
+ context 'before_destroy' do
70
+ it 'should call #delete_file' do
71
+ myloot = FactoryGirl.create(:mdm_loot)
72
+ myloot.should_receive(:delete_file)
73
+ myloot.destroy
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,128 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::NexposeConsole do
4
+
5
+ context 'factory' do
6
+ it 'should be valid' do
7
+ nexpose_console = FactoryGirl.build(:mdm_nexpose_console)
8
+ nexpose_console.should be_valid
9
+ end
10
+ end
11
+
12
+ context 'database' do
13
+
14
+ context 'timestamps'do
15
+ it { should have_db_column(:created_at).of_type(:datetime).with_options(:null => false) }
16
+ it { should have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) }
17
+ end
18
+
19
+ context 'columns' do
20
+ it { should have_db_column(:enabled).of_type(:boolean).with_options(:default => true) }
21
+ it { should have_db_column(:owner).of_type(:text) }
22
+ it { should have_db_column(:address).of_type(:text) }
23
+ it { should have_db_column(:port).of_type(:integer).with_options(:default => 3780) }
24
+ it { should have_db_column(:username).of_type(:text) }
25
+ it { should have_db_column(:password).of_type(:text) }
26
+ it { should have_db_column(:status).of_type(:text) }
27
+ it { should have_db_column(:version).of_type(:text) }
28
+ it { should have_db_column(:cert).of_type(:text) }
29
+ it { should have_db_column(:cached_sites).of_type(:binary) }
30
+ it { should have_db_column(:name).of_type(:text) }
31
+ end
32
+ end
33
+
34
+ context '#destroy' do
35
+ it 'should successfully destroy the object' do
36
+ nexpose_console = FactoryGirl.create(:mdm_nexpose_console)
37
+ expect {
38
+ nexpose_console.destroy
39
+ }.to_not raise_error
40
+ expect {
41
+ nexpose_console.reload
42
+ }.to raise_error(ActiveRecord::RecordNotFound)
43
+ end
44
+ end
45
+
46
+ context 'validations' do
47
+ context 'address' do
48
+ it 'should require an address' do
49
+ addressless_nexpose_console = FactoryGirl.build(:mdm_nexpose_console, :address => nil)
50
+ addressless_nexpose_console.should_not be_valid
51
+ addressless_nexpose_console.errors[:address].should include("can't be blank")
52
+ end
53
+
54
+ it 'should be valid for IPv4 format' do
55
+ ipv4_nexpose_console = FactoryGirl.build(:mdm_nexpose_console, :address => '192.168.1.120')
56
+ ipv4_nexpose_console.should be_valid
57
+ end
58
+
59
+ it 'should be valid for IPv6 format' do
60
+ ipv6_nexpose_console = FactoryGirl.build(:mdm_nexpose_console, :address => '2001:0db8:85a3:0000:0000:8a2e:0370:7334')
61
+ ipv6_nexpose_console.should be_valid
62
+ end
63
+
64
+ it 'should not be valid for strings not conforming to IPv4 or IPv6' do
65
+ invalid_nexpose_console = FactoryGirl.build(:mdm_nexpose_console, :address => '1234-fark')
66
+ invalid_nexpose_console.should_not be_valid
67
+ end
68
+ end
69
+
70
+ context 'port' do
71
+ it 'should require a port' do
72
+ portless_nexpose_console = FactoryGirl.build(:mdm_nexpose_console, :port => nil)
73
+ portless_nexpose_console.should_not be_valid
74
+ portless_nexpose_console.errors[:port].should include("is not included in the list")
75
+ end
76
+
77
+ it 'should not be valid for out-of-range numbers' do
78
+ out_of_range = FactoryGirl.build(:mdm_nexpose_console, :port => 70000)
79
+ out_of_range.should_not be_valid
80
+ out_of_range.errors[:port].should include("is not included in the list")
81
+ end
82
+
83
+ it 'should not be valid for port 0' do
84
+ out_of_range = FactoryGirl.build(:mdm_nexpose_console, :port => 0)
85
+ out_of_range.should_not be_valid
86
+ out_of_range.errors[:port].should include("is not included in the list")
87
+ end
88
+
89
+ it 'should not be valid for decimal numbers' do
90
+ out_of_range = FactoryGirl.build(:mdm_nexpose_console, :port => 5.67)
91
+ out_of_range.should_not be_valid
92
+ out_of_range.errors[:port].should include("must be an integer")
93
+ end
94
+
95
+ it 'should not be valid for a negative number' do
96
+ out_of_range = FactoryGirl.build(:mdm_nexpose_console, :port => -8)
97
+ out_of_range.should_not be_valid
98
+ out_of_range.errors[:port].should include("is not included in the list")
99
+ end
100
+ end
101
+
102
+ context 'name' do
103
+ it 'should require a name' do
104
+ unnamed_console = FactoryGirl.build(:mdm_nexpose_console, :name => nil)
105
+ unnamed_console.should_not be_valid
106
+ unnamed_console.errors[:name].should include("can't be blank")
107
+ end
108
+ end
109
+
110
+ context 'username' do
111
+ it 'should require a name' do
112
+ console = FactoryGirl.build(:mdm_nexpose_console, :username => nil)
113
+ console.should_not be_valid
114
+ console.errors[:username].should include("can't be blank")
115
+ end
116
+ end
117
+
118
+ context 'password' do
119
+ it 'should require a password' do
120
+ console = FactoryGirl.build(:mdm_nexpose_console, :password => nil)
121
+ console.should_not be_valid
122
+ console.errors[:password].should include("can't be blank")
123
+ end
124
+ end
125
+
126
+ end
127
+
128
+ end
@@ -0,0 +1,84 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::Note do
4
+
5
+ context 'factory' do
6
+ it 'should be valid' do
7
+ note = FactoryGirl.build(:mdm_note)
8
+ note.should be_valid
9
+ end
10
+ end
11
+
12
+ context 'database' do
13
+
14
+ context 'timestamps'do
15
+ it { should have_db_column(:created_at).of_type(:datetime) }
16
+ it { should have_db_column(:updated_at).of_type(:datetime) }
17
+ end
18
+
19
+ context 'columns' do
20
+ it { should have_db_column(:workspace_id).of_type(:integer).with_options(:null => false, :default =>1) }
21
+ it { should have_db_column(:host_id).of_type(:integer) }
22
+ it { should have_db_column(:service_id).of_type(:integer) }
23
+ it { should have_db_column(:ntype).of_type(:string) }
24
+ it { should have_db_column(:critical).of_type(:boolean) }
25
+ it { should have_db_column(:seen).of_type(:boolean) }
26
+ it { should have_db_column(:data).of_type(:text) }
27
+ end
28
+ end
29
+
30
+ context '#destroy' do
31
+ it 'should successfully destroy the object' do
32
+ note = FactoryGirl.create(:mdm_note)
33
+ expect {
34
+ note.destroy
35
+ }.to_not raise_error
36
+ expect {
37
+ note.reload
38
+ }.to raise_error(ActiveRecord::RecordNotFound)
39
+ end
40
+ end
41
+
42
+ context 'associations' do
43
+ it { should belong_to(:workspace).class_name('Mdm::Workspace') }
44
+ it { should belong_to(:host).class_name('Mdm::Host') }
45
+ it { should belong_to(:service).class_name('Mdm::Service') }
46
+ end
47
+
48
+ context 'scopes' do
49
+ context 'flagged' do
50
+ it 'should exclude non-critical note' do
51
+ flagged_note = FactoryGirl.create(:mdm_note, :critical => true, :seen => false)
52
+ non_critical_note = FactoryGirl.create(:mdm_note, :critical => false, :seen => false)
53
+ flagged_set = Mdm::Note.flagged
54
+ flagged_set.should include(flagged_note)
55
+ flagged_set.should_not include(non_critical_note)
56
+ end
57
+
58
+ it 'should exclude seen notes' do
59
+ flagged_note = FactoryGirl.create(:mdm_note, :critical => true, :seen => false)
60
+ non_critical_note = FactoryGirl.create(:mdm_note, :critical => false, :seen => true)
61
+ flagged_set = Mdm::Note.flagged
62
+ flagged_set.should include(flagged_note)
63
+ flagged_set.should_not include(non_critical_note)
64
+ end
65
+ end
66
+
67
+ context 'visible' do
68
+ it 'should only include visible notes' do
69
+ flagged_note = FactoryGirl.create(:mdm_note, :ntype => 'flag.me', :critical => true, :seen => false)
70
+ webform_note = FactoryGirl.create(:mdm_note, :ntype => 'web.form', :critical => true, :seen => false)
71
+ visible_set = Mdm::Note.visible
72
+ visible_set.should include(flagged_note)
73
+ visible_set.should_not include(webform_note)
74
+ end
75
+ end
76
+
77
+ context 'search' do
78
+ it 'should match on ntype' do
79
+ flagged_note = FactoryGirl.create(:mdm_note, :ntype => 'flag.me', :critical => true, :seen => false)
80
+ Mdm::Note.search('flag.me').should include(flagged_note)
81
+ end
82
+ end
83
+ end
84
+ end
@@ -28,6 +28,7 @@ describe Mdm::Ref do
28
28
 
29
29
  # @todo https://www.pivotaltracker.com/story/show/48915453
30
30
  it { should have_many(:vulns_refs).class_name('Mdm::VulnRef') }
31
+ it { should have_many(:vulns).class_name('Mdm::Vuln').through(:vulns_refs) }
31
32
  end
32
33
 
33
34
  context 'database' do
@@ -56,6 +57,18 @@ describe Mdm::Ref do
56
57
  end
57
58
  end
58
59
 
60
+ context '#destroy' do
61
+ it 'should successfully destroy the object' do
62
+ mdm_ref = FactoryGirl.create(:mdm_ref)
63
+ expect {
64
+ mdm_ref.destroy
65
+ }.to_not raise_error
66
+ expect {
67
+ mdm_ref.reload
68
+ }.to raise_error(ActiveRecord::RecordNotFound)
69
+ end
70
+ end
71
+
59
72
  context 'mass assignment security' do
60
73
  it { should allow_mass_assignment_of(:name) }
61
74
  end