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.
Files changed (77) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +1 -1
  3. data/README.md +1 -1
  4. data/app/controllers.rb +1 -0
  5. data/app/controllers/aliases.rb +12 -0
  6. data/app/controllers/core.rb +3 -5
  7. data/app/controllers/enumeration.rb +2 -28
  8. data/app/controllers/enumeration/enum_methods.rb +12 -2
  9. data/app/controllers/wp_version.rb +4 -0
  10. data/app/finders/main_theme/css_style.rb +2 -2
  11. data/app/finders/main_theme/urls_in_homepage.rb +3 -3
  12. data/app/finders/plugin_version.rb +1 -8
  13. data/app/finders/plugins.rb +13 -4
  14. data/app/finders/plugins/body_pattern.rb +27 -0
  15. data/app/finders/plugins/comment.rb +31 -0
  16. data/app/finders/plugins/config_parser.rb +31 -0
  17. data/app/finders/plugins/header_pattern.rb +41 -0
  18. data/app/finders/plugins/javascript_var.rb +29 -0
  19. data/app/finders/plugins/known_locations.rb +5 -5
  20. data/app/finders/plugins/query_parameter.rb +25 -0
  21. data/app/finders/plugins/urls_in_homepage.rb +4 -8
  22. data/app/finders/plugins/xpath.rb +29 -0
  23. data/app/finders/theme_version.rb +1 -1
  24. data/app/finders/theme_version/woo_framework_meta_generator.rb +2 -2
  25. data/app/finders/themes/known_locations.rb +5 -5
  26. data/app/finders/themes/urls_in_homepage.rb +2 -2
  27. data/app/finders/users/login_error_messages.rb +1 -4
  28. data/app/finders/users/wp_json_api.rb +2 -2
  29. data/app/finders/wp_items/urls_in_homepage.rb +1 -1
  30. data/app/finders/wp_version.rb +21 -18
  31. data/app/models/plugin.rb +4 -4
  32. data/app/models/theme.rb +6 -6
  33. data/app/models/timthumb.rb +1 -3
  34. data/app/models/wp_item.rb +15 -15
  35. data/app/views/json/enumeration/plugins.erb +1 -1
  36. data/app/views/json/enumeration/themes.erb +1 -1
  37. data/app/views/json/wp_item.erb +1 -1
  38. data/bin/wpscan +2 -1
  39. data/lib/wpscan/db.rb +14 -10
  40. data/lib/wpscan/db/dynamic_finders/base.rb +41 -0
  41. data/lib/wpscan/db/dynamic_finders/plugin.rb +111 -0
  42. data/lib/wpscan/db/dynamic_finders/theme.rb +16 -0
  43. data/lib/wpscan/db/dynamic_finders/wordpress.rb +75 -0
  44. data/lib/wpscan/db/updater.rb +2 -2
  45. data/lib/wpscan/finders.rb +13 -1
  46. data/lib/wpscan/finders/dynamic_finder/finder.rb +66 -0
  47. data/lib/wpscan/finders/dynamic_finder/version/body_pattern.rb +28 -0
  48. data/lib/wpscan/finders/dynamic_finder/version/comment.rb +16 -0
  49. data/lib/wpscan/finders/dynamic_finder/version/config_parser.rb +52 -0
  50. data/lib/wpscan/finders/dynamic_finder/version/finder.rb +29 -0
  51. data/lib/wpscan/finders/dynamic_finder/version/header_pattern.rb +28 -0
  52. data/lib/wpscan/finders/dynamic_finder/version/javascript_var.rb +56 -0
  53. data/lib/wpscan/finders/dynamic_finder/version/query_parameter.rb +62 -0
  54. data/lib/wpscan/finders/dynamic_finder/version/xpath.rb +34 -0
  55. data/lib/wpscan/finders/dynamic_finder/wp_item_version.rb +42 -0
  56. data/lib/wpscan/finders/dynamic_finder/wp_items/finder.rb +96 -0
  57. data/lib/wpscan/finders/dynamic_finder/wp_version.rb +60 -0
  58. data/lib/wpscan/helper.rb +11 -0
  59. data/lib/wpscan/target/platform/wordpress/custom_directories.rb +16 -1
  60. data/lib/wpscan/version.rb +1 -1
  61. metadata +32 -24
  62. data/app/finders/plugin_version/layer_slider/translation_file.rb +0 -40
  63. data/app/finders/plugin_version/revslider/release_log.rb +0 -35
  64. data/app/finders/plugin_version/shareaholic/meta_tag.rb +0 -27
  65. data/app/finders/plugin_version/sitepress_multilingual_cms/meta_generator.rb +0 -27
  66. data/app/finders/plugin_version/sitepress_multilingual_cms/version_parameter.rb +0 -31
  67. data/app/finders/plugin_version/w3_total_cache/headers.rb +0 -28
  68. data/app/finders/plugins/comments.rb +0 -31
  69. data/app/finders/plugins/headers.rb +0 -36
  70. data/app/finders/wp_version/homepage_stylesheet_numbers.rb +0 -59
  71. data/app/finders/wp_version/install_stylesheet_numbers.rb +0 -16
  72. data/app/finders/wp_version/meta_generator.rb +0 -27
  73. data/app/finders/wp_version/opml_generator.rb +0 -23
  74. data/app/finders/wp_version/sitemap_generator.rb +0 -23
  75. data/app/finders/wp_version/upgrade_stylesheet_numbers.rb +0 -13
  76. data/lib/wpscan/db/dynamic_finders.rb +0 -55
  77. data/lib/wpscan/finders/finder/plugin_version/comments.rb +0 -27
@@ -1,40 +0,0 @@
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
@@ -1,35 +0,0 @@
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
@@ -1,27 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module PluginVersion
4
- module Shareaholic
5
- # Version from the meta
6
- class MetaTag < CMSScanner::Finders::Finder
7
- # @param [ Hash ] opts
8
- #
9
- # @return [ Version ]
10
- def passive(_opts = {})
11
- target.target.homepage_res.html.css('meta[name="shareaholic:wp_version"]').each do |node|
12
- next unless node['content'] =~ /\A([0-9\.]+)/i
13
-
14
- return WPScan::Version.new(
15
- Regexp.last_match(1),
16
- found_by: found_by,
17
- confidence: 50,
18
- interesting_entries: ["#{target.target.url}, Match: '#{node.to_s.strip}'"]
19
- )
20
- end
21
- nil
22
- end
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,27 +0,0 @@
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
@@ -1,31 +0,0 @@
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
@@ -1,28 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module PluginVersion
4
- module W3TotalCache
5
- # Version from Headers
6
- class Headers < CMSScanner::Finders::Finder
7
- PATTERN = %r{W3 Total Cache/([0-9.]+)}i
8
-
9
- # @param [ Hash ] opts
10
- #
11
- # @return [ Version ]
12
- def passive(_opts = {})
13
- headers = target.target.headers
14
-
15
- return unless headers && headers['X-Powered-By'].to_s =~ PATTERN
16
-
17
- WPScan::Version.new(
18
- Regexp.last_match[1],
19
- found_by: found_by,
20
- confidence: 80,
21
- interesting_entries: ["#{target.target.url}, Match: '#{Regexp.last_match}'"]
22
- )
23
- end
24
- end
25
- end
26
- end
27
- end
28
- end
@@ -1,31 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module Plugins
4
- # Plugins from Comments Finder
5
- class Comments < CMSScanner::Finders::Finder
6
- # @param [ Hash ] opts
7
- # @option opts [ Boolean ] :unique Default: true
8
- #
9
- # @return [ Array<Plugin> ]
10
- def passive(opts = {})
11
- found = []
12
- opts[:unique] = true unless opts.key?(:unique)
13
-
14
- target.homepage_res.html.xpath('//comment()').each do |node|
15
- comment = node.text.to_s.strip
16
-
17
- DB::DynamicPluginFinders.comments.each do |name, config|
18
- next unless comment =~ config['pattern']
19
-
20
- plugin = WPScan::Plugin.new(name, target, opts.merge(found_by: found_by, confidence: 70))
21
-
22
- found << plugin unless opts[:unique] && found.include?(plugin)
23
- end
24
- end
25
-
26
- found
27
- end
28
- end
29
- end
30
- end
31
- end
@@ -1,36 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module Plugins
4
- # Plugins from Headers Finder
5
- class Headers < CMSScanner::Finders::Finder
6
- # @param [ Hash ] opts
7
- #
8
- # @return [ Array<Plugin> ]
9
- def passive(opts = {})
10
- plugin_names_from_headers(opts).reduce([]) do |a, e|
11
- a << WPScan::Plugin.new(e, target, opts.merge(found_by: found_by, confidence: 60))
12
- end
13
- end
14
-
15
- # X-Powered-By: W3 Total Cache/0.9.2.5
16
- # WP-Super-Cache: Served supercache file from PHP
17
- #
18
- # @return [ Array<String> ]
19
- def plugin_names_from_headers(_opts = {})
20
- found = []
21
- headers = target.homepage_res.headers
22
-
23
- if headers
24
- powered_by = headers['X-Powered-By'].to_s
25
- wp_super_cache = headers['wp-super-cache'].to_s
26
-
27
- found << 'w3-total-cache' if powered_by =~ Finders::PluginVersion::W3TotalCache::Headers::PATTERN
28
- found << 'wp-super-cache' if wp_super_cache =~ /supercache/i
29
- end
30
-
31
- found
32
- end
33
- end
34
- end
35
- end
36
- end
@@ -1,59 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module WpVersion
4
- # Stylesheets Version Finder from Homepage
5
- #
6
- # TODO: Maybe put such methods in the CMSScanner to have a generic
7
- # way of getting those versions, and allow the confidence to be
8
- # customised
9
- class HomepageStylesheetNumbers < CMSScanner::Finders::Finder
10
- # @return [ Array<WpVersion> ]
11
- def passive(_opts = {})
12
- wp_versions(target.homepage_url)
13
- end
14
-
15
- protected
16
-
17
- # @param [ String ] url
18
- #
19
- # @return [ Array<WpVersion> ]
20
- def wp_versions(url)
21
- found = []
22
-
23
- scan_page(url).each do |version_number, occurences|
24
- next unless WPScan::WpVersion.valid?(version_number) # Skip invalid versions
25
-
26
- found << WPScan::WpVersion.new(
27
- version_number,
28
- found_by: found_by,
29
- confidence: 5 * occurences.count,
30
- interesting_entries: occurences
31
- )
32
- end
33
-
34
- found
35
- end
36
-
37
- # @param [ String ] url
38
- #
39
- # @return [ Hash ]
40
- def scan_page(url)
41
- found = {}
42
- pattern = /\bver=([0-9\.]+)/i
43
-
44
- target.in_scope_urls(Browser.get(url), '//link|//script') do |stylesheet_url, _tag|
45
- uri = Addressable::URI.parse(stylesheet_url)
46
- next unless uri.query&.match(pattern)
47
-
48
- version = Regexp.last_match[1].to_s
49
-
50
- found[version] ||= []
51
- found[version] << stylesheet_url
52
- end
53
-
54
- found
55
- end
56
- end
57
- end
58
- end
59
- end
@@ -1,16 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module WpVersion
4
- # Stylesheets Version Finder from Install page
5
- class InstallStylesheetNumbers < HomepageStylesheetNumbers
6
- # Overrides the parent
7
- def passive(_ops = {}); end
8
-
9
- # @return [ Array<WpVersion> ]
10
- def aggressive(_opts = {})
11
- wp_versions(target.url('wp-admin/install.php'))
12
- end
13
- end
14
- end
15
- end
16
- end
@@ -1,27 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module WpVersion
4
- # Meta Generator Version Finder
5
- class MetaGenerator < CMSScanner::Finders::Finder
6
- # @return [ WpVersion ]
7
- def passive(_opts = {})
8
- target.homepage_res.html.css('meta[name="generator"]').each do |node|
9
- next unless node.attribute('content').to_s =~ /wordpress ([0-9\.]+)/i
10
-
11
- number = Regexp.last_match(1)
12
-
13
- next unless WPScan::WpVersion.valid?(number)
14
-
15
- return WPScan::WpVersion.new(
16
- number,
17
- found_by: 'Meta Generator (Passive detection)',
18
- confidence: 80,
19
- interesting_entries: ["#{target.url}, Match: '#{node.to_s.strip}'"]
20
- )
21
- end
22
- nil
23
- end
24
- end
25
- end
26
- end
27
- end
@@ -1,23 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module WpVersion
4
- # Sitemap Generator Version Finder
5
- class OpmlGenerator < CMSScanner::Finders::Finder
6
- # @return [ WpVersion ]
7
- def aggressive(_opts = {})
8
- target.comments_from_page(%r{\Agenerator="wordpress/([^"]+)"\z}i, 'wp-links-opml.php') do |match, node|
9
- next unless WPScan::WpVersion.valid?(match[1])
10
-
11
- return WPScan::WpVersion.new(
12
- match[1],
13
- found_by: 'OPML Generator (Aggressive Detection)',
14
- confidence: 80,
15
- interesting_entries: ["#{target.url('wp-links-opml.php')}, Match: '#{node.to_s.strip}'"]
16
- )
17
- end
18
- nil
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,23 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module WpVersion
4
- # Sitemap Generator Version Finder
5
- class SitemapGenerator < CMSScanner::Finders::Finder
6
- # @return [ WpVersion ]
7
- def aggressive(_opts = {})
8
- target.comments_from_page(%r{\Agenerator="wordpress/([^"]+)"\z}i, 'sitemap.xml') do |match, node|
9
- next unless WPScan::WpVersion.valid?(match[1])
10
-
11
- return WPScan::WpVersion.new(
12
- match[1],
13
- found_by: 'Sitemap Generator (Aggressive Detection)',
14
- confidence: 80,
15
- interesting_entries: ["#{target.url('sitemap.xml')}, #{node.to_s.strip}"]
16
- )
17
- end
18
- nil
19
- end
20
- end
21
- end
22
- end
23
- end
@@ -1,13 +0,0 @@
1
- module WPScan
2
- module Finders
3
- module WpVersion
4
- # Stylesheets Version Finder from Upgrade page
5
- class UpgradeStylesheetNumbers < InstallStylesheetNumbers
6
- # @return [ Array<WpVersion> ]
7
- def aggressive(_opts = {})
8
- wp_versions(target.url('wp-admin/upgrade.php'))
9
- end
10
- end
11
- end
12
- end
13
- end
@@ -1,55 +0,0 @@
1
- module WPScan
2
- module DB
3
- # Dynamic Finders
4
- class DynamicFinders
5
- # @return [ String ]
6
- def self.db_file
7
- @db_file ||= File.join(DB_DIR, 'dynamic_finders_01.yml')
8
- end
9
-
10
- # @return [ Hash ]
11
- def self.db_data
12
- @db_data ||= YAML.safe_load(File.read(db_file), [Regexp])
13
- end
14
-
15
- # @return [ Hash ]
16
- def self.finder_configs(finder_klass)
17
- configs = {}
18
-
19
- db_data.each do |slug, config|
20
- next unless config[finder_klass]
21
-
22
- configs[slug] = config[finder_klass].dup
23
- end
24
-
25
- configs
26
- end
27
- end
28
-
29
- # Dynamic Plugin Finders
30
- class DynamicPluginFinders < DynamicFinders
31
- # @return [ Hash ]
32
- def self.db_data
33
- @db_data ||= super['plugins'] || {}
34
- end
35
-
36
- # @return [ Hash ]
37
- def self.comments
38
- @comments ||= finder_configs('Comments')
39
- end
40
-
41
- # @return [ Hash ]
42
- def self.urls_in_page
43
- @urls_in_page ||= finder_configs('UrlsInPage')
44
- end
45
- end
46
-
47
- # Dynamic Theme Finders (none ATM)
48
- class DynamicThemeFinders < DynamicFinders
49
- # @return [ Hash ]
50
- def self.db_data
51
- @db_data ||= super['themes'] || {}
52
- end
53
- end
54
- end
55
- end