metasploit_data_models 0.21.0 → 0.21.1
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.
- checksums.yaml +8 -8
- data/Gemfile +3 -3
- data/app/models/mdm/host.rb +2 -2
- data/lib/mdm/host/operating_system_normalization.rb +803 -888
- data/lib/metasploit_data_models/version.rb +1 -1
- data/metasploit_data_models.gemspec +3 -0
- data/spec/app/models/mdm/host_spec.rb +337 -127
- data/spec/dummy/db/structure.sql +679 -0
- metadata +17 -172
@@ -6,7 +6,7 @@ module MetasploitDataModels
|
|
6
6
|
# The minor version number, scoped to the {MAJOR} version number.
|
7
7
|
MINOR = 21
|
8
8
|
# The patch number, scoped to the {MINOR} version number.
|
9
|
-
PATCH =
|
9
|
+
PATCH = 1
|
10
10
|
|
11
11
|
# The full version string, including the {MAJOR}, {MINOR}, {PATCH}, and optionally, the `PRERELEASE` in the
|
12
12
|
# {http://semver.org/spec/v2.0.0.html semantic versioning v2.0.0} format.
|
@@ -39,6 +39,9 @@ Gem::Specification.new do |s|
|
|
39
39
|
# @see MSP-2971
|
40
40
|
s.add_runtime_dependency 'activerecord', '>= 3.2.13', '< 4.0.0'
|
41
41
|
s.add_runtime_dependency 'activesupport'
|
42
|
+
# os fingerprinting
|
43
|
+
s.add_runtime_dependency 'recog', '~> 1.0'
|
44
|
+
|
42
45
|
s.add_runtime_dependency 'metasploit-concern', '~> 0.3.0'
|
43
46
|
s.add_runtime_dependency 'metasploit-model', '~> 0.28.0'
|
44
47
|
s.add_runtime_dependency 'railties', '< 4.0.0'
|
@@ -47,6 +47,11 @@ describe Mdm::Host do
|
|
47
47
|
end
|
48
48
|
end
|
49
49
|
|
50
|
+
context 'Constants' do
|
51
|
+
subject(:max_nmap_certainty) { described_class::MAX_NMAP_CERTAINTY }
|
52
|
+
it { should eq(0.84) }
|
53
|
+
end
|
54
|
+
|
50
55
|
context '#destroy' do
|
51
56
|
it 'should successfully destroy the object and the dependent objects' do
|
52
57
|
host = FactoryGirl.create(:mdm_host)
|
@@ -547,126 +552,152 @@ describe Mdm::Host do
|
|
547
552
|
end
|
548
553
|
|
549
554
|
context '#parse_windows_os_str' do
|
550
|
-
it 'should always return the os_name as
|
555
|
+
it 'should always return the os_name as Windows' do
|
551
556
|
result = host.send(:parse_windows_os_str, '')
|
552
|
-
result[
|
557
|
+
result['os.product'].should == 'Windows'
|
553
558
|
end
|
554
559
|
|
555
560
|
context 'arch' do
|
556
561
|
it 'should return a value for arch if there is one' do
|
557
562
|
result = host.send(:parse_windows_os_str, 'Windows x64')
|
558
|
-
result[
|
563
|
+
result['os.arch'].should == 'x64'
|
559
564
|
end
|
560
565
|
|
561
566
|
it "should not have an arch key if we don't know the arch" do
|
562
567
|
result = host.send(:parse_windows_os_str, 'Windows')
|
563
|
-
result.has_key?(
|
568
|
+
result.has_key?('os.arch').should == false
|
564
569
|
end
|
565
570
|
end
|
566
571
|
|
567
572
|
context 'Service Pack' do
|
568
573
|
it 'should be returned if we see Service Pack X' do
|
569
574
|
result = host.send(:parse_windows_os_str, 'Windows XP Service Pack 1')
|
570
|
-
result[
|
575
|
+
result['os.version'].should == 'SP1'
|
571
576
|
end
|
572
577
|
|
573
578
|
it 'should be returned if we see SPX' do
|
574
579
|
result = host.send(:parse_windows_os_str, 'Windows XP SP3')
|
575
|
-
result[
|
580
|
+
result['os.version'].should == 'SP3'
|
576
581
|
end
|
577
582
|
end
|
578
583
|
|
579
|
-
context 'os
|
580
|
-
|
584
|
+
context 'os product' do
|
585
|
+
|
586
|
+
it "should appear as Windows 95 for 'Windows 95" do
|
587
|
+
result = host.send(:parse_windows_os_str, 'Windows 95')
|
588
|
+
result['os.product'].should == 'Windows 95'
|
589
|
+
end
|
590
|
+
|
591
|
+
it "should appear as Windows NT 3.51 for 'Windows NT 3.51" do
|
592
|
+
result = host.send(:parse_windows_os_str, 'Windows NT 3.51')
|
593
|
+
result['os.product'].should == 'Windows NT 3.51'
|
594
|
+
end
|
595
|
+
|
596
|
+
it "should appear as Windows NT 4.0 for 'Windows NT 4.0" do
|
597
|
+
result = host.send(:parse_windows_os_str, 'Windows NT 4.0')
|
598
|
+
result['os.product'].should == 'Windows NT 4.0'
|
599
|
+
end
|
600
|
+
|
601
|
+
it "should appear as Windows 98 for 'Windows 98" do
|
602
|
+
result = host.send(:parse_windows_os_str, 'Windows 98')
|
603
|
+
result['os.product'].should == 'Windows 98'
|
604
|
+
end
|
605
|
+
|
606
|
+
it "should appear as Windows ME for 'Windows ME" do
|
607
|
+
result = host.send(:parse_windows_os_str, 'Windows ME')
|
608
|
+
result['os.product'].should == 'Windows ME'
|
609
|
+
end
|
610
|
+
|
611
|
+
it "should appear as Windows 2003 for '.NET Server'" do
|
581
612
|
result = host.send(:parse_windows_os_str, 'Windows .NET Server')
|
582
|
-
result[
|
613
|
+
result['os.product'].should == 'Windows Server 2003'
|
583
614
|
end
|
584
615
|
|
585
|
-
it 'should be recognized for XP' do
|
616
|
+
it 'should be recognized for Windows XP' do
|
586
617
|
result = host.send(:parse_windows_os_str, 'Windows XP')
|
587
|
-
result[
|
618
|
+
result['os.product'].should == 'Windows XP'
|
588
619
|
end
|
589
620
|
|
590
|
-
it 'should be recognized for 2000' do
|
621
|
+
it 'should be recognized for Windows Server 2000' do
|
591
622
|
result = host.send(:parse_windows_os_str, 'Windows 2000')
|
592
|
-
result[
|
623
|
+
result['os.product'].should == 'Windows Server 2000'
|
593
624
|
end
|
594
625
|
|
595
|
-
it 'should be recognized for 2003' do
|
626
|
+
it 'should be recognized for Windows Server 2003' do
|
596
627
|
result = host.send(:parse_windows_os_str, 'Windows 2003')
|
597
|
-
result[
|
628
|
+
result['os.product'].should == 'Windows Server 2003'
|
598
629
|
end
|
599
630
|
|
600
|
-
it 'should be recognized for 2008' do
|
631
|
+
it 'should be recognized for Windows 2008' do
|
601
632
|
result = host.send(:parse_windows_os_str, 'Windows 2008')
|
602
|
-
result[
|
633
|
+
result['os.product'].should == 'Windows Server 2008'
|
603
634
|
end
|
604
635
|
|
605
|
-
it 'should be recognized for
|
606
|
-
result = host.send(:parse_windows_os_str, 'Windows
|
607
|
-
result[
|
636
|
+
it 'should be recognized for Windows 2012' do
|
637
|
+
result = host.send(:parse_windows_os_str, 'Windows 2012')
|
638
|
+
result['os.product'].should == 'Windows Server 2012'
|
608
639
|
end
|
609
640
|
|
610
|
-
it 'should be recognized for
|
611
|
-
result = host.send(:parse_windows_os_str, 'Windows
|
612
|
-
result[
|
641
|
+
it 'should be recognized for Windows Vista' do
|
642
|
+
result = host.send(:parse_windows_os_str, 'Windows Vista')
|
643
|
+
result['os.product'].should == 'Windows Vista'
|
613
644
|
end
|
614
645
|
|
615
|
-
it 'should be recognized for
|
646
|
+
it 'should be recognized for Windows Server 2000' do
|
616
647
|
result = host.send(:parse_windows_os_str, 'Windows 2000 Advanced Server')
|
617
|
-
result[
|
648
|
+
result['os.product'].should == 'Windows Server 2000'
|
618
649
|
end
|
619
650
|
|
620
|
-
it 'should be recognized for 7' do
|
651
|
+
it 'should be recognized for Windows 7' do
|
621
652
|
result = host.send(:parse_windows_os_str, 'Windows 7')
|
622
|
-
result[
|
653
|
+
result['os.product'].should == 'Windows 7'
|
623
654
|
end
|
624
655
|
|
625
|
-
it 'should be recognized for 7
|
656
|
+
it 'should be recognized for Windows 7 Ultimate Edition' do
|
626
657
|
result = host.send(:parse_windows_os_str, 'Windows 7 Ultimate Edition')
|
627
|
-
result[
|
658
|
+
result['os.product'].should == 'Windows 7'
|
659
|
+
result['os.edition'].should == 'Ultimate'
|
628
660
|
end
|
629
661
|
|
630
|
-
it 'should be recognized for 8' do
|
662
|
+
it 'should be recognized for Windows 8' do
|
631
663
|
result = host.send(:parse_windows_os_str, 'Windows 8')
|
632
|
-
result[
|
664
|
+
result['os.product'].should == 'Windows 8'
|
633
665
|
end
|
634
666
|
|
635
|
-
it 'should be
|
636
|
-
|
637
|
-
|
667
|
+
it 'should be recognized for Windows 8.1' do
|
668
|
+
result = host.send(:parse_windows_os_str, 'Windows 8.1')
|
669
|
+
result['os.product'].should == 'Windows 8.1'
|
638
670
|
end
|
639
|
-
end
|
640
671
|
|
641
|
-
|
642
|
-
|
643
|
-
result
|
644
|
-
result[:type].should == 'server'
|
672
|
+
it 'should be recognized for Windows 8.2' do
|
673
|
+
result = host.send(:parse_windows_os_str, 'Windows 8.2')
|
674
|
+
result['os.product'].should == 'Windows 8.2'
|
645
675
|
end
|
646
676
|
|
647
|
-
it 'should be
|
648
|
-
result = host.send(:parse_windows_os_str, 'Windows
|
649
|
-
result[
|
677
|
+
it 'should be recognized as Windows XP, Build 2600, SP3' do
|
678
|
+
result = host.send(:parse_windows_os_str, 'Windows XP (Build 2600, Service Pack 3).')
|
679
|
+
result['os.product'].should == 'Windows XP'
|
680
|
+
result['os.build'].should == '2600'
|
681
|
+
result['os.version'].should == 'SP3'
|
650
682
|
end
|
651
683
|
|
652
|
-
it 'should be
|
653
|
-
result = host.send(:parse_windows_os_str, 'Windows
|
654
|
-
result[
|
684
|
+
it 'should be recognized as Windows Server 2003, Build 3790' do
|
685
|
+
result = host.send(:parse_windows_os_str, 'Windows .NET Server (Build 3790).')
|
686
|
+
result['os.product'].should == 'Windows Server 2003'
|
687
|
+
result['os.build'].should == '3790'
|
655
688
|
end
|
656
689
|
|
657
|
-
it 'should be
|
658
|
-
result = host.send(:parse_windows_os_str, 'Windows
|
659
|
-
result[
|
690
|
+
it 'should be recognized as Windows Server 2008, Build 6001, SP1' do
|
691
|
+
result = host.send(:parse_windows_os_str, 'Windows 2008 (Build 6001, Service Pack 1).')
|
692
|
+
result['os.product'].should == 'Windows Server 2008'
|
693
|
+
result['os.build'].should == '6001'
|
694
|
+
result['os.version'].should == 'SP1'
|
660
695
|
end
|
661
696
|
|
662
|
-
it 'should
|
663
|
-
|
664
|
-
|
665
|
-
|
666
|
-
|
667
|
-
it 'should be client for anything else' do
|
668
|
-
result = host.send(:parse_windows_os_str, 'Windows XP')
|
669
|
-
result[:type].should == 'client'
|
697
|
+
it 'should default to Windows <name> if all else fails' do
|
698
|
+
result = host.send(:parse_windows_os_str, 'Windows Foobar Service Pack 3')
|
699
|
+
result['os.product'].should == 'Windows Foobar'
|
700
|
+
result['os.version'].should == 'SP3'
|
670
701
|
end
|
671
702
|
end
|
672
703
|
end
|
@@ -681,7 +712,7 @@ describe Mdm::Host do
|
|
681
712
|
host.validate_fingerprint_data(fingerprint).should == false
|
682
713
|
end
|
683
714
|
|
684
|
-
it 'should return false for
|
715
|
+
it 'should return false for postgresql fingerprints' do
|
685
716
|
fingerprint= FactoryGirl.build(:mdm_note, :ntype => 'postgresql.fingerprint', :data => {})
|
686
717
|
host.validate_fingerprint_data(fingerprint).should == false
|
687
718
|
end
|
@@ -692,81 +723,261 @@ describe Mdm::Host do
|
|
692
723
|
end
|
693
724
|
end
|
694
725
|
|
726
|
+
|
727
|
+
context '#apply_match_to_host' do
|
728
|
+
|
729
|
+
before(:each) do
|
730
|
+
stub_const('Rex::Text', Module.new)
|
731
|
+
allow(Rex::Text).to receive(:ascii_safe_hex) do |unsanitized|
|
732
|
+
# Pass back the sanitized value for the stub
|
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
|
+
|
737
|
+
it 'should set host.mac when host.mac is present' do
|
738
|
+
match = { 'host.mac' => '00:11:22:33:44:55' }
|
739
|
+
host.send(:apply_match_to_host, match)
|
740
|
+
host.mac.should == '00:11:22:33:44:55'
|
741
|
+
end
|
742
|
+
|
743
|
+
it 'should set host.name when host.name is present' do
|
744
|
+
match = { 'host.name' => 'webbyweb' }
|
745
|
+
host.send(:apply_match_to_host, match)
|
746
|
+
host.name.should == 'webbyweb'
|
747
|
+
end
|
748
|
+
|
749
|
+
it 'should set host.arch when os.arch is present' do
|
750
|
+
match = { 'os.arch' => 'x86' }
|
751
|
+
host.send(:apply_match_to_host, match)
|
752
|
+
host.arch.should == 'x86'
|
753
|
+
end
|
754
|
+
|
755
|
+
it 'should set host.name to an escaped hex value when host.name contains high bytes' do
|
756
|
+
match = { 'host.name' => "HighBytes\xff\xf0".force_encoding('binary') }
|
757
|
+
host.send(:apply_match_to_host, match)
|
758
|
+
host.name.should == "HighBytes\\xff\\xf0"
|
759
|
+
end
|
760
|
+
|
761
|
+
it 'should set host.purpose to client when os.product is Windows XP' do
|
762
|
+
match = { 'os.product' => 'Windows XP' }
|
763
|
+
host.send(:apply_match_to_host, match)
|
764
|
+
host.os_name.should == 'Windows XP'
|
765
|
+
host.purpose.should == 'client'
|
766
|
+
end
|
767
|
+
|
768
|
+
it 'should set host.purpose to server when os.product is Windows 2012' do
|
769
|
+
match = { 'os.product' => 'Windows 2012' }
|
770
|
+
host.send(:apply_match_to_host, match)
|
771
|
+
host.os_name.should == 'Windows 2012'
|
772
|
+
host.purpose.should == 'server'
|
773
|
+
end
|
774
|
+
|
775
|
+
it 'should set host.purpose to printer when os.device is Print server' do
|
776
|
+
match = { 'os.device' => 'Print server' }
|
777
|
+
host.send(:apply_match_to_host, match)
|
778
|
+
host.purpose.should == 'printer'
|
779
|
+
end
|
780
|
+
|
781
|
+
it 'should set host.os_lang to English when os.language is English' do
|
782
|
+
match = { 'os.language' => 'English' }
|
783
|
+
host.send(:apply_match_to_host, match)
|
784
|
+
host.os_lang.should == 'English'
|
785
|
+
end
|
786
|
+
|
787
|
+
it 'should set host.os_name to Windows 8.1 when os.product is Windows 8.1' do
|
788
|
+
match = { 'os.product' => 'Windows 8.1' }
|
789
|
+
host.send(:apply_match_to_host, match)
|
790
|
+
host.os_name.should == 'Windows 8.1'
|
791
|
+
end
|
792
|
+
|
793
|
+
it 'should set host.os_name to Windows when os.product is not set and os.family is Windows' do
|
794
|
+
match = { 'os.family' => 'Windows' }
|
795
|
+
host.send(:apply_match_to_host, match)
|
796
|
+
host.os_name.should == 'Windows'
|
797
|
+
end
|
798
|
+
|
799
|
+
it 'should set host.os_flavor to Professional when os.edition is Professional' do
|
800
|
+
match = { 'os.edition' => 'Professional' }
|
801
|
+
host.send(:apply_match_to_host, match)
|
802
|
+
host.os_flavor.should == 'Professional'
|
803
|
+
end
|
804
|
+
|
805
|
+
it 'should set host.os_sp to SP2 when os.version is SP2' do
|
806
|
+
match = { 'os.version' => 'SP2' }
|
807
|
+
host.send(:apply_match_to_host, match)
|
808
|
+
host.os_sp.should == 'SP2'
|
809
|
+
end
|
810
|
+
|
811
|
+
it 'should set host.os_sp to 3.2.11 when os.version is nil and linux.kernel.version is 3.2.11' do
|
812
|
+
match = { 'linux.kernel.version' => '3.2.11' }
|
813
|
+
host.send(:apply_match_to_host, match)
|
814
|
+
host.os_sp.should == '3.2.11'
|
815
|
+
end
|
816
|
+
end
|
817
|
+
|
818
|
+
context '#normalize_match' do
|
819
|
+
|
820
|
+
it 'should convert Service Pack X to SPX' do
|
821
|
+
match = { 'os.version' => 'Service Pack 2' }
|
822
|
+
result = host.send(:normalize_match, match)
|
823
|
+
result['os.version'].should == 'SP2'
|
824
|
+
end
|
825
|
+
|
826
|
+
it 'should not convert No Service Pack to SP' do
|
827
|
+
match = { 'os.version' => 'No Service Pack' }
|
828
|
+
result = host.send(:normalize_match, match)
|
829
|
+
result['os.version'].should == 'No Service Pack'
|
830
|
+
end
|
831
|
+
|
832
|
+
it 'should convert Apple Mac OS X to Mac OS X' do
|
833
|
+
match = { 'os.product' => 'Apple Mac OS X' }
|
834
|
+
result = host.send(:normalize_match, match)
|
835
|
+
result['os.product'].should == 'Mac OS X'
|
836
|
+
result['os.vendor'].should == 'Apple'
|
837
|
+
end
|
838
|
+
|
839
|
+
it 'should convert Microsoft Windows to Windows' do
|
840
|
+
match = { 'os.product' => 'Microsoft Windows 7' }
|
841
|
+
result = host.send(:normalize_match, match)
|
842
|
+
result['os.product'].should == 'Windows 7'
|
843
|
+
result['os.vendor'].should == 'Microsoft'
|
844
|
+
end
|
845
|
+
|
846
|
+
it 'should convert Windows Server 2012 to Windows 2012' do
|
847
|
+
match = { 'os.product' => 'Windows Server 2012' }
|
848
|
+
result = host.send(:normalize_match, match)
|
849
|
+
result['os.product'].should == 'Windows 2012'
|
850
|
+
end
|
851
|
+
end
|
852
|
+
|
853
|
+
context '#guess_purpose_from_match' do
|
854
|
+
|
855
|
+
it 'should detect Windows XP as a client' do
|
856
|
+
match = { 'os.product' => 'Windows XP' }
|
857
|
+
result = host.send(:guess_purpose_from_match, match)
|
858
|
+
result.should == 'client'
|
859
|
+
end
|
860
|
+
|
861
|
+
it 'should detect Windows 8.1 as a client' do
|
862
|
+
match = { 'os.product' => 'Windows 8.1' }
|
863
|
+
result = host.send(:guess_purpose_from_match, match)
|
864
|
+
result.should == 'client'
|
865
|
+
end
|
866
|
+
|
867
|
+
it 'should detect Windows 2000 as a server' do
|
868
|
+
match = { 'os.product' => 'Windows 2000' }
|
869
|
+
result = host.send(:guess_purpose_from_match, match)
|
870
|
+
result.should == 'server'
|
871
|
+
end
|
872
|
+
|
873
|
+
it 'should detect Windows Server 2012 as a server' do
|
874
|
+
match = { 'os.product' => 'Windows Server 2012' }
|
875
|
+
result = host.send(:guess_purpose_from_match, match)
|
876
|
+
result.should == 'server'
|
877
|
+
end
|
878
|
+
|
879
|
+
it 'should detect Linux as a server' do
|
880
|
+
match = { 'os.product' => 'Linux' }
|
881
|
+
result = host.send(:guess_purpose_from_match, match)
|
882
|
+
result.should == 'server'
|
883
|
+
end
|
884
|
+
|
885
|
+
it 'should detect JetDirect as a printer' do
|
886
|
+
match = { 'os.product' => 'JetDirect', 'os.device' => 'Print server' }
|
887
|
+
result = host.send(:guess_purpose_from_match, match)
|
888
|
+
result.should == 'printer'
|
889
|
+
end
|
890
|
+
|
891
|
+
it 'should detect Unknown Printer as a printer' do
|
892
|
+
match = { 'os.product' => 'Unknown Printer' }
|
893
|
+
result = host.send(:guess_purpose_from_match, match)
|
894
|
+
result.should == 'printer'
|
895
|
+
end
|
896
|
+
|
897
|
+
it 'should detect Linksys Router as a router' do
|
898
|
+
match = { 'os.product' => 'Linksys', 'os.device' => 'Router' }
|
899
|
+
result = host.send(:guess_purpose_from_match, match)
|
900
|
+
result.should == 'router'
|
901
|
+
end
|
902
|
+
|
903
|
+
it 'should detect CheckPoint Firewall-1 as a firewall' do
|
904
|
+
match = { 'os.vendor' => 'Check Point', 'os.product' => 'Firewall-1' }
|
905
|
+
result = host.send(:guess_purpose_from_match, match)
|
906
|
+
result.should == 'firewall'
|
907
|
+
end
|
908
|
+
end
|
909
|
+
|
695
910
|
context '#normalize_scanner_fp' do
|
696
911
|
context 'for session_fingerprint' do
|
697
912
|
it 'should return all the correct data for Windows XP SP3 x86' do
|
698
913
|
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host)
|
699
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
700
|
-
result[
|
701
|
-
result[
|
702
|
-
result[
|
703
|
-
result[
|
704
|
-
result[
|
705
|
-
result[:name].should == nil
|
706
|
-
result[:certainty].should == 0.8
|
914
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
915
|
+
result['os.product'].should == 'Windows XP'
|
916
|
+
result['os.version'].should == 'SP3'
|
917
|
+
result['os.arch'].should == 'x86'
|
918
|
+
result['host.name'].should == nil
|
919
|
+
result['os.certainty'].to_f.should == 0.8
|
707
920
|
end
|
708
921
|
|
709
922
|
it 'should return all the correct data for Windows 2008 SP1 x64' do
|
710
923
|
fp_data = { :os => 'Microsoft Windows 2008 SP1', :arch => 'x64'}
|
711
924
|
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
712
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
713
|
-
result[
|
714
|
-
result[
|
715
|
-
result[
|
716
|
-
result[
|
717
|
-
result[
|
718
|
-
result[:name].should == nil
|
719
|
-
result[:certainty].should == 0.8
|
925
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
926
|
+
result['os.product'].should == 'Windows Server 2008'
|
927
|
+
result['os.version'].should == 'SP1'
|
928
|
+
result['os.arch'].should == 'x64'
|
929
|
+
result['host.name'].should == nil
|
930
|
+
result['os.certainty'].to_f.should == 0.8
|
720
931
|
end
|
721
932
|
|
722
933
|
it 'should fingerprint Metasploitable correctly' do
|
723
934
|
# Taken from an actual session_fingerprint of Metasploitable 2
|
724
935
|
fp_data = { :os => 'Linux 2.6.24-16-server (i386)', :name => 'metasploitable'}
|
725
936
|
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
726
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
727
|
-
result[
|
728
|
-
result[
|
729
|
-
result[
|
730
|
-
result[
|
731
|
-
result[
|
937
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
938
|
+
result['os.product'].should == 'Linux'
|
939
|
+
result['host.name'].should == 'metasploitable'
|
940
|
+
result['os.version'].should == '2.6.24-16-server'
|
941
|
+
result['os.arch'].should == 'x86'
|
942
|
+
result['os.certainty'].to_f.should == 0.8
|
732
943
|
end
|
733
944
|
|
734
945
|
it 'should just populate os_name if it is unsure' do
|
735
946
|
fp_data = { :os => 'Darwin 12.3.0 x86_64 i386'}
|
736
947
|
fingerprint = FactoryGirl.build(:mdm_session_fingerprint, :host => host, :data => fp_data)
|
737
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
738
|
-
result[
|
739
|
-
result[
|
740
|
-
result[
|
741
|
-
result[
|
948
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
949
|
+
result['os.product'].should == 'Darwin 12.3.0 x86_64 i386'
|
950
|
+
result['os.version'].should == nil
|
951
|
+
result['os.arch'].should == nil
|
952
|
+
result['os.certainty'].should == 0.8
|
742
953
|
end
|
743
954
|
end
|
744
955
|
|
745
956
|
context 'for nmap_fingerprint' do
|
746
|
-
it 'should return OS name
|
957
|
+
it 'should return OS name for a Windows XP fingerprint' do
|
747
958
|
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host)
|
748
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
749
|
-
result[
|
750
|
-
result[
|
751
|
-
result[:certainty].should == 1
|
959
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
960
|
+
result['os.product'].should == 'Windows XP'
|
961
|
+
result['os.certainty'].to_f.should == described_class::MAX_NMAP_CERTAINTY
|
752
962
|
end
|
753
963
|
|
754
|
-
it 'should return OS name
|
964
|
+
it 'should return OS name for a Metasploitable fingerprint' do
|
755
965
|
fp_data = {:os_vendor=>"Linux", :os_family=>"Linux", :os_version=>"2.6.X", :os_accuracy=>100}
|
756
966
|
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host, :data => fp_data)
|
757
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
758
|
-
result[
|
759
|
-
result[
|
760
|
-
result[
|
967
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
968
|
+
result['os.product'].should == 'Linux'
|
969
|
+
result['os.version'].should == '2.6.X'
|
970
|
+
result['os.certainty'].to_f.should == described_class::MAX_NMAP_CERTAINTY
|
761
971
|
end
|
762
972
|
|
763
973
|
it 'should return OS name and flavor fo an OSX fingerprint' do
|
764
974
|
fp_data = {:os_vendor=>"Apple", :os_family=>"Mac OS X", :os_version=>"10.8.X", :os_accuracy=>100}
|
765
975
|
fingerprint = FactoryGirl.build(:mdm_nmap_fingerprint, :host => host, :data => fp_data)
|
766
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
767
|
-
result[
|
768
|
-
result[
|
769
|
-
result[
|
976
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
977
|
+
result['os.product'].should == 'Mac OS X'
|
978
|
+
result['os.vendor'].should == 'Apple'
|
979
|
+
result['os.version'].should == '10.8.X'
|
980
|
+
result['os.certainty'].to_f.should == described_class::MAX_NMAP_CERTAINTY
|
770
981
|
end
|
771
982
|
end
|
772
983
|
|
@@ -774,50 +985,51 @@ describe Mdm::Host do
|
|
774
985
|
context 'of a Windows system' do
|
775
986
|
it 'should return a generic Windows fingerprint with no product info' do
|
776
987
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host)
|
777
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
778
|
-
result[
|
779
|
-
result[
|
780
|
-
result[
|
988
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
989
|
+
result['os.product'].should == 'Windows'
|
990
|
+
result['os.arch'].should == 'x86'
|
991
|
+
result['os.certainty'].to_f.should == 0.67
|
781
992
|
end
|
782
993
|
|
783
994
|
it 'should recognize a Windows 7 fingerprint' do
|
784
995
|
fp_data = {:family=>"Windows", :certainty=>"0.67", :vendor=>"Microsoft", :arch=>"x86", :product => 'Windows 7', :version => 'SP1'}
|
785
996
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
786
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
787
|
-
result[
|
788
|
-
result[
|
789
|
-
result[
|
790
|
-
result[
|
791
|
-
result[:certainty].should == 0.67
|
997
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
998
|
+
result['os.product'].should == 'Windows 7'
|
999
|
+
result['os.version'].should == 'SP1'
|
1000
|
+
result['os.arch'].should == 'x86'
|
1001
|
+
result['os.certainty'].to_f.should == 0.67
|
792
1002
|
end
|
793
1003
|
end
|
794
1004
|
|
795
1005
|
it 'should recognize an OSX fingerprint' do
|
796
1006
|
fp_data = {:family=>"Mac OS X", :certainty=>"0.80", :vendor=>"Apple"}
|
797
1007
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
798
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
799
|
-
result[
|
1008
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1009
|
+
result['os.product'].should == 'Mac OS X'
|
1010
|
+
result['os.vendor'].should == "Apple"
|
800
1011
|
end
|
801
1012
|
|
802
1013
|
it 'should recognize a Cisco fingerprint' do
|
803
1014
|
fp_data = {:family=>"IOS", :certainty=>"1.00", :vendor=>"Cisco", :version=>"11.2(8)SA2"}
|
804
1015
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
805
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
806
|
-
result[
|
1016
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1017
|
+
result['os.product'].should == 'IOS'
|
1018
|
+
result['os.vendor'].should == 'Cisco'
|
807
1019
|
end
|
808
1020
|
|
809
|
-
it 'should recognize an
|
1021
|
+
it 'should recognize an embedded fingerprint' do
|
810
1022
|
fp_data = {:family=>"embedded", :certainty=>"1.00", :vendor=>"Footek"}
|
811
1023
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
812
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
813
|
-
result[
|
1024
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1025
|
+
result['os.product'].should == 'Footek'
|
814
1026
|
end
|
815
1027
|
|
816
1028
|
it 'should handle an unknown fingerprint' do
|
817
1029
|
fp_data = {:certainty=>"1.00", :vendor=>"Footek"}
|
818
1030
|
fingerprint = FactoryGirl.build(:mdm_nexpose_fingerprint, :host => host, :data => fp_data)
|
819
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
820
|
-
result[
|
1031
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1032
|
+
result['os.product'].should == 'Footek'
|
821
1033
|
end
|
822
1034
|
|
823
1035
|
|
@@ -826,21 +1038,19 @@ describe Mdm::Host do
|
|
826
1038
|
context 'for retina_fingerprint' do
|
827
1039
|
it 'should recognize a Windows fingerprint' do
|
828
1040
|
fingerprint = FactoryGirl.build(:mdm_retina_fingerprint, :host => host)
|
829
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
830
|
-
result[
|
831
|
-
result[
|
832
|
-
result[
|
833
|
-
result[
|
834
|
-
result[:type].should == 'server'
|
835
|
-
result[:certainty].should == 0.8
|
1041
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1042
|
+
result['os.product'].should == 'Windows Server 2003'
|
1043
|
+
result['os.arch'].should == 'x64'
|
1044
|
+
result['os.version'].should == 'SP2'
|
1045
|
+
result['os.certainty'].to_f.should == 0.8
|
836
1046
|
end
|
837
1047
|
|
838
1048
|
it 'should otherwise jsut copy the fingerprint to os_name' do
|
839
1049
|
fp_data = { :os => 'Linux 2.6.X (i386)'}
|
840
1050
|
fingerprint = FactoryGirl.build(:mdm_retina_fingerprint, :host => host, :data => fp_data)
|
841
|
-
result = host.send(:normalize_scanner_fp, fingerprint)
|
842
|
-
result[
|
843
|
-
result[
|
1051
|
+
result = host.send(:normalize_scanner_fp, fingerprint).first
|
1052
|
+
result['os.product'].should == 'Linux 2.6.X (i386)'
|
1053
|
+
result['os.certainty'].to_f.should == 0.8
|
844
1054
|
end
|
845
1055
|
end
|
846
1056
|
end
|