wpscan 3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/Gemfile.lock +139 -0
- data/LICENSE +74 -0
- data/README.md +146 -0
- data/app/app.rb +3 -0
- data/app/controllers.rb +6 -0
- data/app/controllers/brute_force.rb +126 -0
- data/app/controllers/core.rb +104 -0
- data/app/controllers/custom_directories.rb +23 -0
- data/app/controllers/enumeration.rb +53 -0
- data/app/controllers/enumeration/cli_options.rb +126 -0
- data/app/controllers/enumeration/enum_methods.rb +157 -0
- data/app/controllers/main_theme.rb +27 -0
- data/app/controllers/wp_version.rb +30 -0
- data/app/finders.rb +13 -0
- data/app/finders/config_backups.rb +17 -0
- data/app/finders/config_backups/known_filenames.rb +46 -0
- data/app/finders/interesting_findings.rb +33 -0
- data/app/finders/interesting_findings/backup_db.rb +25 -0
- data/app/finders/interesting_findings/debug_log.rb +20 -0
- data/app/finders/interesting_findings/duplicator_installer_log.rb +23 -0
- data/app/finders/interesting_findings/full_path_disclosure.rb +23 -0
- data/app/finders/interesting_findings/mu_plugins.rb +48 -0
- data/app/finders/interesting_findings/multisite.rb +29 -0
- data/app/finders/interesting_findings/readme.rb +26 -0
- data/app/finders/interesting_findings/registration.rb +31 -0
- data/app/finders/interesting_findings/tmm_db_migrate.rb +24 -0
- data/app/finders/interesting_findings/upload_directory_listing.rb +24 -0
- data/app/finders/interesting_findings/upload_sql_dump.rb +28 -0
- data/app/finders/main_theme.rb +22 -0
- data/app/finders/main_theme/css_style.rb +43 -0
- data/app/finders/main_theme/urls_in_homepage.rb +25 -0
- data/app/finders/main_theme/woo_framework_meta_generator.rb +22 -0
- data/app/finders/medias.rb +17 -0
- data/app/finders/medias/attachment_brute_forcing.rb +44 -0
- data/app/finders/plugin_version.rb +44 -0
- data/app/finders/plugin_version/layer_slider/translation_file.rb +40 -0
- data/app/finders/plugin_version/readme.rb +79 -0
- data/app/finders/plugin_version/revslider/release_log.rb +35 -0
- data/app/finders/plugin_version/sitepress_multilingual_cms/meta_generator.rb +27 -0
- data/app/finders/plugin_version/sitepress_multilingual_cms/version_parameter.rb +31 -0
- data/app/finders/plugin_version/w3_total_cache/headers.rb +28 -0
- data/app/finders/plugins.rb +24 -0
- data/app/finders/plugins/comments.rb +31 -0
- data/app/finders/plugins/headers.rb +36 -0
- data/app/finders/plugins/known_locations.rb +48 -0
- data/app/finders/plugins/urls_in_homepage.rb +29 -0
- data/app/finders/theme_version.rb +41 -0
- data/app/finders/theme_version/style.rb +43 -0
- data/app/finders/theme_version/woo_framework_meta_generator.rb +19 -0
- data/app/finders/themes.rb +20 -0
- data/app/finders/themes/known_locations.rb +48 -0
- data/app/finders/themes/urls_in_homepage.rb +23 -0
- data/app/finders/timthumb_version.rb +17 -0
- data/app/finders/timthumb_version/bad_request.rb +21 -0
- data/app/finders/timthumbs.rb +17 -0
- data/app/finders/timthumbs/known_locations.rb +56 -0
- data/app/finders/users.rb +24 -0
- data/app/finders/users/author_id_brute_forcing.rb +111 -0
- data/app/finders/users/author_posts.rb +61 -0
- data/app/finders/users/login_error_messages.rb +50 -0
- data/app/finders/users/wp_json_api.rb +31 -0
- data/app/finders/wp_items.rb +1 -0
- data/app/finders/wp_items/urls_in_homepage.rb +68 -0
- data/app/finders/wp_version.rb +34 -0
- data/app/finders/wp_version/atom_generator.rb +40 -0
- data/app/finders/wp_version/meta_generator.rb +27 -0
- data/app/finders/wp_version/opml_generator.rb +23 -0
- data/app/finders/wp_version/rdf_generator.rb +38 -0
- data/app/finders/wp_version/readme.rb +28 -0
- data/app/finders/wp_version/rss_generator.rb +43 -0
- data/app/finders/wp_version/sitemap_generator.rb +23 -0
- data/app/finders/wp_version/stylesheets.rb +55 -0
- data/app/finders/wp_version/unique_fingerprinting.rb +64 -0
- data/app/models.rb +10 -0
- data/app/models/config_backup.rb +5 -0
- data/app/models/interesting_finding.rb +6 -0
- data/app/models/media.rb +5 -0
- data/app/models/plugin.rb +25 -0
- data/app/models/theme.rb +99 -0
- data/app/models/timthumb.rb +74 -0
- data/app/models/user.rb +31 -0
- data/app/models/wp_item.rb +142 -0
- data/app/models/wp_version.rb +49 -0
- data/app/models/xml_rpc.rb +19 -0
- data/app/views/cli/brute_force/error.erb +1 -0
- data/app/views/cli/brute_force/found.erb +2 -0
- data/app/views/cli/brute_force/users.erb +9 -0
- data/app/views/cli/core/banner.erb +14 -0
- data/app/views/cli/core/db_update_finished.erb +8 -0
- data/app/views/cli/core/db_update_started.erb +1 -0
- data/app/views/cli/core/not_fully_configured.erb +1 -0
- data/app/views/cli/enumeration/config_backups.erb +11 -0
- data/app/views/cli/enumeration/medias.erb +11 -0
- data/app/views/cli/enumeration/plugins.erb +35 -0
- data/app/views/cli/enumeration/themes.erb +11 -0
- data/app/views/cli/enumeration/timthumbs.erb +18 -0
- data/app/views/cli/enumeration/users.erb +11 -0
- data/app/views/cli/finding.erb +32 -0
- data/app/views/cli/info.erb +1 -0
- data/app/views/cli/main_theme/theme.erb +6 -0
- data/app/views/cli/notice.erb +1 -0
- data/app/views/cli/theme.erb +64 -0
- data/app/views/cli/usage.erb +3 -0
- data/app/views/cli/vulnerability.erb +14 -0
- data/app/views/cli/wp_version/version.erb +6 -0
- data/app/views/json/brute_force/users.erb +10 -0
- data/app/views/json/core/banner.erb +12 -0
- data/app/views/json/core/db_update_finished.erb +2 -0
- data/app/views/json/core/db_update_started.erb +1 -0
- data/app/views/json/core/not_fully_configured.erb +1 -0
- data/app/views/json/enumeration/config_backups.erb +10 -0
- data/app/views/json/enumeration/medias.erb +10 -0
- data/app/views/json/enumeration/plugins.erb +25 -0
- data/app/views/json/enumeration/themes.erb +10 -0
- data/app/views/json/enumeration/timthumbs.erb +19 -0
- data/app/views/json/enumeration/users.erb +11 -0
- data/app/views/json/finding.erb +26 -0
- data/app/views/json/main_theme/theme.erb +7 -0
- data/app/views/json/theme.erb +38 -0
- data/app/views/json/wp_version/version.erb +8 -0
- data/bin/wpscan +15 -0
- data/coverage/assets/0.10.0/application.css +799 -0
- data/coverage/assets/0.10.0/application.js +1707 -0
- data/coverage/assets/0.10.0/colorbox/border.png +0 -0
- data/coverage/assets/0.10.0/colorbox/controls.png +0 -0
- data/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
- data/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
- data/coverage/assets/0.10.0/favicon_green.png +0 -0
- data/coverage/assets/0.10.0/favicon_red.png +0 -0
- data/coverage/assets/0.10.0/favicon_yellow.png +0 -0
- data/coverage/assets/0.10.0/loading.gif +0 -0
- data/coverage/assets/0.10.0/magnify.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
- data/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
- data/coverage/index.html +27510 -0
- data/lib/wpscan.rb +44 -0
- data/lib/wpscan/browser.rb +16 -0
- data/lib/wpscan/controller.rb +8 -0
- data/lib/wpscan/controllers.rb +8 -0
- data/lib/wpscan/db.rb +28 -0
- data/lib/wpscan/db/dynamic_finders.rb +63 -0
- data/lib/wpscan/db/plugin.rb +11 -0
- data/lib/wpscan/db/plugins.rb +11 -0
- data/lib/wpscan/db/schema.rb +39 -0
- data/lib/wpscan/db/theme.rb +11 -0
- data/lib/wpscan/db/themes.rb +11 -0
- data/lib/wpscan/db/updater.rb +148 -0
- data/lib/wpscan/db/wp_item.rb +18 -0
- data/lib/wpscan/db/wp_items.rb +21 -0
- data/lib/wpscan/db/wp_version.rb +11 -0
- data/lib/wpscan/errors/http.rb +34 -0
- data/lib/wpscan/errors/update.rb +8 -0
- data/lib/wpscan/errors/wordpress.rb +22 -0
- data/lib/wpscan/finders.rb +14 -0
- data/lib/wpscan/finders/finder/plugin_version/comments.rb +25 -0
- data/lib/wpscan/finders/finder/wp_version/smart_url_checker.rb +23 -0
- data/lib/wpscan/helper.rb +6 -0
- data/lib/wpscan/references.rb +31 -0
- data/lib/wpscan/target.rb +81 -0
- data/lib/wpscan/target/platform/wordpress.rb +74 -0
- data/lib/wpscan/target/platform/wordpress/custom_directories.rb +93 -0
- data/lib/wpscan/version.rb +4 -0
- data/lib/wpscan/vulnerability.rb +25 -0
- data/lib/wpscan/vulnerable.rb +10 -0
- data/wpscan-v3.sublime-project +8 -0
- data/wpscan-v3.sublime-workspace +895 -0
- data/wpscan.gemspec +55 -0
- metadata +419 -0
@@ -0,0 +1,28 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module InterestingFindings
|
4
|
+
# UploadSQLDump finder
|
5
|
+
class UploadSQLDump < CMSScanner::Finders::Finder
|
6
|
+
SQL_PATTERN = /(?:(?:(?:DROP|CREATE) TABLE)|INSERT INTO)/
|
7
|
+
|
8
|
+
# @return [ InterestingFinding ]
|
9
|
+
def aggressive(_opts = {})
|
10
|
+
url = dump_url
|
11
|
+
res = Browser.get(url)
|
12
|
+
|
13
|
+
return unless res.code == 200 && res.body =~ SQL_PATTERN
|
14
|
+
|
15
|
+
WPScan::InterestingFinding.new(
|
16
|
+
url,
|
17
|
+
confidence: 100,
|
18
|
+
found_by: DIRECT_ACCESS
|
19
|
+
)
|
20
|
+
end
|
21
|
+
|
22
|
+
def dump_url
|
23
|
+
target.url('wp-content/uploads/dump.sql')
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require_relative 'main_theme/css_style'
|
2
|
+
require_relative 'main_theme/woo_framework_meta_generator'
|
3
|
+
require_relative 'main_theme/urls_in_homepage'
|
4
|
+
|
5
|
+
module WPScan
|
6
|
+
module Finders
|
7
|
+
module MainTheme
|
8
|
+
# Main Theme Finder
|
9
|
+
class Base
|
10
|
+
include CMSScanner::Finders::UniqueFinder
|
11
|
+
|
12
|
+
# @param [ WPScan::Target ] target
|
13
|
+
def initialize(target)
|
14
|
+
finders <<
|
15
|
+
MainTheme::CssStyle.new(target) <<
|
16
|
+
MainTheme::WooFrameworkMetaGenerator.new(target) <<
|
17
|
+
MainTheme::UrlsInHomepage.new(target)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module MainTheme
|
4
|
+
# From the css style
|
5
|
+
class CssStyle < CMSScanner::Finders::Finder
|
6
|
+
include Finders::WpItems::URLsInHomepage
|
7
|
+
|
8
|
+
def create_theme(name, style_url, opts)
|
9
|
+
WPScan::Theme.new(
|
10
|
+
name,
|
11
|
+
target,
|
12
|
+
opts.merge(found_by: found_by, confidence: 70, style_url: style_url)
|
13
|
+
)
|
14
|
+
end
|
15
|
+
|
16
|
+
def passive(opts = {})
|
17
|
+
passive_from_css_href(target.homepage_res, opts) || passive_from_style_code(target.homepage_res, opts)
|
18
|
+
end
|
19
|
+
|
20
|
+
def passive_from_css_href(res, opts)
|
21
|
+
target.in_scope_urls(res, '//style|//link') do |url|
|
22
|
+
next unless Addressable::URI.parse(url).path =~ %r{/themes/([^\/]+)/style.css\z}i
|
23
|
+
|
24
|
+
return create_theme(Regexp.last_match[1], url, opts)
|
25
|
+
end
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def passive_from_style_code(res, opts)
|
30
|
+
res.html.css('style').each do |tag|
|
31
|
+
code = tag.text.to_s
|
32
|
+
next if code.empty?
|
33
|
+
|
34
|
+
next unless code =~ %r{#{item_code_pattern('themes')}\\?/style\.css[^"'\( ]*}i
|
35
|
+
|
36
|
+
return create_theme(Regexp.last_match[1], Regexp.last_match[0].strip, opts)
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module MainTheme
|
4
|
+
# URLs In Homepage Finder
|
5
|
+
class UrlsInHomepage < CMSScanner::Finders::Finder
|
6
|
+
include WpItems::URLsInHomepage
|
7
|
+
|
8
|
+
# @param [ Hash ] opts
|
9
|
+
#
|
10
|
+
# @return [ Array<Theme> ]
|
11
|
+
def passive(opts = {})
|
12
|
+
found = []
|
13
|
+
|
14
|
+
names = items_from_links('themes', false) + items_from_codes('themes', false)
|
15
|
+
|
16
|
+
names.each_with_object(Hash.new(0)) { |name, counts| counts[name] += 1 }.each do |name, occurences|
|
17
|
+
found << WPScan::Theme.new(name, target, opts.merge(found_by: found_by, confidence: 2 * occurences))
|
18
|
+
end
|
19
|
+
|
20
|
+
found
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module MainTheme
|
4
|
+
# From the WooFramework meta generators
|
5
|
+
class WooFrameworkMetaGenerator < CMSScanner::Finders::Finder
|
6
|
+
THEME_PATTERN = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?"\s+/?>}
|
7
|
+
FRAMEWORK_PATTERN = %r{<meta name="generator" content="WooFramework\s?([^"]+)?"\s+/?>}
|
8
|
+
PATTERN = /#{THEME_PATTERN}\s+#{FRAMEWORK_PATTERN}/i
|
9
|
+
|
10
|
+
def passive(opts = {})
|
11
|
+
return unless target.homepage_res.body =~ PATTERN
|
12
|
+
|
13
|
+
WPScan::Theme.new(
|
14
|
+
Regexp.last_match[1],
|
15
|
+
target,
|
16
|
+
opts.merge(found_by: found_by, confidence: 80)
|
17
|
+
)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require_relative 'medias/attachment_brute_forcing'
|
2
|
+
|
3
|
+
module WPScan
|
4
|
+
module Finders
|
5
|
+
module Medias
|
6
|
+
# Medias Finder
|
7
|
+
class Base
|
8
|
+
include CMSScanner::Finders::SameTypeFinder
|
9
|
+
|
10
|
+
# @param [ WPScan::Target ] target
|
11
|
+
def initialize(target)
|
12
|
+
finders << Medias::AttachmentBruteForcing.new(target)
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module Medias
|
4
|
+
# Medias Finder
|
5
|
+
class AttachmentBruteForcing < CMSScanner::Finders::Finder
|
6
|
+
include CMSScanner::Finders::Finder::Enumerator
|
7
|
+
|
8
|
+
# @param [ Hash ] opts
|
9
|
+
# @option opts [ Range ] :range Mandatory
|
10
|
+
#
|
11
|
+
# @return [ Array<Media> ]
|
12
|
+
def aggressive(opts = {})
|
13
|
+
found = []
|
14
|
+
|
15
|
+
enumerate(target_urls(opts), opts) do |res|
|
16
|
+
next unless res.code == 200
|
17
|
+
|
18
|
+
found << WPScan::Media.new(res.effective_url, opts.merge(found_by: found_by, confidence: 100))
|
19
|
+
end
|
20
|
+
|
21
|
+
found
|
22
|
+
end
|
23
|
+
|
24
|
+
# @param [ Hash ] opts
|
25
|
+
# @option opts [ Range ] :range Mandatory
|
26
|
+
#
|
27
|
+
# @return [ Hash ]
|
28
|
+
def target_urls(opts = {})
|
29
|
+
urls = {}
|
30
|
+
|
31
|
+
opts[:range].each do |id|
|
32
|
+
urls[target.uri.join("?attachment_id=#{id}").to_s] = id
|
33
|
+
end
|
34
|
+
|
35
|
+
urls
|
36
|
+
end
|
37
|
+
|
38
|
+
def create_progress_bar(opts = {})
|
39
|
+
super(opts.merge(title: ' Brute Forcing Attachment Ids -'))
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require_relative 'plugin_version/readme'
|
2
|
+
# Plugins Specific
|
3
|
+
require_relative 'plugin_version/layer_slider/translation_file'
|
4
|
+
require_relative 'plugin_version/revslider/release_log'
|
5
|
+
require_relative 'plugin_version/sitepress_multilingual_cms/version_parameter'
|
6
|
+
require_relative 'plugin_version/sitepress_multilingual_cms/meta_generator'
|
7
|
+
require_relative 'plugin_version/w3_total_cache/headers'
|
8
|
+
|
9
|
+
module WPScan
|
10
|
+
module Finders
|
11
|
+
module PluginVersion
|
12
|
+
# Plugin Version Finder
|
13
|
+
class Base
|
14
|
+
include CMSScanner::Finders::UniqueFinder
|
15
|
+
|
16
|
+
# @param [ WPScan::Plugin ] plugin
|
17
|
+
def initialize(plugin)
|
18
|
+
finders << PluginVersion::Readme.new(plugin)
|
19
|
+
|
20
|
+
load_specific_finders(plugin)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Load the finders associated with the plugin
|
24
|
+
#
|
25
|
+
# @param [ WPScan::Plugin ] plugin
|
26
|
+
def load_specific_finders(plugin)
|
27
|
+
module_name = plugin.classify_name.to_sym
|
28
|
+
|
29
|
+
return unless Finders::PluginVersion.constants.include?(module_name)
|
30
|
+
|
31
|
+
mod = Finders::PluginVersion.const_get(module_name)
|
32
|
+
|
33
|
+
mod.constants.each do |constant|
|
34
|
+
c = mod.const_get(constant)
|
35
|
+
|
36
|
+
next unless c.is_a?(Class)
|
37
|
+
|
38
|
+
finders << c.new(plugin)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module PluginVersion
|
4
|
+
module LayerSlider
|
5
|
+
# Version from a Translation file
|
6
|
+
#
|
7
|
+
# See https://github.com/wpscanteam/wpscan/issues/765
|
8
|
+
class TranslationFile < CMSScanner::Finders::Finder
|
9
|
+
# @param [ Hash ] opts
|
10
|
+
#
|
11
|
+
# @return [ Version ]
|
12
|
+
def aggressive(_opts = {})
|
13
|
+
potential_urls.each do |url|
|
14
|
+
res = Browser.get(url)
|
15
|
+
|
16
|
+
next unless res.code == 200 && res.body =~ /Project-Id-Version: LayerSlider WP v?([0-9\.][^\\\s]+)/
|
17
|
+
|
18
|
+
return WPScan::Version.new(
|
19
|
+
Regexp.last_match[1],
|
20
|
+
found_by: 'Translation File (Aggressive Detection)',
|
21
|
+
confidence: 90,
|
22
|
+
interesting_entries: ["#{url}, Match: '#{Regexp.last_match}'"]
|
23
|
+
)
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [ Array<String> ] The potential URLs where the version is disclosed
|
29
|
+
def potential_urls
|
30
|
+
# Recent versions seem to use the 'locales' directory instead of the 'languages' one.
|
31
|
+
# Maybe also check other locales ?
|
32
|
+
%w(locales languages).reduce([]) do |a, e|
|
33
|
+
a << target.url("#{e}/LayerSlider-en_US.po")
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module PluginVersion
|
4
|
+
# Plugin Version Finder from the readme.txt file
|
5
|
+
class Readme < CMSScanner::Finders::Finder
|
6
|
+
# @return [ Version ]
|
7
|
+
def aggressive(_opts = {})
|
8
|
+
found_by_msg = 'Readme - %s (Aggressive Detection)'
|
9
|
+
|
10
|
+
WPScan::WpItem::READMES.each do |file|
|
11
|
+
url = target.url(file)
|
12
|
+
res = Browser.get(url)
|
13
|
+
|
14
|
+
next unless res.code == 200 && !(numbers = version_numbers(res.body)).empty?
|
15
|
+
|
16
|
+
return numbers.reduce([]) do |a, e|
|
17
|
+
a << WPScan::Version.new(
|
18
|
+
e[0],
|
19
|
+
found_by: format(found_by_msg, e[1]),
|
20
|
+
confidence: e[2],
|
21
|
+
interesting_entries: [url]
|
22
|
+
)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
# @return [ Array<String, String, Integer> ] number, found_by, confidence
|
29
|
+
def version_numbers(body)
|
30
|
+
numbers = []
|
31
|
+
|
32
|
+
if (number = from_stable_tag(body))
|
33
|
+
numbers << [number, 'Stable Tag', 80]
|
34
|
+
end
|
35
|
+
|
36
|
+
if (number = from_changelog_section(body))
|
37
|
+
numbers << [number, 'ChangeLog Section', 50]
|
38
|
+
end
|
39
|
+
|
40
|
+
numbers
|
41
|
+
end
|
42
|
+
|
43
|
+
# @param [ String ] body
|
44
|
+
#
|
45
|
+
# @return [ String, nil ] The version number detected from the stable tag
|
46
|
+
def from_stable_tag(body)
|
47
|
+
return unless body =~ /\b(?:stable tag|version):\s*(?!trunk)([0-9a-z\.-]+)/i
|
48
|
+
|
49
|
+
number = Regexp.last_match[1]
|
50
|
+
|
51
|
+
number if number =~ /[0-9]+/
|
52
|
+
end
|
53
|
+
|
54
|
+
# @param [ String ] body
|
55
|
+
#
|
56
|
+
# @return [ String, nil ] The best version number detected from the changelog section
|
57
|
+
def from_changelog_section(body)
|
58
|
+
extracted_versions = body.scan(%r{[=]+\s+(?:v(?:ersion)?\s*)?([0-9\.-]+)[ \ta-z0-9\(\)\.\-\/]*[=]+}i)
|
59
|
+
|
60
|
+
return if extracted_versions.nil? || extracted_versions.empty?
|
61
|
+
|
62
|
+
extracted_versions.flatten!
|
63
|
+
# must contain at least one number
|
64
|
+
extracted_versions = extracted_versions.select { |x| x =~ /[0-9]+/ }
|
65
|
+
|
66
|
+
sorted = extracted_versions.sort do |x, y|
|
67
|
+
begin
|
68
|
+
Gem::Version.new(x) <=> Gem::Version.new(y)
|
69
|
+
rescue
|
70
|
+
0
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
sorted.last
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module PluginVersion
|
4
|
+
module Revslider
|
5
|
+
# Version from the release_log.html
|
6
|
+
#
|
7
|
+
# See https://github.com/wpscanteam/wpscan/issues/817
|
8
|
+
class ReleaseLog < CMSScanner::Finders::Finder
|
9
|
+
# @param [ Hash ] opts
|
10
|
+
#
|
11
|
+
# @return [ Version ]
|
12
|
+
def aggressive(_opts = {})
|
13
|
+
res = Browser.get(release_log_url)
|
14
|
+
|
15
|
+
res.html.css('h3.version-number:first').each do |node|
|
16
|
+
next unless node.text =~ /\AVersion ([0-9\.]+).*\z/i
|
17
|
+
|
18
|
+
return WPScan::Version.new(
|
19
|
+
Regexp.last_match[1],
|
20
|
+
found_by: found_by,
|
21
|
+
confidence: 90,
|
22
|
+
interesting_entries: ["#{release_log_url}, Match: '#{Regexp.last_match}'"]
|
23
|
+
)
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
|
28
|
+
def release_log_url
|
29
|
+
target.url('release_log.html')
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module PluginVersion
|
4
|
+
module SitepressMultilingualCms
|
5
|
+
# Version from the meta generator
|
6
|
+
class MetaGenerator < CMSScanner::Finders::Finder
|
7
|
+
# @param [ Hash ] opts
|
8
|
+
#
|
9
|
+
# @return [ Version ]
|
10
|
+
def passive(_opts = {})
|
11
|
+
target.target.homepage_res.html.css('meta[name="generator"]').each do |node|
|
12
|
+
next unless node['content'] =~ /\AWPML\sver:([0-9\.]+)\sstt/i
|
13
|
+
|
14
|
+
return WPScan::Version.new(
|
15
|
+
Regexp.last_match(1),
|
16
|
+
found_by: 'Meta Generator (Passive detection)',
|
17
|
+
confidence: 50,
|
18
|
+
interesting_entries: ["#{target.target.url}, Match: '#{node}'"]
|
19
|
+
)
|
20
|
+
end
|
21
|
+
nil
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module WPScan
|
2
|
+
module Finders
|
3
|
+
module PluginVersion
|
4
|
+
module SitepressMultilingualCms
|
5
|
+
# Version from the v parameter in href / src of stylesheets / scripts
|
6
|
+
class VersionParameter < CMSScanner::Finders::Finder
|
7
|
+
# @param [ Hash ] opts
|
8
|
+
#
|
9
|
+
# @return [ Version ]
|
10
|
+
def passive(_opts = {})
|
11
|
+
pattern = %r{#{Regexp.escape(target.target.plugins_dir)}/sitepress-multilingual-cms/}i
|
12
|
+
|
13
|
+
target.target.in_scope_urls(target.target.homepage_res, '//link|//script') do |url|
|
14
|
+
uri = Addressable::URI.parse(url)
|
15
|
+
|
16
|
+
next unless uri.path =~ pattern && uri.query =~ /v=([0-9\.]+)/
|
17
|
+
|
18
|
+
return WPScan::Version.new(
|
19
|
+
Regexp.last_match[1],
|
20
|
+
found_by: found_by,
|
21
|
+
confidence: 50,
|
22
|
+
interesting_entries: [url]
|
23
|
+
)
|
24
|
+
end
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|