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.
- 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,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
|