metasploit_data_models 0.15.2 → 0.16.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. data/Gemfile +2 -0
  2. data/app/models/mdm/client.rb +0 -1
  3. data/app/models/mdm/cred.rb +1 -1
  4. data/app/models/mdm/exploited_host.rb +0 -1
  5. data/app/models/mdm/listener.rb +2 -1
  6. data/app/models/mdm/nexpose_console.rb +2 -2
  7. data/app/models/mdm/session.rb +5 -1
  8. data/app/models/mdm/workspace.rb +0 -1
  9. data/db/migrate/20130525015035_remove_campaign_id_from_clients.rb +9 -0
  10. data/db/migrate/20130525212420_drop_table_imported_creds.rb +14 -0
  11. data/db/migrate/20130531144949_making_host_tags_a_real_ar_model.rb +6 -0
  12. data/lib/mdm/host/operating_system_normalization.rb +4 -4
  13. data/lib/metasploit_data_models/version.rb +1 -1
  14. data/spec/app/models/mdm/client_spec.rb +43 -0
  15. data/spec/app/models/mdm/cred_spec.rb +211 -0
  16. data/spec/app/models/mdm/events_spec.rb +85 -0
  17. data/spec/app/models/mdm/exploit_attempt_spec.rb +60 -0
  18. data/spec/app/models/mdm/exploited_host_spec.rb +44 -0
  19. data/spec/app/models/mdm/host_detail_spec.rb +49 -0
  20. data/spec/app/models/mdm/host_spec.rb +468 -0
  21. data/spec/app/models/mdm/host_tag_spec.rb +26 -0
  22. data/spec/app/models/mdm/listener_spec.rb +108 -0
  23. data/spec/app/models/mdm/loot_spec.rb +77 -0
  24. data/spec/app/models/mdm/nexpose_console_spec.rb +128 -0
  25. data/spec/app/models/mdm/note_spec.rb +84 -0
  26. data/spec/app/models/mdm/ref_spec.rb +13 -0
  27. data/spec/app/models/mdm/report_spec.rb +104 -0
  28. data/spec/app/models/mdm/report_template_spec.rb +52 -0
  29. data/spec/app/models/mdm/route_spec.rb +36 -0
  30. data/spec/app/models/mdm/service_spec.rb +70 -15
  31. data/spec/app/models/mdm/session_event_spec.rb +42 -0
  32. data/spec/app/models/mdm/session_spec.rb +114 -0
  33. data/spec/app/models/mdm/tag_spec.rb +104 -0
  34. data/spec/app/models/mdm/task_creds_spec.rb +32 -0
  35. data/spec/app/models/mdm/task_host_spec.rb +33 -0
  36. data/spec/app/models/mdm/task_service_spec.rb +33 -0
  37. data/spec/app/models/mdm/task_spec.rb +59 -5
  38. data/spec/app/models/mdm/user_spec.rb +51 -0
  39. data/spec/app/models/mdm/vuln_attempt_spec.rb +54 -0
  40. data/spec/app/models/mdm/vuln_details_spec.rb +66 -0
  41. data/spec/app/models/mdm/vuln_ref_spec.rb +24 -0
  42. data/spec/app/models/mdm/vuln_spec.rb +25 -0
  43. data/spec/app/models/mdm/web_form_spec.rb +47 -0
  44. data/spec/app/models/mdm/web_page_spec.rb +55 -0
  45. data/spec/app/models/mdm/web_site_spec.rb +86 -0
  46. data/spec/app/models/mdm/web_vuln_spec.rb +12 -0
  47. data/spec/app/models/mdm/workspace_spec.rb +567 -0
  48. data/spec/dummy/db/schema.rb +5 -13
  49. data/spec/factories/mdm/addresses.rb +5 -0
  50. data/spec/factories/mdm/clients.rb +8 -0
  51. data/spec/factories/mdm/events.rb +15 -0
  52. data/spec/factories/mdm/exploit_attempts.rb +8 -0
  53. data/spec/factories/mdm/exploited_hosts.rb +7 -0
  54. data/spec/factories/mdm/fingerprints/nessus_fingerprints.rb +6 -0
  55. data/spec/factories/mdm/fingerprints/nexpose_fingerprints.rb +6 -0
  56. data/spec/factories/mdm/fingerprints/nmap_fingerprints.rb +6 -0
  57. data/spec/factories/mdm/fingerprints/retina_fingerprints.rb +6 -0
  58. data/spec/factories/mdm/fingerprints/session_fingerprints.rb +6 -0
  59. data/spec/factories/mdm/host_details.rb +8 -0
  60. data/spec/factories/mdm/listeners.rb +12 -0
  61. data/spec/factories/mdm/loots.rb +11 -0
  62. data/spec/factories/mdm/nexpose_consoles.rb +15 -0
  63. data/spec/factories/mdm/notes.rb +12 -0
  64. data/spec/factories/mdm/report_templates.rb +8 -0
  65. data/spec/factories/mdm/reports.rb +13 -0
  66. data/spec/factories/mdm/routes.rb +36 -0
  67. data/spec/factories/mdm/session_events.rb +8 -0
  68. data/spec/factories/mdm/sessions.rb +13 -0
  69. data/spec/factories/mdm/vuln_attempts.rb +8 -0
  70. data/spec/factories/mdm/vuln_details.rb +8 -0
  71. data/spec/factories/mdm/web_forms.rb +33 -0
  72. data/spec/factories/mdm/web_pages.rb +64 -0
  73. metadata +95 -5
  74. data/app/models/mdm/imported_cred.rb +0 -10
@@ -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