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.
- data/Gemfile +2 -0
- data/app/models/mdm/client.rb +0 -1
- data/app/models/mdm/cred.rb +1 -1
- data/app/models/mdm/exploited_host.rb +0 -1
- data/app/models/mdm/listener.rb +2 -1
- data/app/models/mdm/nexpose_console.rb +2 -2
- data/app/models/mdm/session.rb +5 -1
- data/app/models/mdm/workspace.rb +0 -1
- data/db/migrate/20130525015035_remove_campaign_id_from_clients.rb +9 -0
- data/db/migrate/20130525212420_drop_table_imported_creds.rb +14 -0
- data/db/migrate/20130531144949_making_host_tags_a_real_ar_model.rb +6 -0
- data/lib/mdm/host/operating_system_normalization.rb +4 -4
- data/lib/metasploit_data_models/version.rb +1 -1
- data/spec/app/models/mdm/client_spec.rb +43 -0
- data/spec/app/models/mdm/cred_spec.rb +211 -0
- data/spec/app/models/mdm/events_spec.rb +85 -0
- data/spec/app/models/mdm/exploit_attempt_spec.rb +60 -0
- data/spec/app/models/mdm/exploited_host_spec.rb +44 -0
- data/spec/app/models/mdm/host_detail_spec.rb +49 -0
- data/spec/app/models/mdm/host_spec.rb +468 -0
- data/spec/app/models/mdm/host_tag_spec.rb +26 -0
- data/spec/app/models/mdm/listener_spec.rb +108 -0
- data/spec/app/models/mdm/loot_spec.rb +77 -0
- data/spec/app/models/mdm/nexpose_console_spec.rb +128 -0
- data/spec/app/models/mdm/note_spec.rb +84 -0
- data/spec/app/models/mdm/ref_spec.rb +13 -0
- data/spec/app/models/mdm/report_spec.rb +104 -0
- data/spec/app/models/mdm/report_template_spec.rb +52 -0
- data/spec/app/models/mdm/route_spec.rb +36 -0
- data/spec/app/models/mdm/service_spec.rb +70 -15
- data/spec/app/models/mdm/session_event_spec.rb +42 -0
- data/spec/app/models/mdm/session_spec.rb +114 -0
- data/spec/app/models/mdm/tag_spec.rb +104 -0
- data/spec/app/models/mdm/task_creds_spec.rb +32 -0
- data/spec/app/models/mdm/task_host_spec.rb +33 -0
- data/spec/app/models/mdm/task_service_spec.rb +33 -0
- data/spec/app/models/mdm/task_spec.rb +59 -5
- data/spec/app/models/mdm/user_spec.rb +51 -0
- data/spec/app/models/mdm/vuln_attempt_spec.rb +54 -0
- data/spec/app/models/mdm/vuln_details_spec.rb +66 -0
- data/spec/app/models/mdm/vuln_ref_spec.rb +24 -0
- data/spec/app/models/mdm/vuln_spec.rb +25 -0
- data/spec/app/models/mdm/web_form_spec.rb +47 -0
- data/spec/app/models/mdm/web_page_spec.rb +55 -0
- data/spec/app/models/mdm/web_site_spec.rb +86 -0
- data/spec/app/models/mdm/web_vuln_spec.rb +12 -0
- data/spec/app/models/mdm/workspace_spec.rb +567 -0
- data/spec/dummy/db/schema.rb +5 -13
- data/spec/factories/mdm/addresses.rb +5 -0
- data/spec/factories/mdm/clients.rb +8 -0
- data/spec/factories/mdm/events.rb +15 -0
- data/spec/factories/mdm/exploit_attempts.rb +8 -0
- data/spec/factories/mdm/exploited_hosts.rb +7 -0
- data/spec/factories/mdm/fingerprints/nessus_fingerprints.rb +6 -0
- data/spec/factories/mdm/fingerprints/nexpose_fingerprints.rb +6 -0
- data/spec/factories/mdm/fingerprints/nmap_fingerprints.rb +6 -0
- data/spec/factories/mdm/fingerprints/retina_fingerprints.rb +6 -0
- data/spec/factories/mdm/fingerprints/session_fingerprints.rb +6 -0
- data/spec/factories/mdm/host_details.rb +8 -0
- data/spec/factories/mdm/listeners.rb +12 -0
- data/spec/factories/mdm/loots.rb +11 -0
- data/spec/factories/mdm/nexpose_consoles.rb +15 -0
- data/spec/factories/mdm/notes.rb +12 -0
- data/spec/factories/mdm/report_templates.rb +8 -0
- data/spec/factories/mdm/reports.rb +13 -0
- data/spec/factories/mdm/routes.rb +36 -0
- data/spec/factories/mdm/session_events.rb +8 -0
- data/spec/factories/mdm/sessions.rb +13 -0
- data/spec/factories/mdm/vuln_attempts.rb +8 -0
- data/spec/factories/mdm/vuln_details.rb +8 -0
- data/spec/factories/mdm/web_forms.rb +33 -0
- data/spec/factories/mdm/web_pages.rb +64 -0
- metadata +95 -5
- data/app/models/mdm/imported_cred.rb +0 -10
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mdm::ExploitAttempt do
|
4
|
+
|
5
|
+
context 'associations' do
|
6
|
+
it { should belong_to(:host).class_name('Mdm::Host') }
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'database' do
|
10
|
+
|
11
|
+
context 'timestamps'do
|
12
|
+
it { should have_db_column(:attempted_at).of_type(:datetime) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'columns' do
|
16
|
+
it { should have_db_column(:host_id).of_type(:integer) }
|
17
|
+
it { should have_db_column(:service_id).of_type(:integer) }
|
18
|
+
it { should have_db_column(:vuln_id).of_type(:integer) }
|
19
|
+
it { should have_db_column(:exploited).of_type(:boolean) }
|
20
|
+
it { should have_db_column(:fail_reason).of_type(:string) }
|
21
|
+
it { should have_db_column(:username).of_type(:string) }
|
22
|
+
it { should have_db_column(:module).of_type(:text) }
|
23
|
+
it { should have_db_column(:session_id).of_type(:integer) }
|
24
|
+
it { should have_db_column(:loot_id).of_type(:integer) }
|
25
|
+
it { should have_db_column(:port).of_type(:integer) }
|
26
|
+
it { should have_db_column(:proto).of_type(:string) }
|
27
|
+
it { should have_db_column(:fail_detail).of_type(:text) }
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
context '#destroy' do
|
32
|
+
it 'should successfully destroy the object and all dependent objects' do
|
33
|
+
exploit_attempt = FactoryGirl.create(:mdm_exploit_attempt)
|
34
|
+
expect {
|
35
|
+
exploit_attempt.destroy
|
36
|
+
}.to_not raise_error
|
37
|
+
expect {
|
38
|
+
exploit_attempt.reload
|
39
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
40
|
+
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context 'validations' do
|
45
|
+
it 'should only be valid with a host_id' do
|
46
|
+
orphaned_attempt = FactoryGirl.build(:mdm_exploit_attempt, :host => nil)
|
47
|
+
orphaned_attempt.should_not be_valid
|
48
|
+
orphaned_attempt.errors[:host_id].should include("can't be blank")
|
49
|
+
propper_attempt = FactoryGirl.build(:mdm_exploit_attempt)
|
50
|
+
propper_attempt.should be_valid
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
context 'factory' do
|
55
|
+
it 'should be valid' do
|
56
|
+
exploit_attempt = FactoryGirl.build(:mdm_exploit_attempt)
|
57
|
+
exploit_attempt.should be_valid
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mdm::ExploitedHost do
|
4
|
+
context 'associations' do
|
5
|
+
it { should belong_to(:host).class_name('Mdm::Host') }
|
6
|
+
it { should belong_to(:service).class_name('Mdm::Service') }
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'database' do
|
10
|
+
|
11
|
+
context 'timestamps'do
|
12
|
+
it { should have_db_column(:created_at).of_type(:datetime).with_options(:null => false) }
|
13
|
+
it { should have_db_column(:updated_at).of_type(:datetime).with_options(:null => false) }
|
14
|
+
end
|
15
|
+
|
16
|
+
context 'columns' do
|
17
|
+
it { should have_db_column(:host_id).of_type(:integer).with_options(:null => false) }
|
18
|
+
it { should have_db_column(:service_id).of_type(:integer) }
|
19
|
+
it { should have_db_column(:name).of_type(:string) }
|
20
|
+
it { should have_db_column(:session_uuid).of_type(:string) }
|
21
|
+
it { should have_db_column(:payload).of_type(:string) }
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context '#destroy' do
|
26
|
+
it 'should successfully destroy the object and all dependent objects' do
|
27
|
+
exploited_host = FactoryGirl.create(:mdm_exploited_host)
|
28
|
+
expect {
|
29
|
+
exploited_host.destroy
|
30
|
+
}.to_not raise_error
|
31
|
+
expect {
|
32
|
+
exploited_host.reload
|
33
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context 'factory' do
|
38
|
+
it 'should be valid' do
|
39
|
+
exploited_host = FactoryGirl.build(:mdm_exploited_host)
|
40
|
+
exploited_host.should be_valid
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Mdm::HostDetail do
|
4
|
+
|
5
|
+
context 'associations' do
|
6
|
+
it { should belong_to(:host).class_name('Mdm::Host') }
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'database' do
|
10
|
+
it { should have_db_column(:host_id).of_type(:integer) }
|
11
|
+
it { should have_db_column(:nx_console_id).of_type(:integer) }
|
12
|
+
it { should have_db_column(:nx_device_id).of_type(:integer) }
|
13
|
+
it { should have_db_column(:src).of_type(:string) }
|
14
|
+
it { should have_db_column(:nx_site_name).of_type(:string) }
|
15
|
+
it { should have_db_column(:nx_site_importance).of_type(:string) }
|
16
|
+
it { should have_db_column(:src).of_type(:string) }
|
17
|
+
it { should have_db_column(:nx_site_name).of_type(:string) }
|
18
|
+
it { should have_db_column(:nx_scan_template).of_type(:string) }
|
19
|
+
it { should have_db_column(:nx_risk_score).of_type(:float) }
|
20
|
+
end
|
21
|
+
|
22
|
+
context 'validations' do
|
23
|
+
it 'should only be valid with a host_id' do
|
24
|
+
orphan_detail = FactoryGirl.build(:mdm_host_detail, :host => nil)
|
25
|
+
orphan_detail.should_not be_valid
|
26
|
+
orphan_detail.errors[:host_id].should include("can't be blank")
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
context 'factory' do
|
31
|
+
it 'should be valid' do
|
32
|
+
host_detail = FactoryGirl.build(:mdm_host_detail)
|
33
|
+
host_detail.should be_valid
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
context '#destroy' do
|
38
|
+
it 'should successfully destroy the object' do
|
39
|
+
detail = FactoryGirl.create(:mdm_host_detail)
|
40
|
+
expect{
|
41
|
+
detail.destroy
|
42
|
+
}.to_not raise_error
|
43
|
+
expect {
|
44
|
+
detail.reload
|
45
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
@@ -37,6 +37,63 @@ describe Mdm::Host do
|
|
37
37
|
]
|
38
38
|
end
|
39
39
|
|
40
|
+
context 'factory' do
|
41
|
+
it 'should be valid' do
|
42
|
+
host = FactoryGirl.build(:mdm_host)
|
43
|
+
host.should be_valid
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context '#destroy' do
|
48
|
+
it 'should successfully destroy the object and the dependent objects' do
|
49
|
+
host = FactoryGirl.create(:mdm_host)
|
50
|
+
exploit_attempt = FactoryGirl.create(:mdm_exploit_attempt, :host => host)
|
51
|
+
exploited_host = FactoryGirl.create(:mdm_exploited_host, :host => host)
|
52
|
+
host_detail = FactoryGirl.create(:mdm_host_detail, :host => host)
|
53
|
+
loot = FactoryGirl.create(:mdm_loot, :host => host)
|
54
|
+
task_host = FactoryGirl.create(:mdm_task_host, :host => host)
|
55
|
+
note = FactoryGirl.create(:mdm_note, :host => host)
|
56
|
+
svc = FactoryGirl.create(:mdm_service, :host => host)
|
57
|
+
session = FactoryGirl.create(:mdm_session, :host => host)
|
58
|
+
vuln = FactoryGirl.create(:mdm_vuln, :host => host)
|
59
|
+
|
60
|
+
|
61
|
+
expect {
|
62
|
+
host.destroy
|
63
|
+
}.to_not raise_error
|
64
|
+
expect {
|
65
|
+
host.reload
|
66
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
67
|
+
expect {
|
68
|
+
exploit_attempt.reload
|
69
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
70
|
+
expect {
|
71
|
+
exploited_host.reload
|
72
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
73
|
+
expect {
|
74
|
+
host_detail.reload
|
75
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
76
|
+
expect {
|
77
|
+
loot.reload
|
78
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
79
|
+
expect {
|
80
|
+
task_host.reload
|
81
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
82
|
+
expect {
|
83
|
+
note.reload
|
84
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
85
|
+
expect {
|
86
|
+
svc.reload
|
87
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
88
|
+
expect {
|
89
|
+
session.reload
|
90
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
91
|
+
expect {
|
92
|
+
vuln.reload
|
93
|
+
}.to raise_error(ActiveRecord::RecordNotFound)
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
40
97
|
context 'associations' do
|
41
98
|
it { should have_many(:creds).class_name('Mdm::Cred').through(:services) }
|
42
99
|
it { should have_many(:exploit_attempts).class_name('Mdm::ExploitAttempt').dependent(:destroy) }
|
@@ -415,4 +472,415 @@ describe Mdm::Host do
|
|
415
472
|
end
|
416
473
|
end
|
417
474
|
end
|
475
|
+
|
476
|
+
context 'os normalization' do
|
477
|
+
context '#get_arch_from_string' do
|
478
|
+
context "should return 'x64'" do
|
479
|
+
it "when the string contains 'x64'" do
|
480
|
+
host.send(:get_arch_from_string, 'blahx64blah').should == 'x64'
|
481
|
+
end
|
482
|
+
|
483
|
+
it "when the string contains 'X64'" do
|
484
|
+
host.send(:get_arch_from_string, 'blahX64blah').should == 'x64'
|
485
|
+
end
|
486
|
+
|
487
|
+
it "when the string contains 'x86_64'" do
|
488
|
+
host.send(:get_arch_from_string, 'blahx86_64blah').should == 'x64'
|
489
|
+
end
|
490
|
+
|
491
|
+
it "when the string contains 'X86_64'" do
|
492
|
+
host.send(:get_arch_from_string, 'blahX86_64blah').should == 'x64'
|
493
|
+
end
|
494
|
+
|
495
|
+
it "when the string contains 'amd64'" do
|
496
|
+
host.send(:get_arch_from_string, 'blahamd64blah').should == 'x64'
|
497
|
+
end
|
498
|
+
|
499
|
+
it "when the string contains 'AMD64'" do
|
500
|
+
host.send(:get_arch_from_string, 'blahAMD64blah').should == 'x64'
|
501
|
+
end
|
502
|
+
|
503
|
+
it "when the string contains 'aMd64'" do
|
504
|
+
host.send(:get_arch_from_string, 'blahamd64blah').should == 'x64'
|
505
|
+
end
|
506
|
+
end
|
507
|
+
|
508
|
+
context "should return 'x86'" do
|
509
|
+
it "when the string contains 'x86'" do
|
510
|
+
host.send(:get_arch_from_string, 'blahx86blah').should == 'x86'
|
511
|
+
end
|
512
|
+
|
513
|
+
it "when the string contains 'X86'" do
|
514
|
+
host.send(:get_arch_from_string, 'blahX86blah').should == 'x86'
|
515
|
+
end
|
516
|
+
|
517
|
+
it "when the string contains 'i386'" do
|
518
|
+
host.send(:get_arch_from_string, 'blahi386blah').should == 'x86'
|
519
|
+
end
|
520
|
+
|
521
|
+
it "when the string contains 'I386'" do
|
522
|
+
host.send(:get_arch_from_string, 'blahI386blah').should == 'x86'
|
523
|
+
end
|
524
|
+
|
525
|
+
it "when the string contains 'i486'" do
|
526
|
+
host.send(:get_arch_from_string, 'blahi486blah').should == 'x86'
|
527
|
+
end
|
528
|
+
|
529
|
+
it "when the string contains 'i586'" do
|
530
|
+
host.send(:get_arch_from_string, 'blahi586blah').should == 'x86'
|
531
|
+
end
|
532
|
+
|
533
|
+
it "when the string contains 'i686'" do
|
534
|
+
host.send(:get_arch_from_string, 'blahi386blah').should == 'x86'
|
535
|
+
end
|
536
|
+
end
|
537
|
+
|
538
|
+
context "should return 'ppc'" do
|
539
|
+
it "when the string contains 'PowerPC'" do
|
540
|
+
host.send(:get_arch_from_string, 'blahPowerPCblah').should == 'ppc'
|
541
|
+
end
|
542
|
+
|
543
|
+
it "when the string contains 'PPC'" do
|
544
|
+
host.send(:get_arch_from_string, 'blahPPCblah').should == 'ppc'
|
545
|
+
end
|
546
|
+
|
547
|
+
it "when the string contains 'POWER'" do
|
548
|
+
host.send(:get_arch_from_string, 'blahPOWERblah').should == 'ppc'
|
549
|
+
end
|
550
|
+
|
551
|
+
it "when the string contains 'ppc'" do
|
552
|
+
host.send(:get_arch_from_string, 'blahppcblah').should == 'ppc'
|
553
|
+
end
|
554
|
+
end
|
555
|
+
|
556
|
+
context 'should return nil' do
|
557
|
+
it 'when PowerPC is cased incorrectly' do
|
558
|
+
host.send(:get_arch_from_string, 'powerPC').should == nil
|
559
|
+
host.send(:get_arch_from_string, 'Powerpc').should == nil
|
560
|
+
end
|
561
|
+
|
562
|
+
it 'when no recognized arch string is present' do
|
563
|
+
host.send(:get_arch_from_string, 'blahblah').should == nil
|
564
|
+
end
|
565
|
+
end
|
566
|
+
|
567
|
+
it "should return 'sparc' if the string contains SPARC, regardless of case" do
|
568
|
+
host.send(:get_arch_from_string, 'blahSPARCblah').should == 'sparc'
|
569
|
+
host.send(:get_arch_from_string, 'blahSPaRCblah').should == 'sparc'
|
570
|
+
host.send(:get_arch_from_string, 'blahsparcblah').should == 'sparc'
|
571
|
+
end
|
572
|
+
|
573
|
+
it "should return 'arm' if the string contains 'ARM', regardless of case" do
|
574
|
+
host.send(:get_arch_from_string, 'blahARMblah').should == 'arm'
|
575
|
+
host.send(:get_arch_from_string, 'blahArMblah').should == 'arm'
|
576
|
+
host.send(:get_arch_from_string, 'blaharmblah').should == 'arm'
|
577
|
+
end
|
578
|
+
|
579
|
+
it "should return 'mips' if the string contains 'MIPS', regardless of case" do
|
580
|
+
host.send(:get_arch_from_string, 'blahMIPSblah').should == 'mips'
|
581
|
+
host.send(:get_arch_from_string, 'blahMiPslah').should == 'mips'
|
582
|
+
host.send(:get_arch_from_string, 'blahmipsblah').should == 'mips'
|
583
|
+
end
|
584
|
+
end
|
585
|
+
|
586
|
+
context '#parse_windows_os_str' do
|
587
|
+
it 'should always return the os_name as Microsoft Windows' do
|
588
|
+
result = host.send(:parse_windows_os_str, '')
|
589
|
+
result[:os_name].should == 'Microsoft Windows'
|
590
|
+
end
|
591
|
+
|
592
|
+
context 'arch' do
|
593
|
+
it 'should return a value for arch if there is one' do
|
594
|
+
result = host.send(:parse_windows_os_str, 'Windows x64')
|
595
|
+
result[:arch].should == 'x64'
|
596
|
+
end
|
597
|
+
|
598
|
+
it "should not have an arch key if we don't know the arch" do
|
599
|
+
result = host.send(:parse_windows_os_str, 'Windows')
|
600
|
+
result.has_key?(:arch).should == false
|
601
|
+
end
|
602
|
+
end
|
603
|
+
|
604
|
+
context 'Service Pack' do
|
605
|
+
it 'should be returned if we see Service Pack X' do
|
606
|
+
result = host.send(:parse_windows_os_str, 'Windows XP Service Pack 1')
|
607
|
+
result[:os_sp].should == 'SP1'
|
608
|
+
end
|
609
|
+
|
610
|
+
it 'should be returned if we see SPX' do
|
611
|
+
result = host.send(:parse_windows_os_str, 'Windows XP SP3')
|
612
|
+
result[:os_sp].should == 'SP3'
|
613
|
+
end
|
614
|
+
end
|
615
|
+
|
616
|
+
context 'os flavor' do
|
617
|
+
it "should appear as 2003 for '.NET Server'" do
|
618
|
+
result = host.send(:parse_windows_os_str, 'Windows .NET Server')
|
619
|
+
result[:os_flavor].should == '2003'
|
620
|
+
end
|
621
|
+
|
622
|
+
it 'should be recognized for XP' do
|
623
|
+
result = host.send(:parse_windows_os_str, 'Windows XP')
|
624
|
+
result[:os_flavor].should == 'XP'
|
625
|
+
end
|
626
|
+
|
627
|
+
it 'should be recognized for 2000' do
|
628
|
+
result = host.send(:parse_windows_os_str, 'Windows 2000')
|
629
|
+
result[:os_flavor].should == '2000'
|
630
|
+
end
|
631
|
+
|
632
|
+
it 'should be recognized for 2003' do
|
633
|
+
result = host.send(:parse_windows_os_str, 'Windows 2003')
|
634
|
+
result[:os_flavor].should == '2003'
|
635
|
+
end
|
636
|
+
|
637
|
+
it 'should be recognized for 2008' do
|
638
|
+
result = host.send(:parse_windows_os_str, 'Windows 2008')
|
639
|
+
result[:os_flavor].should == '2008'
|
640
|
+
end
|
641
|
+
|
642
|
+
it 'should be recognized for Vista' do
|
643
|
+
result = host.send(:parse_windows_os_str, 'Windows Vista')
|
644
|
+
result[:os_flavor].should == 'Vista'
|
645
|
+
end
|
646
|
+
|
647
|
+
it 'should be recognized for SBS' do
|
648
|
+
result = host.send(:parse_windows_os_str, 'Windows SBS')
|
649
|
+
result[:os_flavor].should == 'SBS'
|
650
|
+
end
|
651
|
+
|
652
|
+
it 'should be recognized for 2000 Advanced Server' do
|
653
|
+
result = host.send(:parse_windows_os_str, 'Windows 2000 Advanced Server')
|
654
|
+
result[:os_flavor].should == '2000 Advanced Server'
|
655
|
+
end
|
656
|
+
|
657
|
+
it 'should be recognized for 7' do
|
658
|
+
result = host.send(:parse_windows_os_str, 'Windows 7')
|
659
|
+
result[:os_flavor].should == '7'
|
660
|
+
end
|
661
|
+
|
662
|
+
it 'should be recognized for 7 X Edition' do
|
663
|
+
result = host.send(:parse_windows_os_str, 'Windows 7 Ultimate Edition')
|
664
|
+
result[:os_flavor].should == '7 Ultimate Edition'
|
665
|
+
end
|
666
|
+
|
667
|
+
it 'should be recognized for 8' do
|
668
|
+
result = host.send(:parse_windows_os_str, 'Windows 8')
|
669
|
+
result[:os_flavor].should == '8'
|
670
|
+
end
|
671
|
+
|
672
|
+
it 'should be guessed at if all else fails' do
|
673
|
+
result = host.send(:parse_windows_os_str, 'Windows Foobar Service Pack 3')
|
674
|
+
result[:os_flavor].should == 'Foobar'
|
675
|
+
end
|
676
|
+
end
|
677
|
+
|
678
|
+
context 'os type' do
|
679
|
+
it 'should be server for Windows NT' do
|
680
|
+
result = host.send(:parse_windows_os_str, 'Windows NT 4')
|
681
|
+
result[:type].should == 'server'
|
682
|
+
end
|
683
|
+
|
684
|
+
it 'should be server for Windows 2003' do
|
685
|
+
result = host.send(:parse_windows_os_str, 'Windows 2003')
|
686
|
+
result[:type].should == 'server'
|
687
|
+
end
|
688
|
+
|
689
|
+
it 'should be server for Windows 2008' do
|
690
|
+
result = host.send(:parse_windows_os_str, 'Windows 2008')
|
691
|
+
result[:type].should == 'server'
|
692
|
+
end
|
693
|
+
|
694
|
+
it 'should be server for Windows SBS' do
|
695
|
+
result = host.send(:parse_windows_os_str, 'Windows SBS')
|
696
|
+
result[:type].should == 'server'
|
697
|
+
end
|
698
|
+
|
699
|
+
it 'should be server for anything with Server in the string' do
|
700
|
+
result = host.send(:parse_windows_os_str, 'Windows Foobar Server')
|
701
|
+
result[:type].should == 'server'
|
702
|
+
end
|
703
|
+
|
704
|
+
it 'should be client for anything else' do
|
705
|
+
result = host.send(:parse_windows_os_str, 'Windows XP')
|
706
|
+
result[:type].should == 'client'
|
707
|
+
end
|
708
|
+
end
|
709
|
+
end
|
710
|
+
|
711
|
+
context '#validate_fingerprint_data' do
|
712
|
+
before(:each) do
|
713
|
+
host.stub(:dlog)
|
714
|
+
end
|
715
|
+
|
716
|
+
it 'should return false for an empty hash' do
|
717
|
+
fingerprint= FactoryGirl.build(:mdm_note, :data => {})
|
718
|
+
host.validate_fingerprint_data(fingerprint).should == false
|
719
|
+
end
|
720
|
+
|
721
|
+
it 'should return false for postgressql fingerprints' do
|
722
|
+
fingerprint= FactoryGirl.build(:mdm_note, :ntype => 'postgresql.fingerprint', :data => {})
|
723
|
+
host.validate_fingerprint_data(fingerprint).should == false
|
724
|
+
end
|
725
|
+
|
726
|
+
it 'should return false if the fingerprint does not contain a hash' do
|
727
|
+
fingerprint= FactoryGirl.build(:mdm_note, :data => 'this is not a fingerprint')
|
728
|
+
host.validate_fingerprint_data(fingerprint).should == false
|
729
|
+
end
|
730
|
+
end
|
731
|
+
|
732
|
+
context '#normalize_scanner_fp' do
|
733
|
+
context 'for session_fingerprint' do
|
734
|
+
it 'should return all the correct data for Windows XP SP3 x86' do
|
735
|
+
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host)
|
736
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
737
|
+
result[:os_name].should == 'Microsoft Windows'
|
738
|
+
result[:os_flavor].should == 'XP'
|
739
|
+
result[:os_sp].should == 'SP3'
|
740
|
+
result[:arch].should == 'x86'
|
741
|
+
result[:type].should == 'client'
|
742
|
+
result[:name].should == nil
|
743
|
+
result[:certainty].should == 0.8
|
744
|
+
end
|
745
|
+
|
746
|
+
it 'should return all the correct data for Windows 2008 SP1 x64' do
|
747
|
+
fp_data = { :os => 'Microsoft Windows 2008 SP1', :arch => 'x64'}
|
748
|
+
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
749
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
750
|
+
result[:os_name].should == 'Microsoft Windows'
|
751
|
+
result[:os_flavor].should == '2008'
|
752
|
+
result[:os_sp].should == 'SP1'
|
753
|
+
result[:arch].should == 'x64'
|
754
|
+
result[:type].should == 'server'
|
755
|
+
result[:name].should == nil
|
756
|
+
result[:certainty].should == 0.8
|
757
|
+
end
|
758
|
+
|
759
|
+
it 'should fingerprint Metasploitable correctly' do
|
760
|
+
# Taken from an actual session_fingerprint of Metasploitable 2
|
761
|
+
fp_data = { :os => 'Linux 2.6.24-16-server (i386)', :name => 'metasploitable'}
|
762
|
+
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
763
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
764
|
+
result[:os_name].should == 'Linux'
|
765
|
+
result[:name].should == 'metasploitable'
|
766
|
+
result[:os_sp].should == '2.6.24-16-server'
|
767
|
+
result[:arch].should == 'x86'
|
768
|
+
result[:certainty].should == 0.8
|
769
|
+
end
|
770
|
+
|
771
|
+
it 'should just populate os_name if it is unsure' do
|
772
|
+
fp_data = { :os => 'Darwin 12.3.0 x86_64 i386'}
|
773
|
+
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
774
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
775
|
+
result[:os_name].should == 'Darwin 12.3.0 x86_64 i386'
|
776
|
+
result[:os_sp].should == nil
|
777
|
+
result[:arch].should == nil
|
778
|
+
result[:certainty].should == 0.8
|
779
|
+
end
|
780
|
+
end
|
781
|
+
|
782
|
+
context 'for nmap_fingerprint' do
|
783
|
+
it 'should return OS name and flavor for a Windows XP fingerprint' do
|
784
|
+
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host)
|
785
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
786
|
+
result[:os_name].should == 'Microsoft Windows'
|
787
|
+
result[:os_flavor].should == 'XP'
|
788
|
+
result[:certainty].should == 1
|
789
|
+
end
|
790
|
+
|
791
|
+
it 'should return OS name and flavor for a Metasploitable fingerprint' do
|
792
|
+
fp_data = {:os_vendor=>"Linux", :os_family=>"Linux", :os_version=>"2.6.X", :os_accuracy=>100}
|
793
|
+
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host, :data => fp_data)
|
794
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
795
|
+
result[:os_name].should == 'Linux'
|
796
|
+
result[:os_flavor].should == '2.6.X'
|
797
|
+
result[:certainty].should == 1
|
798
|
+
end
|
799
|
+
|
800
|
+
it 'should return OS name and flavor fo an OSX fingerprint' do
|
801
|
+
fp_data = {:os_vendor=>"Apple", :os_family=>"Mac OS X", :os_version=>"10.8.X", :os_accuracy=>100}
|
802
|
+
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host, :data => fp_data)
|
803
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
804
|
+
result[:os_name].should == 'Apple Mac OS X'
|
805
|
+
result[:os_flavor].should == '10.8.X'
|
806
|
+
result[:certainty].should == 1
|
807
|
+
end
|
808
|
+
end
|
809
|
+
|
810
|
+
context 'for nexpose_fingerprint' do
|
811
|
+
context 'of a Windows system' do
|
812
|
+
it 'should return a generic Windows fingerprint with no product info' do
|
813
|
+
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host)
|
814
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
815
|
+
result[:os_name].should == 'Microsoft Windows'
|
816
|
+
result[:arch].should == 'x86'
|
817
|
+
result[:certainty].should == 0.67
|
818
|
+
end
|
819
|
+
|
820
|
+
it 'should recognize a Windows 7 fingerprint' do
|
821
|
+
fp_data = {:family=>"Windows", :certainty=>"0.67", :vendor=>"Microsoft", :arch=>"x86", :product => 'Windows 7', :version => 'SP1'}
|
822
|
+
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
823
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
824
|
+
result[:os_name].should == 'Microsoft Windows'
|
825
|
+
result[:os_flavor].should == '7'
|
826
|
+
result[:os_sp].should == 'SP1'
|
827
|
+
result[:arch].should == 'x86'
|
828
|
+
result[:certainty].should == 0.67
|
829
|
+
end
|
830
|
+
end
|
831
|
+
|
832
|
+
it 'should recognize an OSX fingerprint' do
|
833
|
+
fp_data = {:family=>"Mac OS X", :certainty=>"0.80", :vendor=>"Apple"}
|
834
|
+
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
835
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
836
|
+
result[:os_name].should == 'Apple Mac OS X'
|
837
|
+
end
|
838
|
+
|
839
|
+
it 'should recognize a Cisco fingerprint' do
|
840
|
+
fp_data = {:family=>"IOS", :certainty=>"1.00", :vendor=>"Cisco", :version=>"11.2(8)SA2"}
|
841
|
+
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
842
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
843
|
+
result[:os_name].should == 'Cisco IOS'
|
844
|
+
end
|
845
|
+
|
846
|
+
it 'should recognize an embeeded fingerprint' do
|
847
|
+
fp_data = {:family=>"embedded", :certainty=>"1.00", :vendor=>"Footek"}
|
848
|
+
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
849
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
850
|
+
result[:os_name].should == 'Footek'
|
851
|
+
end
|
852
|
+
|
853
|
+
it 'should handle an unknown fingerprint' do
|
854
|
+
fp_data = {:certainty=>"1.00", :vendor=>"Footek"}
|
855
|
+
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
856
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
857
|
+
result[:os_name].should == 'Footek'
|
858
|
+
end
|
859
|
+
|
860
|
+
|
861
|
+
end
|
862
|
+
|
863
|
+
context 'for retina_fingerprint' do
|
864
|
+
it 'should recognize a Windows fingerprint' do
|
865
|
+
fingerprint = FactoryGirl.build(:mdm_retina_fingerprint, :host => host)
|
866
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
867
|
+
result[:os_name].should == 'Microsoft Windows'
|
868
|
+
result[:os_flavor].should == '2003'
|
869
|
+
result[:arch].should == 'x64'
|
870
|
+
result[:os_sp].should == 'SP2'
|
871
|
+
result[:type].should == 'server'
|
872
|
+
result[:certainty].should == 0.8
|
873
|
+
end
|
874
|
+
|
875
|
+
it 'should otherwise jsut copy the fingerprint to os_name' do
|
876
|
+
fp_data = { :os => 'Linux 2.6.X (i386)'}
|
877
|
+
fingerprint = FactoryGirl.build(:mdm_retina_fingerprint, :host => host, :data => fp_data)
|
878
|
+
result = host.send(:normalize_scanner_fp, fingerprint)
|
879
|
+
result[:os_name].should == 'Linux 2.6.X (i386)'
|
880
|
+
result[:certainty].should == 0.8
|
881
|
+
end
|
882
|
+
end
|
883
|
+
end
|
884
|
+
|
885
|
+
end
|
418
886
|
end
|