metasploit_data_models 0.24.1.pre.rspec.pre.3.pre.1 → 0.24.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rspec +3 -3
- data/Gemfile +3 -1
- data/app/models/metasploit_data_models/ip_address/v4/segmented.rb +1 -1
- data/app/models/metasploit_data_models/search/visitor/where.rb +1 -1
- data/app/validators/password_is_strong_validator.rb +1 -1
- data/lib/mdm/host/operating_system_normalization.rb +10 -0
- data/lib/metasploit_data_models/version.rb +1 -2
- data/metasploit_data_models.gemspec +1 -1
- data/spec/app/models/mdm/api_key_spec.rb +3 -1
- data/spec/app/models/mdm/client_spec.rb +11 -9
- data/spec/app/models/mdm/cred_spec.rb +54 -42
- data/spec/app/models/mdm/event_spec.rb +23 -21
- data/spec/app/models/mdm/exploit_attempt_spec.rb +21 -19
- data/spec/app/models/mdm/exploited_host_spec.rb +13 -11
- data/spec/app/models/mdm/host_detail_spec.rb +17 -15
- data/spec/app/models/mdm/host_spec.rb +260 -261
- data/spec/app/models/mdm/host_tag_spec.rb +8 -6
- data/spec/app/models/mdm/listener_spec.rb +32 -30
- data/spec/app/models/mdm/loot_spec.rb +23 -21
- data/spec/app/models/mdm/macro_spec.rb +3 -1
- data/spec/app/models/mdm/mod_ref_spec.rb +3 -1
- data/spec/app/models/mdm/module/action_spec.rb +12 -10
- data/spec/app/models/mdm/module/arch_spec.rb +12 -10
- data/spec/app/models/mdm/module/author_spec.rb +17 -22
- data/spec/app/models/mdm/module/detail_spec.rb +75 -184
- data/spec/app/models/mdm/module/mixin_spec.rb +12 -10
- data/spec/app/models/mdm/module/platform_spec.rb +12 -10
- data/spec/app/models/mdm/module/ref_spec.rb +12 -10
- data/spec/app/models/mdm/module/target_spec.rb +15 -13
- data/spec/app/models/mdm/nexpose_console_spec.rb +37 -35
- data/spec/app/models/mdm/note_spec.rb +25 -23
- data/spec/app/models/mdm/profile_spec.rb +3 -1
- data/spec/app/models/mdm/ref_spec.rb +12 -10
- data/spec/app/models/mdm/route_spec.rb +8 -6
- data/spec/app/models/mdm/service_spec.rb +40 -38
- data/spec/app/models/mdm/session_event_spec.rb +12 -10
- data/spec/app/models/mdm/session_spec.rb +15 -13
- data/spec/app/models/mdm/tag_spec.rb +29 -29
- data/spec/app/models/mdm/task_cred_spec.rb +11 -9
- data/spec/app/models/mdm/task_host_spec.rb +11 -9
- data/spec/app/models/mdm/task_service_spec.rb +11 -9
- data/spec/app/models/mdm/task_session_spec.rb +9 -7
- data/spec/app/models/mdm/task_spec.rb +29 -27
- data/spec/app/models/mdm/user_spec.rb +19 -17
- data/spec/app/models/mdm/vuln_attempt_spec.rb +16 -14
- data/spec/app/models/mdm/vuln_detail_spec.rb +28 -26
- data/spec/app/models/mdm/vuln_ref_spec.rb +10 -8
- data/spec/app/models/mdm/vuln_spec.rb +26 -24
- data/spec/app/models/mdm/web_form_spec.rb +13 -11
- data/spec/app/models/mdm/web_page_spec.rb +21 -19
- data/spec/app/models/mdm/web_site_spec.rb +23 -21
- data/spec/app/models/mdm/web_vuln_spec.rb +65 -63
- data/spec/app/models/mdm/wmap_request_spec.rb +3 -1
- data/spec/app/models/mdm/wmap_target_spec.rb +3 -1
- data/spec/app/models/mdm/workspace_spec.rb +100 -97
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_result_spec.rb +5 -3
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_set_spec.rb +15 -13
- data/spec/app/models/metasploit_data_models/automatic_exploitation/match_spec.rb +3 -1
- data/spec/app/models/metasploit_data_models/automatic_exploitation/run_spec.rb +3 -1
- data/spec/app/models/metasploit_data_models/ip_address/v4/cidr_spec.rb +12 -10
- data/spec/app/models/metasploit_data_models/ip_address/v4/nmap_spec.rb +6 -4
- data/spec/app/models/metasploit_data_models/ip_address/v4/range_spec.rb +23 -21
- data/spec/app/models/metasploit_data_models/ip_address/v4/segment/nmap/list_spec.rb +11 -9
- data/spec/app/models/metasploit_data_models/ip_address/v4/segment/nmap/range_spec.rb +23 -21
- data/spec/app/models/metasploit_data_models/ip_address/v4/segment/segmented_spec.rb +6 -4
- data/spec/app/models/metasploit_data_models/ip_address/v4/segment/single_spec.rb +15 -22
- data/spec/app/models/metasploit_data_models/ip_address/v4/single_spec.rb +6 -4
- data/spec/app/models/metasploit_data_models/module_run_spec.rb +3 -1
- data/spec/app/models/metasploit_data_models/search/operation/ip_address_spec.rb +20 -18
- data/spec/app/models/metasploit_data_models/search/operation/port/number_spec.rb +8 -6
- data/spec/app/models/metasploit_data_models/search/operation/port/range_spec.rb +10 -8
- data/spec/app/models/metasploit_data_models/search/operation/range_spec.rb +10 -8
- data/spec/app/models/metasploit_data_models/search/operator/ip_address_spec.rb +4 -2
- data/spec/app/models/metasploit_data_models/search/operator/multitext_spec.rb +10 -8
- data/spec/app/models/metasploit_data_models/search/operator/port/list_spec.rb +8 -6
- data/spec/app/models/metasploit_data_models/search/visitor/attribute_spec.rb +11 -9
- data/spec/app/models/metasploit_data_models/search/visitor/includes_spec.rb +7 -5
- data/spec/app/models/metasploit_data_models/search/visitor/joins_spec.rb +19 -17
- data/spec/app/models/metasploit_data_models/search/visitor/method_spec.rb +7 -5
- data/spec/app/models/metasploit_data_models/search/visitor/relation_spec.rb +23 -61
- data/spec/app/models/metasploit_data_models/search/visitor/where_spec.rb +10 -8
- data/spec/app/validators/parameters_validator_spec.rb +29 -29
- data/spec/app/validators/password_is_strong_validator_spec.rb +46 -54
- data/spec/factories/mdm/module/details.rb +1 -1
- data/spec/lib/base64_serializer_spec.rb +19 -19
- data/spec/lib/metasploit_data_models/ip_address/cidr_spec.rb +12 -18
- data/spec/lib/metasploit_data_models/ip_address/range_spec.rb +6 -4
- data/spec/lib/metasploit_data_models/match/child_spec.rb +4 -2
- data/spec/lib/metasploit_data_models/match/parent_spec.rb +6 -4
- data/spec/lib/metasploit_data_models/version_spec.rb +5 -3
- data/spec/spec_helper.rb +6 -72
- data/spec/support/shared/examples/mdm/module/detail/does_not_support_stance_with_mtype.rb +2 -2
- data/spec/support/shared/examples/mdm/module/detail/supports_stance_with_mtype.rb +4 -4
- data/spec/support/shared/examples/metasploit_data_models/search/operation/ipaddress/match.rb +2 -2
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/includes/visit/with_children.rb +5 -5
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/includes/visit/with_metasploit_model_search_operation_base.rb +5 -5
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/where/visit/with_equality.rb +3 -3
- data/spec/support/shared/examples/metasploit_data_models/search/visitor/where/visit/with_metasploit_model_search_group_base.rb +6 -7
- metadata +7 -7
@@ -1,29 +1,31 @@
|
|
1
|
-
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mdm::ExploitAttempt do
|
2
4
|
it_should_behave_like 'Metasploit::Concern.run'
|
3
5
|
|
4
6
|
context 'associations' do
|
5
|
-
it {
|
7
|
+
it { should belong_to(:host).class_name('Mdm::Host') }
|
6
8
|
end
|
7
9
|
|
8
10
|
context 'database' do
|
9
11
|
|
10
12
|
context 'timestamps'do
|
11
|
-
it {
|
13
|
+
it { should have_db_column(:attempted_at).of_type(:datetime) }
|
12
14
|
end
|
13
15
|
|
14
16
|
context 'columns' do
|
15
|
-
it {
|
16
|
-
it {
|
17
|
-
it {
|
18
|
-
it {
|
19
|
-
it {
|
20
|
-
it {
|
21
|
-
it {
|
22
|
-
it {
|
23
|
-
it {
|
24
|
-
it {
|
25
|
-
it {
|
26
|
-
it {
|
17
|
+
it { should have_db_column(:host_id).of_type(:integer) }
|
18
|
+
it { should have_db_column(:service_id).of_type(:integer) }
|
19
|
+
it { should have_db_column(:vuln_id).of_type(:integer) }
|
20
|
+
it { should have_db_column(:exploited).of_type(:boolean) }
|
21
|
+
it { should have_db_column(:fail_reason).of_type(:string) }
|
22
|
+
it { should have_db_column(:username).of_type(:string) }
|
23
|
+
it { should have_db_column(:module).of_type(:text) }
|
24
|
+
it { should have_db_column(:session_id).of_type(:integer) }
|
25
|
+
it { should have_db_column(:loot_id).of_type(:integer) }
|
26
|
+
it { should have_db_column(:port).of_type(:integer) }
|
27
|
+
it { should have_db_column(:proto).of_type(:string) }
|
28
|
+
it { should have_db_column(:fail_detail).of_type(:text) }
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
@@ -43,17 +45,17 @@ RSpec.describe Mdm::ExploitAttempt, type: :model do
|
|
43
45
|
context 'validations' do
|
44
46
|
it 'should only be valid with a host_id' do
|
45
47
|
orphaned_attempt = FactoryGirl.build(:mdm_exploit_attempt, :host => nil)
|
46
|
-
|
47
|
-
|
48
|
+
orphaned_attempt.should_not be_valid
|
49
|
+
orphaned_attempt.errors[:host_id].should include("can't be blank")
|
48
50
|
propper_attempt = FactoryGirl.build(:mdm_exploit_attempt)
|
49
|
-
|
51
|
+
propper_attempt.should be_valid
|
50
52
|
end
|
51
53
|
end
|
52
54
|
|
53
55
|
context 'factory' do
|
54
56
|
it 'should be valid' do
|
55
57
|
exploit_attempt = FactoryGirl.build(:mdm_exploit_attempt)
|
56
|
-
|
58
|
+
exploit_attempt.should be_valid
|
57
59
|
end
|
58
60
|
end
|
59
61
|
end
|
@@ -1,24 +1,26 @@
|
|
1
|
-
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mdm::ExploitedHost do
|
2
4
|
it_should_behave_like 'Metasploit::Concern.run'
|
3
5
|
|
4
6
|
context 'associations' do
|
5
|
-
it {
|
6
|
-
it {
|
7
|
+
it { should belong_to(:host).class_name('Mdm::Host') }
|
8
|
+
it { should belong_to(:service).class_name('Mdm::Service') }
|
7
9
|
end
|
8
10
|
|
9
11
|
context 'database' do
|
10
12
|
|
11
13
|
context 'timestamps'do
|
12
|
-
it {
|
13
|
-
it {
|
14
|
+
it { should have_db_column(:created_at).of_type(:datetime).with_options(:null => false) }
|
15
|
+
it { should have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) }
|
14
16
|
end
|
15
17
|
|
16
18
|
context 'columns' do
|
17
|
-
it {
|
18
|
-
it {
|
19
|
-
it {
|
20
|
-
it {
|
21
|
-
it {
|
19
|
+
it { should have_db_column(:host_id).of_type(:integer).with_options(:null => false) }
|
20
|
+
it { should have_db_column(:service_id).of_type(:integer) }
|
21
|
+
it { should have_db_column(:name).of_type(:string) }
|
22
|
+
it { should have_db_column(:session_uuid).of_type(:string) }
|
23
|
+
it { should have_db_column(:payload).of_type(:string) }
|
22
24
|
end
|
23
25
|
end
|
24
26
|
|
@@ -37,7 +39,7 @@ RSpec.describe Mdm::ExploitedHost, type: :model do
|
|
37
39
|
context 'factory' do
|
38
40
|
it 'should be valid' do
|
39
41
|
exploited_host = FactoryGirl.build(:mdm_exploited_host)
|
40
|
-
|
42
|
+
exploited_host.should be_valid
|
41
43
|
end
|
42
44
|
end
|
43
45
|
|
@@ -1,35 +1,37 @@
|
|
1
|
-
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mdm::HostDetail do
|
2
4
|
it_should_behave_like 'Metasploit::Concern.run'
|
3
5
|
|
4
6
|
context 'associations' do
|
5
|
-
it {
|
7
|
+
it { should belong_to(:host).class_name('Mdm::Host') }
|
6
8
|
end
|
7
9
|
|
8
10
|
context 'database' do
|
9
|
-
it {
|
10
|
-
it {
|
11
|
-
it {
|
12
|
-
it {
|
13
|
-
it {
|
14
|
-
it {
|
15
|
-
it {
|
16
|
-
it {
|
17
|
-
it {
|
18
|
-
it {
|
11
|
+
it { should have_db_column(:host_id).of_type(:integer) }
|
12
|
+
it { should have_db_column(:nx_console_id).of_type(:integer) }
|
13
|
+
it { should have_db_column(:nx_device_id).of_type(:integer) }
|
14
|
+
it { should have_db_column(:src).of_type(:string) }
|
15
|
+
it { should have_db_column(:nx_site_name).of_type(:string) }
|
16
|
+
it { should have_db_column(:nx_site_importance).of_type(:string) }
|
17
|
+
it { should have_db_column(:src).of_type(:string) }
|
18
|
+
it { should have_db_column(:nx_site_name).of_type(:string) }
|
19
|
+
it { should have_db_column(:nx_scan_template).of_type(:string) }
|
20
|
+
it { should have_db_column(:nx_risk_score).of_type(:float) }
|
19
21
|
end
|
20
22
|
|
21
23
|
context 'validations' do
|
22
24
|
it 'should only be valid with a host_id' do
|
23
25
|
orphan_detail = FactoryGirl.build(:mdm_host_detail, :host => nil)
|
24
|
-
|
25
|
-
|
26
|
+
orphan_detail.should_not be_valid
|
27
|
+
orphan_detail.errors[:host_id].should include("can't be blank")
|
26
28
|
end
|
27
29
|
end
|
28
30
|
|
29
31
|
context 'factory' do
|
30
32
|
it 'should be valid' do
|
31
33
|
host_detail = FactoryGirl.build(:mdm_host_detail)
|
32
|
-
|
34
|
+
host_detail.should be_valid
|
33
35
|
end
|
34
36
|
end
|
35
37
|
|
@@ -1,4 +1,6 @@
|
|
1
|
-
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mdm::Host do
|
2
4
|
subject(:host) do
|
3
5
|
FactoryGirl.build(:mdm_host)
|
4
6
|
end
|
@@ -39,18 +41,15 @@ RSpec.describe Mdm::Host, type: :model do
|
|
39
41
|
it_should_behave_like 'Metasploit::Concern.run'
|
40
42
|
|
41
43
|
context 'factory' do
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
}
|
46
|
-
|
47
|
-
it { is_expected.to be_valid }
|
44
|
+
it 'should be valid' do
|
45
|
+
host = FactoryGirl.build(:mdm_host)
|
46
|
+
host.should be_valid
|
48
47
|
end
|
49
48
|
end
|
50
49
|
|
51
50
|
context 'Constants' do
|
52
51
|
subject(:max_nmap_certainty) { described_class::MAX_NMAP_CERTAINTY }
|
53
|
-
it {
|
52
|
+
it { should eq(0.84) }
|
54
53
|
end
|
55
54
|
|
56
55
|
context '#destroy' do
|
@@ -104,19 +103,19 @@ RSpec.describe Mdm::Host, type: :model do
|
|
104
103
|
end
|
105
104
|
|
106
105
|
context 'associations' do
|
107
|
-
it {
|
108
|
-
it {
|
109
|
-
it {
|
110
|
-
it {
|
111
|
-
it {
|
112
|
-
it {
|
113
|
-
it {
|
114
|
-
it {
|
115
|
-
it {
|
116
|
-
it {
|
106
|
+
it { should have_many(:creds).class_name('Mdm::Cred').through(:services) }
|
107
|
+
it { should have_many(:clients).class_name('Mdm::Client').dependent(:destroy) }
|
108
|
+
it { should have_many(:exploit_attempts).class_name('Mdm::ExploitAttempt').dependent(:destroy) }
|
109
|
+
it { should have_many(:exploited_hosts).class_name('Mdm::ExploitedHost').dependent(:destroy) }
|
110
|
+
it { should have_many(:host_details).class_name('Mdm::HostDetail').dependent(:destroy) }
|
111
|
+
it { should have_many(:hosts_tags).class_name('Mdm::HostTag') }
|
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') }
|
114
|
+
it { should have_many(:task_hosts).class_name('Mdm::TaskHost').dependent(:destroy) }
|
115
|
+
it { should have_many(:tasks).class_name('Mdm::Task').through(:task_hosts) }
|
117
116
|
|
118
117
|
context 'module_details' do
|
119
|
-
it {
|
118
|
+
it { should have_many(:module_details).class_name('Mdm::Module::Detail').through(:module_refs) }
|
120
119
|
|
121
120
|
context 'with Mdm::Vulns' do
|
122
121
|
let!(:vulns) do
|
@@ -189,8 +188,8 @@ RSpec.describe Mdm::Host, type: :model do
|
|
189
188
|
module_details << module_ref.detail
|
190
189
|
end
|
191
190
|
|
192
|
-
|
193
|
-
|
191
|
+
host.module_details.count.should < module_details.length
|
192
|
+
module_details.uniq.count.should == host.module_details.count
|
194
193
|
end
|
195
194
|
end
|
196
195
|
end
|
@@ -199,17 +198,17 @@ RSpec.describe Mdm::Host, type: :model do
|
|
199
198
|
end
|
200
199
|
end
|
201
200
|
|
202
|
-
it {
|
203
|
-
it {
|
204
|
-
it {
|
205
|
-
it {
|
206
|
-
it {
|
207
|
-
it {
|
208
|
-
it {
|
209
|
-
it {
|
210
|
-
it {
|
211
|
-
it {
|
212
|
-
it {
|
201
|
+
it { should have_many(:module_refs).class_name('Mdm::Module::Ref').through(:refs) }
|
202
|
+
it { should have_many(:notes).class_name('Mdm::Note').dependent(:delete_all).order('notes.created_at') }
|
203
|
+
it { should have_many(:refs).class_name('Mdm::Ref').through(:vuln_refs) }
|
204
|
+
it { should have_many(:services).class_name('Mdm::Service').dependent(:destroy).order('services.port, services.proto') }
|
205
|
+
it { should have_many(:service_notes).through(:services) }
|
206
|
+
it { should have_many(:sessions).class_name('Mdm::Session').dependent(:destroy).order('sessions.opened_at') }
|
207
|
+
it { should have_many(:tags).class_name('Mdm::Tag').through(:hosts_tags) }
|
208
|
+
it { should have_many(:vulns).class_name('Mdm::Vuln').dependent(:delete_all) }
|
209
|
+
it { should have_many(:vuln_refs).class_name('Mdm::VulnRef') }
|
210
|
+
it { should have_many(:web_sites).class_name('Mdm::WebSite').through(:services) }
|
211
|
+
it { should belong_to(:workspace).class_name('Mdm::Workspace') }
|
213
212
|
end
|
214
213
|
|
215
214
|
context 'CONSTANTS' do
|
@@ -219,70 +218,70 @@ RSpec.describe Mdm::Host, type: :model do
|
|
219
218
|
end
|
220
219
|
|
221
220
|
it 'should be an Array<String>' do
|
222
|
-
|
221
|
+
architectures.should be_an Array
|
223
222
|
|
224
223
|
architectures.each do |architecture|
|
225
|
-
|
224
|
+
architecture.should be_a String
|
226
225
|
end
|
227
226
|
end
|
228
227
|
|
229
228
|
it 'should include both endians of ARM' do
|
230
|
-
|
231
|
-
|
229
|
+
architectures.should include('armbe')
|
230
|
+
architectures.should include('armle')
|
232
231
|
end
|
233
232
|
|
234
233
|
it 'should include 32-bit and 64-bit versions of Cell Broadband Engine Architecture' do
|
235
|
-
|
236
|
-
|
234
|
+
architectures.should include('cbea')
|
235
|
+
architectures.should include('cbea64')
|
237
236
|
end
|
238
237
|
|
239
238
|
it 'should include cmd for command shell' do
|
240
|
-
|
239
|
+
architectures.should include('cmd')
|
241
240
|
end
|
242
241
|
|
243
242
|
it 'should include java for Java Virtual Machine' do
|
244
|
-
|
243
|
+
architectures.should include('java')
|
245
244
|
end
|
246
245
|
|
247
246
|
it 'should include plain and endian-ware MIPS' do
|
248
|
-
|
249
|
-
|
250
|
-
|
247
|
+
architectures.should include('mips')
|
248
|
+
architectures.should include('mipsbe')
|
249
|
+
architectures.should include('mipsle')
|
251
250
|
end
|
252
251
|
|
253
252
|
it 'should include php for PHP code' do
|
254
|
-
|
253
|
+
architectures.should include('php')
|
255
254
|
end
|
256
255
|
|
257
256
|
it 'should include 32-bit and 64-bit PowerPC' do
|
258
|
-
|
259
|
-
|
257
|
+
architectures.should include('ppc')
|
258
|
+
architectures.should include('ppc64')
|
260
259
|
end
|
261
260
|
|
262
261
|
it 'should include ruby for Ruby code' do
|
263
|
-
|
262
|
+
architectures.should include('ruby')
|
264
263
|
end
|
265
264
|
|
266
265
|
it 'should include sparc for Sparc' do
|
267
|
-
|
266
|
+
architectures.should include('sparc')
|
268
267
|
end
|
269
268
|
|
270
269
|
it 'should include tty for Terminals' do
|
271
|
-
|
270
|
+
architectures.should include('tty')
|
272
271
|
end
|
273
272
|
|
274
273
|
it 'should include 32-bit and 64-bit x86' do
|
275
|
-
|
276
|
-
|
277
|
-
|
274
|
+
architectures.should include('x64')
|
275
|
+
architectures.should include('x86')
|
276
|
+
architectures.should include('x86_64')
|
278
277
|
end
|
279
278
|
|
280
279
|
it 'should include blank string to indicate no detection has happened' do
|
281
|
-
|
280
|
+
architectures.should include('')
|
282
281
|
end
|
283
282
|
|
284
283
|
it 'should include "Unknown" for failed detection attempts' do
|
285
|
-
|
284
|
+
architectures.should include('Unknown')
|
286
285
|
end
|
287
286
|
|
288
287
|
end
|
@@ -293,71 +292,71 @@ RSpec.describe Mdm::Host, type: :model do
|
|
293
292
|
end
|
294
293
|
|
295
294
|
it 'should be an Array<String>' do
|
296
|
-
|
295
|
+
search_fields.should be_an Array
|
297
296
|
|
298
297
|
search_fields.each { |search_field|
|
299
|
-
|
298
|
+
search_field.should be_a String
|
300
299
|
}
|
301
300
|
end
|
302
301
|
|
303
302
|
it 'should cast address to text' do
|
304
|
-
|
303
|
+
search_fields.should include('address::text')
|
305
304
|
end
|
306
305
|
|
307
|
-
it {
|
308
|
-
it {
|
309
|
-
it {
|
310
|
-
it {
|
311
|
-
it {
|
312
|
-
it {
|
313
|
-
it {
|
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') }
|
314
313
|
end
|
315
314
|
|
316
315
|
it 'should define STATES in any order' do
|
317
|
-
|
316
|
+
described_class::STATES.should =~ states
|
318
317
|
end
|
319
318
|
end
|
320
319
|
|
321
320
|
context 'database' do
|
322
321
|
context 'columns' do
|
323
|
-
it {
|
324
|
-
it {
|
325
|
-
it {
|
326
|
-
it {
|
327
|
-
it {
|
328
|
-
it {
|
329
|
-
it {
|
330
|
-
it {
|
331
|
-
it {
|
332
|
-
it {
|
333
|
-
it {
|
334
|
-
it {
|
335
|
-
it {
|
336
|
-
it {
|
337
|
-
it {
|
338
|
-
it {
|
322
|
+
it { should have_db_column(:address).of_type(:string).with_options(:null => false) }
|
323
|
+
it { should have_db_column(:arch).of_type(:string) }
|
324
|
+
it { should have_db_column(:comm).of_type(:string) }
|
325
|
+
it { should have_db_column(:comments).of_type(:text) }
|
326
|
+
it { should have_db_column(:info).of_type(:string).with_options(:limit => 2 ** 16) }
|
327
|
+
it { should have_db_column(:mac).of_type(:string) }
|
328
|
+
it { should have_db_column(:name).of_type(:string) }
|
329
|
+
it { should have_db_column(:os_flavor).of_type(:string) }
|
330
|
+
it { should have_db_column(:os_lang).of_type(:string) }
|
331
|
+
it { should have_db_column(:os_name).of_type(:string) }
|
332
|
+
it { should have_db_column(:os_sp).of_type(:string) }
|
333
|
+
it { should have_db_column(:purpose).of_type(:text) }
|
334
|
+
it { should have_db_column(:scope).of_type(:text) }
|
335
|
+
it { should have_db_column(:state).of_type(:string) }
|
336
|
+
it { should have_db_column(:virtual_host).of_type(:text) }
|
337
|
+
it { should have_db_column(:workspace_id).of_type(:integer).with_options(:null => false) }
|
339
338
|
|
340
339
|
context 'counter caches' do
|
341
|
-
it {
|
342
|
-
it {
|
343
|
-
it {
|
344
|
-
it {
|
345
|
-
it {
|
340
|
+
it { should have_db_column(:exploit_attempt_count).of_type(:integer).with_options(:default => 0) }
|
341
|
+
it { should have_db_column(:host_detail_count).of_type(:integer).with_options(:default => 0) }
|
342
|
+
it { should have_db_column(:note_count).of_type(:integer).with_options(:default => 0) }
|
343
|
+
it { should have_db_column(:service_count).of_type(:integer).with_options(:default => 0) }
|
344
|
+
it { should have_db_column(:vuln_count).of_type(:integer).with_options(:default => 0) }
|
346
345
|
end
|
347
346
|
|
348
347
|
context 'timestamps' do
|
349
|
-
it {
|
350
|
-
it {
|
348
|
+
it { should have_db_column(:created_at).of_type(:datetime) }
|
349
|
+
it { should have_db_column(:updated_at).of_type(:datetime) }
|
351
350
|
end
|
352
351
|
end
|
353
352
|
|
354
353
|
context 'indices' do
|
355
|
-
it {
|
356
|
-
it {
|
357
|
-
it {
|
358
|
-
it {
|
359
|
-
it {
|
360
|
-
it {
|
354
|
+
it { should have_db_index([:workspace_id, :address]).unique(true) }
|
355
|
+
it { should have_db_index(:name) }
|
356
|
+
it { should have_db_index(:os_flavor) }
|
357
|
+
it { should have_db_index(:os_name) }
|
358
|
+
it { should have_db_index(:purpose) }
|
359
|
+
it { should have_db_index(:state) }
|
361
360
|
end
|
362
361
|
end
|
363
362
|
|
@@ -367,7 +366,7 @@ RSpec.describe Mdm::Host, type: :model do
|
|
367
366
|
FactoryGirl.build(:full_mdm_host)
|
368
367
|
end
|
369
368
|
|
370
|
-
it {
|
369
|
+
it { should be_valid }
|
371
370
|
end
|
372
371
|
|
373
372
|
context 'mdm_host' do
|
@@ -375,14 +374,14 @@ RSpec.describe Mdm::Host, type: :model do
|
|
375
374
|
FactoryGirl.build(:mdm_host)
|
376
375
|
end
|
377
376
|
|
378
|
-
it {
|
377
|
+
it { should be_valid }
|
379
378
|
end
|
380
379
|
end
|
381
380
|
|
382
381
|
context 'validations' do
|
383
382
|
context 'address' do
|
384
|
-
it {
|
385
|
-
it {
|
383
|
+
it { should ensure_exclusion_of(:address).in_array(['127.0.0.1']) }
|
384
|
+
it { should validate_presence_of(:address) }
|
386
385
|
|
387
386
|
# can't use validate_uniqueness_of(:address).scoped_to(:workspace_id) because it will attempt to set workspace_id
|
388
387
|
# to `nil`, which will make the `:null => false` constraint on hosts.workspace_id to fail.
|
@@ -394,8 +393,8 @@ RSpec.describe Mdm::Host, type: :model do
|
|
394
393
|
|
395
394
|
duplicate_host = FactoryGirl.build(:mdm_host, :address => address, :workspace => workspace)
|
396
395
|
|
397
|
-
|
398
|
-
|
396
|
+
duplicate_host.should_not be_valid
|
397
|
+
duplicate_host.errors[:address].should include('has already been taken')
|
399
398
|
end
|
400
399
|
end
|
401
400
|
|
@@ -406,19 +405,19 @@ RSpec.describe Mdm::Host, type: :model do
|
|
406
405
|
context 'with an unknown architecture' do
|
407
406
|
let(:arch) { "asdfasdf" }
|
408
407
|
it 'should normalize to Unknown' do
|
409
|
-
|
410
|
-
|
408
|
+
host.should be_valid
|
409
|
+
host.arch.should be described_class::UNKNOWN_ARCHITECTURE
|
411
410
|
end
|
412
411
|
end
|
413
412
|
described_class::ARCHITECTURES.each do |arch|
|
414
413
|
context "with known architecture '#{arch}'" do
|
415
414
|
let(:arch) { arch }
|
416
|
-
it {
|
415
|
+
it { should be_valid }
|
417
416
|
end
|
418
417
|
end
|
419
418
|
end
|
420
|
-
it {
|
421
|
-
it {
|
419
|
+
it { should ensure_inclusion_of(:state).in_array(states).allow_nil }
|
420
|
+
it { should validate_presence_of(:workspace) }
|
422
421
|
end
|
423
422
|
|
424
423
|
context 'search scope' do
|
@@ -432,13 +431,13 @@ RSpec.describe Mdm::Host, type: :model do
|
|
432
431
|
|
433
432
|
context 'searching for an empty string' do
|
434
433
|
it 'should return any hosts in the database' do
|
435
|
-
|
434
|
+
search_for('').should include(subject)
|
436
435
|
end
|
437
436
|
end
|
438
437
|
|
439
438
|
context 'searching for an existing Host\'s name' do
|
440
439
|
it 'should return the host' do
|
441
|
-
|
440
|
+
search_for(subject.name).should include(subject)
|
442
441
|
end
|
443
442
|
end
|
444
443
|
end
|
@@ -447,139 +446,139 @@ RSpec.describe Mdm::Host, type: :model do
|
|
447
446
|
context '#get_arch_from_string' do
|
448
447
|
context "should return 'x64'" do
|
449
448
|
it "when the string contains 'x64'" do
|
450
|
-
|
449
|
+
host.send(:get_arch_from_string, 'blahx64blah').should == 'x64'
|
451
450
|
end
|
452
451
|
|
453
452
|
it "when the string contains 'X64'" do
|
454
|
-
|
453
|
+
host.send(:get_arch_from_string, 'blahX64blah').should == 'x64'
|
455
454
|
end
|
456
455
|
|
457
456
|
it "when the string contains 'x86_64'" do
|
458
|
-
|
457
|
+
host.send(:get_arch_from_string, 'blahx86_64blah').should == 'x64'
|
459
458
|
end
|
460
459
|
|
461
460
|
it "when the string contains 'X86_64'" do
|
462
|
-
|
461
|
+
host.send(:get_arch_from_string, 'blahX86_64blah').should == 'x64'
|
463
462
|
end
|
464
463
|
|
465
464
|
it "when the string contains 'amd64'" do
|
466
|
-
|
465
|
+
host.send(:get_arch_from_string, 'blahamd64blah').should == 'x64'
|
467
466
|
end
|
468
467
|
|
469
468
|
it "when the string contains 'AMD64'" do
|
470
|
-
|
469
|
+
host.send(:get_arch_from_string, 'blahAMD64blah').should == 'x64'
|
471
470
|
end
|
472
471
|
|
473
472
|
it "when the string contains 'aMd64'" do
|
474
|
-
|
473
|
+
host.send(:get_arch_from_string, 'blahamd64blah').should == 'x64'
|
475
474
|
end
|
476
475
|
end
|
477
476
|
|
478
477
|
context "should return 'x86'" do
|
479
478
|
it "when the string contains 'x86'" do
|
480
|
-
|
479
|
+
host.send(:get_arch_from_string, 'blahx86blah').should == 'x86'
|
481
480
|
end
|
482
481
|
|
483
482
|
it "when the string contains 'X86'" do
|
484
|
-
|
483
|
+
host.send(:get_arch_from_string, 'blahX86blah').should == 'x86'
|
485
484
|
end
|
486
485
|
|
487
486
|
it "when the string contains 'i386'" do
|
488
|
-
|
487
|
+
host.send(:get_arch_from_string, 'blahi386blah').should == 'x86'
|
489
488
|
end
|
490
489
|
|
491
490
|
it "when the string contains 'I386'" do
|
492
|
-
|
491
|
+
host.send(:get_arch_from_string, 'blahI386blah').should == 'x86'
|
493
492
|
end
|
494
493
|
|
495
494
|
it "when the string contains 'i486'" do
|
496
|
-
|
495
|
+
host.send(:get_arch_from_string, 'blahi486blah').should == 'x86'
|
497
496
|
end
|
498
497
|
|
499
498
|
it "when the string contains 'i586'" do
|
500
|
-
|
499
|
+
host.send(:get_arch_from_string, 'blahi586blah').should == 'x86'
|
501
500
|
end
|
502
501
|
|
503
502
|
it "when the string contains 'i686'" do
|
504
|
-
|
503
|
+
host.send(:get_arch_from_string, 'blahi386blah').should == 'x86'
|
505
504
|
end
|
506
505
|
end
|
507
506
|
|
508
507
|
context "should return 'ppc'" do
|
509
508
|
it "when the string contains 'PowerPC'" do
|
510
|
-
|
509
|
+
host.send(:get_arch_from_string, 'blahPowerPCblah').should == 'ppc'
|
511
510
|
end
|
512
511
|
|
513
512
|
it "when the string contains 'PPC'" do
|
514
|
-
|
513
|
+
host.send(:get_arch_from_string, 'blahPPCblah').should == 'ppc'
|
515
514
|
end
|
516
515
|
|
517
516
|
it "when the string contains 'POWER'" do
|
518
|
-
|
517
|
+
host.send(:get_arch_from_string, 'blahPOWERblah').should == 'ppc'
|
519
518
|
end
|
520
519
|
|
521
520
|
it "when the string contains 'ppc'" do
|
522
|
-
|
521
|
+
host.send(:get_arch_from_string, 'blahppcblah').should == 'ppc'
|
523
522
|
end
|
524
523
|
end
|
525
524
|
|
526
525
|
context 'should return nil' do
|
527
526
|
it 'when PowerPC is cased incorrectly' do
|
528
|
-
|
529
|
-
|
527
|
+
host.send(:get_arch_from_string, 'powerPC').should == nil
|
528
|
+
host.send(:get_arch_from_string, 'Powerpc').should == nil
|
530
529
|
end
|
531
530
|
|
532
531
|
it 'when no recognized arch string is present' do
|
533
|
-
|
532
|
+
host.send(:get_arch_from_string, 'blahblah').should == nil
|
534
533
|
end
|
535
534
|
end
|
536
535
|
|
537
536
|
it "should return 'sparc' if the string contains SPARC, regardless of case" do
|
538
|
-
|
539
|
-
|
540
|
-
|
537
|
+
host.send(:get_arch_from_string, 'blahSPARCblah').should == 'sparc'
|
538
|
+
host.send(:get_arch_from_string, 'blahSPaRCblah').should == 'sparc'
|
539
|
+
host.send(:get_arch_from_string, 'blahsparcblah').should == 'sparc'
|
541
540
|
end
|
542
541
|
|
543
542
|
it "should return 'arm' if the string contains 'ARM', regardless of case" do
|
544
|
-
|
545
|
-
|
546
|
-
|
543
|
+
host.send(:get_arch_from_string, 'blahARMblah').should == 'arm'
|
544
|
+
host.send(:get_arch_from_string, 'blahArMblah').should == 'arm'
|
545
|
+
host.send(:get_arch_from_string, 'blaharmblah').should == 'arm'
|
547
546
|
end
|
548
547
|
|
549
548
|
it "should return 'mips' if the string contains 'MIPS', regardless of case" do
|
550
|
-
|
551
|
-
|
552
|
-
|
549
|
+
host.send(:get_arch_from_string, 'blahMIPSblah').should == 'mips'
|
550
|
+
host.send(:get_arch_from_string, 'blahMiPslah').should == 'mips'
|
551
|
+
host.send(:get_arch_from_string, 'blahmipsblah').should == 'mips'
|
553
552
|
end
|
554
553
|
end
|
555
554
|
|
556
555
|
context '#parse_windows_os_str' do
|
557
556
|
it 'should always return the os_name as Windows' do
|
558
557
|
result = host.send(:parse_windows_os_str, '')
|
559
|
-
|
558
|
+
result['os.product'].should == 'Windows'
|
560
559
|
end
|
561
560
|
|
562
561
|
context 'arch' do
|
563
562
|
it 'should return a value for arch if there is one' do
|
564
563
|
result = host.send(:parse_windows_os_str, 'Windows x64')
|
565
|
-
|
564
|
+
result['os.arch'].should == 'x64'
|
566
565
|
end
|
567
566
|
|
568
567
|
it "should not have an arch key if we don't know the arch" do
|
569
568
|
result = host.send(:parse_windows_os_str, 'Windows')
|
570
|
-
|
569
|
+
result.has_key?('os.arch').should == false
|
571
570
|
end
|
572
571
|
end
|
573
572
|
|
574
573
|
context 'Service Pack' do
|
575
574
|
it 'should be returned if we see Service Pack X' do
|
576
575
|
result = host.send(:parse_windows_os_str, 'Windows XP Service Pack 1')
|
577
|
-
|
576
|
+
result['os.version'].should == 'SP1'
|
578
577
|
end
|
579
578
|
|
580
579
|
it 'should be returned if we see SPX' do
|
581
580
|
result = host.send(:parse_windows_os_str, 'Windows XP SP3')
|
582
|
-
|
581
|
+
result['os.version'].should == 'SP3'
|
583
582
|
end
|
584
583
|
end
|
585
584
|
|
@@ -587,137 +586,141 @@ RSpec.describe Mdm::Host, type: :model do
|
|
587
586
|
|
588
587
|
it "should appear as Windows 95 for 'Windows 95" do
|
589
588
|
result = host.send(:parse_windows_os_str, 'Windows 95')
|
590
|
-
|
589
|
+
result['os.product'].should == 'Windows 95'
|
591
590
|
end
|
592
591
|
|
593
592
|
it "should appear as Windows NT 3.51 for 'Windows NT 3.51" do
|
594
593
|
result = host.send(:parse_windows_os_str, 'Windows NT 3.51')
|
595
|
-
|
594
|
+
result['os.product'].should == 'Windows NT 3.51'
|
596
595
|
end
|
597
596
|
|
598
597
|
it "should appear as Windows NT 4.0 for 'Windows NT 4.0" do
|
599
598
|
result = host.send(:parse_windows_os_str, 'Windows NT 4.0')
|
600
|
-
|
599
|
+
result['os.product'].should == 'Windows NT 4.0'
|
601
600
|
end
|
602
601
|
|
603
602
|
it "should appear as Windows 98 for 'Windows 98" do
|
604
603
|
result = host.send(:parse_windows_os_str, 'Windows 98')
|
605
|
-
|
604
|
+
result['os.product'].should == 'Windows 98'
|
606
605
|
end
|
607
606
|
|
608
607
|
it "should appear as Windows ME for 'Windows ME" do
|
609
608
|
result = host.send(:parse_windows_os_str, 'Windows ME')
|
610
|
-
|
609
|
+
result['os.product'].should == 'Windows ME'
|
611
610
|
end
|
612
611
|
|
613
612
|
it "should appear as Windows 2003 for '.NET Server'" do
|
614
613
|
result = host.send(:parse_windows_os_str, 'Windows .NET Server')
|
615
|
-
|
614
|
+
result['os.product'].should == 'Windows Server 2003'
|
616
615
|
end
|
617
616
|
|
618
617
|
it 'should be recognized for Windows XP' do
|
619
618
|
result = host.send(:parse_windows_os_str, 'Windows XP')
|
620
|
-
|
619
|
+
result['os.product'].should == 'Windows XP'
|
621
620
|
end
|
622
621
|
|
623
622
|
it 'should be recognized for Windows Server 2000' do
|
624
623
|
result = host.send(:parse_windows_os_str, 'Windows 2000')
|
625
|
-
|
624
|
+
result['os.product'].should == 'Windows Server 2000'
|
626
625
|
end
|
627
626
|
|
628
627
|
it 'should be recognized for Windows Server 2003' do
|
629
628
|
result = host.send(:parse_windows_os_str, 'Windows 2003')
|
630
|
-
|
629
|
+
result['os.product'].should == 'Windows Server 2003'
|
631
630
|
end
|
632
631
|
|
633
632
|
it 'should be recognized for Windows 2008' do
|
634
633
|
result = host.send(:parse_windows_os_str, 'Windows 2008')
|
635
|
-
|
634
|
+
result['os.product'].should == 'Windows Server 2008'
|
636
635
|
end
|
637
636
|
|
638
637
|
it 'should be recognized for Windows 2012' do
|
639
638
|
result = host.send(:parse_windows_os_str, 'Windows 2012')
|
640
|
-
|
639
|
+
result['os.product'].should == 'Windows Server 2012'
|
641
640
|
end
|
642
641
|
|
643
642
|
it 'should be recognized for Windows Vista' do
|
644
643
|
result = host.send(:parse_windows_os_str, 'Windows Vista')
|
645
|
-
|
644
|
+
result['os.product'].should == 'Windows Vista'
|
646
645
|
end
|
647
646
|
|
648
647
|
it 'should be recognized for Windows Server 2000' do
|
649
648
|
result = host.send(:parse_windows_os_str, 'Windows 2000 Advanced Server')
|
650
|
-
|
649
|
+
result['os.product'].should == 'Windows Server 2000'
|
651
650
|
end
|
652
651
|
|
653
652
|
it 'should be recognized for Windows 7' do
|
654
653
|
result = host.send(:parse_windows_os_str, 'Windows 7')
|
655
|
-
|
654
|
+
result['os.product'].should == 'Windows 7'
|
656
655
|
end
|
657
656
|
|
658
657
|
it 'should be recognized for Windows 7 Ultimate Edition' do
|
659
658
|
result = host.send(:parse_windows_os_str, 'Windows 7 Ultimate Edition')
|
660
|
-
|
661
|
-
|
659
|
+
result['os.product'].should == 'Windows 7'
|
660
|
+
result['os.edition'].should == 'Ultimate'
|
662
661
|
end
|
663
662
|
|
664
663
|
it 'should be recognized for Windows 8' do
|
665
664
|
result = host.send(:parse_windows_os_str, 'Windows 8')
|
666
|
-
|
665
|
+
result['os.product'].should == 'Windows 8'
|
667
666
|
end
|
668
667
|
|
669
668
|
it 'should be recognized for Windows 8.1' do
|
670
669
|
result = host.send(:parse_windows_os_str, 'Windows 8.1')
|
671
|
-
|
670
|
+
result['os.product'].should == 'Windows 8.1'
|
672
671
|
end
|
673
672
|
|
674
673
|
it 'should be recognized for Windows 8.2' do
|
675
674
|
result = host.send(:parse_windows_os_str, 'Windows 8.2')
|
676
|
-
|
675
|
+
result['os.product'].should == 'Windows 8.2'
|
677
676
|
end
|
678
677
|
|
679
678
|
it 'should be recognized as Windows XP, Build 2600, SP3' do
|
680
679
|
result = host.send(:parse_windows_os_str, 'Windows XP (Build 2600, Service Pack 3).')
|
681
|
-
|
682
|
-
|
683
|
-
|
680
|
+
result['os.product'].should == 'Windows XP'
|
681
|
+
result['os.build'].should == '2600'
|
682
|
+
result['os.version'].should == 'SP3'
|
684
683
|
end
|
685
684
|
|
686
685
|
it 'should be recognized as Windows Server 2003, Build 3790' do
|
687
686
|
result = host.send(:parse_windows_os_str, 'Windows .NET Server (Build 3790).')
|
688
|
-
|
689
|
-
|
687
|
+
result['os.product'].should == 'Windows Server 2003'
|
688
|
+
result['os.build'].should == '3790'
|
690
689
|
end
|
691
690
|
|
692
691
|
it 'should be recognized as Windows Server 2008, Build 6001, SP1' do
|
693
692
|
result = host.send(:parse_windows_os_str, 'Windows 2008 (Build 6001, Service Pack 1).')
|
694
|
-
|
695
|
-
|
696
|
-
|
693
|
+
result['os.product'].should == 'Windows Server 2008'
|
694
|
+
result['os.build'].should == '6001'
|
695
|
+
result['os.version'].should == 'SP1'
|
697
696
|
end
|
698
697
|
|
699
698
|
it 'should default to Windows <name> if all else fails' do
|
700
699
|
result = host.send(:parse_windows_os_str, 'Windows Foobar Service Pack 3')
|
701
|
-
|
702
|
-
|
700
|
+
result['os.product'].should == 'Windows Foobar'
|
701
|
+
result['os.version'].should == 'SP3'
|
703
702
|
end
|
704
703
|
end
|
705
704
|
end
|
706
705
|
|
707
706
|
context '#validate_fingerprint_data' do
|
707
|
+
before(:each) do
|
708
|
+
host.stub(:dlog)
|
709
|
+
end
|
710
|
+
|
708
711
|
it 'should return false for an empty hash' do
|
709
712
|
fingerprint= FactoryGirl.build(:mdm_note, :data => {})
|
710
|
-
|
713
|
+
host.validate_fingerprint_data(fingerprint).should == false
|
711
714
|
end
|
712
715
|
|
713
716
|
it 'should return false for postgresql fingerprints' do
|
714
717
|
fingerprint= FactoryGirl.build(:mdm_note, :ntype => 'postgresql.fingerprint', :data => {})
|
715
|
-
|
718
|
+
host.validate_fingerprint_data(fingerprint).should == false
|
716
719
|
end
|
717
720
|
|
718
721
|
it 'should return false if the fingerprint does not contain a hash' do
|
719
722
|
fingerprint= FactoryGirl.build(:mdm_note, :data => 'this is not a fingerprint')
|
720
|
-
|
723
|
+
host.validate_fingerprint_data(fingerprint).should == false
|
721
724
|
end
|
722
725
|
end
|
723
726
|
|
@@ -725,95 +728,91 @@ RSpec.describe Mdm::Host, type: :model do
|
|
725
728
|
context '#apply_match_to_host' do
|
726
729
|
|
727
730
|
before(:each) do
|
728
|
-
stub_const(
|
729
|
-
|
730
|
-
|
731
|
-
|
732
|
-
|
733
|
-
unsanitized.unpack("C*").pack("C*").gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0]}
|
734
|
-
end
|
735
|
-
end
|
736
|
-
)
|
731
|
+
stub_const('Rex::Text', Module.new)
|
732
|
+
allow(Rex::Text).to receive(:ascii_safe_hex) do |unsanitized|
|
733
|
+
# Pass back the sanitized value for the stub
|
734
|
+
unsanitized.unpack("C*").pack("C*").gsub(/([\x00-\x08\x0b\x0c\x0e-\x1f\x80-\xFF])/n){ |x| "\\x%.2x" % x.unpack("C*")[0]}
|
735
|
+
end
|
737
736
|
end
|
738
737
|
|
739
738
|
it 'should set host.mac when host.mac is present' do
|
740
739
|
match = { 'host.mac' => '00:11:22:33:44:55' }
|
741
740
|
host.send(:apply_match_to_host, match)
|
742
|
-
|
741
|
+
host.mac.should == '00:11:22:33:44:55'
|
743
742
|
end
|
744
743
|
|
745
744
|
it 'should set host.name when host.name is present' do
|
746
745
|
match = { 'host.name' => 'webbyweb' }
|
747
746
|
host.send(:apply_match_to_host, match)
|
748
|
-
|
747
|
+
host.name.should == 'webbyweb'
|
749
748
|
end
|
750
749
|
|
751
750
|
it 'should set host.arch when os.arch is present' do
|
752
751
|
match = { 'os.arch' => 'x86' }
|
753
752
|
host.send(:apply_match_to_host, match)
|
754
|
-
|
753
|
+
host.arch.should == 'x86'
|
755
754
|
end
|
756
755
|
|
757
756
|
it 'should set host.name to an escaped hex value when host.name contains high bytes' do
|
758
757
|
match = { 'host.name' => "HighBytes\xff\xf0".force_encoding('binary') }
|
759
758
|
host.send(:apply_match_to_host, match)
|
760
|
-
|
759
|
+
host.name.should == "HighBytes\\xff\\xf0"
|
761
760
|
end
|
762
761
|
|
763
762
|
it 'should set host.purpose to client when os.product is Windows XP' do
|
764
763
|
match = { 'os.product' => 'Windows XP' }
|
765
764
|
host.send(:apply_match_to_host, match)
|
766
|
-
|
767
|
-
|
765
|
+
host.os_name.should == 'Windows XP'
|
766
|
+
host.purpose.should == 'client'
|
768
767
|
end
|
769
768
|
|
770
769
|
it 'should set host.purpose to server when os.product is Windows 2012' do
|
771
770
|
match = { 'os.product' => 'Windows 2012' }
|
772
771
|
host.send(:apply_match_to_host, match)
|
773
|
-
|
774
|
-
|
772
|
+
host.os_name.should == 'Windows 2012'
|
773
|
+
host.purpose.should == 'server'
|
775
774
|
end
|
776
775
|
|
777
776
|
it 'should set host.purpose to printer when os.device is Print server' do
|
778
777
|
match = { 'os.device' => 'Print server' }
|
779
778
|
host.send(:apply_match_to_host, match)
|
780
|
-
|
779
|
+
host.purpose.should == 'printer'
|
781
780
|
end
|
782
781
|
|
783
782
|
it 'should set host.os_lang to English when os.language is English' do
|
784
783
|
match = { 'os.language' => 'English' }
|
785
784
|
host.send(:apply_match_to_host, match)
|
786
|
-
|
785
|
+
host.os_lang.should == 'English'
|
787
786
|
end
|
788
787
|
|
789
788
|
it 'should set host.os_name to Windows 8.1 when os.product is Windows 8.1' do
|
790
789
|
match = { 'os.product' => 'Windows 8.1' }
|
791
790
|
host.send(:apply_match_to_host, match)
|
792
|
-
|
791
|
+
host.os_name.should == 'Windows 8.1'
|
793
792
|
end
|
794
793
|
|
795
794
|
it 'should set host.os_name to Windows when os.product is not set and os.family is Windows' do
|
796
795
|
match = { 'os.family' => 'Windows' }
|
797
796
|
host.send(:apply_match_to_host, match)
|
798
|
-
|
797
|
+
host.os_name.should == 'Windows'
|
799
798
|
end
|
800
799
|
|
801
800
|
it 'should set host.os_flavor to Professional when os.edition is Professional' do
|
802
801
|
match = { 'os.edition' => 'Professional' }
|
803
802
|
host.send(:apply_match_to_host, match)
|
804
|
-
|
803
|
+
host.os_flavor.should == 'Professional'
|
805
804
|
end
|
806
805
|
|
807
806
|
it 'should set host.os_sp to SP2 when os.version is SP2' do
|
808
807
|
match = { 'os.version' => 'SP2' }
|
809
808
|
host.send(:apply_match_to_host, match)
|
810
|
-
|
809
|
+
host.os_sp.should == 'SP2'
|
811
810
|
end
|
812
811
|
|
813
812
|
it 'should set host.os_sp to 3.2.11 when os.version is nil and linux.kernel.version is 3.2.11' do
|
814
813
|
match = { 'linux.kernel.version' => '3.2.11' }
|
815
814
|
host.send(:apply_match_to_host, match)
|
816
|
-
|
815
|
+
host.os_sp.should == '3.2.11'
|
817
816
|
end
|
818
817
|
end
|
819
818
|
|
@@ -822,33 +821,33 @@ RSpec.describe Mdm::Host, type: :model do
|
|
822
821
|
it 'should convert Service Pack X to SPX' do
|
823
822
|
match = { 'os.version' => 'Service Pack 2' }
|
824
823
|
result = host.send(:normalize_match, match)
|
825
|
-
|
824
|
+
result['os.version'].should == 'SP2'
|
826
825
|
end
|
827
826
|
|
828
827
|
it 'should not convert No Service Pack to SP' do
|
829
828
|
match = { 'os.version' => 'No Service Pack' }
|
830
829
|
result = host.send(:normalize_match, match)
|
831
|
-
|
830
|
+
result['os.version'].should == 'No Service Pack'
|
832
831
|
end
|
833
832
|
|
834
833
|
it 'should convert Apple Mac OS X to Mac OS X' do
|
835
834
|
match = { 'os.product' => 'Apple Mac OS X' }
|
836
835
|
result = host.send(:normalize_match, match)
|
837
|
-
|
838
|
-
|
836
|
+
result['os.product'].should == 'Mac OS X'
|
837
|
+
result['os.vendor'].should == 'Apple'
|
839
838
|
end
|
840
839
|
|
841
840
|
it 'should convert Microsoft Windows to Windows' do
|
842
841
|
match = { 'os.product' => 'Microsoft Windows 7' }
|
843
842
|
result = host.send(:normalize_match, match)
|
844
|
-
|
845
|
-
|
843
|
+
result['os.product'].should == 'Windows 7'
|
844
|
+
result['os.vendor'].should == 'Microsoft'
|
846
845
|
end
|
847
846
|
|
848
847
|
it 'should convert Windows Server 2012 to Windows 2012' do
|
849
848
|
match = { 'os.product' => 'Windows Server 2012' }
|
850
849
|
result = host.send(:normalize_match, match)
|
851
|
-
|
850
|
+
result['os.product'].should == 'Windows 2012'
|
852
851
|
end
|
853
852
|
end
|
854
853
|
|
@@ -857,55 +856,55 @@ RSpec.describe Mdm::Host, type: :model do
|
|
857
856
|
it 'should detect Windows XP as a client' do
|
858
857
|
match = { 'os.product' => 'Windows XP' }
|
859
858
|
result = host.send(:guess_purpose_from_match, match)
|
860
|
-
|
859
|
+
result.should == 'client'
|
861
860
|
end
|
862
861
|
|
863
862
|
it 'should detect Windows 8.1 as a client' do
|
864
863
|
match = { 'os.product' => 'Windows 8.1' }
|
865
864
|
result = host.send(:guess_purpose_from_match, match)
|
866
|
-
|
865
|
+
result.should == 'client'
|
867
866
|
end
|
868
867
|
|
869
868
|
it 'should detect Windows 2000 as a server' do
|
870
869
|
match = { 'os.product' => 'Windows 2000' }
|
871
870
|
result = host.send(:guess_purpose_from_match, match)
|
872
|
-
|
871
|
+
result.should == 'server'
|
873
872
|
end
|
874
873
|
|
875
874
|
it 'should detect Windows Server 2012 as a server' do
|
876
875
|
match = { 'os.product' => 'Windows Server 2012' }
|
877
876
|
result = host.send(:guess_purpose_from_match, match)
|
878
|
-
|
877
|
+
result.should == 'server'
|
879
878
|
end
|
880
879
|
|
881
880
|
it 'should detect Linux as a server' do
|
882
881
|
match = { 'os.product' => 'Linux' }
|
883
882
|
result = host.send(:guess_purpose_from_match, match)
|
884
|
-
|
883
|
+
result.should == 'server'
|
885
884
|
end
|
886
885
|
|
887
886
|
it 'should detect JetDirect as a printer' do
|
888
887
|
match = { 'os.product' => 'JetDirect', 'os.device' => 'Print server' }
|
889
888
|
result = host.send(:guess_purpose_from_match, match)
|
890
|
-
|
889
|
+
result.should == 'printer'
|
891
890
|
end
|
892
891
|
|
893
892
|
it 'should detect Unknown Printer as a printer' do
|
894
893
|
match = { 'os.product' => 'Unknown Printer' }
|
895
894
|
result = host.send(:guess_purpose_from_match, match)
|
896
|
-
|
895
|
+
result.should == 'printer'
|
897
896
|
end
|
898
897
|
|
899
898
|
it 'should detect Linksys Router as a router' do
|
900
899
|
match = { 'os.product' => 'Linksys', 'os.device' => 'Router' }
|
901
900
|
result = host.send(:guess_purpose_from_match, match)
|
902
|
-
|
901
|
+
result.should == 'router'
|
903
902
|
end
|
904
903
|
|
905
904
|
it 'should detect CheckPoint Firewall-1 as a firewall' do
|
906
905
|
match = { 'os.vendor' => 'Check Point', 'os.product' => 'Firewall-1' }
|
907
906
|
result = host.send(:guess_purpose_from_match, match)
|
908
|
-
|
907
|
+
result.should == 'firewall'
|
909
908
|
end
|
910
909
|
end
|
911
910
|
|
@@ -914,22 +913,22 @@ RSpec.describe Mdm::Host, type: :model do
|
|
914
913
|
it 'should return all the correct data for Windows XP SP3 x86' do
|
915
914
|
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host)
|
916
915
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
917
|
-
|
918
|
-
|
919
|
-
|
920
|
-
|
921
|
-
|
916
|
+
result['os.product'].should == 'Windows XP'
|
917
|
+
result['os.version'].should == 'SP3'
|
918
|
+
result['os.arch'].should == 'x86'
|
919
|
+
result['host.name'].should == nil
|
920
|
+
result['os.certainty'].to_f.should == 0.8
|
922
921
|
end
|
923
922
|
|
924
923
|
it 'should return all the correct data for Windows 2008 SP1 x64' do
|
925
924
|
fp_data = { :os => 'Microsoft Windows 2008 SP1', :arch => 'x64'}
|
926
925
|
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
927
926
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
928
|
-
|
929
|
-
|
930
|
-
|
931
|
-
|
932
|
-
|
927
|
+
result['os.product'].should == 'Windows Server 2008'
|
928
|
+
result['os.version'].should == 'SP1'
|
929
|
+
result['os.arch'].should == 'x64'
|
930
|
+
result['host.name'].should == nil
|
931
|
+
result['os.certainty'].to_f.should == 0.8
|
933
932
|
end
|
934
933
|
|
935
934
|
it 'should fingerprint Metasploitable correctly' do
|
@@ -937,21 +936,21 @@ RSpec.describe Mdm::Host, type: :model do
|
|
937
936
|
fp_data = { :os => 'Linux 2.6.24-16-server (i386)', :name => 'metasploitable'}
|
938
937
|
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
939
938
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
939
|
+
result['os.product'].should == 'Linux'
|
940
|
+
result['host.name'].should == 'metasploitable'
|
941
|
+
result['os.version'].should == '2.6.24-16-server'
|
942
|
+
result['os.arch'].should == 'x86'
|
943
|
+
result['os.certainty'].to_f.should == 0.8
|
945
944
|
end
|
946
945
|
|
947
946
|
it 'should just populate os_name if it is unsure' do
|
948
947
|
fp_data = { :os => 'Darwin 12.3.0 x86_64 i386'}
|
949
948
|
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
950
949
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
950
|
+
result['os.product'].should == 'Darwin 12.3.0 x86_64 i386'
|
951
|
+
result['os.version'].should == nil
|
952
|
+
result['os.arch'].should == nil
|
953
|
+
result['os.certainty'].should == 0.8
|
955
954
|
end
|
956
955
|
end
|
957
956
|
|
@@ -959,27 +958,27 @@ RSpec.describe Mdm::Host, type: :model do
|
|
959
958
|
it 'should return OS name for a Windows XP fingerprint' do
|
960
959
|
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host)
|
961
960
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
962
|
-
|
963
|
-
|
961
|
+
result['os.product'].should == 'Windows XP'
|
962
|
+
result['os.certainty'].to_f.should == described_class::MAX_NMAP_CERTAINTY
|
964
963
|
end
|
965
964
|
|
966
965
|
it 'should return OS name for a Metasploitable fingerprint' do
|
967
966
|
fp_data = {:os_vendor=>"Linux", :os_family=>"Linux", :os_version=>"2.6.X", :os_accuracy=>100}
|
968
967
|
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host, :data => fp_data)
|
969
968
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
970
|
-
|
971
|
-
|
972
|
-
|
969
|
+
result['os.product'].should == 'Linux'
|
970
|
+
result['os.version'].should == '2.6.X'
|
971
|
+
result['os.certainty'].to_f.should == described_class::MAX_NMAP_CERTAINTY
|
973
972
|
end
|
974
973
|
|
975
974
|
it 'should return OS name and flavor fo an OSX fingerprint' do
|
976
975
|
fp_data = {:os_vendor=>"Apple", :os_family=>"Mac OS X", :os_version=>"10.8.X", :os_accuracy=>100}
|
977
976
|
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host, :data => fp_data)
|
978
977
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
979
|
-
|
980
|
-
|
981
|
-
|
982
|
-
|
978
|
+
result['os.product'].should == 'Mac OS X'
|
979
|
+
result['os.vendor'].should == 'Apple'
|
980
|
+
result['os.version'].should == '10.8.X'
|
981
|
+
result['os.certainty'].to_f.should == described_class::MAX_NMAP_CERTAINTY
|
983
982
|
end
|
984
983
|
end
|
985
984
|
|
@@ -988,19 +987,19 @@ RSpec.describe Mdm::Host, type: :model do
|
|
988
987
|
it 'should return a generic Windows fingerprint with no product info' do
|
989
988
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host)
|
990
989
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
991
|
-
|
992
|
-
|
993
|
-
|
990
|
+
result['os.product'].should == 'Windows'
|
991
|
+
result['os.arch'].should == 'x86'
|
992
|
+
result['os.certainty'].to_f.should == 0.67
|
994
993
|
end
|
995
994
|
|
996
995
|
it 'should recognize a Windows 7 fingerprint' do
|
997
996
|
fp_data = {:family=>"Windows", :certainty=>"0.67", :vendor=>"Microsoft", :arch=>"x86", :product => 'Windows 7', :version => 'SP1'}
|
998
997
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
999
998
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1000
|
-
|
1001
|
-
|
1002
|
-
|
1003
|
-
|
999
|
+
result['os.product'].should == 'Windows 7'
|
1000
|
+
result['os.version'].should == 'SP1'
|
1001
|
+
result['os.arch'].should == 'x86'
|
1002
|
+
result['os.certainty'].to_f.should == 0.67
|
1004
1003
|
end
|
1005
1004
|
end
|
1006
1005
|
|
@@ -1008,30 +1007,30 @@ RSpec.describe Mdm::Host, type: :model do
|
|
1008
1007
|
fp_data = {:family=>"Mac OS X", :certainty=>"0.80", :vendor=>"Apple"}
|
1009
1008
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
1010
1009
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1011
|
-
|
1012
|
-
|
1010
|
+
result['os.product'].should == 'Mac OS X'
|
1011
|
+
result['os.vendor'].should == "Apple"
|
1013
1012
|
end
|
1014
1013
|
|
1015
1014
|
it 'should recognize a Cisco fingerprint' do
|
1016
1015
|
fp_data = {:family=>"IOS", :certainty=>"1.00", :vendor=>"Cisco", :version=>"11.2(8)SA2"}
|
1017
1016
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
1018
1017
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1019
|
-
|
1020
|
-
|
1018
|
+
result['os.product'].should == 'IOS'
|
1019
|
+
result['os.vendor'].should == 'Cisco'
|
1021
1020
|
end
|
1022
1021
|
|
1023
1022
|
it 'should recognize an embedded fingerprint' do
|
1024
1023
|
fp_data = {:family=>"embedded", :certainty=>"1.00", :vendor=>"Footek"}
|
1025
1024
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
1026
1025
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1027
|
-
|
1026
|
+
result['os.product'].should == 'Footek'
|
1028
1027
|
end
|
1029
1028
|
|
1030
1029
|
it 'should handle an unknown fingerprint' do
|
1031
1030
|
fp_data = {:certainty=>"1.00", :vendor=>"Footek"}
|
1032
1031
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
1033
1032
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1034
|
-
|
1033
|
+
result['os.product'].should == 'Footek'
|
1035
1034
|
end
|
1036
1035
|
|
1037
1036
|
|
@@ -1041,18 +1040,18 @@ RSpec.describe Mdm::Host, type: :model do
|
|
1041
1040
|
it 'should recognize a Windows fingerprint' do
|
1042
1041
|
fingerprint = FactoryGirl.build(:mdm_retina_fingerprint, :host => host)
|
1043
1042
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1044
|
-
|
1045
|
-
|
1046
|
-
|
1047
|
-
|
1043
|
+
result['os.product'].should == 'Windows Server 2003'
|
1044
|
+
result['os.arch'].should == 'x64'
|
1045
|
+
result['os.version'].should == 'SP2'
|
1046
|
+
result['os.certainty'].to_f.should == 0.8
|
1048
1047
|
end
|
1049
1048
|
|
1050
1049
|
it 'should otherwise jsut copy the fingerprint to os_name' do
|
1051
1050
|
fp_data = { :os => 'Linux 2.6.X (i386)'}
|
1052
1051
|
fingerprint = FactoryGirl.build(:mdm_retina_fingerprint, :host => host, :data => fp_data)
|
1053
1052
|
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1054
|
-
|
1055
|
-
|
1053
|
+
result['os.product'].should == 'Linux 2.6.X (i386)'
|
1054
|
+
result['os.certainty'].to_f.should == 0.8
|
1056
1055
|
end
|
1057
1056
|
end
|
1058
1057
|
end
|