wpscan 3.0.8 → 3.1.0
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/LICENSE +1 -1
- data/README.md +1 -1
- data/app/controllers.rb +1 -0
- data/app/controllers/aliases.rb +12 -0
- data/app/controllers/core.rb +3 -5
- data/app/controllers/enumeration.rb +2 -28
- data/app/controllers/enumeration/enum_methods.rb +12 -2
- data/app/controllers/wp_version.rb +4 -0
- data/app/finders/main_theme/css_style.rb +2 -2
- data/app/finders/main_theme/urls_in_homepage.rb +3 -3
- data/app/finders/plugin_version.rb +1 -8
- data/app/finders/plugins.rb +13 -4
- data/app/finders/plugins/body_pattern.rb +27 -0
- data/app/finders/plugins/comment.rb +31 -0
- data/app/finders/plugins/config_parser.rb +31 -0
- data/app/finders/plugins/header_pattern.rb +41 -0
- data/app/finders/plugins/javascript_var.rb +29 -0
- data/app/finders/plugins/known_locations.rb +5 -5
- data/app/finders/plugins/query_parameter.rb +25 -0
- data/app/finders/plugins/urls_in_homepage.rb +4 -8
- data/app/finders/plugins/xpath.rb +29 -0
- data/app/finders/theme_version.rb +1 -1
- data/app/finders/theme_version/woo_framework_meta_generator.rb +2 -2
- data/app/finders/themes/known_locations.rb +5 -5
- data/app/finders/themes/urls_in_homepage.rb +2 -2
- data/app/finders/users/login_error_messages.rb +1 -4
- data/app/finders/users/wp_json_api.rb +2 -2
- data/app/finders/wp_items/urls_in_homepage.rb +1 -1
- data/app/finders/wp_version.rb +21 -18
- data/app/models/plugin.rb +4 -4
- data/app/models/theme.rb +6 -6
- data/app/models/timthumb.rb +1 -3
- data/app/models/wp_item.rb +15 -15
- data/app/views/json/enumeration/plugins.erb +1 -1
- data/app/views/json/enumeration/themes.erb +1 -1
- data/app/views/json/wp_item.erb +1 -1
- data/bin/wpscan +2 -1
- data/lib/wpscan/db.rb +14 -10
- data/lib/wpscan/db/dynamic_finders/base.rb +41 -0
- data/lib/wpscan/db/dynamic_finders/plugin.rb +111 -0
- data/lib/wpscan/db/dynamic_finders/theme.rb +16 -0
- data/lib/wpscan/db/dynamic_finders/wordpress.rb +75 -0
- data/lib/wpscan/db/updater.rb +2 -2
- data/lib/wpscan/finders.rb +13 -1
- data/lib/wpscan/finders/dynamic_finder/finder.rb +66 -0
- data/lib/wpscan/finders/dynamic_finder/version/body_pattern.rb +28 -0
- data/lib/wpscan/finders/dynamic_finder/version/comment.rb +16 -0
- data/lib/wpscan/finders/dynamic_finder/version/config_parser.rb +52 -0
- data/lib/wpscan/finders/dynamic_finder/version/finder.rb +29 -0
- data/lib/wpscan/finders/dynamic_finder/version/header_pattern.rb +28 -0
- data/lib/wpscan/finders/dynamic_finder/version/javascript_var.rb +56 -0
- data/lib/wpscan/finders/dynamic_finder/version/query_parameter.rb +62 -0
- data/lib/wpscan/finders/dynamic_finder/version/xpath.rb +34 -0
- data/lib/wpscan/finders/dynamic_finder/wp_item_version.rb +42 -0
- data/lib/wpscan/finders/dynamic_finder/wp_items/finder.rb +96 -0
- data/lib/wpscan/finders/dynamic_finder/wp_version.rb +60 -0
- data/lib/wpscan/helper.rb +11 -0
- data/lib/wpscan/target/platform/wordpress/custom_directories.rb +16 -1
- data/lib/wpscan/version.rb +1 -1
- metadata +32 -24
- data/app/finders/plugin_version/layer_slider/translation_file.rb +0 -40
- data/app/finders/plugin_version/revslider/release_log.rb +0 -35
- data/app/finders/plugin_version/shareaholic/meta_tag.rb +0 -27
- data/app/finders/plugin_version/sitepress_multilingual_cms/meta_generator.rb +0 -27
- data/app/finders/plugin_version/sitepress_multilingual_cms/version_parameter.rb +0 -31
- data/app/finders/plugin_version/w3_total_cache/headers.rb +0 -28
- data/app/finders/plugins/comments.rb +0 -31
- data/app/finders/plugins/headers.rb +0 -36
- data/app/finders/wp_version/homepage_stylesheet_numbers.rb +0 -59
- data/app/finders/wp_version/install_stylesheet_numbers.rb +0 -16
- data/app/finders/wp_version/meta_generator.rb +0 -27
- data/app/finders/wp_version/opml_generator.rb +0 -23
- data/app/finders/wp_version/sitemap_generator.rb +0 -23
- data/app/finders/wp_version/upgrade_stylesheet_numbers.rb +0 -13
- data/lib/wpscan/db/dynamic_finders.rb +0 -55
- data/lib/wpscan/finders/finder/plugin_version/comments.rb +0 -27
@@ -0,0 +1,111 @@
|
|
1
|
+
module WPScan
|
2
|
+
module DB
|
3
|
+
module DynamicFinders
|
4
|
+
class Plugin < Base
|
5
|
+
# @return [ Hash ]
|
6
|
+
def self.db_data
|
7
|
+
@db_data ||= super['plugins'] || {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.version_finder_module
|
11
|
+
Finders::PluginVersion
|
12
|
+
end
|
13
|
+
|
14
|
+
# @param [ Symbol ] finder_class
|
15
|
+
# @param [ Boolean ] aggressive
|
16
|
+
# @return [ Hash ]
|
17
|
+
def self.finder_configs(finder_class, aggressive = false)
|
18
|
+
configs = {}
|
19
|
+
|
20
|
+
return configs unless allowed_classes.include?(finder_class)
|
21
|
+
|
22
|
+
db_data.each do |slug, finders|
|
23
|
+
# Quite sure better can be done with some kind of logic statement in the select
|
24
|
+
fs = if aggressive
|
25
|
+
finders.reject { |_f, c| c['path'].nil? }
|
26
|
+
else
|
27
|
+
finders.select { |_f, c| c['path'].nil? }
|
28
|
+
end
|
29
|
+
|
30
|
+
fs.each do |finder_name, config|
|
31
|
+
klass = config['class'] ? config['class'] : finder_name
|
32
|
+
|
33
|
+
next unless klass.to_sym == finder_class
|
34
|
+
|
35
|
+
configs[slug] ||= {}
|
36
|
+
configs[slug][finder_name] = config
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
configs
|
41
|
+
end
|
42
|
+
|
43
|
+
# @return [ Hash ]
|
44
|
+
def self.versions_finders_configs
|
45
|
+
return @versions_finders_configs if @versions_finders_configs
|
46
|
+
|
47
|
+
@versions_finders_configs = {}
|
48
|
+
|
49
|
+
db_data.each do |slug, finders|
|
50
|
+
finders.each do |finder_name, config|
|
51
|
+
next unless config.key?('version')
|
52
|
+
|
53
|
+
@versions_finders_configs[slug] ||= {}
|
54
|
+
@versions_finders_configs[slug][finder_name] = config
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
@versions_finders_configs
|
59
|
+
end
|
60
|
+
|
61
|
+
# @param [ String ] slug
|
62
|
+
# @return [ Constant ]
|
63
|
+
def self.maybe_create_modudle(slug)
|
64
|
+
# What about slugs such as js_composer which will be done as JsComposer, just like js-composer
|
65
|
+
constant_name = classify_slug(slug)
|
66
|
+
|
67
|
+
unless version_finder_module.constants.include?(constant_name)
|
68
|
+
version_finder_module.const_set(constant_name, Module.new)
|
69
|
+
end
|
70
|
+
|
71
|
+
version_finder_module.const_get(constant_name)
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.create_versions_finders
|
75
|
+
versions_finders_configs.each do |slug, finders|
|
76
|
+
# Kind of an issue here, module is created even if there is no valid classes
|
77
|
+
# Could put the #maybe_ directly in the #send() BUT it would be checked everytime,
|
78
|
+
# which is kind of a waste
|
79
|
+
mod = maybe_create_modudle(slug)
|
80
|
+
|
81
|
+
finders.each do |finder_class, config|
|
82
|
+
klass = config['class'] ? config['class'] : finder_class
|
83
|
+
|
84
|
+
# Instead of raising exceptions, skip unallowed/already defined finders
|
85
|
+
# So that, when new DF configs are put in the .yml
|
86
|
+
# users with old version of WPScan will still be able to scan blogs
|
87
|
+
# when updating the DB but not the tool
|
88
|
+
next if mod.constants.include?(finder_class.to_sym) ||
|
89
|
+
!allowed_classes.include?(klass.to_sym)
|
90
|
+
|
91
|
+
version_finder_super_class(klass).create_child_class(mod, finder_class.to_sym, config)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# The idea here would be to check if the class exist in
|
97
|
+
# the Finders::DynamicFinders::Plugins/Themes::klass or WpItemVersion::klass
|
98
|
+
# and return the related constant when one has been found.
|
99
|
+
#
|
100
|
+
# So far, the Finders::DynamicFinders::WPItemVersion is enought
|
101
|
+
# as nothing else is used
|
102
|
+
#
|
103
|
+
# @param [ String, Symbol ] klass
|
104
|
+
# @return [ Constant ]
|
105
|
+
def self.version_finder_super_class(klass)
|
106
|
+
"WPScan::Finders::DynamicFinder::WpItemVersion::#{klass}".constantize
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module WPScan
|
2
|
+
module DB
|
3
|
+
module DynamicFinders
|
4
|
+
class Theme < Plugin
|
5
|
+
# @return [ Hash ]
|
6
|
+
def self.db_data
|
7
|
+
@db_data ||= super['themes'] || {}
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.version_finder_module
|
11
|
+
Finders::ThemeVersion
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
module WPScan
|
2
|
+
module DB
|
3
|
+
module DynamicFinders
|
4
|
+
class Wordpress < Base
|
5
|
+
# @return [ Hash ]
|
6
|
+
def self.db_data
|
7
|
+
@db_data ||= super['wordpress'] || {}
|
8
|
+
end
|
9
|
+
|
10
|
+
# @return [ Constant ]
|
11
|
+
def self.version_finder_module
|
12
|
+
Finders::WpVersion
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [ Array<Symbol> ]
|
16
|
+
def self.allowed_classes
|
17
|
+
@allowed_classes ||= %i[
|
18
|
+
Comment Xpath HeaderPattern BodyPattern JavascriptVar QueryParameter WpItemQueryParameter
|
19
|
+
]
|
20
|
+
end
|
21
|
+
|
22
|
+
# @param [ Symbol ] finder_class
|
23
|
+
# @param [ Boolean ] aggressive
|
24
|
+
# @return [ Hash ]
|
25
|
+
def self.finder_configs(finder_class, aggressive = false)
|
26
|
+
configs = {}
|
27
|
+
|
28
|
+
return configs unless allowed_classes.include?(finder_class)
|
29
|
+
|
30
|
+
finders = if aggressive
|
31
|
+
db_data.reject { |_f, c| c['path'].nil? }
|
32
|
+
else
|
33
|
+
db_data.select { |_f, c| c['path'].nil? }
|
34
|
+
end
|
35
|
+
|
36
|
+
finders.each do |finder_name, config|
|
37
|
+
klass = config['class'] ? config['class'] : finder_name
|
38
|
+
|
39
|
+
next unless klass.to_sym == finder_class
|
40
|
+
|
41
|
+
configs[finder_name] = config
|
42
|
+
end
|
43
|
+
|
44
|
+
configs
|
45
|
+
end
|
46
|
+
|
47
|
+
# @return [ Hash ]
|
48
|
+
def self.versions_finders_configs
|
49
|
+
@versions_finders_configs ||= db_data.select { |_finder_name, config| config.key?('version') }
|
50
|
+
end
|
51
|
+
|
52
|
+
def self.create_versions_finders
|
53
|
+
versions_finders_configs.each do |finder_class, config|
|
54
|
+
klass = config['class'] ? config['class'] : finder_class
|
55
|
+
|
56
|
+
# Instead of raising exceptions, skip unallowed/already defined finders
|
57
|
+
# So that, when new DF configs are put in the .yml
|
58
|
+
# users with old version of WPScan will still be able to scan blogs
|
59
|
+
# when updating the DB but not the tool
|
60
|
+
next if version_finder_module.constants.include?(finder_class.to_sym) ||
|
61
|
+
!allowed_classes.include?(klass.to_sym)
|
62
|
+
|
63
|
+
version_finder_super_class(klass).create_child_class(version_finder_module, finder_class.to_sym, config)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
# @param [ String, Symbol ] klass
|
68
|
+
# @return [ Constant ]
|
69
|
+
def self.version_finder_super_class(klass)
|
70
|
+
"WPScan::Finders::DynamicFinder::WpVersion::#{klass}".constantize
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
data/lib/wpscan/db/updater.rb
CHANGED
@@ -7,10 +7,10 @@ module WPScan
|
|
7
7
|
FILES = %w[
|
8
8
|
plugins.json themes.json wordpresses.json
|
9
9
|
timthumbs-v3.txt user-agents.txt config_backups.txt
|
10
|
-
|
10
|
+
dynamic_finders.yml wp_fingerprints.json LICENSE
|
11
11
|
].freeze
|
12
12
|
|
13
|
-
OLD_FILES = %w[wordpress.db
|
13
|
+
OLD_FILES = %w[wordpress.db dynamic_finders_01.yml].freeze
|
14
14
|
|
15
15
|
attr_reader :repo_directory
|
16
16
|
|
data/lib/wpscan/finders.rb
CHANGED
@@ -1,5 +1,17 @@
|
|
1
1
|
require 'wpscan/finders/finder/wp_version/smart_url_checker'
|
2
|
-
|
2
|
+
|
3
|
+
require 'wpscan/finders/dynamic_finder/finder'
|
4
|
+
require 'wpscan/finders/dynamic_finder/wp_items/finder'
|
5
|
+
require 'wpscan/finders/dynamic_finder/version/finder'
|
6
|
+
require 'wpscan/finders/dynamic_finder/version/xpath'
|
7
|
+
require 'wpscan/finders/dynamic_finder/version/comment'
|
8
|
+
require 'wpscan/finders/dynamic_finder/version/header_pattern'
|
9
|
+
require 'wpscan/finders/dynamic_finder/version/body_pattern'
|
10
|
+
require 'wpscan/finders/dynamic_finder/version/javascript_var'
|
11
|
+
require 'wpscan/finders/dynamic_finder/version/query_parameter'
|
12
|
+
require 'wpscan/finders/dynamic_finder/version/config_parser'
|
13
|
+
require 'wpscan/finders/dynamic_finder/wp_item_version'
|
14
|
+
require 'wpscan/finders/dynamic_finder/wp_version'
|
3
15
|
|
4
16
|
module WPScan
|
5
17
|
# Custom Finders
|
@@ -0,0 +1,66 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module DynamicFinder
|
4
|
+
# To be used as a base when creating a dynamic finder
|
5
|
+
class Finder < CMSScanner::Finders::Finder
|
6
|
+
# @param [ Array ] args
|
7
|
+
def self.child_class_constant(*args)
|
8
|
+
args.each do |arg|
|
9
|
+
if arg.is_a?(Hash)
|
10
|
+
child_class_constants.merge!(arg)
|
11
|
+
else
|
12
|
+
child_class_constants[arg] = nil
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Needed to have inheritance of the @child_class_constants
|
18
|
+
# If inheritance is not needed, then the #child_class_constant can be used in the classe definition, ie
|
19
|
+
# child_class_constant :FILES, PATTERN: /aaa/i
|
20
|
+
# @return [ Hash ]
|
21
|
+
def self.child_class_constants
|
22
|
+
@child_class_constants ||= { PATH: nil }
|
23
|
+
end
|
24
|
+
|
25
|
+
# @param [ Constant ] mod
|
26
|
+
# @param [ Constant ] klass
|
27
|
+
# @param [ Hash ] config
|
28
|
+
def self.create_child_class(mod, klass, config)
|
29
|
+
# Can't use the #child_class_constants directly in the Class.new(self) do; end below
|
30
|
+
class_constants = child_class_constants
|
31
|
+
|
32
|
+
mod.const_set(
|
33
|
+
klass, Class.new(self) do
|
34
|
+
class_constants.each do |key, value|
|
35
|
+
const_set(key, config[key.downcase.to_s] || value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
)
|
39
|
+
end
|
40
|
+
|
41
|
+
# This method has to be overriden in child classes
|
42
|
+
#
|
43
|
+
# @param [ Typhoeus::Response ] response
|
44
|
+
# @param [ Hash ] opts
|
45
|
+
# @return [ Mixed ]
|
46
|
+
def find(_response, _opts = {})
|
47
|
+
raise NoMethodError
|
48
|
+
end
|
49
|
+
|
50
|
+
# @param [ Hash ] opts
|
51
|
+
def passive(opts = {})
|
52
|
+
return if self.class::PATH
|
53
|
+
|
54
|
+
find(target.homepage_res, opts)
|
55
|
+
end
|
56
|
+
|
57
|
+
# @param [ Hash ] opts
|
58
|
+
def aggressive(opts = {})
|
59
|
+
return unless self.class::PATH
|
60
|
+
|
61
|
+
find(Browser.get(target.url(self.class::PATH)), opts)
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module DynamicFinder
|
4
|
+
module Version
|
5
|
+
# Version finder using Body Pattern method. Tipically used when the response is not
|
6
|
+
# an HTML doc and Xpath can't be used
|
7
|
+
class BodyPattern < WPScan::Finders::DynamicFinder::Version::Finder
|
8
|
+
# @return [ Hash ]
|
9
|
+
def self.child_class_constants
|
10
|
+
@child_class_constants ||= super().merge(PATTERN: nil, CONFIDENCE: 60)
|
11
|
+
end
|
12
|
+
|
13
|
+
# @param [ Typhoeus::Response ] response
|
14
|
+
# @param [ Hash ] opts
|
15
|
+
# @return [ Version ]
|
16
|
+
def find(response, _opts = {})
|
17
|
+
return unless response.body =~ self.class::PATTERN
|
18
|
+
|
19
|
+
create_version(
|
20
|
+
Regexp.last_match[:v],
|
21
|
+
interesting_entries: ["#{response.effective_url}, Match: '#{Regexp.last_match}'"]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module DynamicFinder
|
4
|
+
module Version
|
5
|
+
# Version finder in Comment, which is basically an Xpath one with a default
|
6
|
+
# Xpath of //comment()
|
7
|
+
class Comment < WPScan::Finders::DynamicFinder::Version::Xpath
|
8
|
+
# @return [ Hash ]
|
9
|
+
def self.child_class_constants
|
10
|
+
@child_class_constants ||= super().merge(PATTERN: nil, XPATH: '//comment()')
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,52 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module DynamicFinder
|
4
|
+
module Version
|
5
|
+
# Version finder using by parsing config files, such as composer.json
|
6
|
+
# and so on
|
7
|
+
class ConfigParser < WPScan::Finders::DynamicFinder::Version::Finder
|
8
|
+
ALLOWED_PARSERS = [JSON, YAML].freeze
|
9
|
+
|
10
|
+
def self.child_class_constants
|
11
|
+
@child_class_constants ||= super.merge(
|
12
|
+
PARSER: nil, KEY: nil, PATTERN: /(?<v>\d+\.[\.\d]+)/, CONFIDENCE: 70
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
# @param [ String ] body
|
17
|
+
# @return [ Hash, nil ] The parsed body, with an available parser, if possible
|
18
|
+
def parse(body)
|
19
|
+
parsers = ALLOWED_PARSERS.include?(self.class::PARSER) ? [self.class::PARSER] : ALLOWED_PARSERS
|
20
|
+
|
21
|
+
parsers.each do |parser|
|
22
|
+
begin
|
23
|
+
return parser.respond_to?(:safe_load) ? parser.safe_load(body) : parser.load(body)
|
24
|
+
rescue StandardError
|
25
|
+
next
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
nil # Make sure nil is returned in case none of the parsers manage to parse the body correctly
|
30
|
+
end
|
31
|
+
|
32
|
+
# No Passive way
|
33
|
+
def passive(opts = {}); end
|
34
|
+
|
35
|
+
# @param [ Typhoeus::Response ] response
|
36
|
+
# @param [ Hash ] opts
|
37
|
+
# @return [ Version ]
|
38
|
+
def find(response, _opts = {})
|
39
|
+
parsed_body = parse(response.body)
|
40
|
+
|
41
|
+
return unless (data = parsed_body&.dig(*self.class::KEY.split(':'))) && data =~ self.class::PATTERN
|
42
|
+
|
43
|
+
create_version(
|
44
|
+
Regexp.last_match[:v],
|
45
|
+
interesting_entries: ["#{response.effective_url}, Match: '#{Regexp.last_match}'"]
|
46
|
+
)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module DynamicFinder
|
4
|
+
module Version
|
5
|
+
# To be used as a base when creating
|
6
|
+
# a dynamic finder to find the version of a WP Item (such as theme/plugin)
|
7
|
+
class Finder < Finders::DynamicFinder::Finder
|
8
|
+
protected
|
9
|
+
|
10
|
+
# @param [ String ] number
|
11
|
+
# @param [ Hash ] finding_opts
|
12
|
+
# @return [ WPScan::Version ]
|
13
|
+
def create_version(number, finding_opts)
|
14
|
+
WPScan::Version.new(number, version_finding_opts(finding_opts))
|
15
|
+
end
|
16
|
+
|
17
|
+
# @param [ Hash ] opts
|
18
|
+
# @retutn [ Hash ]
|
19
|
+
def version_finding_opts(opts)
|
20
|
+
opts[:found_by] ||= found_by
|
21
|
+
opts[:confidence] ||= self.class::CONFIDENCE
|
22
|
+
|
23
|
+
opts
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module DynamicFinder
|
4
|
+
module Version
|
5
|
+
# Version finder using Header Pattern method
|
6
|
+
class HeaderPattern < WPScan::Finders::DynamicFinder::Version::Finder
|
7
|
+
# @return [ Hash ]
|
8
|
+
def self.child_class_constants
|
9
|
+
@child_class_constants ||= super().merge(HEADER: nil, PATTERN: nil, CONFIDENCE: 60)
|
10
|
+
end
|
11
|
+
|
12
|
+
# @param [ Typhoeus::Response ] response
|
13
|
+
# @param [ Hash ] opts
|
14
|
+
# @return [ Version ]
|
15
|
+
def find(response, _opts = {})
|
16
|
+
return unless response.headers && response.headers[self.class::HEADER]
|
17
|
+
return unless response.headers[self.class::HEADER].to_s =~ self.class::PATTERN
|
18
|
+
|
19
|
+
create_version(
|
20
|
+
Regexp.last_match[:v],
|
21
|
+
interesting_entries: ["#{response.effective_url}, Match: '#{Regexp.last_match}'"]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|