wpscan 3.7.9 → 3.8.2
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/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
|
- - ">="
|