wpscan 3.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 (180) hide show
  1. checksums.yaml +7 -0
  2. data/Gemfile.lock +139 -0
  3. data/LICENSE +74 -0
  4. data/README.md +146 -0
  5. data/app/app.rb +3 -0
  6. data/app/controllers.rb +6 -0
  7. data/app/controllers/brute_force.rb +126 -0
  8. data/app/controllers/core.rb +104 -0
  9. data/app/controllers/custom_directories.rb +23 -0
  10. data/app/controllers/enumeration.rb +53 -0
  11. data/app/controllers/enumeration/cli_options.rb +126 -0
  12. data/app/controllers/enumeration/enum_methods.rb +157 -0
  13. data/app/controllers/main_theme.rb +27 -0
  14. data/app/controllers/wp_version.rb +30 -0
  15. data/app/finders.rb +13 -0
  16. data/app/finders/config_backups.rb +17 -0
  17. data/app/finders/config_backups/known_filenames.rb +46 -0
  18. data/app/finders/interesting_findings.rb +33 -0
  19. data/app/finders/interesting_findings/backup_db.rb +25 -0
  20. data/app/finders/interesting_findings/debug_log.rb +20 -0
  21. data/app/finders/interesting_findings/duplicator_installer_log.rb +23 -0
  22. data/app/finders/interesting_findings/full_path_disclosure.rb +23 -0
  23. data/app/finders/interesting_findings/mu_plugins.rb +48 -0
  24. data/app/finders/interesting_findings/multisite.rb +29 -0
  25. data/app/finders/interesting_findings/readme.rb +26 -0
  26. data/app/finders/interesting_findings/registration.rb +31 -0
  27. data/app/finders/interesting_findings/tmm_db_migrate.rb +24 -0
  28. data/app/finders/interesting_findings/upload_directory_listing.rb +24 -0
  29. data/app/finders/interesting_findings/upload_sql_dump.rb +28 -0
  30. data/app/finders/main_theme.rb +22 -0
  31. data/app/finders/main_theme/css_style.rb +43 -0
  32. data/app/finders/main_theme/urls_in_homepage.rb +25 -0
  33. data/app/finders/main_theme/woo_framework_meta_generator.rb +22 -0
  34. data/app/finders/medias.rb +17 -0
  35. data/app/finders/medias/attachment_brute_forcing.rb +44 -0
  36. data/app/finders/plugin_version.rb +44 -0
  37. data/app/finders/plugin_version/layer_slider/translation_file.rb +40 -0
  38. data/app/finders/plugin_version/readme.rb +79 -0
  39. data/app/finders/plugin_version/revslider/release_log.rb +35 -0
  40. data/app/finders/plugin_version/sitepress_multilingual_cms/meta_generator.rb +27 -0
  41. data/app/finders/plugin_version/sitepress_multilingual_cms/version_parameter.rb +31 -0
  42. data/app/finders/plugin_version/w3_total_cache/headers.rb +28 -0
  43. data/app/finders/plugins.rb +24 -0
  44. data/app/finders/plugins/comments.rb +31 -0
  45. data/app/finders/plugins/headers.rb +36 -0
  46. data/app/finders/plugins/known_locations.rb +48 -0
  47. data/app/finders/plugins/urls_in_homepage.rb +29 -0
  48. data/app/finders/theme_version.rb +41 -0
  49. data/app/finders/theme_version/style.rb +43 -0
  50. data/app/finders/theme_version/woo_framework_meta_generator.rb +19 -0
  51. data/app/finders/themes.rb +20 -0
  52. data/app/finders/themes/known_locations.rb +48 -0
  53. data/app/finders/themes/urls_in_homepage.rb +23 -0
  54. data/app/finders/timthumb_version.rb +17 -0
  55. data/app/finders/timthumb_version/bad_request.rb +21 -0
  56. data/app/finders/timthumbs.rb +17 -0
  57. data/app/finders/timthumbs/known_locations.rb +56 -0
  58. data/app/finders/users.rb +24 -0
  59. data/app/finders/users/author_id_brute_forcing.rb +111 -0
  60. data/app/finders/users/author_posts.rb +61 -0
  61. data/app/finders/users/login_error_messages.rb +50 -0
  62. data/app/finders/users/wp_json_api.rb +31 -0
  63. data/app/finders/wp_items.rb +1 -0
  64. data/app/finders/wp_items/urls_in_homepage.rb +68 -0
  65. data/app/finders/wp_version.rb +34 -0
  66. data/app/finders/wp_version/atom_generator.rb +40 -0
  67. data/app/finders/wp_version/meta_generator.rb +27 -0
  68. data/app/finders/wp_version/opml_generator.rb +23 -0
  69. data/app/finders/wp_version/rdf_generator.rb +38 -0
  70. data/app/finders/wp_version/readme.rb +28 -0
  71. data/app/finders/wp_version/rss_generator.rb +43 -0
  72. data/app/finders/wp_version/sitemap_generator.rb +23 -0
  73. data/app/finders/wp_version/stylesheets.rb +55 -0
  74. data/app/finders/wp_version/unique_fingerprinting.rb +64 -0
  75. data/app/models.rb +10 -0
  76. data/app/models/config_backup.rb +5 -0
  77. data/app/models/interesting_finding.rb +6 -0
  78. data/app/models/media.rb +5 -0
  79. data/app/models/plugin.rb +25 -0
  80. data/app/models/theme.rb +99 -0
  81. data/app/models/timthumb.rb +74 -0
  82. data/app/models/user.rb +31 -0
  83. data/app/models/wp_item.rb +142 -0
  84. data/app/models/wp_version.rb +49 -0
  85. data/app/models/xml_rpc.rb +19 -0
  86. data/app/views/cli/brute_force/error.erb +1 -0
  87. data/app/views/cli/brute_force/found.erb +2 -0
  88. data/app/views/cli/brute_force/users.erb +9 -0
  89. data/app/views/cli/core/banner.erb +14 -0
  90. data/app/views/cli/core/db_update_finished.erb +8 -0
  91. data/app/views/cli/core/db_update_started.erb +1 -0
  92. data/app/views/cli/core/not_fully_configured.erb +1 -0
  93. data/app/views/cli/enumeration/config_backups.erb +11 -0
  94. data/app/views/cli/enumeration/medias.erb +11 -0
  95. data/app/views/cli/enumeration/plugins.erb +35 -0
  96. data/app/views/cli/enumeration/themes.erb +11 -0
  97. data/app/views/cli/enumeration/timthumbs.erb +18 -0
  98. data/app/views/cli/enumeration/users.erb +11 -0
  99. data/app/views/cli/finding.erb +32 -0
  100. data/app/views/cli/info.erb +1 -0
  101. data/app/views/cli/main_theme/theme.erb +6 -0
  102. data/app/views/cli/notice.erb +1 -0
  103. data/app/views/cli/theme.erb +64 -0
  104. data/app/views/cli/usage.erb +3 -0
  105. data/app/views/cli/vulnerability.erb +14 -0
  106. data/app/views/cli/wp_version/version.erb +6 -0
  107. data/app/views/json/brute_force/users.erb +10 -0
  108. data/app/views/json/core/banner.erb +12 -0
  109. data/app/views/json/core/db_update_finished.erb +2 -0
  110. data/app/views/json/core/db_update_started.erb +1 -0
  111. data/app/views/json/core/not_fully_configured.erb +1 -0
  112. data/app/views/json/enumeration/config_backups.erb +10 -0
  113. data/app/views/json/enumeration/medias.erb +10 -0
  114. data/app/views/json/enumeration/plugins.erb +25 -0
  115. data/app/views/json/enumeration/themes.erb +10 -0
  116. data/app/views/json/enumeration/timthumbs.erb +19 -0
  117. data/app/views/json/enumeration/users.erb +11 -0
  118. data/app/views/json/finding.erb +26 -0
  119. data/app/views/json/main_theme/theme.erb +7 -0
  120. data/app/views/json/theme.erb +38 -0
  121. data/app/views/json/wp_version/version.erb +8 -0
  122. data/bin/wpscan +15 -0
  123. data/coverage/assets/0.10.0/application.css +799 -0
  124. data/coverage/assets/0.10.0/application.js +1707 -0
  125. data/coverage/assets/0.10.0/colorbox/border.png +0 -0
  126. data/coverage/assets/0.10.0/colorbox/controls.png +0 -0
  127. data/coverage/assets/0.10.0/colorbox/loading.gif +0 -0
  128. data/coverage/assets/0.10.0/colorbox/loading_background.png +0 -0
  129. data/coverage/assets/0.10.0/favicon_green.png +0 -0
  130. data/coverage/assets/0.10.0/favicon_red.png +0 -0
  131. data/coverage/assets/0.10.0/favicon_yellow.png +0 -0
  132. data/coverage/assets/0.10.0/loading.gif +0 -0
  133. data/coverage/assets/0.10.0/magnify.png +0 -0
  134. data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_0_aaaaaa_40x100.png +0 -0
  135. data/coverage/assets/0.10.0/smoothness/images/ui-bg_flat_75_ffffff_40x100.png +0 -0
  136. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_55_fbf9ee_1x400.png +0 -0
  137. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_65_ffffff_1x400.png +0 -0
  138. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_dadada_1x400.png +0 -0
  139. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_75_e6e6e6_1x400.png +0 -0
  140. data/coverage/assets/0.10.0/smoothness/images/ui-bg_glass_95_fef1ec_1x400.png +0 -0
  141. data/coverage/assets/0.10.0/smoothness/images/ui-bg_highlight-soft_75_cccccc_1x100.png +0 -0
  142. data/coverage/assets/0.10.0/smoothness/images/ui-icons_222222_256x240.png +0 -0
  143. data/coverage/assets/0.10.0/smoothness/images/ui-icons_2e83ff_256x240.png +0 -0
  144. data/coverage/assets/0.10.0/smoothness/images/ui-icons_454545_256x240.png +0 -0
  145. data/coverage/assets/0.10.0/smoothness/images/ui-icons_888888_256x240.png +0 -0
  146. data/coverage/assets/0.10.0/smoothness/images/ui-icons_cd0a0a_256x240.png +0 -0
  147. data/coverage/index.html +27510 -0
  148. data/lib/wpscan.rb +44 -0
  149. data/lib/wpscan/browser.rb +16 -0
  150. data/lib/wpscan/controller.rb +8 -0
  151. data/lib/wpscan/controllers.rb +8 -0
  152. data/lib/wpscan/db.rb +28 -0
  153. data/lib/wpscan/db/dynamic_finders.rb +63 -0
  154. data/lib/wpscan/db/plugin.rb +11 -0
  155. data/lib/wpscan/db/plugins.rb +11 -0
  156. data/lib/wpscan/db/schema.rb +39 -0
  157. data/lib/wpscan/db/theme.rb +11 -0
  158. data/lib/wpscan/db/themes.rb +11 -0
  159. data/lib/wpscan/db/updater.rb +148 -0
  160. data/lib/wpscan/db/wp_item.rb +18 -0
  161. data/lib/wpscan/db/wp_items.rb +21 -0
  162. data/lib/wpscan/db/wp_version.rb +11 -0
  163. data/lib/wpscan/errors/http.rb +34 -0
  164. data/lib/wpscan/errors/update.rb +8 -0
  165. data/lib/wpscan/errors/wordpress.rb +22 -0
  166. data/lib/wpscan/finders.rb +14 -0
  167. data/lib/wpscan/finders/finder/plugin_version/comments.rb +25 -0
  168. data/lib/wpscan/finders/finder/wp_version/smart_url_checker.rb +23 -0
  169. data/lib/wpscan/helper.rb +6 -0
  170. data/lib/wpscan/references.rb +31 -0
  171. data/lib/wpscan/target.rb +81 -0
  172. data/lib/wpscan/target/platform/wordpress.rb +74 -0
  173. data/lib/wpscan/target/platform/wordpress/custom_directories.rb +93 -0
  174. data/lib/wpscan/version.rb +4 -0
  175. data/lib/wpscan/vulnerability.rb +25 -0
  176. data/lib/wpscan/vulnerable.rb +10 -0
  177. data/wpscan-v3.sublime-project +8 -0
  178. data/wpscan-v3.sublime-workspace +895 -0
  179. data/wpscan.gemspec +55 -0
  180. metadata +419 -0
@@ -0,0 +1,17 @@
1
+ require_relative 'timthumbs/known_locations'
2
+
3
+ module WPScan
4
+ module Finders
5
+ module Timthumbs
6
+ # Timthumbs Finder
7
+ class Base
8
+ include CMSScanner::Finders::SameTypeFinder
9
+
10
+ # @param [ WPScan::Target ] target
11
+ def initialize(target)
12
+ finders << Timthumbs::KnownLocations.new(target)
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,56 @@
1
+ module WPScan
2
+ module Finders
3
+ module Timthumbs
4
+ # Known Locations Timthumbs Finder
5
+ class KnownLocations < CMSScanner::Finders::Finder
6
+ include CMSScanner::Finders::Finder::Enumerator
7
+
8
+ # @param [ Hash ] opts
9
+ # @option opts [ String ] :list Mandatory
10
+ #
11
+ # @return [ Array<Timthumb> ]
12
+ def aggressive(opts = {})
13
+ found = []
14
+
15
+ enumerate(target_urls(opts), opts) do |res|
16
+ next unless res.code == 400 && res.body =~ /no image specified/i
17
+
18
+ found << WPScan::Timthumb.new(res.request.url, opts.merge(found_by: found_by, confidence: 100))
19
+ end
20
+
21
+ found
22
+ end
23
+
24
+ # @param [ Hash ] opts
25
+ # @option opts [ String ] :list Mandatory
26
+ #
27
+ # @return [ Hash ]
28
+ def target_urls(opts = {})
29
+ urls = {}
30
+
31
+ File.open(opts[:list]).each_with_index do |path, index|
32
+ urls[target.url(path.chomp)] = index
33
+ end
34
+
35
+ # Add potential timthumbs located in the main theme
36
+ if target.main_theme
37
+ main_theme_timthumbs_paths.each do |path|
38
+ urls[target.main_theme.url(path)] = 1 # index not important there
39
+ end
40
+ end
41
+
42
+ urls
43
+ end
44
+
45
+ def main_theme_timthumbs_paths
46
+ %w(timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php
47
+ scripts/timthumb.php tools/timthumb.php functions/timthumb.php)
48
+ end
49
+
50
+ def create_progress_bar(opts = {})
51
+ super(opts.merge(title: ' Checking Known Locations -'))
52
+ end
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,24 @@
1
+ require_relative 'users/author_posts'
2
+ require_relative 'users/wp_json_api'
3
+ require_relative 'users/author_id_brute_forcing'
4
+ require_relative 'users/login_error_messages'
5
+
6
+ module WPScan
7
+ module Finders
8
+ module Users
9
+ # Users Finder
10
+ class Base
11
+ include CMSScanner::Finders::SameTypeFinder
12
+
13
+ # @param [ WPScan::Target ] target
14
+ def initialize(target)
15
+ finders <<
16
+ Users::AuthorPosts.new(target) <<
17
+ Users::WpJsonApi.new(target) <<
18
+ Users::AuthorIdBruteForcing.new(target) <<
19
+ Users::LoginErrorMessages.new(target)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,111 @@
1
+ module WPScan
2
+ module Finders
3
+ module Users
4
+ # Author Id Brute Forcing
5
+ class AuthorIdBruteForcing < CMSScanner::Finders::Finder
6
+ include CMSScanner::Finders::Finder::Enumerator
7
+
8
+ # @param [ Hash ] opts
9
+ # @option opts [ Range ] :range Mandatory
10
+ #
11
+ # @return [ Array<User> ]
12
+ def aggressive(opts = {})
13
+ found = []
14
+ found_by_msg = 'Author Id Brute Forcing - %s (Aggressive Detection)'
15
+
16
+ enumerate(target_urls(opts), opts) do |res, id|
17
+ username, found_by, confidence = potential_username(res)
18
+
19
+ next unless username
20
+
21
+ found << WPScan::User.new(
22
+ username,
23
+ id: id,
24
+ found_by: format(found_by_msg, found_by),
25
+ confidence: confidence
26
+ )
27
+ end
28
+
29
+ found
30
+ end
31
+
32
+ # @param [ Hash ] opts
33
+ # @option opts [ Range ] :range
34
+ #
35
+ # @return [ Hash ]
36
+ def target_urls(opts = {})
37
+ urls = {}
38
+
39
+ opts[:range].each do |id|
40
+ urls[target.uri.join("?author=#{id}").to_s] = id
41
+ end
42
+
43
+ urls
44
+ end
45
+
46
+ def create_progress_bar(opts = {})
47
+ super(opts.merge(title: ' Brute Forcing Author Ids -'))
48
+ end
49
+
50
+ def request_params
51
+ { followlocation: true }
52
+ end
53
+
54
+ # @param [ Typhoeus::Response ] res
55
+ #
56
+ # @return [ Array<String, String, Integer>, nil ] username, found_by, confidence
57
+ def potential_username(res)
58
+ username = username_from_author_url(res.effective_url) || username_from_response(res)
59
+
60
+ return username, 'Author Pattern', 100 if username
61
+
62
+ username = display_name_from_body(res.body)
63
+
64
+ return username, 'Display Name', 50 if username
65
+ end
66
+
67
+ # @param [ String ] url
68
+ #
69
+ # @return [ String, nil ]
70
+ def username_from_author_url(url)
71
+ url[%r{/author/([^/\b]+)/?}i, 1]
72
+ end
73
+
74
+ # @param [ Typhoeus::Response ] res
75
+ #
76
+ # @return [ String, nil ] The username found
77
+ def username_from_response(res)
78
+ # Permalink enabled
79
+ target.in_scope_urls(res, '//link|//a') do |url|
80
+ username = username_from_author_url(url)
81
+ return username if username
82
+ end
83
+
84
+ # No permalink
85
+ res.body[/<body class="archive author author-([^\s]+)[ "]/i, 1]
86
+ end
87
+
88
+ # @param [ String ] body
89
+ #
90
+ # @return [ String, nil ]
91
+ def display_name_from_body(body)
92
+ page = Nokogiri::HTML.parse(body)
93
+ # WP >= 3.0
94
+ page.css('h1.page-title span').each do |node|
95
+ return node.text.to_s
96
+ end
97
+
98
+ # WP < 3.0
99
+ page.xpath('//link[@rel="alternate" and @type="application/rss+xml"]').each do |node|
100
+ title = node['title']
101
+
102
+ next unless title =~ /Posts by (.*) Feed\z/i
103
+
104
+ return Regexp.last_match[1] unless Regexp.last_match[1].empty?
105
+ end
106
+ nil
107
+ end
108
+ end
109
+ end
110
+ end
111
+ end
@@ -0,0 +1,61 @@
1
+ module WPScan
2
+ module Finders
3
+ module Users
4
+ # Author Posts
5
+ class AuthorPosts < CMSScanner::Finders::Finder
6
+ # @param [ Hash ] opts
7
+ #
8
+ # @return [ Array<User> ]
9
+ def passive(opts = {})
10
+ found_by_msg = 'Author Posts - %s (Passive Detection)'
11
+
12
+ usernames(opts).reduce([]) do |a, e|
13
+ a << WPScan::User.new(
14
+ e[0],
15
+ found_by: format(found_by_msg, e[1]),
16
+ confidence: e[2]
17
+ )
18
+ end
19
+ end
20
+
21
+ # @param [ Hash ] opts
22
+ #
23
+ # @return [ Array<Array>> ]
24
+ def usernames(_opts = {})
25
+ found = potential_usernames(target.homepage_res)
26
+
27
+ return found unless found.empty?
28
+
29
+ target.homepage_res.html.css('header.entry-header a').each do |post_url_node|
30
+ url = post_url_node['href']
31
+
32
+ next if url.nil? || url.empty?
33
+
34
+ found += potential_usernames(Browser.get(url))
35
+ end
36
+
37
+ found.compact.uniq
38
+ end
39
+
40
+ # @param [ Typhoeus::Response ] res
41
+ #
42
+ # @return [ Array<Array> ]
43
+ def potential_usernames(res)
44
+ usernames = []
45
+
46
+ target.in_scope_urls(res, '//a', %w(href)) do |url, node|
47
+ uri = Addressable::URI.parse(url)
48
+
49
+ if uri.path =~ %r{/author/([^/\b]+)/?\z}i
50
+ usernames << [Regexp.last_match[1], 'Author Pattern', 100]
51
+ elsif uri.query =~ /author=[0-9]+/
52
+ usernames << [node.text.to_s.strip, 'Display Name', 30]
53
+ end
54
+ end
55
+
56
+ usernames.uniq
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,50 @@
1
+ module WPScan
2
+ module Finders
3
+ module Users
4
+ # Login Error Messages
5
+ #
6
+ # Existing username:
7
+ # WP < 3.1 - Incorrect password.
8
+ # WP >= 3.1 - The password you entered for the username admin is incorrect.
9
+ # Non existent username: Invalid username.
10
+ #
11
+ class LoginErrorMessages < CMSScanner::Finders::Finder
12
+ # @param [ Hash ] opts
13
+ # @option opts [ String ] :list
14
+ #
15
+ # @return [ Array<User> ]
16
+ def aggressive(opts = {})
17
+ found = []
18
+
19
+ usernames(opts).each do |username|
20
+ res = target.do_login(username, SecureRandom.hex[0, 8])
21
+
22
+ return found unless res.code == 200
23
+
24
+ error = res.html.css('div#login_error').text.strip
25
+
26
+ return found if error.empty? # Protection plugin / error disabled
27
+
28
+ next unless error =~ /The password you entered for the username|Incorrect Password/i
29
+
30
+ found << WPScan::User.new(username, found_by: found_by, confidence: 100)
31
+ end
32
+
33
+ found
34
+ end
35
+
36
+ # @return [ Array<String> ] List of usernames to check
37
+ def usernames(opts = {})
38
+ # usernames from the potential Users found
39
+ unames = opts[:found].map(&:username)
40
+
41
+ if opts[:list]
42
+ File.open(opts[:list]).each { |uname| unames << uname.chomp }
43
+ end
44
+
45
+ unames.uniq
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,31 @@
1
+ module WPScan
2
+ module Finders
3
+ module Users
4
+ # WP JSON API
5
+ #
6
+ # Since 4.7 - Need more investigation as it seems WP 4.7.1 reduces the exposure, see https://github.com/wpscanteam/wpscan/issues/1038)
7
+ #
8
+ class WpJsonApi < CMSScanner::Finders::Finder
9
+ # @param [ Hash ] opts
10
+ #
11
+ # @return [ Array<User> ]
12
+ def aggressive(_opts = {})
13
+ found = []
14
+
15
+ JSON.parse(Browser.get(api_url).body).each do |user|
16
+ found << WPScan::User.new(user['slug'], id: user['id'], found_by: found_by, confidence: 100)
17
+ end
18
+
19
+ found
20
+ rescue JSON::ParserError
21
+ found
22
+ end
23
+
24
+ # @return [ String ] The URL of the API listing the Users
25
+ def api_url
26
+ @api_url ||= target.url('wp-json/wp/v2/users/')
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1 @@
1
+ require_relative 'wp_items/urls_in_homepage'
@@ -0,0 +1,68 @@
1
+ module WPScan
2
+ module Finders
3
+ module WpItems
4
+ # URLs In Homepage Module to use in plugins & themes finders
5
+ module URLsInHomepage
6
+ # @param [ String ] type plugins / themes
7
+ # @param [ Boolean ] uniq Wether or not to apply the #uniq on the results
8
+ #
9
+ # @return [Array<String> ] The plugins/themes detected in the href, src attributes of the homepage
10
+ def items_from_links(type, uniq = true)
11
+ found = []
12
+
13
+ target.in_scope_urls(target.homepage_res) do |url|
14
+ next unless url =~ item_attribute_pattern(type)
15
+
16
+ found << Regexp.last_match[1]
17
+ end
18
+
19
+ uniq ? found.uniq.sort : found.sort
20
+ end
21
+
22
+ # @param [ String ] type plugins / themes
23
+ # @param [ Boolean ] uniq Wether or not to apply the #uniq on the results
24
+ #
25
+ # @return [Array<String> ] The plugins/themes detected in the javascript/style of the homepage
26
+ def items_from_codes(type, uniq = true)
27
+ found = []
28
+
29
+ target.homepage_res.html.css('script,style').each do |tag|
30
+ code = tag.text.to_s
31
+ next if code.empty?
32
+
33
+ code.scan(item_code_pattern(type)).flatten.uniq.each { |name| found << name }
34
+ end
35
+
36
+ uniq ? found.uniq.sort : found.sort
37
+ end
38
+
39
+ # @param [ String ] type
40
+ #
41
+ # @return [ Regexp ]
42
+ def item_attribute_pattern(type)
43
+ @item_attribute_pattern ||= %r{\A#{item_url_pattern(type)}([^/]+)/}i
44
+ end
45
+
46
+ # @param [ String ] type
47
+ #
48
+ # @return [ Regexp ]
49
+ def item_code_pattern(type)
50
+ @item_code_pattern ||= %r{["'\( ]#{item_url_pattern(type)}([^\\\/\)"']+)}i
51
+ end
52
+
53
+ # @param [ String ] type
54
+ #
55
+ # @return [ Regexp ]
56
+ def item_url_pattern(type)
57
+ item_dir = type == 'plugins' ? target.plugins_dir : target.content_dir
58
+ item_url = type == 'plugins' ? target.plugins_url : target.content_url
59
+
60
+ url = /#{item_url.gsub(/\A(?:http|https)/i, 'https?').gsub('/', '\\\\\?\/')}/i
61
+ item_dir = %r{(?:#{url}|\\?\/#{item_dir.gsub('/', '\\\\\?\/')}\\?/)}i
62
+
63
+ type == 'plugins' ? item_dir : %r{#{item_dir}#{type}\\?\/}i
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,34 @@
1
+ require_relative 'wp_version/meta_generator'
2
+ require_relative 'wp_version/rss_generator'
3
+ require_relative 'wp_version/atom_generator'
4
+ require_relative 'wp_version/rdf_generator'
5
+ require_relative 'wp_version/readme'
6
+ require_relative 'wp_version/sitemap_generator'
7
+ require_relative 'wp_version/opml_generator'
8
+ require_relative 'wp_version/stylesheets'
9
+ require_relative 'wp_version/unique_fingerprinting'
10
+
11
+ module WPScan
12
+ module Finders
13
+ module WpVersion
14
+ # Wp Version Finder
15
+ class Base
16
+ include CMSScanner::Finders::UniqueFinder
17
+
18
+ # @param [ WPScan::Target ] target
19
+ def initialize(target)
20
+ finders <<
21
+ WpVersion::MetaGenerator.new(target) <<
22
+ WpVersion::RSSGenerator.new(target) <<
23
+ WpVersion::AtomGenerator.new(target) <<
24
+ WpVersion::Stylesheets.new(target) <<
25
+ WpVersion::RDFGenerator.new(target) <<
26
+ WpVersion::Readme.new(target) <<
27
+ WpVersion::SitemapGenerator.new(target) <<
28
+ WpVersion::OpmlGenerator.new(target) <<
29
+ WpVersion::UniqueFingerprinting.new(target)
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end