wpscan 3.8.2 → 3.8.3
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/app/controllers/password_attack.rb +21 -21
- data/app/finders/interesting_findings/mu_plugins.rb +1 -1
- data/app/finders/interesting_findings/multisite.rb +2 -2
- data/app/finders/main_theme/css_style_in_homepage.rb +2 -2
- data/app/finders/passwords/wp_login.rb +1 -1
- data/app/finders/passwords/xml_rpc.rb +1 -1
- data/app/finders/passwords/xml_rpc_multicall.rb +35 -9
- data/app/finders/plugin_version/readme.rb +2 -2
- data/app/finders/theme_version/style.rb +1 -1
- data/app/finders/users.rb +1 -1
- data/app/finders/users/login_error_messages.rb +1 -1
- data/app/finders/users/rss_generator.rb +1 -1
- data/app/finders/users/yoast_seo_author_sitemap.rb +1 -1
- data/app/finders/wp_items/urls_in_page.rb +3 -3
- data/app/models/plugin.rb +1 -1
- data/app/models/theme.rb +2 -2
- data/app/models/wp_item.rb +1 -1
- data/app/models/wp_version.rb +1 -1
- data/lib/wpscan/errors/wordpress.rb +6 -0
- data/lib/wpscan/finders/dynamic_finder/version/config_parser.rb +1 -1
- data/lib/wpscan/finders/dynamic_finder/version/query_parameter.rb +1 -1
- data/lib/wpscan/finders/dynamic_finder/version/xpath.rb +1 -1
- data/lib/wpscan/finders/dynamic_finder/wp_version.rb +1 -1
- data/lib/wpscan/helper.rb +1 -1
- data/lib/wpscan/target.rb +4 -4
- data/lib/wpscan/target/platform/wordpress.rb +8 -7
- data/lib/wpscan/target/platform/wordpress/custom_directories.rb +3 -3
- data/lib/wpscan/version.rb +1 -1
- metadata +8 -8
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 658d14ca9901acb16c2da34ed977e5ad75296c4c8aba3e66ba897ffb5dd55f86
|
4
|
+
data.tar.gz: 788c5a27c5bf10dba5b35e977c3efdfafca97944485cf605f03e34faf65ae68b
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: be04200a71b1d710d47e0a8be2b914731803a48c94a8da7bfa1ad777de8f1e103fe9ac785589d70ca905c389c369bd4567118bae6d3585f88f7bf12c52c053af
|
7
|
+
data.tar.gz: 42f54d70d4aea2433c5b619abb5c516e731f7cfefafe9d4e0d8876956eb8470012e211b826c4790b1c7144ff091431906597b2e2a7c1cd63f25b07ab87013caf
|
@@ -23,27 +23,32 @@ module WPScan
|
|
23
23
|
]
|
24
24
|
end
|
25
25
|
|
26
|
-
def
|
27
|
-
|
28
|
-
|
29
|
-
if user_interaction?
|
30
|
-
output('@info',
|
31
|
-
msg: "Performing password attack on #{attacker.titleize} against #{users.size} user/s")
|
32
|
-
end
|
33
|
-
|
34
|
-
attack_opts = {
|
26
|
+
def attack_opts
|
27
|
+
@attack_opts ||= {
|
35
28
|
show_progression: user_interaction?,
|
36
29
|
multicall_max_passwords: ParsedCli.multicall_max_passwords
|
37
30
|
}
|
31
|
+
end
|
32
|
+
|
33
|
+
def run
|
34
|
+
return unless ParsedCli.passwords
|
38
35
|
|
39
36
|
begin
|
40
37
|
found = []
|
41
38
|
|
42
|
-
|
39
|
+
if user_interaction?
|
40
|
+
output('@info',
|
41
|
+
msg: "Performing password attack on #{attacker.titleize} against #{users.size} user/s")
|
42
|
+
end
|
43
|
+
|
44
|
+
attacker.attack(users, ParsedCli.passwords, attack_opts) do |user|
|
43
45
|
found << user
|
44
46
|
|
45
47
|
attacker.progress_bar.log("[SUCCESS] - #{user.username} / #{user.password}")
|
46
48
|
end
|
49
|
+
rescue Error::NoLoginInterfaceDetected => e
|
50
|
+
# TODO: Maybe output that in JSON as well.
|
51
|
+
output('@notice', msg: e.to_s) if user_interaction?
|
47
52
|
ensure
|
48
53
|
output('users', users: found)
|
49
54
|
end
|
@@ -65,6 +70,8 @@ module WPScan
|
|
65
70
|
|
66
71
|
case ParsedCli.password_attack
|
67
72
|
when :wp_login
|
73
|
+
raise Error::NoLoginInterfaceDetected unless target.login_url
|
74
|
+
|
68
75
|
Finders::Passwords::WpLogin.new(target)
|
69
76
|
when :xmlrpc
|
70
77
|
raise Error::XMLRPCNotDetected unless xmlrpc
|
@@ -82,7 +89,7 @@ module WPScan
|
|
82
89
|
if xmlrpc&.enabled? &&
|
83
90
|
xmlrpc.available_methods.include?('wp.getUsersBlogs') &&
|
84
91
|
xmlrpc.method_call('wp.getUsersBlogs', [SecureRandom.hex[0, 6], SecureRandom.hex[0, 4]])
|
85
|
-
.run.body !~ /XML
|
92
|
+
.run.body !~ /XML-RPC services are disabled/
|
86
93
|
|
87
94
|
true
|
88
95
|
else
|
@@ -100,8 +107,10 @@ module WPScan
|
|
100
107
|
else
|
101
108
|
Finders::Passwords::XMLRPC.new(xmlrpc)
|
102
109
|
end
|
103
|
-
|
110
|
+
elsif target.login_url
|
104
111
|
Finders::Passwords::WpLogin.new(target)
|
112
|
+
else
|
113
|
+
raise Error::NoLoginInterfaceDetected
|
105
114
|
end
|
106
115
|
end
|
107
116
|
|
@@ -113,15 +122,6 @@ module WPScan
|
|
113
122
|
acc << Model::User.new(elem.chomp)
|
114
123
|
end
|
115
124
|
end
|
116
|
-
|
117
|
-
# @param [ String ] wordlist_path
|
118
|
-
#
|
119
|
-
# @return [ Array<String> ]
|
120
|
-
def passwords(wordlist_path)
|
121
|
-
@passwords ||= File.open(wordlist_path).reduce([]) do |acc, elem|
|
122
|
-
acc << elem.chomp
|
123
|
-
end
|
124
|
-
end
|
125
125
|
end
|
126
126
|
end
|
127
127
|
end
|
@@ -7,7 +7,7 @@ module WPScan
|
|
7
7
|
class MuPlugins < CMSScanner::Finders::Finder
|
8
8
|
# @return [ InterestingFinding ]
|
9
9
|
def passive(_opts = {})
|
10
|
-
pattern = %r{#{target.content_dir}/mu
|
10
|
+
pattern = %r{#{target.content_dir}/mu-plugins/}i
|
11
11
|
|
12
12
|
target.in_scope_uris(target.homepage_res, '(//@href|//@src)[contains(., "mu-plugins")]') do |uri|
|
13
13
|
next unless uri.path&.match?(pattern)
|
@@ -12,8 +12,8 @@ module WPScan
|
|
12
12
|
location = res.headers_hash['location']
|
13
13
|
|
14
14
|
return unless [200, 302].include?(res.code)
|
15
|
-
return if res.code == 302 && location
|
16
|
-
return unless res.code == 200 || res.code == 302 && location
|
15
|
+
return if res.code == 302 && location&.include?('wp-login.php?action=register')
|
16
|
+
return unless res.code == 200 || res.code == 302 && location&.include?('wp-signup.php')
|
17
17
|
|
18
18
|
target.multisite = true
|
19
19
|
|
@@ -21,7 +21,7 @@ module WPScan
|
|
21
21
|
|
22
22
|
def passive_from_css_href(res, opts)
|
23
23
|
target.in_scope_uris(res, '//link/@href[contains(., "style.css")]') do |uri|
|
24
|
-
next unless uri.path =~ %r{/themes/([
|
24
|
+
next unless uri.path =~ %r{/themes/([^/]+)/style.css\z}i
|
25
25
|
|
26
26
|
return create_theme(Regexp.last_match[1], uri.to_s, opts)
|
27
27
|
end
|
@@ -33,7 +33,7 @@ module WPScan
|
|
33
33
|
code = tag.text.to_s
|
34
34
|
next if code.empty?
|
35
35
|
|
36
|
-
next unless code =~ %r{#{item_code_pattern('themes')}\\?/style\.css[^"'
|
36
|
+
next unless code =~ %r{#{item_code_pattern('themes')}\\?/style\.css[^"'( ]*}i
|
37
37
|
|
38
38
|
return create_theme(Regexp.last_match[1], Regexp.last_match[0].strip, opts)
|
39
39
|
end
|
@@ -13,7 +13,7 @@ module WPScan
|
|
13
13
|
|
14
14
|
def valid_credentials?(response)
|
15
15
|
response.code == 302 &&
|
16
|
-
|
16
|
+
Array(response.headers['Set-Cookie'])&.any? { |cookie| cookie =~ /wordpress_logged_in_/i }
|
17
17
|
end
|
18
18
|
|
19
19
|
def errored_response?(response)
|
@@ -22,8 +22,30 @@ module WPScan
|
|
22
22
|
target.multi_call(methods, cache_ttl: 0).run
|
23
23
|
end
|
24
24
|
|
25
|
+
# @param [ IO ] file
|
26
|
+
# @param [ Integer ] passwords_size
|
27
|
+
# @return [ Array<String> ] The passwords from the last checked position in the file until there are
|
28
|
+
# passwords_size passwords retrieved
|
29
|
+
def passwords_from_wordlist(file, passwords_size)
|
30
|
+
pwds = []
|
31
|
+
added_pwds = 0
|
32
|
+
|
33
|
+
return pwds if passwords_size.zero?
|
34
|
+
|
35
|
+
# Make sure that the main code does not call #sysseek or #count etc
|
36
|
+
# otherwise the file descriptor will be set to somwehere else
|
37
|
+
file.each_line(chomp: true) do |line|
|
38
|
+
pwds << line
|
39
|
+
added_pwds += 1
|
40
|
+
|
41
|
+
break if added_pwds == passwords_size
|
42
|
+
end
|
43
|
+
|
44
|
+
pwds
|
45
|
+
end
|
46
|
+
|
25
47
|
# @param [ Array<Model::User> ] users
|
26
|
-
# @param [
|
48
|
+
# @param [ String ] wordlist_path
|
27
49
|
# @param [ Hash ] opts
|
28
50
|
# @option opts [ Boolean ] :show_progression
|
29
51
|
# @option opts [ Integer ] :multicall_max_passwords
|
@@ -33,18 +55,22 @@ module WPScan
|
|
33
55
|
# TODO: Make rubocop happy about metrics etc
|
34
56
|
#
|
35
57
|
# rubocop:disable all
|
36
|
-
def attack(users,
|
37
|
-
|
58
|
+
def attack(users, wordlist_path, opts = {})
|
59
|
+
checked_passwords = 0
|
60
|
+
wordlist = File.open(wordlist_path)
|
61
|
+
wordlist_size = wordlist.count
|
38
62
|
max_passwords = opts[:multicall_max_passwords]
|
39
63
|
current_passwords_size = passwords_size(max_passwords, users.size)
|
40
64
|
|
41
|
-
create_progress_bar(total: (
|
65
|
+
create_progress_bar(total: (wordlist_size / current_passwords_size.round(1)).ceil,
|
42
66
|
show_progression: opts[:show_progression])
|
43
67
|
|
68
|
+
wordlist.sysseek(0) # reset the descriptor to the beginning of the file as it changed with #count
|
69
|
+
|
44
70
|
loop do
|
45
|
-
current_users
|
46
|
-
current_passwords
|
47
|
-
|
71
|
+
current_users = users.select { |user| user.password.nil? }
|
72
|
+
current_passwords = passwords_from_wordlist(wordlist, current_passwords_size)
|
73
|
+
checked_passwords += current_passwords_size
|
48
74
|
|
49
75
|
break if current_users.empty? || current_passwords.nil? || current_passwords.empty?
|
50
76
|
|
@@ -75,9 +101,9 @@ module WPScan
|
|
75
101
|
progress_bar.stop
|
76
102
|
break
|
77
103
|
end
|
78
|
-
|
104
|
+
|
79
105
|
begin
|
80
|
-
progress_bar.total = progress_bar.progress + ((
|
106
|
+
progress_bar.total = progress_bar.progress + ((wordlist_size - checked_passwords) / current_passwords_size.round(1)).ceil
|
81
107
|
rescue ProgressBar::InvalidProgressError
|
82
108
|
end
|
83
109
|
end
|
@@ -48,7 +48,7 @@ module WPScan
|
|
48
48
|
#
|
49
49
|
# @return [ String, nil ] The version number detected from the stable tag
|
50
50
|
def from_stable_tag(body)
|
51
|
-
return unless body =~ /\b(?:stable tag|version):\s*(?!trunk)([0-9a-z
|
51
|
+
return unless body =~ /\b(?:stable tag|version):\s*(?!trunk)([0-9a-z.-]+)/i
|
52
52
|
|
53
53
|
number = Regexp.last_match[1]
|
54
54
|
|
@@ -59,7 +59,7 @@ module WPScan
|
|
59
59
|
#
|
60
60
|
# @return [ String, nil ] The best version number detected from the changelog section
|
61
61
|
def from_changelog_section(body)
|
62
|
-
extracted_versions = body.scan(%r{
|
62
|
+
extracted_versions = body.scan(%r{=+\s+(?:v(?:ersion)?\s*)?([0-9.-]+)[ \ta-z0-9().\-/]*=+}i)
|
63
63
|
|
64
64
|
return if extracted_versions.nil? || extracted_versions.empty?
|
65
65
|
|
@@ -30,7 +30,7 @@ module WPScan
|
|
30
30
|
|
31
31
|
# @return [ Version ]
|
32
32
|
def style_version
|
33
|
-
return unless Browser.get(target.style_url).body =~ /Version:[\t ]*(?!trunk)([0-9a-z
|
33
|
+
return unless Browser.get(target.style_url).body =~ /Version:[\t ]*(?!trunk)([0-9a-z.-]+)/i
|
34
34
|
|
35
35
|
Model::Version.new(
|
36
36
|
Regexp.last_match[1],
|
data/app/finders/users.rb
CHANGED
@@ -6,7 +6,7 @@ require_relative 'users/oembed_api'
|
|
6
6
|
require_relative 'users/rss_generator'
|
7
7
|
require_relative 'users/author_id_brute_forcing'
|
8
8
|
require_relative 'users/login_error_messages'
|
9
|
-
require_relative 'users/yoast_seo_author_sitemap
|
9
|
+
require_relative 'users/yoast_seo_author_sitemap'
|
10
10
|
|
11
11
|
module WPScan
|
12
12
|
module Finders
|
@@ -13,7 +13,7 @@ module WPScan
|
|
13
13
|
found = []
|
14
14
|
|
15
15
|
Browser.get(sitemap_url).html.xpath('//url/loc').each do |user_tag|
|
16
|
-
username = user_tag.text.to_s[%r{/author/([
|
16
|
+
username = user_tag.text.to_s[%r{/author/([^/]+)/}, 1]
|
17
17
|
|
18
18
|
next unless username && !username.strip.empty?
|
19
19
|
|
@@ -55,7 +55,7 @@ module WPScan
|
|
55
55
|
#
|
56
56
|
# @return [ Regexp ]
|
57
57
|
def item_code_pattern(type)
|
58
|
-
@item_code_pattern ||= %r{["'
|
58
|
+
@item_code_pattern ||= %r{["'( ]#{item_url_pattern(type)}([^\\/)"']+)}i
|
59
59
|
end
|
60
60
|
|
61
61
|
# @param [ String ] type
|
@@ -66,9 +66,9 @@ module WPScan
|
|
66
66
|
item_url = type == 'plugins' ? target.plugins_url : target.content_url
|
67
67
|
|
68
68
|
url = /#{item_url.gsub(/\A(?:https?)/i, 'https?').gsub('/', '\\\\\?\/')}/i
|
69
|
-
item_dir = %r{(?:#{url}
|
69
|
+
item_dir = %r{(?:#{url}|\\?/#{item_dir.gsub('/', '\\\\\?\/')}\\?/)}i
|
70
70
|
|
71
|
-
type == 'plugins' ? item_dir : %r{#{item_dir}#{type}
|
71
|
+
type == 'plugins' ? item_dir : %r{#{item_dir}#{type}\\?/}i
|
72
72
|
end
|
73
73
|
end
|
74
74
|
end
|
data/app/models/plugin.rb
CHANGED
@@ -38,7 +38,7 @@ module WPScan
|
|
38
38
|
|
39
39
|
# @return [ Array<String> ]
|
40
40
|
def potential_readme_filenames
|
41
|
-
@potential_readme_filenames ||=
|
41
|
+
@potential_readme_filenames ||= Array((DB::DynamicFinders::Plugin.df_data.dig(slug, 'Readme', 'path') || super))
|
42
42
|
end
|
43
43
|
end
|
44
44
|
end
|
data/app/models/theme.rb
CHANGED
@@ -45,7 +45,7 @@ module WPScan
|
|
45
45
|
# @return [ Theme ]
|
46
46
|
def parent_theme
|
47
47
|
return unless template
|
48
|
-
return unless style_body =~ /^@import\surl\(["']?([^"'
|
48
|
+
return unless style_body =~ /^@import\surl\(["']?([^"')]+)["']?\);\s*$/i
|
49
49
|
|
50
50
|
opts = detection_opts.merge(
|
51
51
|
style_url: url(Regexp.last_match[1]),
|
@@ -101,7 +101,7 @@ module WPScan
|
|
101
101
|
#
|
102
102
|
# @return [ String ]
|
103
103
|
def parse_style_tag(body, tag)
|
104
|
-
value = body[/#{Regexp.escape(tag)}:[\t ]*([^\r\n
|
104
|
+
value = body[/#{Regexp.escape(tag)}:[\t ]*([^\r\n*]+)/i, 1]
|
105
105
|
|
106
106
|
value && !value.strip.empty? ? value.strip : nil
|
107
107
|
end
|
data/app/models/wp_item.rb
CHANGED
@@ -39,7 +39,7 @@ module WPScan
|
|
39
39
|
|
40
40
|
@vulnerabilities = []
|
41
41
|
|
42
|
-
|
42
|
+
Array(db_data['vulnerabilities']).each do |json_vuln|
|
43
43
|
vulnerability = Vulnerability.load_from_json(json_vuln)
|
44
44
|
@vulnerabilities << vulnerability if vulnerable_to?(vulnerability)
|
45
45
|
end
|
data/app/models/wp_version.rb
CHANGED
@@ -29,5 +29,11 @@ module WPScan
|
|
29
29
|
' use the --scope option or make sure the --url value given is the correct one'
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
class NoLoginInterfaceDetected < Standard
|
34
|
+
def to_s
|
35
|
+
'Could not find a login interface to perform the password attack against'
|
36
|
+
end
|
37
|
+
end
|
32
38
|
end
|
33
39
|
end
|
@@ -9,7 +9,7 @@ module WPScan
|
|
9
9
|
# @return [ Hash ]
|
10
10
|
def self.child_class_constants
|
11
11
|
@child_class_constants ||= super().merge(
|
12
|
-
XPATH: nil, FILES: nil, PATTERN: /(?:v|ver|version)
|
12
|
+
XPATH: nil, FILES: nil, PATTERN: /(?:v|ver|version)=(?<v>\d+\.[.\d]+)/i, CONFIDENCE_PER_OCCURENCE: 10
|
13
13
|
)
|
14
14
|
end
|
15
15
|
|
data/lib/wpscan/helper.rb
CHANGED
@@ -13,7 +13,7 @@ end
|
|
13
13
|
#
|
14
14
|
# @return [ Symbol ]
|
15
15
|
def classify_slug(slug)
|
16
|
-
classified = slug.to_s.gsub(/[^a-z\d\-]/i, '-').gsub(
|
16
|
+
classified = slug.to_s.gsub(/[^a-z\d\-]/i, '-').gsub(/-{1,}/, '_').camelize.to_s
|
17
17
|
classified = "D_#{classified}" if /\d/.match?(classified[0])
|
18
18
|
|
19
19
|
classified.to_sym
|
data/lib/wpscan/target.rb
CHANGED
@@ -19,13 +19,13 @@ module WPScan
|
|
19
19
|
# @return [ Boolean ]
|
20
20
|
def vulnerable?
|
21
21
|
[@wp_version, @main_theme, @plugins, @themes, @timthumbs].each do |e|
|
22
|
-
|
22
|
+
Array(e).each { |ae| return true if ae && ae.vulnerable? } # rubocop:disable Style/SafeNavigation
|
23
23
|
end
|
24
24
|
|
25
|
-
return true unless
|
26
|
-
return true unless
|
25
|
+
return true unless Array(@config_backups).empty?
|
26
|
+
return true unless Array(@db_exports).empty?
|
27
27
|
|
28
|
-
|
28
|
+
Array(@users).each { |u| return true if u.password }
|
29
29
|
|
30
30
|
false
|
31
31
|
end
|
@@ -11,9 +11,9 @@ module WPScan
|
|
11
11
|
module WordPress
|
12
12
|
include CMSScanner::Target::Platform::PHP
|
13
13
|
|
14
|
-
WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|(?:mu
|
15
|
-
WP_JSON_OEMBED_PATTERN = %r{/wp
|
16
|
-
WP_ADMIN_AJAX_PATTERN = %r{\\?/wp
|
14
|
+
WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|(?:mu-)?plugins|uploads))|wp-includes)/}i.freeze
|
15
|
+
WP_JSON_OEMBED_PATTERN = %r{/wp-json/oembed/}i.freeze
|
16
|
+
WP_ADMIN_AJAX_PATTERN = %r{\\?/wp-admin\\?/admin-ajax\.php}i.freeze
|
17
17
|
|
18
18
|
# These methods are used in the associated interesting_findings finders
|
19
19
|
# to keep the boolean state of the finding rather than re-check the whole thing again
|
@@ -139,15 +139,16 @@ module WPScan
|
|
139
139
|
# the first time the method is called, and the effective_url is then used
|
140
140
|
# if suitable, otherwise the default wp-login will be.
|
141
141
|
#
|
142
|
-
# @return [ String ] The URL to the login page
|
142
|
+
# @return [ String, false ] The URL to the login page or false if not detected
|
143
143
|
def login_url
|
144
|
-
return @login_url
|
144
|
+
return @login_url unless @login_url.nil?
|
145
145
|
|
146
|
-
@login_url = url('wp-login.php')
|
146
|
+
@login_url = url('wp-login.php') # TODO: url(ParsedCli.login_uri)
|
147
147
|
|
148
148
|
res = Browser.get_and_follow_location(@login_url)
|
149
149
|
|
150
|
-
@login_url = res.effective_url if res.effective_url =~ /wp
|
150
|
+
@login_url = res.effective_url if res.effective_url =~ /wp-login\.php\z/i && in_scope?(res.effective_url)
|
151
|
+
@login_url = false if res.code == 404
|
151
152
|
|
152
153
|
@login_url
|
153
154
|
end
|
@@ -104,7 +104,7 @@ module WPScan
|
|
104
104
|
return @sub_dir unless @sub_dir.nil?
|
105
105
|
|
106
106
|
# url_pattern is from CMSScanner::Target
|
107
|
-
pattern = %r{#{url_pattern}(.+?)/(?:xmlrpc\.php|wp
|
107
|
+
pattern = %r{#{url_pattern}(.+?)/(?:xmlrpc\.php|wp-includes/)}i
|
108
108
|
xpath = '(//@src|//@href|//@data-src)[contains(., "xmlrpc.php") or contains(., "wp-includes/")]'
|
109
109
|
|
110
110
|
[homepage_res, error_404_res].each do |page_res|
|
@@ -124,9 +124,9 @@ module WPScan
|
|
124
124
|
def url(path = nil)
|
125
125
|
return @uri.to_s unless path
|
126
126
|
|
127
|
-
if %r{wp
|
127
|
+
if %r{wp-content/plugins}i.match?(path)
|
128
128
|
path = +path.gsub('wp-content/plugins', plugins_dir)
|
129
|
-
elsif /wp
|
129
|
+
elsif /wp-content/i.match?(path)
|
130
130
|
path = +path.gsub('wp-content', content_dir)
|
131
131
|
elsif path[0] != '/' && sub_dir
|
132
132
|
path = "#{sub_dir}/#{path}"
|
data/lib/wpscan/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: wpscan
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.8.
|
4
|
+
version: 3.8.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- WPScanTeam
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-07-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: cms_scanner
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: 0.
|
19
|
+
version: 0.12.0
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: 0.
|
26
|
+
version: 0.12.0
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: bundler
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -100,28 +100,28 @@ dependencies:
|
|
100
100
|
requirements:
|
101
101
|
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
|
-
version: 0.
|
103
|
+
version: 0.88.0
|
104
104
|
type: :development
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
108
|
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
|
-
version: 0.
|
110
|
+
version: 0.88.0
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: rubocop-performance
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
115
|
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
|
-
version: 1.
|
117
|
+
version: 1.7.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
122
|
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
|
-
version: 1.
|
124
|
+
version: 1.7.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: simplecov
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|