cms_scanner 0.0.43.2 → 0.0.44.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/app/controllers/core.rb +10 -10
- data/app/controllers/core/cli_options.rb +4 -1
- data/app/controllers/interesting_findings.rb +1 -1
- data/lib/cms_scanner.rb +1 -0
- data/lib/cms_scanner/browser.rb +1 -1
- data/lib/cms_scanner/browser/options.rb +2 -5
- data/lib/cms_scanner/controller.rb +7 -23
- data/lib/cms_scanner/controllers.rb +5 -6
- data/lib/cms_scanner/finders/finder/breadth_first_dictionary_attack.rb +1 -1
- data/lib/cms_scanner/parsed_cli.rb +38 -0
- data/lib/cms_scanner/scan.rb +2 -4
- data/lib/cms_scanner/target/platform/php.rb +1 -1
- data/lib/cms_scanner/version.rb +1 -1
- metadata +6 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 36cf3a147ed137b39e8b2d7f1663bfd454639cce4b8d0f45764af3e3ab0b4b48
|
4
|
+
data.tar.gz: a4e4d72d4b8951a04c4f619cc20d1e1293eba77b15533e668738a2e0e62d3306
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cadfdee997e1ef6c7f10ce9f7b8b841acdb1fd5818b5682070f3a07dd5ea34658d55ffd9d86055ac6b7ccf60b5fd965213ba61f22f138873fc6852e137997f0f
|
7
|
+
data.tar.gz: 4a37dc5d1eae53a72894f6317cb72132dc07541f76d48ce9067d15fdf4e89d026b074cc4314163883dce3d2006305ff7c607831d8d0cb9c1c4d22e4978b53a91
|
data/app/controllers/core.rb
CHANGED
@@ -7,12 +7,12 @@ module CMSScanner
|
|
7
7
|
# Core Controller
|
8
8
|
class Core < Base
|
9
9
|
def setup_cache
|
10
|
-
return unless
|
10
|
+
return unless NS::ParsedCli.cache_dir
|
11
11
|
|
12
|
-
storage_path = File.join(
|
12
|
+
storage_path = File.join(NS::ParsedCli.cache_dir, Digest::MD5.hexdigest(target.url))
|
13
13
|
|
14
14
|
Typhoeus::Config.cache = Cache::Typhoeus.new(storage_path)
|
15
|
-
Typhoeus::Config.cache.clean if
|
15
|
+
Typhoeus::Config.cache.clean if NS::ParsedCli.clear_cache
|
16
16
|
end
|
17
17
|
|
18
18
|
def before_scan
|
@@ -23,12 +23,12 @@ module CMSScanner
|
|
23
23
|
end
|
24
24
|
|
25
25
|
def maybe_output_banner_help_and_version
|
26
|
-
output('banner') if
|
27
|
-
output('help', help: option_parser.simple_help, simple: true) if
|
28
|
-
output('help', help: option_parser.full_help, simple: false) if
|
29
|
-
output('version') if
|
26
|
+
output('banner') if NS::ParsedCli.banner
|
27
|
+
output('help', help: option_parser.simple_help, simple: true) if NS::ParsedCli.help
|
28
|
+
output('help', help: option_parser.full_help, simple: false) if NS::ParsedCli.hh
|
29
|
+
output('version') if NS::ParsedCli.version
|
30
30
|
|
31
|
-
exit(NS::ExitCode::OK) if
|
31
|
+
exit(NS::ExitCode::OK) if NS::ParsedCli.help || NS::ParsedCli.hh || NS::ParsedCli.version
|
32
32
|
end
|
33
33
|
|
34
34
|
# Checks that the target is accessible, raises related errors otherwise
|
@@ -43,7 +43,7 @@ module CMSScanner
|
|
43
43
|
when 401
|
44
44
|
raise Error::HTTPAuthRequired
|
45
45
|
when 403
|
46
|
-
raise Error::AccessForbidden,
|
46
|
+
raise Error::AccessForbidden, NS::ParsedCli.random_user_agent
|
47
47
|
when 407
|
48
48
|
raise Error::ProxyAuthRequired
|
49
49
|
end
|
@@ -54,7 +54,7 @@ module CMSScanner
|
|
54
54
|
|
55
55
|
return if target.in_scope?(effective_url)
|
56
56
|
|
57
|
-
raise Error::HTTPRedirect, effective_url unless
|
57
|
+
raise Error::HTTPRedirect, effective_url unless NS::ParsedCli.ignore_main_redirect
|
58
58
|
|
59
59
|
target.homepage_res = res
|
60
60
|
end
|
@@ -46,7 +46,10 @@ module CMSScanner
|
|
46
46
|
OptBoolean.new(['--random-user-agent', '--rua',
|
47
47
|
'Use a random user-agent for each scan']),
|
48
48
|
OptFilePath.new(['--user-agents-list FILE-PATH',
|
49
|
-
'List of agents to use with --random-user-agent'],
|
49
|
+
'List of agents to use with --random-user-agent'],
|
50
|
+
exists: true,
|
51
|
+
advanced: true,
|
52
|
+
default: APP_DIR.join('user_agents.txt')),
|
50
53
|
OptCredentials.new(['--http-auth login:password']),
|
51
54
|
OptPositiveInteger.new(['-t', '--max-threads VALUE', 'The max threads to use'],
|
52
55
|
default: 5),
|
@@ -15,7 +15,7 @@ module CMSScanner
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def run
|
18
|
-
mode =
|
18
|
+
mode = NS::ParsedCli.interesting_findings_detection || NS::ParsedCli.detection_mode
|
19
19
|
findings = target.interesting_findings(mode: mode)
|
20
20
|
|
21
21
|
output('findings', findings: findings) unless findings.empty?
|
data/lib/cms_scanner.rb
CHANGED
@@ -24,6 +24,7 @@ require 'cms_scanner/public_suffix/domain' # Adds a Domain#match method and logi
|
|
24
24
|
require 'cms_scanner/numeric' # Adds a Numeric#bytes_to_human
|
25
25
|
# Custom Libs
|
26
26
|
require 'cms_scanner/scan'
|
27
|
+
require 'cms_scanner/parsed_cli'
|
27
28
|
require 'cms_scanner/helper'
|
28
29
|
require 'cms_scanner/exit_code'
|
29
30
|
require 'cms_scanner/errors'
|
data/lib/cms_scanner/browser.rb
CHANGED
@@ -62,6 +62,8 @@ module CMSScanner
|
|
62
62
|
|
63
63
|
@user_agents = []
|
64
64
|
|
65
|
+
# The user_agents_list is managed by the CLI options, with the default being
|
66
|
+
# APP_DIR/user_agents.txt
|
65
67
|
File.open(user_agents_list).each do |line|
|
66
68
|
next if line == "\n" || line[0, 1] == '#'
|
67
69
|
|
@@ -71,11 +73,6 @@ module CMSScanner
|
|
71
73
|
@user_agents
|
72
74
|
end
|
73
75
|
|
74
|
-
# @return [ String ] The path to the user agents list
|
75
|
-
def user_agents_list
|
76
|
-
@user_agents_list ||= File.join(APP_DIR, 'user_agents.txt')
|
77
|
-
end
|
78
|
-
|
79
76
|
# @param [ value ] The throttle time in milliseconds
|
80
77
|
#
|
81
78
|
# if value > 0, the max_threads will be set to 1
|
@@ -22,15 +22,14 @@ module CMSScanner
|
|
22
22
|
# Reset all the class attibutes
|
23
23
|
# Currently only used in specs
|
24
24
|
def self.reset
|
25
|
-
@@target
|
26
|
-
@@
|
27
|
-
@@
|
28
|
-
@@formatter = nil
|
25
|
+
@@target = nil
|
26
|
+
@@datastore = nil
|
27
|
+
@@formatter = nil
|
29
28
|
end
|
30
29
|
|
31
30
|
# @return [ Target ]
|
32
31
|
def target
|
33
|
-
@@target ||= NS::Target.new(
|
32
|
+
@@target ||= NS::Target.new(NS::ParsedCli.url, NS::ParsedCli.options)
|
34
33
|
end
|
35
34
|
|
36
35
|
# @param [ OptParsevalidator::OptParser ] parser
|
@@ -43,21 +42,6 @@ module CMSScanner
|
|
43
42
|
@@option_parser
|
44
43
|
end
|
45
44
|
|
46
|
-
# Set the parsed options and initialize the browser
|
47
|
-
# with them
|
48
|
-
#
|
49
|
-
# @param [ Hash ] options
|
50
|
-
def self.parsed_options=(options)
|
51
|
-
@@parsed_options = options
|
52
|
-
|
53
|
-
NS::Browser.instance(options)
|
54
|
-
end
|
55
|
-
|
56
|
-
# @return [ Hash ]
|
57
|
-
def parsed_options
|
58
|
-
@@parsed_options ||= {}
|
59
|
-
end
|
60
|
-
|
61
45
|
# @return [ Hash ]
|
62
46
|
def datastore
|
63
47
|
@@datastore ||= {}
|
@@ -65,7 +49,7 @@ module CMSScanner
|
|
65
49
|
|
66
50
|
# @return [ Formatter::Base ]
|
67
51
|
def formatter
|
68
|
-
@@formatter ||= NS::Formatter.load(
|
52
|
+
@@formatter ||= NS::Formatter.load(NS::ParsedCli.format, datastore[:views])
|
69
53
|
end
|
70
54
|
|
71
55
|
# @see Formatter#output
|
@@ -84,7 +68,7 @@ module CMSScanner
|
|
84
68
|
|
85
69
|
# @return [ Boolean ]
|
86
70
|
def user_interaction?
|
87
|
-
formatter.user_interaction? && !
|
71
|
+
formatter.user_interaction? && !NS::ParsedCli.output
|
88
72
|
end
|
89
73
|
|
90
74
|
# @return [ String ]
|
@@ -108,7 +92,7 @@ module CMSScanner
|
|
108
92
|
|
109
93
|
# @return [ Hash ] All the instance variable keys (and their values) and the verbose value
|
110
94
|
def instance_variable_values
|
111
|
-
h = { verbose:
|
95
|
+
h = { verbose: NS::ParsedCli.verbose }
|
112
96
|
instance_variables.each do |a|
|
113
97
|
s = a.to_s
|
114
98
|
n = s[1..s.size]
|
@@ -35,13 +35,12 @@ module CMSScanner
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def run
|
38
|
-
|
39
|
-
first.class.option_parser
|
40
|
-
first.class.parsed_options = parsed_options
|
38
|
+
NS::ParsedCli.options = option_parser.results
|
39
|
+
first.class.option_parser = option_parser # To be able to output the help when -h/--hh
|
41
40
|
|
42
|
-
redirect_output_to_file(
|
41
|
+
redirect_output_to_file(NS::ParsedCli.output) if NS::ParsedCli.output
|
43
42
|
|
44
|
-
Timeout.timeout(
|
43
|
+
Timeout.timeout(NS::ParsedCli.max_scan_duration, NS::Error::MaxScanDurationReached) do
|
45
44
|
each(&:before_scan)
|
46
45
|
|
47
46
|
@running = true
|
@@ -49,7 +48,7 @@ module CMSScanner
|
|
49
48
|
each(&:run)
|
50
49
|
end
|
51
50
|
ensure
|
52
|
-
Browser.instance.hydra.abort
|
51
|
+
NS::Browser.instance.hydra.abort
|
53
52
|
|
54
53
|
# Reverse is used here as the app/controllers/core#after_scan finishes the output
|
55
54
|
# and must be the last one to be executed. It also guarantee that stats will be output
|
@@ -103,7 +103,7 @@ module CMSScanner
|
|
103
103
|
'Request timed out.'
|
104
104
|
elsif response.code.zero?
|
105
105
|
"No response from remote server. WAF/IPS? (#{response.return_message})"
|
106
|
-
elsif response.code.to_s
|
106
|
+
elsif /^50/.match?(response.code.to_s)
|
107
107
|
'Server error, try reducing the number of threads.'
|
108
108
|
else
|
109
109
|
"Unknown response received Code: #{response.code}\nBody: #{response.body}"
|
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module CMSScanner
|
4
|
+
# Class to hold the parsed CLI options and have them available via
|
5
|
+
# methods, such as #verbose?, rather than from the hash.
|
6
|
+
# This is similar to an OpenStruct, but class wise (rather than instance), and with
|
7
|
+
# the logic to update the Browser options accordinly
|
8
|
+
class ParsedCli
|
9
|
+
@options = {}
|
10
|
+
|
11
|
+
class << self
|
12
|
+
attr_reader :options
|
13
|
+
end
|
14
|
+
|
15
|
+
# Sets the CLI options, and put them into the Browser as well
|
16
|
+
# @param [ Hash ] options
|
17
|
+
def self.options=(options)
|
18
|
+
@options = options.dup
|
19
|
+
|
20
|
+
NS::Browser.reset
|
21
|
+
NS::Browser.instance(@options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [ Boolean ]
|
25
|
+
def self.verbose?
|
26
|
+
options[:verbose] ? true : false
|
27
|
+
end
|
28
|
+
|
29
|
+
# Unknown methods will return nil, this is the expected behaviour
|
30
|
+
# rubocop:disable Style/MissingRespondToMissing
|
31
|
+
def self.method_missing(method_name, *_args, &_block)
|
32
|
+
super if method_name == :new
|
33
|
+
|
34
|
+
options[method_name.to_sym]
|
35
|
+
end
|
36
|
+
# rubocop:enable Style/MissingRespondToMissing
|
37
|
+
end
|
38
|
+
end
|
data/lib/cms_scanner/scan.rb
CHANGED
@@ -32,7 +32,7 @@ module CMSScanner
|
|
32
32
|
formatter.output('@scan_aborted',
|
33
33
|
reason: e.is_a?(Interrupt) ? 'Canceled by User' : e.message,
|
34
34
|
trace: e.backtrace,
|
35
|
-
verbose:
|
35
|
+
verbose: NS::ParsedCli.verbose ||
|
36
36
|
run_error_exit_code == NS::ExitCode::EXCEPTION)
|
37
37
|
ensure
|
38
38
|
formatter.beautify
|
@@ -61,10 +61,8 @@ module CMSScanner
|
|
61
61
|
at_exit do
|
62
62
|
exit(run_error_exit_code) if run_error
|
63
63
|
|
64
|
-
controller = controllers.first
|
65
|
-
|
66
64
|
# The parsed_option[:url] must be checked to avoid raising erros when only -h/-v are given
|
67
|
-
exit(NS::ExitCode::VULNERABLE) if
|
65
|
+
exit(NS::ExitCode::VULNERABLE) if NS::ParsedCli.url && controllers.first.target.vulnerable?
|
68
66
|
exit(NS::ExitCode::OK)
|
69
67
|
end
|
70
68
|
end
|
@@ -20,7 +20,7 @@ module CMSScanner
|
|
20
20
|
# which can be huge (~ 2Go)
|
21
21
|
res = head_and_get(path, [200], get: params.merge(headers: { 'Range' => 'bytes=0-700' }))
|
22
22
|
|
23
|
-
res.body
|
23
|
+
res.body&.match?(pattern) ? true : false
|
24
24
|
end
|
25
25
|
|
26
26
|
# @param [ String ] path
|
data/lib/cms_scanner/version.rb
CHANGED
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.44.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- WPScanTeam
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2019-04-
|
11
|
+
date: 2019-04-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: nokogiri
|
@@ -184,14 +184,14 @@ dependencies:
|
|
184
184
|
requirements:
|
185
185
|
- - "~>"
|
186
186
|
- !ruby/object:Gem::Version
|
187
|
-
version: 0.
|
187
|
+
version: 0.67.1
|
188
188
|
type: :development
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
|
-
version: 0.
|
194
|
+
version: 0.67.1
|
195
195
|
- !ruby/object:Gem::Dependency
|
196
196
|
name: simplecov
|
197
197
|
requirement: !ruby/object:Gem::Requirement
|
@@ -299,6 +299,7 @@ files:
|
|
299
299
|
- lib/cms_scanner/formatter/buffer.rb
|
300
300
|
- lib/cms_scanner/helper.rb
|
301
301
|
- lib/cms_scanner/numeric.rb
|
302
|
+
- lib/cms_scanner/parsed_cli.rb
|
302
303
|
- lib/cms_scanner/progressbar_null_output.rb
|
303
304
|
- lib/cms_scanner/public_suffix/domain.rb
|
304
305
|
- lib/cms_scanner/references.rb
|
@@ -330,7 +331,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
330
331
|
requirements:
|
331
332
|
- - ">="
|
332
333
|
- !ruby/object:Gem::Version
|
333
|
-
version: '2.
|
334
|
+
version: '2.4'
|
334
335
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
335
336
|
requirements:
|
336
337
|
- - ">="
|