cms_scanner 0.0.12 → 0.0.13
Sign up to get free protection for your applications and to get access to all the features.
- 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
|