|
6 | 6 |
|
7 | 7 | RSpec.describe Metasploit::Framework::LoginScanner do |
8 | 8 |
|
9 | | - subject { described_class.classes_for_service(service) } |
10 | | - let(:port) { nil } |
11 | | - let(:name) { nil } |
12 | | - |
13 | | - let(:service) do |
14 | | - s = double('service') |
15 | | - allow(s).to receive(:port) { port } |
16 | | - allow(s).to receive(:name) { name } |
17 | | - s |
18 | | - end |
| 9 | + describe '.classes_for_service' do |
| 10 | + subject { described_class.classes_for_service(service) } |
| 11 | + let(:port) { nil } |
| 12 | + let(:name) { nil } |
19 | 13 |
|
20 | | - context "with name 'smb'" do |
21 | | - let(:name) { 'smb' } |
| 14 | + let(:service) do |
| 15 | + instance_double(Mdm::Service, port: port, name: name) |
| 16 | + end |
22 | 17 |
|
23 | | - it { is_expected.to include Metasploit::Framework::LoginScanner::SMB } |
24 | | - it { is_expected.not_to include Metasploit::Framework::LoginScanner::HTTP } |
25 | | - end |
| 18 | + context "with name 'smb'" do |
| 19 | + let(:name) { 'smb' } |
26 | 20 |
|
| 21 | + it { is_expected.to include Metasploit::Framework::LoginScanner::SMB } |
| 22 | + it { is_expected.not_to include Metasploit::Framework::LoginScanner::HTTP } |
| 23 | + end |
27 | 24 |
|
28 | | - context "with port 445" do |
29 | | - let(:port) { 445 } |
| 25 | + context "with port 445" do |
| 26 | + let(:port) { 445 } |
30 | 27 |
|
31 | | - it { is_expected.to include Metasploit::Framework::LoginScanner::SMB } |
32 | | - it { is_expected.not_to include Metasploit::Framework::LoginScanner::HTTP } |
33 | | - it { is_expected.not_to include Metasploit::Framework::LoginScanner::VNC } |
34 | | - end |
| 28 | + it { is_expected.to include Metasploit::Framework::LoginScanner::SMB } |
| 29 | + it { is_expected.not_to include Metasploit::Framework::LoginScanner::HTTP } |
| 30 | + it { is_expected.not_to include Metasploit::Framework::LoginScanner::VNC } |
| 31 | + end |
35 | 32 |
|
| 33 | + context "with name 'http'" do |
| 34 | + let(:name) { 'http' } |
36 | 35 |
|
37 | | - context "with name 'http'" do |
38 | | - let(:name) { 'http' } |
| 36 | + it { is_expected.to include Metasploit::Framework::LoginScanner::HTTP } |
| 37 | + it { is_expected.not_to include Metasploit::Framework::LoginScanner::SMB } |
| 38 | + it { is_expected.not_to include Metasploit::Framework::LoginScanner::VNC } |
| 39 | + end |
39 | 40 |
|
40 | | - it { is_expected.to include Metasploit::Framework::LoginScanner::HTTP } |
41 | | - it { is_expected.not_to include Metasploit::Framework::LoginScanner::SMB } |
42 | | - it { is_expected.not_to include Metasploit::Framework::LoginScanner::VNC } |
| 41 | + [ 80, 8080, 8000, 443 ].each do |foo| |
| 42 | + context "with port #{foo}" do |
| 43 | + let(:port) { foo } |
| 44 | + |
| 45 | + it { is_expected.to include Metasploit::Framework::LoginScanner::HTTP } |
| 46 | + it { is_expected.to include Metasploit::Framework::LoginScanner::Axis2 } |
| 47 | + it { is_expected.to include Metasploit::Framework::LoginScanner::Tomcat } |
| 48 | + it { is_expected.not_to include Metasploit::Framework::LoginScanner::SMB } |
| 49 | + end |
| 50 | + end |
43 | 51 | end |
44 | 52 |
|
45 | | - [ 80, 8080, 8000, 443 ].each do |foo| |
46 | | - context "with port #{foo}" do |
47 | | - let(:port) { foo } |
| 53 | + describe '.all_http_classes' do |
| 54 | + let(:http_classes) { described_class.all_http_classes } |
48 | 55 |
|
49 | | - it { is_expected.to include Metasploit::Framework::LoginScanner::HTTP } |
50 | | - it { is_expected.to include Metasploit::Framework::LoginScanner::Axis2 } |
51 | | - it { is_expected.to include Metasploit::Framework::LoginScanner::Tomcat } |
52 | | - it { is_expected.not_to include Metasploit::Framework::LoginScanner::SMB } |
| 56 | + it 'returns a populated array' do |
| 57 | + expect(http_classes).to be_a Array |
| 58 | + expect(http_classes).to_not be_empty |
| 59 | + end |
| 60 | + |
| 61 | + it 'includes HTTP classes' do |
| 62 | + expect(http_classes).to include Metasploit::Framework::LoginScanner::TeamCity |
| 63 | + expect(http_classes).to include Metasploit::Framework::LoginScanner::Ivanti |
| 64 | + end |
| 65 | + |
| 66 | + it 'does not include non-HTTP classes' do |
| 67 | + # Base HTTP scanner should not be present |
| 68 | + expect(http_classes).to_not include Metasploit::Framework::LoginScanner::HTTP |
| 69 | + expect(http_classes).to_not include Metasploit::Framework::LoginScanner::SMB |
| 70 | + expect(http_classes).to_not include Metasploit::Framework::LoginScanner::VNC |
53 | 71 | end |
54 | 72 | end |
55 | 73 |
|
|
69 | 87 | expect(service_names).to include 'https' |
70 | 88 | expect(service_names).to include 'smb' |
71 | 89 | end |
72 | | - end |
73 | | - |
74 | | - describe '.classes_for_service' do |
75 | | - described_class.all_service_names.each do |service_name| |
76 | | - context "with service #{service_name}" do |
77 | | - let(:name) { service_name } |
78 | | - let(:login_scanners) { described_class.classes_for_service(service) } |
79 | | - |
80 | | - it 'returns at least one class' do |
81 | | - expect(login_scanners).to_not be_empty |
82 | | - end |
83 | | - |
84 | 90 |
|
85 | | - MockService = Struct.new(:name, :port) |
86 | | - |
87 | | - described_class.classes_for_service(MockService.new(name: service_name)).each do |login_scanner| |
88 | | - context "when the login scanner is #{login_scanner.name}" do |
89 | | - it 'is a LoginScanner' do |
90 | | - expect(login_scanner).to include Metasploit::Framework::LoginScanner::Base |
91 | | - end |
92 | | - |
93 | | - it 'can be initialized with a single argument' do |
94 | | - expect { |
95 | | - # here we emulate how Pro will initialize the class by passing a single configuration hash argument |
96 | | - login_scanner.new({ |
97 | | - bruteforce_speed: 5, |
98 | | - host: '192.0.2.1', |
99 | | - port: 1234, |
100 | | - stop_on_success: true |
101 | | - }) |
102 | | - }.to_not raise_error |
103 | | - end |
| 91 | + it 'returns a list of valid services' do |
| 92 | + all_scanners = service_names.flat_map do |service_name| |
| 93 | + service = instance_double Mdm::Service, name: service_name, port: nil |
| 94 | + classes = described_class.classes_for_service(service) |
| 95 | + expect(classes).to_not be_empty |
| 96 | + classes |
| 97 | + end.uniq |
| 98 | + expect(all_scanners).to_not be_empty |
| 99 | + |
| 100 | + all_scanners.each do |scanner| |
| 101 | + # Emulate how Pro will initialize the class by passing a single configuration hash argument |
| 102 | + options = { |
| 103 | + bruteforce_speed: 5, |
| 104 | + host: '192.0.2.1', |
| 105 | + port: 1234, |
| 106 | + stop_on_success: true |
| 107 | + } |
| 108 | + aggregate_failures "#{scanner} is a valid scanner" do |
| 109 | + expect(scanner.const_defined?(:PRIVATE_TYPES)).to be(true), "for #{scanner}" |
| 110 | + expect(scanner.const_defined?(:LIKELY_SERVICE_NAMES)).to be(true), "for #{scanner}" |
| 111 | + expect(scanner.const_defined?(:LIKELY_PORTS)).to be(true), "for #{scanner}" |
| 112 | + if scanner.ancestors.include?(Metasploit::Framework::LoginScanner::HTTP) && scanner != Metasploit::Framework::LoginScanner::WinRM |
| 113 | + expect(scanner::LIKELY_SERVICE_NAMES).to include('http', 'https'), "for #{scanner}" |
| 114 | + expect(scanner::LIKELY_PORTS).to include(80, 443, 8000, 8080), "for #{scanner}" |
104 | 115 | end |
| 116 | + expect { scanner.new(options) }.to_not raise_error, "for #{scanner}" |
105 | 117 | end |
106 | 118 | end |
107 | 119 | end |
|
0 commit comments