wpscan 3.7.9 → 3.8.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +14 -15
- data/app/controllers/enumeration/cli_options.rb +2 -3
- data/app/controllers/vuln_api.rb +4 -2
- data/app/finders/db_exports/known_locations.rb +1 -1
- data/app/finders/interesting_findings/backup_db.rb +1 -2
- data/app/finders/interesting_findings/debug_log.rb +1 -5
- data/app/finders/interesting_findings/duplicator_installer_log.rb +1 -6
- data/app/finders/interesting_findings/emergency_pwd_reset_script.rb +1 -4
- data/app/finders/interesting_findings/full_path_disclosure.rb +1 -2
- data/app/finders/interesting_findings/mu_plugins.rb +2 -14
- data/app/finders/interesting_findings/multisite.rb +1 -7
- data/app/finders/interesting_findings/registration.rb +1 -6
- data/app/finders/interesting_findings/tmm_db_migrate.rb +1 -6
- data/app/finders/interesting_findings/upload_directory_listing.rb +1 -6
- data/app/finders/interesting_findings/upload_sql_dump.rb +1 -5
- data/app/finders/interesting_findings/wp_cron.rb +1 -11
- data/app/finders/passwords/xml_rpc.rb +1 -1
- data/app/finders/passwords/xml_rpc_multicall.rb +13 -6
- data/app/finders/plugin_version/readme.rb +3 -5
- data/app/finders/users/wp_json_api.rb +1 -1
- data/app/models/interesting_finding.rb +66 -1
- data/app/models/timthumb.rb +6 -6
- data/app/models/xml_rpc.rb +1 -1
- data/app/views/cli/password_attack/users.erb +1 -1
- data/app/views/cli/vulnerability.erb +3 -0
- data/app/views/json/finding.erb +3 -0
- data/lib/wpscan/db/updater.rb +12 -14
- data/lib/wpscan/errors/update.rb +12 -0
- data/lib/wpscan/finders/dynamic_finder/finder.rb +1 -1
- data/lib/wpscan/finders/dynamic_finder/version/config_parser.rb +4 -6
- data/lib/wpscan/references.rb +1 -1
- data/lib/wpscan/target/platform/wordpress.rb +1 -1
- data/lib/wpscan/version.rb +1 -1
- data/lib/wpscan/vulnerability.rb +4 -3
- metadata +9 -9
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '095c33e6d410081b90f0ea858284cd4c2040b551830fd1756ab7f70dcae34022'
|
4
|
+
data.tar.gz: b8f36a805212d33d7448ebba76a908a2a0cf51e72d1b3df6ce3e434987359864
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 921466d7d508f0d6f6dddd8e53bab8bf1ce0a7202c778f477ce669c724c9a5348a3e94befafc51e18a331dcc8566946c330493c69c415ba8701612bc59efe4ad
|
7
|
+
data.tar.gz: eba875df92089460d02b2bf8b4d00b47149f3d176ff203767dbe02b4a20612db0e868c3b3f17e1e5b3a1f16096f1d89d704ecbbee854cc5f2de7a3b39fea6855
|
data/README.md
CHANGED
@@ -7,10 +7,10 @@
|
|
7
7
|
<h3 align="center">WPScan</h3>
|
8
8
|
|
9
9
|
<p align="center">
|
10
|
-
WordPress
|
10
|
+
WordPress Security Scanner
|
11
11
|
<br>
|
12
12
|
<br>
|
13
|
-
<a href="https://wpscan.org/" title="homepage" target="_blank">Homepage</a> - <a href="https://wpscan.io/" title="wpscan.io" target="_blank">WPScan.io</a> - <a href="https://wpvulndb.com/" title="vulnerability database" target="_blank">Vulnerability Database</a> - <a href="https://wordpress.org/plugins/wpscan/" title="wordpress plugin" target="_blank">WordPress Plugin</a>
|
13
|
+
<a href="https://wpscan.org/" title="homepage" target="_blank">Homepage</a> - <a href="https://wpscan.io/" title="wpscan.io" target="_blank">WPScan.io</a> - <a href="https://wpvulndb.com/" title="vulnerability database" target="_blank">Vulnerability Database</a> - <a href="https://wordpress.org/plugins/wpscan/" title="wordpress security plugin" target="_blank">WordPress Security Plugin</a>
|
14
14
|
</p>
|
15
15
|
|
16
16
|
<p align="center">
|
@@ -31,7 +31,11 @@
|
|
31
31
|
- RubyGems - Recommended: latest
|
32
32
|
- Nokogiri might require packages to be installed via your package manager depending on your OS, see https://nokogiri.org/tutorials/installing_nokogiri.html
|
33
33
|
|
34
|
-
###
|
34
|
+
### In a Pentesting distribution
|
35
|
+
|
36
|
+
When using a pentesting distubution (such as Kali Linux), it is recommended to install/update wpscan via the package manager if available.
|
37
|
+
|
38
|
+
### From RubyGems
|
35
39
|
|
36
40
|
```shell
|
37
41
|
gem install wpscan
|
@@ -39,18 +43,6 @@ gem install wpscan
|
|
39
43
|
|
40
44
|
On MacOSX, if a ```Gem::FilePermissionError``` is raised due to the Apple's System Integrity Protection (SIP), either install RVM and install wpscan again, or run ```sudo gem install -n /usr/local/bin wpscan``` (see [#1286](https://github.com/wpscanteam/wpscan/issues/1286))
|
41
45
|
|
42
|
-
### From sources (NOT Recommended)
|
43
|
-
|
44
|
-
Prerequisites: Git
|
45
|
-
|
46
|
-
```shell
|
47
|
-
git clone https://github.com/wpscanteam/wpscan
|
48
|
-
|
49
|
-
cd wpscan/
|
50
|
-
|
51
|
-
bundle install && rake install
|
52
|
-
```
|
53
|
-
|
54
46
|
# Updating
|
55
47
|
|
56
48
|
You can update the local database by using ```wpscan --update```
|
@@ -77,6 +69,8 @@ docker run -it --rm wpscanteam/wpscan --url https://target.tld/ --enumerate u1-1
|
|
77
69
|
|
78
70
|
# Usage
|
79
71
|
|
72
|
+
Full user documentation can be found here; https://github.com/wpscanteam/wpscan/wiki/WPScan-User-Documentation
|
73
|
+
|
80
74
|
```wpscan --url blog.tld``` This will scan the blog using default options with a good compromise between speed and accuracy. For example, the plugins will be checked passively but their version with a mixed detection mode (passively + aggressively). Potential config backup files will also be checked, along with other interesting findings.
|
81
75
|
|
82
76
|
If a more stealthy approach is required, then ```wpscan --stealthy --url blog.tld``` can be used.
|
@@ -130,6 +124,11 @@ cli_options:
|
|
130
124
|
api_token: YOUR_API_TOKEN
|
131
125
|
```
|
132
126
|
|
127
|
+
## Load API Token From ENV (since v3.7.10)
|
128
|
+
|
129
|
+
The API Token will be automatically loaded from the ENV variable `WPSCAN_API_TOKEN` if present. If the `--api-token` CLI option is also provided, the value from the CLI will be used.
|
130
|
+
|
131
|
+
|
133
132
|
## Enumerating usernames
|
134
133
|
|
135
134
|
```shell
|
@@ -51,7 +51,7 @@ module WPScan
|
|
51
51
|
OptSmartList.new(['--plugins-list LIST', 'List of plugins to enumerate'], advanced: true),
|
52
52
|
OptChoice.new(
|
53
53
|
['--plugins-detection MODE',
|
54
|
-
'Use the supplied mode to enumerate Plugins
|
54
|
+
'Use the supplied mode to enumerate Plugins.'],
|
55
55
|
choices: %w[mixed passive aggressive], normalize: :to_sym, default: :passive
|
56
56
|
),
|
57
57
|
OptBoolean.new(
|
@@ -62,8 +62,7 @@ module WPScan
|
|
62
62
|
),
|
63
63
|
OptChoice.new(
|
64
64
|
['--plugins-version-detection MODE',
|
65
|
-
'Use the supplied mode to check plugins versions
|
66
|
-
'or --plugins-detection modes.'],
|
65
|
+
'Use the supplied mode to check plugins\' versions.'],
|
67
66
|
choices: %w[mixed passive aggressive], normalize: :to_sym, default: :mixed
|
68
67
|
),
|
69
68
|
OptInteger.new(
|
data/app/controllers/vuln_api.rb
CHANGED
@@ -4,6 +4,8 @@ module WPScan
|
|
4
4
|
module Controller
|
5
5
|
# Controller to handle the API token
|
6
6
|
class VulnApi < CMSScanner::Controller::Base
|
7
|
+
ENV_KEY = 'WPSCAN_API_TOKEN'
|
8
|
+
|
7
9
|
def cli_options
|
8
10
|
[
|
9
11
|
OptString.new(['--api-token TOKEN', 'The WPVulnDB API Token to display vulnerability data'])
|
@@ -11,9 +13,9 @@ module WPScan
|
|
11
13
|
end
|
12
14
|
|
13
15
|
def before_scan
|
14
|
-
return unless ParsedCli.api_token
|
16
|
+
return unless ParsedCli.api_token || ENV.key?(ENV_KEY)
|
15
17
|
|
16
|
-
DB::VulnApi.token = ParsedCli.api_token
|
18
|
+
DB::VulnApi.token = ParsedCli.api_token || ENV[ENV_KEY]
|
17
19
|
|
18
20
|
api_status = DB::VulnApi.status
|
19
21
|
|
@@ -40,7 +40,7 @@ module WPScan
|
|
40
40
|
# @return [ Hash ]
|
41
41
|
def potential_urls(opts = {})
|
42
42
|
urls = {}
|
43
|
-
domain_name = PublicSuffix.domain(target.uri.host)[/(^[\w|-]+)/, 1]
|
43
|
+
domain_name = (PublicSuffix.domain(target.uri.host) || target.uri.host)[/(^[\w|-]+)/, 1]
|
44
44
|
|
45
45
|
File.open(opts[:list]).each_with_index do |path, index|
|
46
46
|
path.gsub!('{domain_name}', domain_name)
|
@@ -16,8 +16,7 @@ module WPScan
|
|
16
16
|
target.url(path),
|
17
17
|
confidence: 70,
|
18
18
|
found_by: DIRECT_ACCESS,
|
19
|
-
interesting_entries: target.directory_listing_entries(path)
|
20
|
-
references: { url: 'https://github.com/wpscanteam/wpscan/issues/422' }
|
19
|
+
interesting_entries: target.directory_listing_entries(path)
|
21
20
|
)
|
22
21
|
end
|
23
22
|
end
|
@@ -11,11 +11,7 @@ module WPScan
|
|
11
11
|
|
12
12
|
return unless target.debug_log?(path)
|
13
13
|
|
14
|
-
Model::DebugLog.new(
|
15
|
-
target.url(path),
|
16
|
-
confidence: 100, found_by: DIRECT_ACCESS,
|
17
|
-
references: { url: 'https://codex.wordpress.org/Debugging_in_WordPress' }
|
18
|
-
)
|
14
|
+
Model::DebugLog.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS)
|
19
15
|
end
|
20
16
|
end
|
21
17
|
end
|
@@ -11,12 +11,7 @@ module WPScan
|
|
11
11
|
|
12
12
|
return unless /DUPLICATOR INSTALL-LOG/.match?(target.head_and_get(path).body)
|
13
13
|
|
14
|
-
Model::DuplicatorInstallerLog.new(
|
15
|
-
target.url(path),
|
16
|
-
confidence: 100,
|
17
|
-
found_by: DIRECT_ACCESS,
|
18
|
-
references: { url: 'https://www.exploit-db.com/ghdb/3981/' }
|
19
|
-
)
|
14
|
+
Model::DuplicatorInstallerLog.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS)
|
20
15
|
end
|
21
16
|
end
|
22
17
|
end
|
@@ -15,10 +15,7 @@ module WPScan
|
|
15
15
|
Model::EmergencyPwdResetScript.new(
|
16
16
|
target.url(path),
|
17
17
|
confidence: /password/i.match?(res.body) ? 100 : 40,
|
18
|
-
found_by: DIRECT_ACCESS
|
19
|
-
references: {
|
20
|
-
url: 'https://codex.wordpress.org/Resetting_Your_Password#Using_the_Emergency_Password_Reset_Script'
|
21
|
-
}
|
18
|
+
found_by: DIRECT_ACCESS
|
22
19
|
)
|
23
20
|
end
|
24
21
|
end
|
@@ -16,13 +16,7 @@ module WPScan
|
|
16
16
|
|
17
17
|
target.mu_plugins = true
|
18
18
|
|
19
|
-
return Model::MuPlugins.new(
|
20
|
-
url,
|
21
|
-
confidence: 70,
|
22
|
-
found_by: 'URLs In Homepage (Passive Detection)',
|
23
|
-
to_s: "This site has 'Must Use Plugins': #{url}",
|
24
|
-
references: { url: 'http://codex.wordpress.org/Must_Use_Plugins' }
|
25
|
-
)
|
19
|
+
return Model::MuPlugins.new(url, confidence: 70, found_by: 'URLs In Homepage (Passive Detection)')
|
26
20
|
end
|
27
21
|
nil
|
28
22
|
end
|
@@ -37,13 +31,7 @@ module WPScan
|
|
37
31
|
|
38
32
|
target.mu_plugins = true
|
39
33
|
|
40
|
-
Model::MuPlugins.new(
|
41
|
-
url,
|
42
|
-
confidence: 80,
|
43
|
-
found_by: DIRECT_ACCESS,
|
44
|
-
to_s: "This site has 'Must Use Plugins': #{url}",
|
45
|
-
references: { url: 'http://codex.wordpress.org/Must_Use_Plugins' }
|
46
|
-
)
|
34
|
+
Model::MuPlugins.new(url, confidence: 80, found_by: DIRECT_ACCESS)
|
47
35
|
end
|
48
36
|
end
|
49
37
|
end
|
@@ -17,13 +17,7 @@ module WPScan
|
|
17
17
|
|
18
18
|
target.multisite = true
|
19
19
|
|
20
|
-
Model::Multisite.new(
|
21
|
-
url,
|
22
|
-
confidence: 100,
|
23
|
-
found_by: DIRECT_ACCESS,
|
24
|
-
to_s: 'This site seems to be a multisite',
|
25
|
-
references: { url: 'http://codex.wordpress.org/Glossary#Multisite' }
|
26
|
-
)
|
20
|
+
Model::Multisite.new(url, confidence: 100, found_by: DIRECT_ACCESS)
|
27
21
|
end
|
28
22
|
end
|
29
23
|
end
|
@@ -20,12 +20,7 @@ module WPScan
|
|
20
20
|
|
21
21
|
target.registration_enabled = true
|
22
22
|
|
23
|
-
Model::Registration.new(
|
24
|
-
res.effective_url,
|
25
|
-
confidence: 100,
|
26
|
-
found_by: DIRECT_ACCESS,
|
27
|
-
to_s: "Registration is enabled: #{res.effective_url}"
|
28
|
-
)
|
23
|
+
Model::Registration.new(res.effective_url, confidence: 100, found_by: DIRECT_ACCESS)
|
29
24
|
end
|
30
25
|
end
|
31
26
|
end
|
@@ -13,12 +13,7 @@ module WPScan
|
|
13
13
|
|
14
14
|
return unless res.code == 200 && res.headers['Content-Type'] =~ %r{\Aapplication/zip}i
|
15
15
|
|
16
|
-
Model::TmmDbMigrate.new(
|
17
|
-
url,
|
18
|
-
confidence: 100,
|
19
|
-
found_by: DIRECT_ACCESS,
|
20
|
-
references: { packetstorm: 131_957 }
|
21
|
-
)
|
16
|
+
Model::TmmDbMigrate.new(url, confidence: 100, found_by: DIRECT_ACCESS)
|
22
17
|
end
|
23
18
|
end
|
24
19
|
end
|
@@ -13,12 +13,7 @@ module WPScan
|
|
13
13
|
|
14
14
|
url = target.url(path)
|
15
15
|
|
16
|
-
Model::UploadDirectoryListing.new(
|
17
|
-
url,
|
18
|
-
confidence: 100,
|
19
|
-
found_by: DIRECT_ACCESS,
|
20
|
-
to_s: "Upload directory has listing enabled: #{url}"
|
21
|
-
)
|
16
|
+
Model::UploadDirectoryListing.new(url, confidence: 100, found_by: DIRECT_ACCESS)
|
22
17
|
end
|
23
18
|
end
|
24
19
|
end
|
@@ -14,11 +14,7 @@ module WPScan
|
|
14
14
|
|
15
15
|
return unless SQL_PATTERN.match?(res.body)
|
16
16
|
|
17
|
-
Model::UploadSQLDump.new(
|
18
|
-
target.url(path),
|
19
|
-
confidence: 100,
|
20
|
-
found_by: DIRECT_ACCESS
|
21
|
-
)
|
17
|
+
Model::UploadSQLDump.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS)
|
22
18
|
end
|
23
19
|
end
|
24
20
|
end
|
@@ -11,17 +11,7 @@ module WPScan
|
|
11
11
|
|
12
12
|
return unless res.code == 200
|
13
13
|
|
14
|
-
Model::WPCron.new(
|
15
|
-
wp_cron_url,
|
16
|
-
confidence: 60,
|
17
|
-
found_by: DIRECT_ACCESS,
|
18
|
-
references: {
|
19
|
-
url: [
|
20
|
-
'https://www.iplocation.net/defend-wordpress-from-ddos',
|
21
|
-
'https://github.com/wpscanteam/wpscan/issues/1299'
|
22
|
-
]
|
23
|
-
}
|
24
|
-
)
|
14
|
+
Model::WPCron.new(wp_cron_url, confidence: 60, found_by: DIRECT_ACCESS)
|
25
15
|
end
|
26
16
|
|
27
17
|
def wp_cron_url
|
@@ -75,17 +75,20 @@ module WPScan
|
|
75
75
|
progress_bar.stop
|
76
76
|
break
|
77
77
|
end
|
78
|
-
|
79
|
-
|
78
|
+
|
79
|
+
begin
|
80
|
+
progress_bar.total = progress_bar.progress + ((passwords.size - wordlist_index) / current_passwords_size.round(1)).ceil
|
81
|
+
rescue ProgressBar::InvalidProgressError
|
82
|
+
end
|
80
83
|
end
|
81
84
|
end
|
82
85
|
# Maybe a progress_bar.stop ?
|
83
86
|
end
|
84
|
-
# rubocop:
|
87
|
+
# rubocop:enable all
|
85
88
|
|
86
89
|
def passwords_size(max_passwords, users_size)
|
87
90
|
return 1 if max_passwords < users_size
|
88
|
-
return 0 if users_size
|
91
|
+
return 0 if users_size.zero?
|
89
92
|
|
90
93
|
max_passwords / users_size
|
91
94
|
end
|
@@ -94,9 +97,13 @@ module WPScan
|
|
94
97
|
def check_and_output_errors(res)
|
95
98
|
progress_bar.log("Incorrect response: #{res.code} / #{res.return_message}") unless res.code == 200
|
96
99
|
|
97
|
-
|
100
|
+
if /parse error. not well formed/i.match?(res.body)
|
101
|
+
progress_bar.log('Parsing error, might be caused by a too high --max-passwords value (such as >= 2k)')
|
102
|
+
end
|
103
|
+
|
104
|
+
return unless /requested method [^ ]+ does not exist/i.match?(res.body)
|
98
105
|
|
99
|
-
progress_bar.log('The requested method is not supported')
|
106
|
+
progress_bar.log('The requested method is not supported')
|
100
107
|
end
|
101
108
|
end
|
102
109
|
end
|
@@ -68,11 +68,9 @@ module WPScan
|
|
68
68
|
extracted_versions = extracted_versions.select { |x| x =~ /[0-9]+/ }
|
69
69
|
|
70
70
|
sorted = extracted_versions.sort do |x, y|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
0
|
75
|
-
end
|
71
|
+
Gem::Version.new(x) <=> Gem::Version.new(y)
|
72
|
+
rescue StandardError
|
73
|
+
0
|
76
74
|
end
|
77
75
|
|
78
76
|
sorted.last
|
@@ -21,7 +21,7 @@ module WPScan
|
|
21
21
|
loop do
|
22
22
|
current_page += 1
|
23
23
|
|
24
|
-
res =
|
24
|
+
res = Browser.get(api_url, params: { per_page: MAX_PER_PAGE, page: current_page })
|
25
25
|
|
26
26
|
total_pages ||= res.headers['X-WP-TotalPages'].to_i
|
27
27
|
|
@@ -8,45 +8,110 @@ module WPScan
|
|
8
8
|
end
|
9
9
|
|
10
10
|
#
|
11
|
-
#
|
11
|
+
# Some classes are empty for the #type to be correctly displayed (as taken from the self.class from the parent)
|
12
12
|
#
|
13
13
|
class BackupDB < InterestingFinding
|
14
|
+
# @return [ Hash ]
|
15
|
+
def references
|
16
|
+
@references ||= { url: ['https://github.com/wpscanteam/wpscan/issues/422'] }
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
class DebugLog < InterestingFinding
|
21
|
+
# @ return [ Hash ]
|
22
|
+
def references
|
23
|
+
@references ||= { url: ['https://codex.wordpress.org/Debugging_in_WordPress'] }
|
24
|
+
end
|
17
25
|
end
|
18
26
|
|
19
27
|
class DuplicatorInstallerLog < InterestingFinding
|
28
|
+
# @return [ Hash ]
|
29
|
+
def references
|
30
|
+
@references ||= { url: ['https://www.exploit-db.com/ghdb/3981/'] }
|
31
|
+
end
|
20
32
|
end
|
21
33
|
|
22
34
|
class EmergencyPwdResetScript < InterestingFinding
|
35
|
+
def references
|
36
|
+
@references ||= {
|
37
|
+
url: ['https://codex.wordpress.org/Resetting_Your_Password#Using_the_Emergency_Password_Reset_Script']
|
38
|
+
}
|
39
|
+
end
|
23
40
|
end
|
24
41
|
|
25
42
|
class FullPathDisclosure < InterestingFinding
|
43
|
+
# @return [ Hash ]
|
44
|
+
def references
|
45
|
+
@references ||= { url: ['https://www.owasp.org/index.php/Full_Path_Disclosure'] }
|
46
|
+
end
|
26
47
|
end
|
27
48
|
|
28
49
|
class MuPlugins < InterestingFinding
|
50
|
+
# @return [ String ]
|
51
|
+
def to_s
|
52
|
+
@to_s ||= "This site has 'Must Use Plugins': #{url}"
|
53
|
+
end
|
54
|
+
|
55
|
+
# @return [ Hash ]
|
56
|
+
def references
|
57
|
+
@references ||= { url: ['http://codex.wordpress.org/Must_Use_Plugins'] }
|
58
|
+
end
|
29
59
|
end
|
30
60
|
|
31
61
|
class Multisite < InterestingFinding
|
62
|
+
# @return [ String ]
|
63
|
+
def to_s
|
64
|
+
@to_s ||= 'This site seems to be a multisite'
|
65
|
+
end
|
66
|
+
|
67
|
+
# @return [ Hash ]
|
68
|
+
def references
|
69
|
+
@references ||= { url: ['http://codex.wordpress.org/Glossary#Multisite'] }
|
70
|
+
end
|
32
71
|
end
|
33
72
|
|
34
73
|
class Readme < InterestingFinding
|
35
74
|
end
|
36
75
|
|
37
76
|
class Registration < InterestingFinding
|
77
|
+
# @return [ String ]
|
78
|
+
def to_s
|
79
|
+
@to_s ||= "Registration is enabled: #{url}"
|
80
|
+
end
|
38
81
|
end
|
39
82
|
|
40
83
|
class TmmDbMigrate < InterestingFinding
|
84
|
+
# @return [ Hash ]
|
85
|
+
def references
|
86
|
+
@references ||= { packetstorm: [131_957] }
|
87
|
+
end
|
41
88
|
end
|
42
89
|
|
43
90
|
class UploadDirectoryListing < InterestingFinding
|
91
|
+
# @return [ String ]
|
92
|
+
def to_s
|
93
|
+
@to_s ||= "Upload directory has listing enabled: #{url}"
|
94
|
+
end
|
44
95
|
end
|
45
96
|
|
46
97
|
class UploadSQLDump < InterestingFinding
|
47
98
|
end
|
48
99
|
|
49
100
|
class WPCron < InterestingFinding
|
101
|
+
# @return [ String ]
|
102
|
+
def to_s
|
103
|
+
@to_s ||= "The external WP-Cron seems to be enabled: #{url}"
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [ Hash ]
|
107
|
+
def references
|
108
|
+
@references ||= {
|
109
|
+
url: [
|
110
|
+
'https://www.iplocation.net/defend-wordpress-from-ddos',
|
111
|
+
'https://github.com/wpscanteam/wpscan/issues/1299'
|
112
|
+
]
|
113
|
+
}
|
114
|
+
end
|
50
115
|
end
|
51
116
|
end
|
52
117
|
end
|
data/app/models/timthumb.rb
CHANGED
@@ -40,9 +40,9 @@ module WPScan
|
|
40
40
|
def rce_132_vuln
|
41
41
|
Vulnerability.new(
|
42
42
|
'Timthumb <= 1.32 Remote Code Execution',
|
43
|
-
{ exploitdb: ['17602'] },
|
44
|
-
'RCE',
|
45
|
-
'1.33'
|
43
|
+
references: { exploitdb: ['17602'] },
|
44
|
+
type: 'RCE',
|
45
|
+
fixed_in: '1.33'
|
46
46
|
)
|
47
47
|
end
|
48
48
|
|
@@ -50,12 +50,12 @@ module WPScan
|
|
50
50
|
def rce_webshot_vuln
|
51
51
|
Vulnerability.new(
|
52
52
|
'Timthumb <= 2.8.13 WebShot Remote Code Execution',
|
53
|
-
{
|
53
|
+
references: {
|
54
54
|
url: ['http://seclists.org/fulldisclosure/2014/Jun/117', 'https://github.com/wpscanteam/wpscan/issues/519'],
|
55
55
|
cve: '2014-4663'
|
56
56
|
},
|
57
|
-
'RCE',
|
58
|
-
'2.8.14'
|
57
|
+
type: 'RCE',
|
58
|
+
fixed_in: '2.8.14'
|
59
59
|
)
|
60
60
|
end
|
61
61
|
|
data/app/models/xml_rpc.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
<% if @users.empty? -%>
|
3
3
|
<%= notice_icon %> No Valid Passwords Found.
|
4
4
|
<% else -%>
|
5
|
-
<%=
|
5
|
+
<%= critical_icon %> Valid Combinations Found:
|
6
6
|
<% @users.each do |user| -%>
|
7
7
|
| Username: <%= user.username %>, Password: <%= user.password %>
|
8
8
|
<% end -%>
|
data/app/views/json/finding.erb
CHANGED
@@ -19,6 +19,9 @@
|
|
19
19
|
<% vulns.each_with_index do |v, index| -%>
|
20
20
|
{
|
21
21
|
"title": <%= v.title.to_json %>,
|
22
|
+
<% if v.cvss -%>
|
23
|
+
"cvss": <%= v.cvss.to_json %>,
|
24
|
+
<% end -%>
|
22
25
|
"fixed_in": <%= v.fixed_in.to_json %>,
|
23
26
|
"references": <%= v.references.to_json %>
|
24
27
|
}<% unless index == last_index -%>,<% end -%>
|
data/lib/wpscan/db/updater.rb
CHANGED
@@ -139,24 +139,22 @@ module WPScan
|
|
139
139
|
updated = []
|
140
140
|
|
141
141
|
FILES.each do |filename|
|
142
|
-
|
143
|
-
db_checksum = remote_file_checksum(filename)
|
142
|
+
db_checksum = remote_file_checksum(filename)
|
144
143
|
|
145
|
-
|
146
|
-
|
144
|
+
# Checking if the file needs to be updated
|
145
|
+
next if File.exist?(local_file_path(filename)) && db_checksum == local_file_checksum(filename)
|
147
146
|
|
148
|
-
|
149
|
-
|
147
|
+
create_backup(filename)
|
148
|
+
dl_checksum = download(filename)
|
150
149
|
|
151
|
-
|
150
|
+
raise Error::ChecksumsMismatch, filename unless dl_checksum == db_checksum
|
152
151
|
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
end
|
152
|
+
updated << filename
|
153
|
+
rescue StandardError => e
|
154
|
+
restore_backup(filename)
|
155
|
+
raise e
|
156
|
+
ensure
|
157
|
+
delete_backup(filename) if File.exist?(backup_file_path(filename))
|
160
158
|
end
|
161
159
|
|
162
160
|
File.write(last_update_file, Time.now)
|
data/lib/wpscan/errors/update.rb
CHANGED
@@ -8,5 +8,17 @@ module WPScan
|
|
8
8
|
'Update required, you can not run a scan if a database file is missing.'
|
9
9
|
end
|
10
10
|
end
|
11
|
+
|
12
|
+
class ChecksumsMismatch < Standard
|
13
|
+
attr_reader :db_file
|
14
|
+
|
15
|
+
def initialize(db_file)
|
16
|
+
@db_file = db_file
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_s
|
20
|
+
"#{db_file}: checksums do not match. Please try again in a few minutes."
|
21
|
+
end
|
22
|
+
end
|
11
23
|
end
|
12
24
|
end
|
@@ -17,7 +17,7 @@ module WPScan
|
|
17
17
|
end
|
18
18
|
|
19
19
|
# Needed to have inheritance of the @child_class_constants
|
20
|
-
# If inheritance is not needed, then the #child_class_constant can be used in the
|
20
|
+
# If inheritance is not needed, then the #child_class_constant can be used in the class definition, ie
|
21
21
|
# child_class_constant :FILES, PATTERN: /aaa/i
|
22
22
|
# @return [ Hash ]
|
23
23
|
def self.child_class_constants
|
@@ -21,13 +21,11 @@ module WPScan
|
|
21
21
|
parsers = ALLOWED_PARSERS.include?(self.class::PARSER) ? [self.class::PARSER] : ALLOWED_PARSERS
|
22
22
|
|
23
23
|
parsers.each do |parser|
|
24
|
-
|
25
|
-
parsed = parser.respond_to?(:safe_load) ? parser.safe_load(body) : parser.load(body)
|
24
|
+
parsed = parser.respond_to?(:safe_load) ? parser.safe_load(body) : parser.load(body)
|
26
25
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
end
|
26
|
+
return parsed if parsed.is_a?(Hash) || parsed.is_a?(Array)
|
27
|
+
rescue StandardError
|
28
|
+
next
|
31
29
|
end
|
32
30
|
|
33
31
|
nil # Make sure nil is returned in case none of the parsers managed to parse the body correctly
|
data/lib/wpscan/references.rb
CHANGED
@@ -48,7 +48,7 @@ module WPScan
|
|
48
48
|
# @param [ Typhoeus::Response ] response
|
49
49
|
# @return [ Boolean ]
|
50
50
|
def wordpress_from_meta_comments_or_scripts?(response)
|
51
|
-
in_scope_uris(response, '//link/@href|//script/@src
|
51
|
+
in_scope_uris(response, '//link/@href|//script/@src') do |uri|
|
52
52
|
return true if WORDPRESS_PATTERN.match?(uri.path) || WP_JSON_OEMBED_PATTERN.match?(uri.path)
|
53
53
|
end
|
54
54
|
|
data/lib/wpscan/version.rb
CHANGED
data/lib/wpscan/vulnerability.rb
CHANGED
@@ -18,9 +18,10 @@ module WPScan
|
|
18
18
|
|
19
19
|
new(
|
20
20
|
json_data['title'],
|
21
|
-
references,
|
22
|
-
json_data['vuln_type'],
|
23
|
-
json_data['fixed_in']
|
21
|
+
references: references,
|
22
|
+
type: json_data['vuln_type'],
|
23
|
+
fixed_in: json_data['fixed_in'],
|
24
|
+
cvss: json_data['cvss']&.symbolize_keys
|
24
25
|
)
|
25
26
|
end
|
26
27
|
end
|
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.
|
4
|
+
version: 3.8.2
|
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-06-08 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.10.1
|
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.10.1
|
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.85.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.85.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.6.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.6.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: simplecov
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
@@ -388,7 +388,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
388
388
|
requirements:
|
389
389
|
- - ">="
|
390
390
|
- !ruby/object:Gem::Version
|
391
|
-
version: '2.
|
391
|
+
version: '2.5'
|
392
392
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
393
393
|
requirements:
|
394
394
|
- - ">="
|