cms_scanner 0.0.2
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 +7 -0
- data/.gitignore +18 -0
- data/.rspec +2 -0
- data/.rubocop.yml +6 -0
- data/.travis.yml +14 -0
- data/Gemfile +6 -0
- data/README.md +20 -0
- data/Rakefile +9 -0
- data/app/app.rb +4 -0
- data/app/controllers.rb +2 -0
- data/app/controllers/core.rb +46 -0
- data/app/controllers/core/cli_options.rb +68 -0
- data/app/controllers/interesting_files.rb +12 -0
- data/app/finders.rb +1 -0
- data/app/finders/interesting_files.rb +21 -0
- data/app/finders/interesting_files/fantastico_fileslist.rb +23 -0
- data/app/finders/interesting_files/headers.rb +15 -0
- data/app/finders/interesting_files/robots_txt.rb +22 -0
- data/app/finders/interesting_files/search_replace_db_2.rb +28 -0
- data/app/finders/interesting_files/xml_rpc.rb +62 -0
- data/app/formatters.rb +3 -0
- data/app/formatters/cli.rb +18 -0
- data/app/formatters/cli_no_colour.rb +15 -0
- data/app/formatters/json.rb +12 -0
- data/app/models.rb +5 -0
- data/app/models/fantastico_fileslist.rb +20 -0
- data/app/models/headers.rb +37 -0
- data/app/models/interesting_file.rb +30 -0
- data/app/models/robots_txt.rb +20 -0
- data/app/models/xml_rpc.rb +35 -0
- data/app/views/cli/core/finished.erb +4 -0
- data/app/views/cli/core/started.erb +3 -0
- data/app/views/cli/interesting_files/findings.erb +19 -0
- data/app/views/cli/scan_aborted.erb +4 -0
- data/app/views/json/core/finished.erb +3 -0
- data/app/views/json/core/started.erb +3 -0
- data/app/views/json/interesting_files/findings.erb +1 -0
- data/app/views/json/scan_aborted.erb +4 -0
- data/cms_scanner.gemspec +37 -0
- data/examples/views/cli/wp_custom/test.erb +1 -0
- data/examples/views/json/wp_custom/test.erb +1 -0
- data/examples/wpscan.rb +29 -0
- data/lib/cms_scanner.rb +71 -0
- data/lib/cms_scanner/browser.rb +68 -0
- data/lib/cms_scanner/browser/actions.rb +48 -0
- data/lib/cms_scanner/browser/options.rb +53 -0
- data/lib/cms_scanner/cache/file_store.rb +75 -0
- data/lib/cms_scanner/cache/typhoeus.rb +21 -0
- data/lib/cms_scanner/controller.rb +90 -0
- data/lib/cms_scanner/controllers.rb +34 -0
- data/lib/cms_scanner/errors/auth_errors.rb +15 -0
- data/lib/cms_scanner/finders.rb +5 -0
- data/lib/cms_scanner/finders/finder.rb +27 -0
- data/lib/cms_scanner/finders/finding.rb +32 -0
- data/lib/cms_scanner/finders/findings.rb +25 -0
- data/lib/cms_scanner/finders/independent_finder.rb +30 -0
- data/lib/cms_scanner/finders/independent_finders.rb +41 -0
- data/lib/cms_scanner/formatter.rb +118 -0
- data/lib/cms_scanner/formatter/buffer.rb +15 -0
- data/lib/cms_scanner/target.rb +33 -0
- data/lib/cms_scanner/target/platform.rb +2 -0
- data/lib/cms_scanner/target/platform/php.rb +39 -0
- data/lib/cms_scanner/target/platform/wordpress.rb +35 -0
- data/lib/cms_scanner/target/platform/wordpress/custom_directories.rb +62 -0
- data/lib/cms_scanner/target/server.rb +3 -0
- data/lib/cms_scanner/target/server/apache.rb +43 -0
- data/lib/cms_scanner/target/server/generic.rb +34 -0
- data/lib/cms_scanner/target/server/iis.rb +48 -0
- data/lib/cms_scanner/version.rb +4 -0
- data/lib/cms_scanner/web_site.rb +68 -0
- data/lib/helper.rb +24 -0
- data/spec/app/controllers/core_spec.rb +152 -0
- data/spec/app/controllers/interesting_files_spec.rb +50 -0
- data/spec/app/finders/interesting_files/fantastico_fileslist_spec.rb +68 -0
- data/spec/app/finders/interesting_files/headers_spec.rb +38 -0
- data/spec/app/finders/interesting_files/robots_txt_spec.rb +56 -0
- data/spec/app/finders/interesting_files/search_replace_db_2_spec.rb +55 -0
- data/spec/app/finders/interesting_files/xml_rpc_spec.rb +138 -0
- data/spec/app/finders/interesting_files_spec.rb +13 -0
- data/spec/app/formatters/cli_no_colour_spec.rb +17 -0
- data/spec/app/formatters/cli_spec.rb +21 -0
- data/spec/app/formatters/json_spec.rb +33 -0
- data/spec/app/models/fantastico_fileslist_spec.rb +32 -0
- data/spec/app/models/headers_spec.rb +52 -0
- data/spec/app/models/interesting_file_spec.rb +51 -0
- data/spec/app/models/robots_txt_spec.rb +28 -0
- data/spec/app/models/xml_rpc_spec.rb +47 -0
- data/spec/cache/.gitignore +4 -0
- data/spec/dummy_finders.rb +41 -0
- data/spec/fixtures/interesting_files/fantastico_fileslist/fantastico_fileslist.txt +12 -0
- data/spec/fixtures/interesting_files/file.txt +4 -0
- data/spec/fixtures/interesting_files/headers/interesting.txt +14 -0
- data/spec/fixtures/interesting_files/headers/no_interesting.txt +12 -0
- data/spec/fixtures/interesting_files/robots_txt/robots.txt +10 -0
- data/spec/fixtures/interesting_files/search_replace_db_2/searchreplacedb2.php +188 -0
- data/spec/fixtures/interesting_files/xml_rpc/homepage_in_scope_pingback.html +7 -0
- data/spec/fixtures/interesting_files/xml_rpc/homepage_out_of_scope_pingback.html +7 -0
- data/spec/fixtures/interesting_files/xml_rpc/xmlrpc.php +1 -0
- data/spec/fixtures/output.txt +0 -0
- data/spec/fixtures/target/platform/php/debug_log/debug.log +2 -0
- data/spec/fixtures/target/platform/php/fpd/wp_rss_functions.php +2 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/custom_w_spaces.html +10 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/default.html +14 -0
- data/spec/fixtures/target/platform/wordpress/custom_directories/https.html +12 -0
- data/spec/fixtures/target/platform/wordpress/detection/default.html +4 -0
- data/spec/fixtures/target/platform/wordpress/detection/not_wp.html +8 -0
- data/spec/fixtures/target/platform/wordpress/detection/wp_includes.html +3 -0
- data/spec/fixtures/target/server/apache/directory_listing/2.2.16.html +15 -0
- data/spec/fixtures/target/server/generic/server/apache/basic.txt +5 -0
- data/spec/fixtures/target/server/generic/server/iis/basic.txt +6 -0
- data/spec/fixtures/target/server/generic/server/not_detected.txt +3 -0
- data/spec/fixtures/target/server/iis/directory_listing/no_parent.html +3 -0
- data/spec/fixtures/target/server/iis/directory_listing/with_parent.html +3 -0
- data/spec/fixtures/views/base/ctrl/local.erb +1 -0
- data/spec/fixtures/views/base/ctrl/test.erb +3 -0
- data/spec/fixtures/views/base/global.erb +1 -0
- data/spec/fixtures/views/base/test.erb +2 -0
- data/spec/fixtures/views/based_format/test.erb +1 -0
- data/spec/fixtures/views/json/render_me.erb +4 -0
- data/spec/lib/browser_spec.rb +141 -0
- data/spec/lib/cache/file_store_spec.rb +101 -0
- data/spec/lib/cache/typhoeus_spec.rb +30 -0
- data/spec/lib/cms_scanner_spec.rb +45 -0
- data/spec/lib/controller_spec.rb +23 -0
- data/spec/lib/controllers_spec.rb +52 -0
- data/spec/lib/finders/findings_spec.rb +49 -0
- data/spec/lib/finders/independent_finders_spec.rb +98 -0
- data/spec/lib/formatter_spec.rb +136 -0
- data/spec/lib/sub_scanner_spec.rb +27 -0
- data/spec/lib/target/platforms_spec.rb +13 -0
- data/spec/lib/target/servers_spec.rb +13 -0
- data/spec/lib/target_spec.rb +50 -0
- data/spec/lib/web_site_spec.rb +124 -0
- data/spec/shared_examples.rb +11 -0
- data/spec/shared_examples/browser_actions.rb +32 -0
- data/spec/shared_examples/finding.rb +20 -0
- data/spec/shared_examples/formatter_buffer.rb +8 -0
- data/spec/shared_examples/formatter_class_methods.rb +26 -0
- data/spec/shared_examples/independent_finder.rb +33 -0
- data/spec/shared_examples/target/platform/php.rb +58 -0
- data/spec/shared_examples/target/platform/wordpress.rb +41 -0
- data/spec/shared_examples/target/platform/wordpress/custom_directories.rb +50 -0
- data/spec/shared_examples/target/server/apache.rb +33 -0
- data/spec/shared_examples/target/server/generic.rb +34 -0
- data/spec/shared_examples/target/server/iis.rb +38 -0
- data/spec/spec_helper.rb +41 -0
- metadata +432 -0
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'dummy_finders'
|
|
3
|
+
|
|
4
|
+
describe CMSScanner::Finders::Findings do
|
|
5
|
+
|
|
6
|
+
subject(:findings) { described_class.new }
|
|
7
|
+
let(:dummy) { CMSScanner::DummyFinding }
|
|
8
|
+
|
|
9
|
+
describe '#<<' do
|
|
10
|
+
after { expect(findings).to eq @expected }
|
|
11
|
+
|
|
12
|
+
context 'when empty array' do
|
|
13
|
+
it 'adds it' do
|
|
14
|
+
findings << 'empty-test'
|
|
15
|
+
@expected = %w(empty-test)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
context 'when not empty' do
|
|
20
|
+
let(:confirmed) { dummy.new('confirmed') }
|
|
21
|
+
|
|
22
|
+
before { findings << dummy.new('test') << confirmed }
|
|
23
|
+
|
|
24
|
+
it 'adds a confirmed result correctly' do
|
|
25
|
+
confirmed_dup = confirmed.dup
|
|
26
|
+
confirmed_dup.confidence = 100
|
|
27
|
+
|
|
28
|
+
findings << dummy.new('test2')
|
|
29
|
+
findings << confirmed_dup
|
|
30
|
+
|
|
31
|
+
confirmed.confirmed_by = confirmed_dup
|
|
32
|
+
|
|
33
|
+
@expected = [] << dummy.new('test') << confirmed << dummy.new('test2')
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
describe '#+' do
|
|
39
|
+
after { expect(findings).to eq @expected }
|
|
40
|
+
|
|
41
|
+
it 'adds it/them' do
|
|
42
|
+
# Dummy assignement to avoid the 'Operator used in void context'
|
|
43
|
+
_ = findings + %w(test1 test2)
|
|
44
|
+
|
|
45
|
+
@expected = %w(test1 test2)
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
end
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
require 'dummy_finders'
|
|
3
|
+
|
|
4
|
+
describe CMSScanner::Finders::IndependentFinders do
|
|
5
|
+
|
|
6
|
+
subject(:finders) { described_class.new }
|
|
7
|
+
|
|
8
|
+
describe '#run' do
|
|
9
|
+
let(:target) { 'target' }
|
|
10
|
+
let(:finding) { CMSScanner::DummyFinding }
|
|
11
|
+
let(:expected_aggressive) { finding.new('test', found_by: 'override', confidence: 100) }
|
|
12
|
+
let(:expected_passive) do
|
|
13
|
+
[
|
|
14
|
+
finding.new('test', found_by: 'DummyFinder (passive detection)'),
|
|
15
|
+
finding.new('spotted', found_by: 'NoAggressiveResult (passive detection)', confidence: 10)
|
|
16
|
+
]
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
before do
|
|
20
|
+
finders << CMSScanner::Finders::DummyFinder.new(target) <<
|
|
21
|
+
CMSScanner::Finders::NoAggressiveResult.new(target)
|
|
22
|
+
|
|
23
|
+
@found = finders.run(mode: mode)
|
|
24
|
+
|
|
25
|
+
expect(@found).to be_a(CMSScanner::Finders::Findings)
|
|
26
|
+
|
|
27
|
+
@found.each { |f| expect(f).to be_a finding }
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
context 'when :passive mode' do
|
|
31
|
+
let(:mode) { :passive }
|
|
32
|
+
|
|
33
|
+
it 'returns 2 results' do
|
|
34
|
+
expect(@found.size).to eq 2
|
|
35
|
+
expect(@found.first).to eql expected_passive.first
|
|
36
|
+
expect(@found.last).to eql expected_passive.last
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
context 'when :aggressive mode' do
|
|
41
|
+
let(:mode) { :aggressive }
|
|
42
|
+
|
|
43
|
+
it 'returns 1 result' do
|
|
44
|
+
expect(@found.size).to eq 1
|
|
45
|
+
expect(@found.first).to eql expected_aggressive
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
context 'when :mixed mode' do
|
|
50
|
+
let(:mode) { :mixed }
|
|
51
|
+
|
|
52
|
+
it 'returns 2 results' do
|
|
53
|
+
expect(@found.size).to eq 2
|
|
54
|
+
expect(@found.first).to eql expected_passive.first
|
|
55
|
+
expect(@found.first.confirmed_by).to eql [expected_aggressive]
|
|
56
|
+
expect(@found.last).to eql expected_passive.last
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
context 'when multiple results returned' do
|
|
61
|
+
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
describe '#symbols_from_mode' do
|
|
66
|
+
after { expect(finders.symbols_from_mode(@mode)).to eq @expected }
|
|
67
|
+
|
|
68
|
+
context 'when :mixed' do
|
|
69
|
+
it 'returns [:passive, :aggressive]' do
|
|
70
|
+
@mode = :mixed
|
|
71
|
+
@expected = [:passive, :aggressive]
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context 'when :passive or :aggresssive' do
|
|
76
|
+
[:passive, :aggressive].each do |symbol|
|
|
77
|
+
it 'returns it in an array' do
|
|
78
|
+
@mode = symbol
|
|
79
|
+
@expected = [*symbol]
|
|
80
|
+
end
|
|
81
|
+
end
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
context 'otherwise' do
|
|
85
|
+
it 'returns []' do
|
|
86
|
+
@mode = :unallowed
|
|
87
|
+
@expected = []
|
|
88
|
+
end
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
describe '#findings' do
|
|
93
|
+
it 'returns a Findings object' do
|
|
94
|
+
expect(finders.findings).to be_a CMSScanner::Finders::Findings
|
|
95
|
+
end
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
end
|
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# Test Module to check the correct inclusion of
|
|
4
|
+
# the class methods
|
|
5
|
+
module OtherFormatter
|
|
6
|
+
include CMSScanner::Formatter
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
[CMSScanner::Formatter, OtherFormatter].each do |f|
|
|
10
|
+
describe "#{f}" do
|
|
11
|
+
subject(:formatter) { f }
|
|
12
|
+
it_behaves_like CMSScanner::Formatter::ClassMethods
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
module CMSScanner
|
|
17
|
+
module Formatter
|
|
18
|
+
module Spec
|
|
19
|
+
# Base Format Test Class
|
|
20
|
+
class BasedFormat < Base
|
|
21
|
+
def base_format
|
|
22
|
+
'base'
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
describe CMSScanner::Formatter::Base do
|
|
30
|
+
|
|
31
|
+
subject(:formatter) { described_class.new }
|
|
32
|
+
|
|
33
|
+
describe '#format' do
|
|
34
|
+
its(:format) { should eq 'base' }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
describe '#render, output' do
|
|
38
|
+
before { formatter.views_directories << FIXTURES_VIEWS }
|
|
39
|
+
|
|
40
|
+
it 'renders the global template and does not override the @views_directories' do
|
|
41
|
+
expect($stdout).to receive(:puts)
|
|
42
|
+
.with("It Works!\nViews Dirs: #{formatter.views_directories}")
|
|
43
|
+
|
|
44
|
+
formatter.output('@test', test: 'Works!', views_directories: 'owned')
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
context 'when global and local rendering are used inside a template' do
|
|
48
|
+
it 'renders them correcly' do
|
|
49
|
+
rendered = formatter.render('test', { var: 'Works' }, 'ctrl')
|
|
50
|
+
|
|
51
|
+
expect(rendered).to eq "Test: Works\nLocal View\nGlobal View"
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it 'raises an error if the controller_name is nil and tpl is not a global one' do
|
|
56
|
+
expect { formatter.output('test') }.to raise_error('The controller_name can not be nil')
|
|
57
|
+
end
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
describe '#view_path' do
|
|
61
|
+
before do
|
|
62
|
+
formatter.views_directories << FIXTURES_VIEWS
|
|
63
|
+
formatter.render('local', {}, 'ctrl') # Used to set the @controller_name
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
context 'when the tpl format is invalid' do
|
|
67
|
+
let(:tpl) { '../try-this' }
|
|
68
|
+
|
|
69
|
+
it 'raises an error' do
|
|
70
|
+
expect { formatter.view_path(tpl) }.to raise_error("Wrong tpl format: 'ctrl/#{tpl}'")
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
context 'when the tpl is not found' do
|
|
75
|
+
let(:tpl) { 'not_there' }
|
|
76
|
+
|
|
77
|
+
it 'raises an error' do
|
|
78
|
+
expect { formatter.view_path(tpl) }.to raise_error("View not found for base/ctrl/#{tpl}")
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context 'when the tpl is found' do
|
|
83
|
+
after { expect(formatter.view_path(@tpl)).to eq @expected }
|
|
84
|
+
|
|
85
|
+
context 'if it\'s a global tpl' do
|
|
86
|
+
it 'returns its path' do
|
|
87
|
+
@expected = File.join(FIXTURES_VIEWS, 'base', 'test.erb')
|
|
88
|
+
@tpl = '@test'
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
context 'if it\s a local tpl' do
|
|
93
|
+
it 'retuns its path' do
|
|
94
|
+
@expected = File.join(FIXTURES_VIEWS, 'base', 'ctrl', 'local.erb')
|
|
95
|
+
@tpl = 'local'
|
|
96
|
+
end
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
context 'when base_format' do
|
|
101
|
+
subject(:formatter) { CMSScanner::Formatter::Spec::BasedFormat.new }
|
|
102
|
+
|
|
103
|
+
after { expect(formatter.view_path(@tpl)).to eq @expected }
|
|
104
|
+
|
|
105
|
+
context 'when the ovverided view exists' do
|
|
106
|
+
it 'returns it' do
|
|
107
|
+
@expected = File.join(FIXTURES_VIEWS, 'based_format', 'test.erb')
|
|
108
|
+
@tpl = '@test'
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it 'returns the base views otherwise' do
|
|
113
|
+
@expected = File.join(FIXTURES_VIEWS, 'base', 'ctrl', 'local.erb')
|
|
114
|
+
@tpl = 'local'
|
|
115
|
+
end
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
describe '#views_directories' do
|
|
121
|
+
let(:default_directories) { [APP_VIEWS] }
|
|
122
|
+
|
|
123
|
+
context 'when default directories' do
|
|
124
|
+
its(:views_directories) { should eq(default_directories) }
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
context 'when adding directories' do
|
|
128
|
+
it 'adds them' do
|
|
129
|
+
formatter.views_directories << 'testing'
|
|
130
|
+
|
|
131
|
+
expect(formatter.views_directories).to eq(default_directories << 'testing')
|
|
132
|
+
end
|
|
133
|
+
end
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
end
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
# Module included the CMSScanner to test its correct inclusion
|
|
4
|
+
module SubScanner
|
|
5
|
+
include CMSScanner
|
|
6
|
+
|
|
7
|
+
# This Target class should be called in the CMSScanner::Controller::Base
|
|
8
|
+
# instead of the CMSScanner::Target
|
|
9
|
+
class Target < CMSScanner::Target
|
|
10
|
+
def new_method
|
|
11
|
+
'working'
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
describe SubScanner::Scan do
|
|
17
|
+
subject(:scanner) { described_class.new }
|
|
18
|
+
let(:controller) { SubScanner::Controller }
|
|
19
|
+
|
|
20
|
+
it 'loads the overrided Target class' do
|
|
21
|
+
target = scanner.controllers.first.target
|
|
22
|
+
|
|
23
|
+
expect(target).to be_a SubScanner::Target
|
|
24
|
+
expect(target.respond_to?(:new_method)).to eq true
|
|
25
|
+
expect(target.new_method).to eq 'working'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
[:WordPress, :PHP].each do |platform|
|
|
4
|
+
describe CMSScanner::Target do
|
|
5
|
+
subject(:target) do
|
|
6
|
+
described_class.new(url).extend(described_class::Platform.const_get(platform))
|
|
7
|
+
end
|
|
8
|
+
let(:url) { 'http://ex.lo' }
|
|
9
|
+
let(:fixtures) { File.join(FIXTURES, 'target', 'platform', platform.to_s.downcase) }
|
|
10
|
+
|
|
11
|
+
it_behaves_like described_class::Platform.const_get(platform)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
[:Generic, :Apache, :IIS].each do |server|
|
|
4
|
+
describe CMSScanner::Target do
|
|
5
|
+
subject(:target) do
|
|
6
|
+
described_class.new(url).extend(described_class::Server.const_get(server))
|
|
7
|
+
end
|
|
8
|
+
let(:url) { 'http://ex.lo' }
|
|
9
|
+
let(:fixtures) { File.join(FIXTURES, 'target', 'server', server.to_s.downcase) }
|
|
10
|
+
|
|
11
|
+
it_behaves_like described_class::Server.const_get(server)
|
|
12
|
+
end
|
|
13
|
+
end
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::Target do
|
|
4
|
+
|
|
5
|
+
subject(:target) { described_class.new(url) }
|
|
6
|
+
let(:url) { 'http://ex.lo' }
|
|
7
|
+
|
|
8
|
+
describe '#in_scope?' do
|
|
9
|
+
after { expect(target.in_scope?(@url)).to eq @expected }
|
|
10
|
+
|
|
11
|
+
[nil, '', 'http://out-of-scope.com', '//jquery.com/j.js'].each do |url|
|
|
12
|
+
it "returns false for #{url}" do
|
|
13
|
+
@url = url
|
|
14
|
+
@expected = false
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
%w(https://ex.lo/file.txt http://ex.lo/ /relative).each do |url|
|
|
19
|
+
it "returns true for #{url}" do
|
|
20
|
+
@url = url
|
|
21
|
+
@expected = true
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
describe '#interesting_files' do
|
|
27
|
+
before do
|
|
28
|
+
expect(CMSScanner::Finders::InterestingFiles).to receive(:find).and_return(stubbed)
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
context 'when no findings' do
|
|
32
|
+
let(:stubbed) { [] }
|
|
33
|
+
|
|
34
|
+
its(:interesting_files) { should eq stubbed }
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
context 'when findings' do
|
|
38
|
+
let(:stubbed) { ['yolo'] }
|
|
39
|
+
|
|
40
|
+
it 'allows findings to be added with <<' do
|
|
41
|
+
expect(target.interesting_files).to eq stubbed
|
|
42
|
+
|
|
43
|
+
target.interesting_files << 'other-finding'
|
|
44
|
+
|
|
45
|
+
expect(target.interesting_files).to eq(stubbed << 'other-finding')
|
|
46
|
+
end
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
end
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
require 'spec_helper'
|
|
2
|
+
|
|
3
|
+
describe CMSScanner::WebSite do
|
|
4
|
+
|
|
5
|
+
subject(:web_site) { described_class.new(url) }
|
|
6
|
+
let(:url) { 'http://ex.lo' }
|
|
7
|
+
|
|
8
|
+
describe '#url=' do
|
|
9
|
+
context 'when the url is incorrect' do
|
|
10
|
+
|
|
11
|
+
after do
|
|
12
|
+
expect { web_site.url = @url }.to raise_error Addressable::URI::InvalidURIError
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
it 'raises an error if empty' do
|
|
16
|
+
@url = ''
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it 'raises an error if wrong format' do
|
|
20
|
+
@url = 'jj'
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
context 'when valid' do
|
|
25
|
+
it 'creates an Addressable object and adds a traling slash' do
|
|
26
|
+
web_site.url = 'http://site.com'
|
|
27
|
+
|
|
28
|
+
expect(web_site.url).to eq('http://site.com/')
|
|
29
|
+
expect(web_site.uri).to be_a Addressable::URI
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
describe '#url' do
|
|
35
|
+
context 'when no path argument' do
|
|
36
|
+
its(:url) { should eql 'http://ex.lo/' }
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
context 'when a path argument' do
|
|
40
|
+
it 'appends the path' do
|
|
41
|
+
expect(web_site.url('file.txt')).to eql "#{url}/file.txt"
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
context 'when relative path' do
|
|
45
|
+
let(:url) { 'http://ex.lo/dir/' }
|
|
46
|
+
|
|
47
|
+
it 'appends it from the host/domain' do
|
|
48
|
+
expect(web_site.url('/sub/file.txt')).to eql 'http://ex.lo/sub/file.txt'
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
describe '#online?' do
|
|
55
|
+
context 'when online' do
|
|
56
|
+
before { stub_request(:get, url).to_return(status: 200) }
|
|
57
|
+
|
|
58
|
+
it { should be_online }
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
context 'when offline' do
|
|
62
|
+
before { stub_request(:get, url).to_return(status: 0) }
|
|
63
|
+
|
|
64
|
+
it { should_not be_online }
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
describe '#http_auth?' do
|
|
69
|
+
context 'when http auth' do
|
|
70
|
+
before { stub_request(:get, url).to_return(status: 401) }
|
|
71
|
+
|
|
72
|
+
it { should be_http_auth }
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
context 'when no http auth' do
|
|
76
|
+
before { stub_request(:get, url).to_return(status: 200) }
|
|
77
|
+
|
|
78
|
+
it { should_not be_http_auth }
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
describe '#proxy_auth?' do
|
|
83
|
+
# Handled in app/controllers/core_spec
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
describe '#redirection' do
|
|
87
|
+
it 'returns nil if no redirection detected' do
|
|
88
|
+
stub_request(:get, web_site.url).to_return(status: 200, body: '')
|
|
89
|
+
|
|
90
|
+
expect(web_site.redirection).to be_nil
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
[301, 302].each do |status_code|
|
|
94
|
+
it "returns http://new-location.com if the status code is #{status_code}" do
|
|
95
|
+
new_location = 'http://new-location.com'
|
|
96
|
+
|
|
97
|
+
stub_request(:get, web_site.url)
|
|
98
|
+
.to_return(status: status_code, headers: { location: new_location })
|
|
99
|
+
|
|
100
|
+
stub_request(:get, new_location).to_return(status: 200)
|
|
101
|
+
|
|
102
|
+
expect(web_site.redirection).to eq new_location
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
context 'when multiple redirections' do
|
|
107
|
+
it 'returns the last redirection' do
|
|
108
|
+
first_redirection = 'www.redirection.com'
|
|
109
|
+
last_redirection = 'redirection.com'
|
|
110
|
+
|
|
111
|
+
stub_request(:get, web_site.url)
|
|
112
|
+
.to_return(status: 301, headers: { location: first_redirection })
|
|
113
|
+
|
|
114
|
+
stub_request(:get, first_redirection)
|
|
115
|
+
.to_return(status: 302, headers: { location: last_redirection })
|
|
116
|
+
|
|
117
|
+
stub_request(:get, last_redirection).to_return(status: 200)
|
|
118
|
+
|
|
119
|
+
expect(web_site.redirection).to eq last_redirection
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
end
|