cms_scanner 0.0.12 → 0.0.13
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 +4 -4
- data/app/controllers/interesting_files.rb +14 -1
- data/app/formatters/cli.rb +12 -0
- data/app/models/headers.rb +4 -3
- data/app/models/version.rb +1 -1
- data/app/views/cli/core/banner.erb +1 -0
- data/app/views/cli/core/started.erb +1 -0
- data/app/views/cli/interesting_files/findings.erb +1 -1
- data/cms_scanner.gemspec +1 -1
- data/lib/cms_scanner.rb +2 -2
- data/lib/cms_scanner/controllers.rb +1 -1
- data/lib/cms_scanner/finders/independent_finders.rb +1 -1
- data/lib/cms_scanner/finders/unique_finders.rb +17 -9
- data/lib/{helper.rb → cms_scanner/helper.rb} +0 -0
- data/lib/cms_scanner/target/scope.rb +9 -18
- data/lib/cms_scanner/version.rb +1 -1
- data/lib/cms_scanner/vulnerability.rb +35 -0
- data/lib/cms_scanner/vulnerability/references.rb +104 -0
- data/spec/app/controllers/interesting_files_spec.rb +27 -5
- data/spec/app/formatters/cli_spec.rb +13 -1
- data/spec/app/models/version_spec.rb +10 -0
- data/spec/dummy_independent_finders.rb +2 -1
- data/spec/dummy_unique_finders.rb +2 -1
- data/spec/fixtures/target/scope/index.html +3 -0
- data/spec/lib/finders/unique_finders_spec.rb +50 -6
- data/spec/lib/target/scope_spec.rb +5 -3
- data/spec/lib/vulnerability/references_spec.rb +63 -0
- data/spec/lib/vulnerability_spec.rb +27 -0
- metadata +12 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 86ad29d942ae76af1543da17f8f8e9ffa73f0373
|
4
|
+
data.tar.gz: bebf3711223c587954b4b4c2f852af89afc1192e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a476cb2079b4633e3a672415952fb420cc55359a5cc4438bc7cd0e8dd4556d7a03ec4769c40a3a1f536ae7b2696e5213470c84136e78db249ae638b3e4a13bd2
|
7
|
+
data.tar.gz: db601c31e7d60b95f1b56b7b0a903ac83cef5966b81c4737e74f4d7e1019ad508245ccb82b11cbb4b9ab9bd662789002b3f4f26f2209d58f8145b8da0cd477eb
|
@@ -2,8 +2,21 @@ module CMSScanner
|
|
2
2
|
module Controller
|
3
3
|
# InterestingFiles Controller
|
4
4
|
class InterestingFiles < Base
|
5
|
+
def cli_options
|
6
|
+
[
|
7
|
+
OptChoice.new(
|
8
|
+
['--interesting-files-detection MODE',
|
9
|
+
'Use the supplied mode for the interesting files detection. ' \
|
10
|
+
'Modes: mixed, passive, aggressive'
|
11
|
+
],
|
12
|
+
choices: %w(mixed passive aggressive),
|
13
|
+
normalize: :to_sym)
|
14
|
+
]
|
15
|
+
end
|
16
|
+
|
5
17
|
def run
|
6
|
-
|
18
|
+
mode = parsed_options[:interesting_files_detection] || parsed_options[:detection_mode]
|
19
|
+
findings = target.interesting_files(mode: mode)
|
7
20
|
|
8
21
|
output('findings', findings: findings) unless findings.empty?
|
9
22
|
end
|
data/app/formatters/cli.rb
CHANGED
@@ -2,6 +2,10 @@ module CMSScanner
|
|
2
2
|
module Formatter
|
3
3
|
# CLI Formatter
|
4
4
|
class Cli < Base
|
5
|
+
def bold(text)
|
6
|
+
colorize(text, 1)
|
7
|
+
end
|
8
|
+
|
5
9
|
def red(text)
|
6
10
|
colorize(text, 31)
|
7
11
|
end
|
@@ -10,6 +14,14 @@ module CMSScanner
|
|
10
14
|
colorize(text, 32)
|
11
15
|
end
|
12
16
|
|
17
|
+
def amber(text)
|
18
|
+
colorize(text, 33)
|
19
|
+
end
|
20
|
+
|
21
|
+
def blue(text)
|
22
|
+
colorize(text, 34)
|
23
|
+
end
|
24
|
+
|
13
25
|
def colorize(text, color_code)
|
14
26
|
"\e[#{color_code}m#{text}\e[0m"
|
15
27
|
end
|
data/app/models/headers.rb
CHANGED
@@ -24,9 +24,10 @@ module CMSScanner
|
|
24
24
|
def known_headers
|
25
25
|
%w(
|
26
26
|
age accept-ranges cache-control content-type content-length connection date etag expires
|
27
|
-
location last-modified link pragma set-cookie strict-transport-security
|
28
|
-
vary x-cache x-content-security-policy x-content-type-options
|
29
|
-
x-permitted-cross-domain-policies x-pingback x-varnish
|
27
|
+
keep-alive location last-modified link pragma set-cookie strict-transport-security
|
28
|
+
transfer-encoding vary x-cache x-content-security-policy x-content-type-options
|
29
|
+
x-frame-options x-language x-permitted-cross-domain-policies x-pingback x-varnish
|
30
|
+
x-webkit-csp x-xss-protection
|
30
31
|
)
|
31
32
|
end
|
32
33
|
|
data/app/models/version.rb
CHANGED
@@ -0,0 +1 @@
|
|
1
|
+
<% # Empty file, the banner should be implemented in each scanner %>
|
data/cms_scanner.gemspec
CHANGED
@@ -32,7 +32,7 @@ Gem::Specification.new do |s|
|
|
32
32
|
s.add_development_dependency 'rspec', '~> 3.2'
|
33
33
|
s.add_development_dependency 'rspec-its', '~> 1.1'
|
34
34
|
s.add_development_dependency 'bundler', '~> 1.6'
|
35
|
-
s.add_development_dependency 'rubocop', '~> 0.
|
35
|
+
s.add_development_dependency 'rubocop', '~> 0.29'
|
36
36
|
s.add_development_dependency 'webmock', '~> 1.20'
|
37
37
|
s.add_development_dependency 'simplecov', '~> 0.9'
|
38
38
|
end
|
data/lib/cms_scanner.rb
CHANGED
@@ -9,12 +9,11 @@ require 'public_suffix'
|
|
9
9
|
require 'erb'
|
10
10
|
require 'fileutils'
|
11
11
|
require 'pathname'
|
12
|
-
# Helpers
|
13
|
-
require 'helper'
|
14
12
|
# Monkey Patches
|
15
13
|
require 'cms_scanner/typhoeus/response'
|
16
14
|
require 'cms_scanner/public_suffix/domain'
|
17
15
|
# Custom Libs
|
16
|
+
require 'cms_scanner/helper'
|
18
17
|
require 'cms_scanner/errors/auth_errors'
|
19
18
|
require 'cms_scanner/cache/typhoeus'
|
20
19
|
require 'cms_scanner/target'
|
@@ -24,6 +23,7 @@ require 'cms_scanner/controller'
|
|
24
23
|
require 'cms_scanner/controllers'
|
25
24
|
require 'cms_scanner/formatter'
|
26
25
|
require 'cms_scanner/finders'
|
26
|
+
require 'cms_scanner/vulnerability'
|
27
27
|
|
28
28
|
# Module
|
29
29
|
module CMSScanner
|
@@ -7,32 +7,40 @@ module CMSScanner
|
|
7
7
|
# returned the best finding
|
8
8
|
class UniqueFinders < IndependentFinders
|
9
9
|
# @param [ Hash ] opts
|
10
|
-
# @option opts [ Symbol ] mode :mixed, :passive or :aggressive
|
10
|
+
# @option opts [ Symbol ] :mode :mixed, :passive or :aggressive
|
11
11
|
# @option opts [ Int ] :confidence_threshold If a finding's confidence reaches this value,
|
12
12
|
# it will be returned as the best finding.
|
13
13
|
# Default is 100.
|
14
14
|
# If <= 0, all finders will be ran.
|
15
15
|
#
|
16
|
-
# @return [ Object ]
|
16
|
+
# @return [ Object ] The best finding
|
17
17
|
def run(opts = {})
|
18
18
|
opts[:confidence_threshold] ||= 100
|
19
19
|
|
20
20
|
symbols_from_mode(opts[:mode]).each do |symbol|
|
21
21
|
each do |finder|
|
22
|
-
[*finder.send(symbol, opts)].each
|
23
|
-
findings << found
|
24
|
-
end
|
22
|
+
[*finder.send(symbol, opts)].compact.each { |found| findings << found }
|
25
23
|
|
26
24
|
next if opts[:confidence_threshold] <= 0
|
27
25
|
|
28
|
-
findings.each
|
29
|
-
return f if f.confidence >= opts[:confidence_threshold]
|
30
|
-
end
|
26
|
+
findings.each { |f| return f if f.confidence >= opts[:confidence_threshold] }
|
31
27
|
end
|
32
28
|
end
|
33
29
|
|
30
|
+
best_finding(findings)
|
31
|
+
end
|
32
|
+
|
33
|
+
# @param [ Array<Object> ] findings
|
34
|
+
#
|
35
|
+
# @return [ Object ] The best finding
|
36
|
+
def best_finding(findings)
|
34
37
|
# results are sorted by confidence ASC
|
35
|
-
findings.sort_by(&:confidence)
|
38
|
+
findings.sort_by!(&:confidence)
|
39
|
+
|
40
|
+
# If all findings have the same confidence, nil is returned
|
41
|
+
return if findings.size > 1 && findings.first.confidence == findings.last.confidence
|
42
|
+
|
43
|
+
findings.last
|
36
44
|
end
|
37
45
|
end
|
38
46
|
end
|
File without changes
|
@@ -6,21 +6,11 @@ module CMSScanner
|
|
6
6
|
@scope ||= Scope.new
|
7
7
|
end
|
8
8
|
|
9
|
-
#
|
10
|
-
# e.g: Addressable::URI.parse('//file').host => file
|
11
|
-
#
|
12
|
-
# Idea: parse the // with PublicSuffix to see if a valid
|
13
|
-
# domain is used
|
14
|
-
#
|
15
|
-
# @param [ String ] url
|
9
|
+
# @param [ String ] url An absolute URL
|
16
10
|
#
|
17
11
|
# @return [ Boolean ] true if the url given is in scope
|
18
12
|
def in_scope?(url)
|
19
|
-
url.strip
|
20
|
-
|
21
|
-
return true if url[0, 1] == '/' && url[1, 1] != '/'
|
22
|
-
|
23
|
-
scope.include?(Addressable::URI.parse(url).host)
|
13
|
+
scope.include?(Addressable::URI.parse(url.strip).host)
|
24
14
|
rescue
|
25
15
|
false
|
26
16
|
end
|
@@ -35,15 +25,16 @@ module CMSScanner
|
|
35
25
|
|
36
26
|
res.html.xpath(xpath).each do |tag|
|
37
27
|
attributes.each do |attribute|
|
38
|
-
|
28
|
+
attr_value = tag[attribute]
|
29
|
+
|
30
|
+
next unless attr_value && !attr_value.empty?
|
39
31
|
|
40
|
-
|
32
|
+
url = uri.join(attr_value.strip).to_s
|
41
33
|
|
42
|
-
|
43
|
-
attr_value = uri.join(attr_value).to_s unless attr_value =~ /\Ahttps?/i
|
34
|
+
next unless in_scope?(url)
|
44
35
|
|
45
|
-
yield
|
46
|
-
found <<
|
36
|
+
yield url if block_given? && !found.include?(url)
|
37
|
+
found << url
|
47
38
|
end
|
48
39
|
end
|
49
40
|
|
data/lib/cms_scanner/version.rb
CHANGED
@@ -0,0 +1,35 @@
|
|
1
|
+
require 'cms_scanner/vulnerability/references'
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
# Generic Vulnerability
|
5
|
+
class Vulnerability
|
6
|
+
attr_reader :title, :references, :type, :fixed_in
|
7
|
+
|
8
|
+
# @param [ String ] title
|
9
|
+
# @param [ Hash ] references
|
10
|
+
# @option references [ Array<String>, String ] cve
|
11
|
+
# @option references [ Array<String>, String ] secunia
|
12
|
+
# @option references [ Array<String>, String ] osvdb
|
13
|
+
# @option references [ Array<String>, String ] exploitdb
|
14
|
+
# @option references [ Array<String> ] url URL(s) to related advisories etc
|
15
|
+
# @option references [ Array<String>, String ] metasploit The related metasploit module(s)
|
16
|
+
# @param [ String ] type
|
17
|
+
# @param [ String ] fixed_in
|
18
|
+
def initialize(title, references = {}, type = nil, fixed_in = nil)
|
19
|
+
@title = title
|
20
|
+
@references = references
|
21
|
+
@type = type
|
22
|
+
@fixed_in = fixed_in
|
23
|
+
end
|
24
|
+
|
25
|
+
# param [ Vulnerability ] other
|
26
|
+
#
|
27
|
+
# @return [ Boolean ]
|
28
|
+
def ==(other)
|
29
|
+
title == other.title &&
|
30
|
+
type == other.type &&
|
31
|
+
references == other.references &&
|
32
|
+
fixed_in == other.fixed_in
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module CMSScanner
|
2
|
+
# References related to the vulnerability
|
3
|
+
class Vulnerability
|
4
|
+
# @return [ Array<String> ] All the references URLs
|
5
|
+
def references_urls
|
6
|
+
cve_urls + secunia_urls + osvdb_urls + exploitdb_urls + msf_urls + packetstorm_urls
|
7
|
+
end
|
8
|
+
|
9
|
+
# @return [ Array<String> ] The CVEs
|
10
|
+
def cves
|
11
|
+
@cve ||= [*references[:cve]].map(&:to_s)
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [ Array<String> ]
|
15
|
+
def cve_urls
|
16
|
+
cves.reduce([]) { |a, e| a << cve_url(e) }
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [ String ] The URL to the CVE
|
20
|
+
def cve_url(cve)
|
21
|
+
"http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-#{cve}"
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [ Array<String> ] The Secunia IDs
|
25
|
+
def secunia_ids
|
26
|
+
@secunia_ids ||= [*references[:secunia]].map(&:to_s)
|
27
|
+
end
|
28
|
+
|
29
|
+
# @return [ Array<String> ]
|
30
|
+
def secunia_urls
|
31
|
+
secunia_ids.reduce([]) { |a, e| a << secunia_url(e) }
|
32
|
+
end
|
33
|
+
|
34
|
+
# @return [ String ] The URL to the Secunia advisory
|
35
|
+
def secunia_url(id)
|
36
|
+
"https://secunia.com/advisories/#{id}"
|
37
|
+
end
|
38
|
+
|
39
|
+
# @return [ Array<String> ] The OSVDB IDs
|
40
|
+
def osvdb_ids
|
41
|
+
@osvdb_ids ||= [*references[:osvdb]].map(&:to_s)
|
42
|
+
end
|
43
|
+
|
44
|
+
# @return [ Array<String> ]
|
45
|
+
def osvdb_urls
|
46
|
+
osvdb_ids.reduce([]) { |a, e| a << osvdb_url(e) }
|
47
|
+
end
|
48
|
+
|
49
|
+
# @return [ String ] The URL to the ExploitDB advisory
|
50
|
+
def osvdb_url(id)
|
51
|
+
"http://osvdb.org/#{id}"
|
52
|
+
end
|
53
|
+
|
54
|
+
# @return [ Array<String> ] The ExploitDB ID
|
55
|
+
def exploitdb_ids
|
56
|
+
@exploitdb_ids ||= [*references[:exploitdb]].map(&:to_s)
|
57
|
+
end
|
58
|
+
|
59
|
+
# @return [ Array<String> ]
|
60
|
+
def exploitdb_urls
|
61
|
+
exploitdb_ids.reduce([]) { |a, e| a << exploitdb_url(e) }
|
62
|
+
end
|
63
|
+
|
64
|
+
# @return [ String ]
|
65
|
+
def exploitdb_url(id)
|
66
|
+
"http://www.exploit-db.com/exploits/#{id}/"
|
67
|
+
end
|
68
|
+
|
69
|
+
# @return [ String<Array> ]
|
70
|
+
def urls
|
71
|
+
@urls ||= [*references[:url]].map(&:to_s)
|
72
|
+
end
|
73
|
+
|
74
|
+
# @return [ Array<String> ] The metasploit modules
|
75
|
+
def msf_modules
|
76
|
+
@msf_modules ||= [*references[:metasploit]].map(&:to_s)
|
77
|
+
end
|
78
|
+
|
79
|
+
# @return [ Array<String> ]
|
80
|
+
def msf_urls
|
81
|
+
msf_modules.reduce([]) { |a, e| a << msf_url(e) }
|
82
|
+
end
|
83
|
+
|
84
|
+
# @return [ String ] The URL to the metasploit module page
|
85
|
+
def msf_url(mod)
|
86
|
+
"http://www.rapid7.com/db/modules/#{mod.sub(/^\//, '')}"
|
87
|
+
end
|
88
|
+
|
89
|
+
# @return [ Array<String> ] The Packetstormsecurity ID
|
90
|
+
def packetstorm_ids
|
91
|
+
@packetstorm_ids ||= [*references[:packetstorm]].map(&:to_s)
|
92
|
+
end
|
93
|
+
|
94
|
+
# @return [ Array<String> ]
|
95
|
+
def packetstorm_urls
|
96
|
+
packetstorm_ids.reduce([]) { |a, e| a << packetstorm_url(e) }
|
97
|
+
end
|
98
|
+
|
99
|
+
# @return [ String ]
|
100
|
+
def packetstorm_url(id)
|
101
|
+
"http://packetstormsecurity.com/files/#{id}/"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -10,30 +10,52 @@ describe CMSScanner::Controller::InterestingFiles do
|
|
10
10
|
described_class.parsed_options = parsed_options
|
11
11
|
end
|
12
12
|
|
13
|
-
its(:cli_options) { should be_nil }
|
14
13
|
its(:before_scan) { should be_nil }
|
15
14
|
its(:after_scan) { should be_nil }
|
16
15
|
|
16
|
+
describe '#cli_options' do
|
17
|
+
its(:cli_options) { should_not be_empty }
|
18
|
+
its(:cli_options) { should be_a Array }
|
19
|
+
|
20
|
+
it 'contains to correct options' do
|
21
|
+
expect(controller.cli_options.map(&:to_sym)).to eq [:interesting_files_detection]
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
17
25
|
describe '#run' do
|
18
26
|
before do
|
19
27
|
expect(controller.target).to receive(:interesting_files)
|
20
|
-
.with(
|
28
|
+
.with(
|
29
|
+
mode: parsed_options[:interesting_files_detection] || parsed_options[:detection_mode]
|
30
|
+
).and_return(stubbed)
|
21
31
|
end
|
32
|
+
|
22
33
|
after { controller.run }
|
23
34
|
|
24
35
|
[:mixed, :passive, :aggressive].each do |mode|
|
25
|
-
context "when #{mode}
|
36
|
+
context "when --detection-mode #{mode}" do
|
26
37
|
let(:parsed_options) { super().merge(detection_mode: mode) }
|
27
38
|
|
28
39
|
context 'when no findings' do
|
29
40
|
let(:stubbed) { [] }
|
30
41
|
|
42
|
+
before { expect(controller.formatter).to_not receive(:output) }
|
43
|
+
|
31
44
|
it 'does not call the formatter' do
|
32
|
-
|
45
|
+
# Handled by the before statements above
|
46
|
+
end
|
47
|
+
|
48
|
+
context 'when --interesting-files-detection mode supplied' do
|
49
|
+
let(:parsed_options) do
|
50
|
+
super().merge(interesting_files_detection: :passive)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'gives the correct detection paramter' do
|
54
|
+
# Handled by before/after statements
|
55
|
+
end
|
33
56
|
end
|
34
57
|
end
|
35
58
|
|
36
|
-
# TODO: Test the output with a dummy finding ?
|
37
59
|
context 'when findings' do
|
38
60
|
let(:stubbed) { ['yolo'] }
|
39
61
|
|
@@ -7,7 +7,11 @@ describe CMSScanner::Formatter::Cli do
|
|
7
7
|
its(:format) { should eq 'cli' }
|
8
8
|
end
|
9
9
|
|
10
|
-
describe '#
|
10
|
+
describe '#bold, #red, #green, #amber, #blue, #colorize' do
|
11
|
+
it 'returns the correct bold string' do
|
12
|
+
expect(formatter.bold('Text')).to eq "\e[1mText\e[0m"
|
13
|
+
end
|
14
|
+
|
11
15
|
it 'returns the correct red string' do
|
12
16
|
expect(formatter.red('Text')).to eq "\e[31mText\e[0m"
|
13
17
|
end
|
@@ -15,5 +19,13 @@ describe CMSScanner::Formatter::Cli do
|
|
15
19
|
it 'returns the correct green string' do
|
16
20
|
expect(formatter.green('Another Text')).to eq "\e[32mAnother Text\e[0m"
|
17
21
|
end
|
22
|
+
|
23
|
+
it 'returns the correct amber string' do
|
24
|
+
expect(formatter.amber('Text')).to eq "\e[33mText\e[0m"
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'returns the correct blue string' do
|
28
|
+
expect(formatter.blue('Text')).to eq "\e[34mText\e[0m"
|
29
|
+
end
|
18
30
|
end
|
19
31
|
end
|
@@ -7,6 +7,16 @@ describe CMSScanner::Version do
|
|
7
7
|
let(:opts) { {} }
|
8
8
|
let(:number) { '1.0' }
|
9
9
|
|
10
|
+
describe '#number' do
|
11
|
+
its(:number) { should eql '1.0' }
|
12
|
+
|
13
|
+
context 'when float number supplied' do
|
14
|
+
let(:number) { 2.0 }
|
15
|
+
|
16
|
+
its(:number) { should eq '2.0' }
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
10
20
|
describe '#==' do
|
11
21
|
context 'when same @number' do
|
12
22
|
it 'returns true' do
|
@@ -6,7 +6,8 @@ module CMSScanner
|
|
6
6
|
# Dummy Test Finder
|
7
7
|
class DummyFinder < Finder
|
8
8
|
def passive(_opts = {})
|
9
|
-
|
9
|
+
# the nil is there to ensure such value is ignored
|
10
|
+
[DummyFinding.new('test', found_by: found_by), nil]
|
10
11
|
end
|
11
12
|
|
12
13
|
def aggressive(_opts = {})
|
@@ -6,7 +6,8 @@ module CMSScanner
|
|
6
6
|
# Dummy Test Finder
|
7
7
|
class Dummy < Finder
|
8
8
|
def passive(_opts = {})
|
9
|
-
|
9
|
+
# the nil is there to ensure such value is ignored
|
10
|
+
[DummyFinding.new('v1', found_by: found_by), nil]
|
10
11
|
end
|
11
12
|
|
12
13
|
def aggressive(_opts = {})
|
@@ -1,6 +1,9 @@
|
|
1
1
|
<a href="http://e.org/f.txt">Link</a>
|
2
2
|
<a href="http://e.org/f.txt">Link</a> <!-- Duplicates should be ignored -->
|
3
3
|
|
4
|
+
<a href="mailto:mail@g.com">eMail me!</a>
|
5
|
+
<a href="jaVaScript:alert(2)">Click me Fool !</a>
|
6
|
+
|
4
7
|
<script src=" https://cdn.e.org/f2.js "></script> <!-- head & tail spaces should be removed -->
|
5
8
|
|
6
9
|
<script src="/script/s.js"></script>
|
@@ -2,13 +2,57 @@ require 'spec_helper'
|
|
2
2
|
require 'dummy_unique_finders'
|
3
3
|
|
4
4
|
describe CMSScanner::Finders::UniqueFinders do
|
5
|
-
subject(:finders)
|
5
|
+
subject(:finders) { described_class.new }
|
6
|
+
let(:unique_finders) { CMSScanner::Finders::Unique }
|
7
|
+
|
8
|
+
describe '#best_finding' do
|
9
|
+
let(:findings) { [] }
|
10
|
+
|
11
|
+
after { expect(finders.best_finding(findings)).to eql @expected }
|
12
|
+
|
13
|
+
context 'when no findings' do
|
14
|
+
it 'returns nil' do
|
15
|
+
@expected = nil
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
context 'when one finding' do
|
20
|
+
let(:findings) { [CMSScanner::DummyFinding.new('one', confidence: 40)] }
|
21
|
+
|
22
|
+
it 'returns it' do
|
23
|
+
@expected = findings[0]
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context 'when multiple findings' do
|
28
|
+
let(:findings) do
|
29
|
+
(1..5).reduce([]) { |a, e| a << CMSScanner::DummyFinding.new(e, confidence: 20) }
|
30
|
+
end
|
31
|
+
|
32
|
+
context 'when they have the same confidence' do
|
33
|
+
it 'returns nil' do
|
34
|
+
@expected = nil
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'when there is a best confidence' do
|
39
|
+
(0..4).each do |position|
|
40
|
+
context "when at [#{position}]" do
|
41
|
+
it 'returns it' do
|
42
|
+
findings[position].confidence = 100
|
43
|
+
|
44
|
+
@expected = findings[position]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
6
51
|
|
7
52
|
describe '#run' do
|
8
|
-
let(:target)
|
9
|
-
let(:finding)
|
10
|
-
let(:
|
11
|
-
let(:opts) { {} }
|
53
|
+
let(:target) { 'target' }
|
54
|
+
let(:finding) { CMSScanner::DummyFinding }
|
55
|
+
let(:opts) { {} }
|
12
56
|
|
13
57
|
before do
|
14
58
|
finders <<
|
@@ -20,7 +64,7 @@ describe CMSScanner::Finders::UniqueFinders do
|
|
20
64
|
after do
|
21
65
|
result = finders.run(opts)
|
22
66
|
|
23
|
-
expect(result).to be_a finding
|
67
|
+
expect(result).to be_a finding if @expected
|
24
68
|
expect(result).to eql @expected
|
25
69
|
end
|
26
70
|
|
@@ -31,13 +31,15 @@ describe CMSScanner::Target do
|
|
31
31
|
|
32
32
|
describe '#in_scope?' do
|
33
33
|
context 'when default scope (target domain)' do
|
34
|
-
[nil, '', 'http://out-of-scope.com', '//jquery.com/j.js'
|
34
|
+
[nil, '', 'http://out-of-scope.com', '//jquery.com/j.js',
|
35
|
+
'javascript:alert(3)', 'mailto:p@g.com'
|
36
|
+
].each do |url|
|
35
37
|
it "returns false for #{url}" do
|
36
38
|
expect(target.in_scope?(url)).to eql false
|
37
39
|
end
|
38
40
|
end
|
39
41
|
|
40
|
-
%w(https://e.org/file.txt http://e.org/
|
42
|
+
%w(https://e.org/file.txt http://e.org/ //e.org).each do |url|
|
41
43
|
it "returns true for #{url}" do
|
42
44
|
expect(target.in_scope?(url)).to eql true
|
43
45
|
end
|
@@ -53,7 +55,7 @@ describe CMSScanner::Target do
|
|
53
55
|
end
|
54
56
|
end
|
55
57
|
|
56
|
-
%w(
|
58
|
+
%w(http://e.org //cdn.e.org/f.txt http://s.e.org/ https://192.168.1.12/h).each do |url|
|
57
59
|
it "returns true for #{url}" do
|
58
60
|
expect(target.in_scope?(url)).to eql true
|
59
61
|
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CMSScanner::Vulnerability do
|
4
|
+
subject(:vuln) { described_class.new(title, references) }
|
5
|
+
let(:title) { 'Test Vuln' }
|
6
|
+
let(:references) { {} }
|
7
|
+
|
8
|
+
describe '#new' do
|
9
|
+
context 'when no references' do
|
10
|
+
[:cves, :secunia_ids, :osvdb_ids, :exploitdb_ids, :urls,
|
11
|
+
:msf_modules, :packetstorm_ids
|
12
|
+
].each do |attribute|
|
13
|
+
its(attribute) { should eql([]) }
|
14
|
+
end
|
15
|
+
|
16
|
+
[:cve_urls, :secunia_urls, :osvdb_urls, :exploitdb_urls, :msf_urls,
|
17
|
+
:packetstorm_urls
|
18
|
+
].each do |attribute|
|
19
|
+
its(attribute) { should eql([]) }
|
20
|
+
end
|
21
|
+
|
22
|
+
its(:references_urls) { should eql([]) }
|
23
|
+
end
|
24
|
+
|
25
|
+
context 'when references provided as string' do
|
26
|
+
let(:references) do
|
27
|
+
{
|
28
|
+
cve: 11,
|
29
|
+
secunia: 12,
|
30
|
+
osvdb: 13,
|
31
|
+
exploitdb: 14,
|
32
|
+
url: 'single-url',
|
33
|
+
metasploit: '/exploit/yolo',
|
34
|
+
packetstorm: 15
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
its(:cves) { should eql %w(11) }
|
39
|
+
its(:cve_urls) { should eql %w(http://web.nvd.nist.gov/view/vuln/detail?vulnId=CVE-11) }
|
40
|
+
|
41
|
+
its(:secunia_ids) { should eql %w(12) }
|
42
|
+
its(:secunia_urls) { should eql %w(https://secunia.com/advisories/12) }
|
43
|
+
|
44
|
+
its(:osvdb_ids) { should eql %w(13) }
|
45
|
+
its(:osvdb_urls) { should eql %w(http://osvdb.org/13) }
|
46
|
+
|
47
|
+
its(:exploitdb_ids) { should eql %w(14) }
|
48
|
+
its(:exploitdb_urls) { should eql %w(http://www.exploit-db.com/exploits/14/) }
|
49
|
+
|
50
|
+
its(:urls) { should eql %w(single-url) }
|
51
|
+
|
52
|
+
its(:msf_modules) { should eql %w(/exploit/yolo) }
|
53
|
+
its(:msf_urls) { should eql %w(http://www.rapid7.com/db/modules/exploit/yolo) }
|
54
|
+
|
55
|
+
its(:packetstorm_ids) { should eq %w(15) }
|
56
|
+
its(:packetstorm_urls) { should eql %w(http://packetstormsecurity.com/files/15/) }
|
57
|
+
end
|
58
|
+
|
59
|
+
context 'when references provided as array' do
|
60
|
+
xit
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe CMSScanner::Vulnerability do
|
4
|
+
subject(:vuln) { described_class.new(title) }
|
5
|
+
let(:title) { 'Test Vuln' }
|
6
|
+
|
7
|
+
describe '#new' do
|
8
|
+
its(:title) { should eql title }
|
9
|
+
its(:references) { should eql({}) }
|
10
|
+
its(:type) { should eql nil }
|
11
|
+
its(:fixed_in) { should eql nil }
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '#==' do
|
15
|
+
context 'when te same vuln' do
|
16
|
+
it 'returns true' do
|
17
|
+
expect(vuln).to eq vuln.dup
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
context 'when not equal' do
|
22
|
+
it 'returns false' do
|
23
|
+
expect(vuln).to_not eq described_class.new('not eq')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cms_scanner
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- WPScanTeam - Erwan Le Rousseau
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: opt_parse_validator
|
@@ -156,14 +156,14 @@ dependencies:
|
|
156
156
|
requirements:
|
157
157
|
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
|
-
version: '0.
|
159
|
+
version: '0.29'
|
160
160
|
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
164
|
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
|
-
version: '0.
|
166
|
+
version: '0.29'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
168
|
name: webmock
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -230,6 +230,7 @@ files:
|
|
230
230
|
- app/models/robots_txt.rb
|
231
231
|
- app/models/version.rb
|
232
232
|
- app/models/xml_rpc.rb
|
233
|
+
- app/views/cli/core/banner.erb
|
233
234
|
- app/views/cli/core/finished.erb
|
234
235
|
- app/views/cli/core/started.erb
|
235
236
|
- app/views/cli/interesting_files/_array.erb
|
@@ -262,6 +263,7 @@ files:
|
|
262
263
|
- lib/cms_scanner/finders/unique_finders.rb
|
263
264
|
- lib/cms_scanner/formatter.rb
|
264
265
|
- lib/cms_scanner/formatter/buffer.rb
|
266
|
+
- lib/cms_scanner/helper.rb
|
265
267
|
- lib/cms_scanner/public_suffix/domain.rb
|
266
268
|
- lib/cms_scanner/target.rb
|
267
269
|
- lib/cms_scanner/target/hashes.rb
|
@@ -274,8 +276,9 @@ files:
|
|
274
276
|
- lib/cms_scanner/target/server/iis.rb
|
275
277
|
- lib/cms_scanner/typhoeus/response.rb
|
276
278
|
- lib/cms_scanner/version.rb
|
279
|
+
- lib/cms_scanner/vulnerability.rb
|
280
|
+
- lib/cms_scanner/vulnerability/references.rb
|
277
281
|
- lib/cms_scanner/web_site.rb
|
278
|
-
- lib/helper.rb
|
279
282
|
- spec/app/controllers/core_spec.rb
|
280
283
|
- spec/app/controllers/interesting_files_spec.rb
|
281
284
|
- spec/app/finders/interesting_files/fantastico_fileslist_spec.rb
|
@@ -344,6 +347,8 @@ files:
|
|
344
347
|
- spec/lib/target/scope_spec.rb
|
345
348
|
- spec/lib/target/servers_spec.rb
|
346
349
|
- spec/lib/target_spec.rb
|
350
|
+
- spec/lib/vulnerability/references_spec.rb
|
351
|
+
- spec/lib/vulnerability_spec.rb
|
347
352
|
- spec/lib/web_site_spec.rb
|
348
353
|
- spec/output/core/finished.cli_no_colour
|
349
354
|
- spec/output/core/finished.json
|
@@ -459,6 +464,8 @@ test_files:
|
|
459
464
|
- spec/lib/target/scope_spec.rb
|
460
465
|
- spec/lib/target/servers_spec.rb
|
461
466
|
- spec/lib/target_spec.rb
|
467
|
+
- spec/lib/vulnerability/references_spec.rb
|
468
|
+
- spec/lib/vulnerability_spec.rb
|
462
469
|
- spec/lib/web_site_spec.rb
|
463
470
|
- spec/output/core/finished.cli_no_colour
|
464
471
|
- spec/output/core/finished.json
|