metasploit_data_models 0.7.0 → 0.11.2

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 (70) hide show
  1. data/.gitignore +3 -0
  2. data/.travis.yml +1 -0
  3. data/app/models/mdm/host.rb +352 -26
  4. data/app/models/mdm/loot.rb +72 -7
  5. data/app/models/mdm/{module_action.rb → module/action.rb} +3 -3
  6. data/app/models/mdm/{module_arch.rb → module/arch.rb} +3 -3
  7. data/app/models/mdm/{module_author.rb → module/author.rb} +3 -3
  8. data/app/models/mdm/module/detail.rb +280 -0
  9. data/app/models/mdm/{module_mixin.rb → module/mixin.rb} +3 -3
  10. data/app/models/mdm/{module_platform.rb → module/platform.rb} +3 -3
  11. data/app/models/mdm/module/ref.rb +48 -0
  12. data/app/models/mdm/{module_target.rb → module/target.rb} +3 -3
  13. data/app/models/mdm/note.rb +61 -6
  14. data/app/models/mdm/ref.rb +39 -1
  15. data/app/models/mdm/service.rb +85 -7
  16. data/app/models/mdm/session.rb +100 -6
  17. data/app/models/mdm/vuln.rb +104 -24
  18. data/db/migrate/20130228214900_change_required_columns_to_null_false_in_web_vulns.rb +1 -17
  19. data/db/migrate/20130412154159_change_foreign_key_in_module_actions.rb +25 -0
  20. data/db/migrate/20130412171844_change_foreign_key_in_module_archs.rb +25 -0
  21. data/db/migrate/20130412173121_change_foreign_key_in_module_authors.rb +25 -0
  22. data/db/migrate/20130412173640_change_foreign_key_in_module_mixins.rb +25 -0
  23. data/db/migrate/20130412174254_change_foreign_key_in_module_platforms.rb +25 -0
  24. data/db/migrate/20130412174719_change_foreign_key_in_module_refs.rb +25 -0
  25. data/db/migrate/20130412175040_change_foreign_key_in_module_targets.rb +25 -0
  26. data/db/migrate/20130430151353_change_required_columns_to_null_false_in_hosts.rb +11 -0
  27. data/db/migrate/20130430162145_enforce_address_uniqueness_in_workspace_in_hosts.rb +23 -0
  28. data/lib/mdm/module.rb +4 -0
  29. data/lib/metasploit_data_models.rb +1 -0
  30. data/lib/metasploit_data_models/change_required_columns_to_null_false.rb +23 -0
  31. data/lib/metasploit_data_models/version.rb +1 -1
  32. data/spec/app/models/mdm/host_spec.rb +411 -0
  33. data/spec/app/models/mdm/host_tag_spec.rb +13 -0
  34. data/spec/app/models/mdm/{module_action_spec.rb → module/action_spec.rb} +6 -6
  35. data/spec/app/models/mdm/{module_arch_spec.rb → module/arch_spec.rb} +6 -6
  36. data/spec/app/models/mdm/{module_author_spec.rb → module/author_spec.rb} +6 -6
  37. data/spec/app/models/mdm/{module_detail_spec.rb → module/detail_spec.rb} +101 -11
  38. data/spec/app/models/mdm/{module_mixin_spec.rb → module/mixin_spec.rb} +6 -6
  39. data/spec/app/models/mdm/{module_platform_spec.rb → module/platform_spec.rb} +6 -6
  40. data/spec/app/models/mdm/module/ref_spec.rb +62 -0
  41. data/spec/app/models/mdm/{module_target_spec.rb → module/target_spec.rb} +6 -6
  42. data/spec/app/models/mdm/ref_spec.rb +62 -0
  43. data/spec/app/models/mdm/tag_spec.rb +13 -0
  44. data/spec/app/models/mdm/vuln_ref_spec.rb +13 -0
  45. data/spec/app/models/mdm/vuln_spec.rb +231 -0
  46. data/spec/dummy/db/schema.rb +20 -20
  47. data/spec/factories/mdm/host_tags.rb +9 -0
  48. data/spec/factories/mdm/hosts.rb +65 -0
  49. data/spec/factories/mdm/module/actions.rb +14 -0
  50. data/spec/factories/mdm/module/archs.rb +14 -0
  51. data/spec/factories/mdm/{module_authors.rb → module/authors.rb} +4 -4
  52. data/spec/factories/mdm/module/details.rb +66 -0
  53. data/spec/factories/mdm/module/mixins.rb +14 -0
  54. data/spec/factories/mdm/module/platforms.rb +14 -0
  55. data/spec/factories/mdm/module/refs.rb +14 -0
  56. data/spec/factories/mdm/{module_targets.rb → module/targets.rb} +3 -3
  57. data/spec/factories/mdm/refs.rb +9 -0
  58. data/spec/factories/mdm/tags.rb +14 -0
  59. data/spec/factories/mdm/vuln_refs.rb +4 -0
  60. data/spec/factories/mdm/vulns.rb +20 -0
  61. metadata +78 -45
  62. data/app/models/mdm/module_detail.rb +0 -59
  63. data/app/models/mdm/module_ref.rb +0 -24
  64. data/spec/app/models/mdm/module_ref_spec.rb +0 -38
  65. data/spec/factories/mdm/module_actions.rb +0 -14
  66. data/spec/factories/mdm/module_archs.rb +0 -14
  67. data/spec/factories/mdm/module_details.rb +0 -9
  68. data/spec/factories/mdm/module_mixins.rb +0 -14
  69. data/spec/factories/mdm/module_platforms.rb +0 -14
  70. data/spec/factories/mdm/module_refs.rb +0 -14
@@ -4,5 +4,5 @@ module MetasploitDataModels
4
4
  # metasploit-framework/data/sql/migrate to db/migrate in this project, not all models have specs that verify the
5
5
  # migrations (with have_db_column and have_db_index) and certain models may not be shared between metasploit-framework
6
6
  # and pro, so models may be removed in the future. Because of the unstable API the version should remain below 1.0.0
7
- VERSION = '0.7.0'
7
+ VERSION = '0.11.2'
8
8
  end
@@ -0,0 +1,411 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::Host do
4
+ subject(:host) do
5
+ FactoryGirl.build(:mdm_host)
6
+ end
7
+
8
+ let(:architectures) do
9
+ [
10
+ 'armbe',
11
+ 'armle',
12
+ 'cbea',
13
+ 'cbea64',
14
+ 'cmd',
15
+ 'java',
16
+ 'mips',
17
+ 'mipsbe',
18
+ 'mipsle',
19
+ 'php',
20
+ 'ppc',
21
+ 'ppc64',
22
+ 'ruby',
23
+ 'sparc',
24
+ 'tty',
25
+ 'x64',
26
+ 'x86',
27
+ 'x86_64'
28
+ ]
29
+ end
30
+
31
+ let(:operating_system_names) do
32
+ [
33
+ 'FreeBSD',
34
+ 'Linux',
35
+ 'Mac OS X',
36
+ 'Microsoft Windows',
37
+ 'NetBSD',
38
+ 'OpenBSD',
39
+ 'Unknown',
40
+ 'VMWare'
41
+ ]
42
+ end
43
+
44
+ let(:states) do
45
+ [
46
+ 'alive',
47
+ 'down',
48
+ 'unknown'
49
+ ]
50
+ end
51
+
52
+ context 'associations' do
53
+ it { should have_many(:creds).class_name('Mdm::Cred').through(:services) }
54
+ it { should have_many(:exploit_attempts).class_name('Mdm::ExploitAttempt').dependent(:destroy) }
55
+ it { should have_many(:exploited_hosts).class_name('Mdm::ExploitedHost').dependent(:destroy) }
56
+ it { should have_many(:host_details).class_name('Mdm::HostDetail').dependent(:destroy) }
57
+ it { should have_many(:hosts_tags).class_name('Mdm::HostTag') }
58
+ it { should have_many(:loots).class_name('Mdm::Loot').dependent(:destroy).order('loots.created_at DESC') }
59
+
60
+ context 'module_details' do
61
+ it { should have_many(:module_details).class_name('Mdm::Module::Detail').through(:module_refs) }
62
+
63
+ context 'with Mdm::Vulns' do
64
+ let!(:vulns) do
65
+ FactoryGirl.create_list(
66
+ :mdm_vuln,
67
+ 2,
68
+ :host => host
69
+ )
70
+ end
71
+
72
+ context 'with Mdm::Ref' do
73
+ let(:name) do
74
+ FactoryGirl.generate :mdm_ref_name
75
+ end
76
+
77
+ let!(:ref) do
78
+ FactoryGirl.create(:mdm_ref, :name => name)
79
+ end
80
+
81
+ context 'with Mdm::VulnRefs' do
82
+ let!(:vuln_refs) do
83
+ vulns.collect { |vuln|
84
+ FactoryGirl.create(:mdm_vuln_ref, :ref => ref, :vuln => vuln)
85
+ }
86
+ end
87
+
88
+ context 'with Mdm::Module::Detail' do
89
+ let!(:module_detail) do
90
+ FactoryGirl.create(
91
+ :mdm_module_detail
92
+ )
93
+ end
94
+
95
+ context 'with Mdm::Module::Ref with same name as Mdm::Ref' do
96
+ let!(:module_ref) do
97
+ FactoryGirl.create(
98
+ :mdm_module_ref,
99
+ :detail => module_detail,
100
+ :name => name
101
+ )
102
+ end
103
+
104
+ it 'should list unique Mdm::Module::Detail' do
105
+ host.module_details.should =~ [module_detail]
106
+ end
107
+
108
+ it 'should have duplicate Mdm::Module::Details if collected through chain' do
109
+ vuln_refs = []
110
+
111
+ host.vulns.each do |vuln|
112
+ # @todo https://www.pivotaltracker.com/story/show/49004623
113
+ vuln_refs += vuln.vulns_refs
114
+ end
115
+
116
+ refs = []
117
+
118
+ vuln_refs.each do |vuln_ref|
119
+ refs << vuln_ref.ref
120
+ end
121
+
122
+ module_refs = []
123
+
124
+ refs.each do |ref|
125
+ module_refs += ref.module_refs
126
+ end
127
+
128
+ module_details = []
129
+
130
+ module_refs.each do |module_ref|
131
+ module_details << module_ref.detail
132
+ end
133
+
134
+ host.module_details.count.should < module_details.length
135
+ module_details.uniq.count.should == host.module_details.count
136
+ end
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ it { should have_many(:module_refs).class_name('Mdm::Module::Ref').through(:refs) }
145
+ it { should have_many(:notes).class_name('Mdm::Note').dependent(:delete_all).order('notes.created_at') }
146
+ it { should have_many(:refs).class_name('Mdm::Ref').through(:vuln_refs) }
147
+ it { should have_many(:services).class_name('Mdm::Service').dependent(:destroy).order('services.port, services.proto') }
148
+ it { should have_many(:service_notes).through(:services) }
149
+ it { should have_many(:sessions).class_name('Mdm::Session').dependent(:destroy).order('sessions.opened_at') }
150
+ it { should have_many(:tags).class_name('Mdm::Tag').through(:hosts_tags) }
151
+ it { should have_many(:vulns).class_name('Mdm::Vuln').dependent(:delete_all) }
152
+ it { should have_many(:vuln_refs).class_name('Mdm::VulnRef') }
153
+ it { should have_many(:web_sites).class_name('Mdm::WebSite').through(:services) }
154
+ it { should belong_to(:workspace).class_name('Mdm::Workspace') }
155
+ end
156
+
157
+ context 'callbacks' do
158
+ context 'before destroy' do
159
+ context 'cleanup_tags' do
160
+ context 'with tags' do
161
+ let!(:tag) do
162
+ FactoryGirl.create(:mdm_tag)
163
+ end
164
+
165
+ let!(:host) do
166
+ FactoryGirl.create(:mdm_host)
167
+ end
168
+
169
+ context 'with only this host' do
170
+ before(:each) do
171
+ FactoryGirl.create(
172
+ :mdm_host_tag,
173
+ :host => host,
174
+ :tag => tag
175
+ )
176
+ end
177
+
178
+ it 'should destroy the tags' do
179
+ expect {
180
+ host.destroy
181
+ }.to change(Mdm::Tag, :count).by(-1)
182
+ end
183
+
184
+ it 'should destroy the host tags' do
185
+ expect {
186
+ host.destroy
187
+ }.to change(Mdm::HostTag, :count).by(-1)
188
+ end
189
+ end
190
+
191
+ context 'with additional hosts' do
192
+ let(:other_host) do
193
+ FactoryGirl.create(:mdm_host)
194
+ end
195
+
196
+ before(:each) do
197
+ FactoryGirl.create(:mdm_host_tag, :host => host, :tag => tag)
198
+ FactoryGirl.create(:mdm_host_tag, :host => other_host, :tag => tag)
199
+ end
200
+
201
+ it 'should not destroy the tag' do
202
+ expect {
203
+ host.destroy
204
+ }.to_not change(Mdm::Tag, :count)
205
+ end
206
+
207
+ it 'should destroy the host tags' do
208
+ expect {
209
+ host.destroy
210
+ }.to change(Mdm::HostTag, :count).by(-1)
211
+ end
212
+
213
+ it "should not destroy the other host's tags" do
214
+ host.destroy
215
+
216
+ other_host.hosts_tags.count.should == 1
217
+ end
218
+ end
219
+ end
220
+ end
221
+ end
222
+ end
223
+
224
+ context 'CONSTANTS' do
225
+ context 'ARCHITECTURES' do
226
+ subject(:architectures) do
227
+ described_class::ARCHITECTURES
228
+ end
229
+
230
+ it 'should be an Array<String>' do
231
+ architectures.should be_an Array
232
+
233
+ architectures.each do |architecture|
234
+ architecture.should be_a String
235
+ end
236
+ end
237
+
238
+ it 'should include both endians of ARM' do
239
+ architectures.should include('armbe')
240
+ architectures.should include('armle')
241
+ end
242
+
243
+ it 'should include 32-bit and 64-bit versions of Cell Broadband Engine Architecture' do
244
+ architectures.should include('cbea')
245
+ architectures.should include('cbea64')
246
+ end
247
+
248
+ it 'should include cmd for command shell' do
249
+ architectures.should include('cmd')
250
+ end
251
+
252
+ it 'should include java for Java Virtual Machine' do
253
+ architectures.should include('java')
254
+ end
255
+
256
+ it 'should include plain and endian-ware MIPS' do
257
+ architectures.should include('mips')
258
+ architectures.should include('mipsbe')
259
+ architectures.should include('mipsle')
260
+ end
261
+
262
+ it 'should include php for PHP code' do
263
+ architectures.should include('php')
264
+ end
265
+
266
+ it 'should include 32-bit and 64-bit PowerPC' do
267
+ architectures.should include('ppc')
268
+ architectures.should include('ppc64')
269
+ end
270
+
271
+ it 'should include ruby for Ruby code' do
272
+ architectures.should include('ruby')
273
+ end
274
+
275
+ it 'should include sparc for Sparc' do
276
+ architectures.should include('sparc')
277
+ end
278
+
279
+ it 'should include tty for Terminals' do
280
+ architectures.should include('tty')
281
+ end
282
+
283
+ it 'should include 32-bit and 64-bit x86' do
284
+ architectures.should include('x64')
285
+ architectures.should include('x86')
286
+ architectures.should include('x86_64')
287
+ end
288
+ end
289
+
290
+ it 'should define OPERATING_SYSTEM_NAMES in any order' do
291
+ described_class::OPERATING_SYSTEM_NAMES.should =~ operating_system_names
292
+ end
293
+
294
+ context 'SEARCH_FIELDS' do
295
+ subject(:search_fields) do
296
+ described_class::SEARCH_FIELDS
297
+ end
298
+
299
+ it 'should be an Array<String>' do
300
+ search_fields.should be_an Array
301
+
302
+ search_fields.each { |search_field|
303
+ search_field.should be_a String
304
+ }
305
+ end
306
+
307
+ it 'should cast address to text' do
308
+ search_fields.should include('address::text')
309
+ end
310
+
311
+ it { should include('comments') }
312
+ it { should include('mac') }
313
+ it { should include('name') }
314
+ it { should include('os_flavor') }
315
+ it { should include('os_name') }
316
+ it { should include('os_sp') }
317
+ it { should include('purpose') }
318
+ end
319
+
320
+ it 'should define STATES in any order' do
321
+ described_class::STATES.should =~ states
322
+ end
323
+ end
324
+
325
+ context 'database' do
326
+ context 'columns' do
327
+ it { should have_db_column(:address).of_type(:string).with_options(:null => false) }
328
+ it { should have_db_column(:arch).of_type(:string) }
329
+ it { should have_db_column(:comm).of_type(:string) }
330
+ it { should have_db_column(:comments).of_type(:text) }
331
+ it { should have_db_column(:info).of_type(:string).with_options(:limit => 2 ** 16) }
332
+ it { should have_db_column(:mac).of_type(:string) }
333
+ it { should have_db_column(:name).of_type(:string) }
334
+ it { should have_db_column(:os_flavor).of_type(:string) }
335
+ it { should have_db_column(:os_lang).of_type(:string) }
336
+ it { should have_db_column(:os_name).of_type(:string) }
337
+ it { should have_db_column(:os_sp).of_type(:string) }
338
+ it { should have_db_column(:purpose).of_type(:text) }
339
+ it { should have_db_column(:scope).of_type(:text) }
340
+ it { should have_db_column(:state).of_type(:string) }
341
+ it { should have_db_column(:virtual_host).of_type(:text) }
342
+ it { should have_db_column(:workspace_id).of_type(:integer).with_options(:null => false) }
343
+
344
+ context 'counter caches' do
345
+ it { should have_db_column(:exploit_attempt_count).of_type(:integer).with_options(:default => 0) }
346
+ it { should have_db_column(:host_detail_count).of_type(:integer).with_options(:default => 0) }
347
+ it { should have_db_column(:note_count).of_type(:integer).with_options(:default => 0) }
348
+ it { should have_db_column(:service_count).of_type(:integer).with_options(:default => 0) }
349
+ it { should have_db_column(:vuln_count).of_type(:integer).with_options(:default => 0) }
350
+ end
351
+
352
+ context 'timestamps' do
353
+ it { should have_db_column(:created_at).of_type(:datetime) }
354
+ it { should have_db_column(:updated_at).of_type(:datetime) }
355
+ end
356
+ end
357
+
358
+ context 'indices' do
359
+ it { should have_db_index([:workspace_id, :address]).unique(true) }
360
+ it { should have_db_index(:name) }
361
+ it { should have_db_index(:os_flavor) }
362
+ it { should have_db_index(:os_name) }
363
+ it { should have_db_index(:purpose) }
364
+ it { should have_db_index(:state) }
365
+ end
366
+ end
367
+
368
+ context 'factories' do
369
+ context 'full_mdm_host' do
370
+ subject(:full_mdm_host) do
371
+ FactoryGirl.build(:full_mdm_host)
372
+ end
373
+
374
+ it { should be_valid }
375
+ end
376
+
377
+ context 'mdm_host' do
378
+ subject(:mdm_host) do
379
+ FactoryGirl.build(:mdm_host)
380
+ end
381
+
382
+ it { should be_valid }
383
+ end
384
+ end
385
+
386
+ context 'validations' do
387
+ context 'address' do
388
+ it { should ensure_exclusion_of(:address).in_array(['127.0.0.1']) }
389
+ it { should validate_presence_of(:address) }
390
+
391
+ # can't use validate_uniqueness_of(:address).scoped_to(:workspace_id) because it will attempt to set workspace_id
392
+ # to `nil`, which will make the `:null => false` constraint on hosts.workspace_id to fail.
393
+ it 'should validate uniqueness of address scoped to workspace_id' do
394
+ address = '192.168.0.1'
395
+
396
+ workspace = FactoryGirl.create(:mdm_workspace)
397
+ FactoryGirl.create(:mdm_host, :address => address, :workspace => workspace)
398
+
399
+ duplicate_host = FactoryGirl.build(:mdm_host, :address => address, :workspace => workspace)
400
+
401
+ duplicate_host.should_not be_valid
402
+ duplicate_host.errors[:address].should include('has already been taken')
403
+ end
404
+ end
405
+
406
+ it { should ensure_inclusion_of(:arch).in_array(architectures).allow_nil }
407
+ it { should ensure_inclusion_of(:os_name).in_array(operating_system_names).allow_nil }
408
+ it { should ensure_inclusion_of(:state).in_array(states).allow_nil }
409
+ it { should validate_presence_of(:workspace) }
410
+ end
411
+ end
@@ -0,0 +1,13 @@
1
+ require 'spec_helper'
2
+
3
+ describe Mdm::HostTag do
4
+ context 'factories' do
5
+ context 'mdm_host_tag' do
6
+ subject(:mdm_host_tag) do
7
+ FactoryGirl.build(:mdm_host_tag)
8
+ end
9
+
10
+ it { should be_valid }
11
+ end
12
+ end
13
+ end
@@ -1,18 +1,18 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe Mdm::ModuleAction do
3
+ describe Mdm::Module::Action do
4
4
  context 'associations' do
5
- it { should belong_to(:module_detail).class_name('Mdm::ModuleDetail') }
5
+ it { should belong_to(:detail).class_name('Mdm::Module::Detail') }
6
6
  end
7
7
 
8
8
  context 'database' do
9
9
  context 'columns' do
10
- it { should have_db_column(:module_detail_id).of_type(:integer) }
10
+ it { should have_db_column(:detail_id).of_type(:integer) }
11
11
  it { should have_db_column(:name).of_type(:text) }
12
12
  end
13
13
 
14
14
  context 'indices' do
15
- it { should have_db_index(:module_detail_id) }
15
+ it { should have_db_index(:detail_id) }
16
16
  end
17
17
  end
18
18
 
@@ -27,12 +27,12 @@ describe Mdm::ModuleAction do
27
27
  end
28
28
 
29
29
  context 'mass assignment security' do
30
- it { should_not allow_mass_assignment_of(:module_detail_id) }
30
+ it { should_not allow_mass_assignment_of(:detail_id) }
31
31
  it { should allow_mass_assignment_of(:name) }
32
32
  end
33
33
 
34
34
  context 'validations' do
35
- it { should validate_presence_of(:module_detail) }
35
+ it { should validate_presence_of(:detail) }
36
36
  it { should validate_presence_of(:name) }
37
37
  end
38
38
  end