Compare commits
61 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
cdc1dab4a6 | ||
|
|
431739ab19 | ||
|
|
1780399050 | ||
|
|
eb75d38716 | ||
|
|
06f82d78f4 | ||
|
|
dee4da1c0e | ||
|
|
e341ec7c60 | ||
|
|
9146609e4a | ||
|
|
f90615ca41 | ||
|
|
8a2a6a05ff | ||
|
|
5a787f8ed5 | ||
|
|
a904053002 | ||
|
|
70ecd30dcc | ||
|
|
b0976d7e47 | ||
|
|
bb5e55016c | ||
|
|
abdf285c69 | ||
|
|
fd4da23d4f | ||
|
|
bb8f58c83b | ||
|
|
077da6ae86 | ||
|
|
d5222d7e9a | ||
|
|
01702c127b | ||
|
|
87902cbfb4 | ||
|
|
fcaa393ffe | ||
|
|
18bac6e792 | ||
|
|
9a21efebe3 | ||
|
|
357182ef17 | ||
|
|
5fad540a4c | ||
|
|
c1fc153420 | ||
|
|
73a1974f85 | ||
|
|
dec73c21b6 | ||
|
|
46a00cc864 | ||
|
|
62455be165 | ||
|
|
17ef5ef918 | ||
|
|
922b6fffd0 | ||
|
|
b47bf006d0 | ||
|
|
d60269f4bc | ||
|
|
1ce057a78e | ||
|
|
a0fe04b990 | ||
|
|
31c9172e19 | ||
|
|
7f23cbef71 | ||
|
|
4884defaed | ||
|
|
3039218c40 | ||
|
|
8bbc2f32ae | ||
|
|
4ca46ab3ba | ||
|
|
7442c72d01 | ||
|
|
01cd8350bc | ||
|
|
8b5ea589db | ||
|
|
3555ca1d1e | ||
|
|
ae034a47ed | ||
|
|
ec3862c930 | ||
|
|
c63804d1c5 | ||
|
|
c5e6752f75 | ||
|
|
e4f3e9d11c | ||
|
|
f3713536b9 | ||
|
|
fb751c0a51 | ||
|
|
9d3464055a | ||
|
|
0fea814f5d | ||
|
|
ae70a6df9d | ||
|
|
4afc756ccd | ||
|
|
adc5841261 | ||
|
|
804a8c34c6 |
@@ -1 +1 @@
|
||||
2.5.3
|
||||
2.6.0
|
||||
|
||||
4
.simplecov
Normal file
4
.simplecov
Normal file
@@ -0,0 +1,4 @@
|
||||
SimpleCov.start do
|
||||
add_filter '/spec/'
|
||||
add_filter 'helper'
|
||||
end
|
||||
@@ -20,10 +20,11 @@ rvm:
|
||||
- 2.5.1
|
||||
- 2.5.2
|
||||
- 2.5.3
|
||||
- 2.6.0
|
||||
- ruby-head
|
||||
before_install:
|
||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||
- "gem update --system"
|
||||
- gem update --system
|
||||
matrix:
|
||||
allow_failures:
|
||||
- rvm: ruby-head
|
||||
|
||||
6
LICENSE
6
LICENSE
@@ -1,6 +1,6 @@
|
||||
WPScan Public Source License
|
||||
|
||||
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2018 WPScan Team.
|
||||
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2019 WPScan Team.
|
||||
|
||||
Cases that include commercialization of WPScan require a commercial, non-free license. Otherwise, WPScan can be used without charge under the terms set out below.
|
||||
|
||||
@@ -8,7 +8,7 @@ Cases that include commercialization of WPScan require a commercial, non-free li
|
||||
|
||||
1.1 “License” means this document.
|
||||
1.2 “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns WPScan.
|
||||
1.3 “WPScan Team” means WPScan’s core developers, an updated list of whom can be found within the CREDITS file.
|
||||
1.3 “WPScan Team” means WPScan’s core developers.
|
||||
|
||||
2. Commercialization
|
||||
|
||||
@@ -29,8 +29,6 @@ Example cases which do not require a commercial license, and thus fall under the
|
||||
|
||||
If you need to purchase a commercial license or are unsure whether you need to purchase a commercial license contact us - team@wpscan.org.
|
||||
|
||||
We may grant commercial licenses at no monetary cost at our own discretion if the commercial usage is deemed by the WPScan Team to significantly benefit WPScan.
|
||||
|
||||
Free-use Terms and Conditions;
|
||||
|
||||
3. Redistribution
|
||||
|
||||
47
README.md
47
README.md
@@ -9,17 +9,22 @@
|
||||
|
||||
## Prerequisites:
|
||||
|
||||
- (Optional but highly recommended: [RVM](https://rvm.io/rvm/install))
|
||||
- Ruby >= 2.3 - Recommended: latest
|
||||
- Curl >= 7.21 - Recommended: latest - FYI the 7.29 has a segfault
|
||||
- Ruby 2.5.0 to 2.5.3 can cause an 'undefined symbol: rmpd_util_str_to_d' error in some systems, see [#1283](https://github.com/wpscanteam/wpscan/issues/1283)
|
||||
- Curl >= 7.21 - Recommended: latest
|
||||
- The 7.29 has a segfault
|
||||
- RubyGems - Recommended: latest
|
||||
|
||||
### From RubyGems:
|
||||
### From RubyGems (Recommended):
|
||||
|
||||
```
|
||||
gem install wpscan
|
||||
```
|
||||
|
||||
### From sources:
|
||||
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))
|
||||
|
||||
### From sources (NOT Recommended):
|
||||
|
||||
Prerequisites: Git
|
||||
|
||||
@@ -31,10 +36,27 @@ cd wpscan/
|
||||
bundle install && rake install
|
||||
```
|
||||
|
||||
# Updating
|
||||
|
||||
You can update the local database by using ```wpscan --update```
|
||||
|
||||
Updating WPScan itself is either done via ```gem update wpscan``` or the packages manager (this is quite important for distributions such as in Kali Linux: ```apt-get update && apt-get upgrade```) depending how WPScan was (pre)installed
|
||||
|
||||
# Docker
|
||||
|
||||
Pull the repo with ```docker pull wpscanteam/wpscan```
|
||||
|
||||
Enumerating usernames
|
||||
```
|
||||
docker run -it --rm wpscanteam/wpscan --url https://target.tld/ --enumerate u
|
||||
```
|
||||
|
||||
Enumerating a range of usernames
|
||||
```
|
||||
docker run -it --rm wpscanteam/wpscan --url https://target.tld/ --enumerate u1-100
|
||||
```
|
||||
** replace u1-100 with a range of your choice.
|
||||
|
||||
# Usage
|
||||
|
||||
```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. If a more stealthy approach is required, then ```wpscan --stealthy --url blog.tld``` can be used.
|
||||
@@ -69,6 +91,19 @@ url: 'http://target.tld'
|
||||
|
||||
Running ```wpscan``` in the current directory (pwd), is the same as ```wpscan -v --proxy socks5://127.0.0.1:9090 --url http://target.tld```
|
||||
|
||||
|
||||
Enumerating usernames
|
||||
```
|
||||
wpscan --url https://target.tld/ --enumerate u
|
||||
```
|
||||
|
||||
Enumerating a range of usernames
|
||||
```
|
||||
wpscan --url https://target.tld/ --enumerate u1-100
|
||||
```
|
||||
** replace u1-100 with a range of your choice.
|
||||
|
||||
|
||||
# PROJECT HOME
|
||||
|
||||
[https://wpscan.org](https://wpscan.org)
|
||||
@@ -81,7 +116,7 @@ Running ```wpscan``` in the current directory (pwd), is the same as ```wpscan -v
|
||||
|
||||
## WPScan Public Source License
|
||||
|
||||
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2018 WPScan Team.
|
||||
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2019 WPScan Team.
|
||||
|
||||
Cases that include commercialization of WPScan require a commercial, non-free license. Otherwise, WPScan can be used without charge under the terms set out below.
|
||||
|
||||
@@ -91,7 +126,7 @@ Cases that include commercialization of WPScan require a commercial, non-free li
|
||||
|
||||
1.2 "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns WPScan.
|
||||
|
||||
1.3 "WPScan Team" means WPScan’s core developers, an updated list of whom can be found within the CREDITS file.
|
||||
1.3 "WPScan Team" means WPScan’s core developers.
|
||||
|
||||
### 2. Commercialization
|
||||
|
||||
@@ -112,8 +147,6 @@ Example cases which do not require a commercial license, and thus fall under the
|
||||
|
||||
If you need to purchase a commercial license or are unsure whether you need to purchase a commercial license contact us - team@wpscan.org.
|
||||
|
||||
We may grant commercial licenses at no monetary cost at our own discretion if the commercial usage is deemed by the WPScan Team to significantly benefit WPScan.
|
||||
|
||||
Free-use Terms and Conditions;
|
||||
|
||||
### 3. Redistribution
|
||||
|
||||
@@ -71,7 +71,7 @@ module WPScan
|
||||
exit(WPScan::ExitCode::VULNERABLE)
|
||||
end
|
||||
|
||||
raise NotWordPressError unless target.wordpress? || parsed_options[:force]
|
||||
raise NotWordPressError unless target.wordpress?(parsed_options[:detection_mode]) || parsed_options[:force]
|
||||
end
|
||||
|
||||
# Loads the related server module in the target
|
||||
|
||||
@@ -15,20 +15,20 @@ module WPScan
|
||||
OptMultiChoices.new(
|
||||
['-e', '--enumerate [OPTS]', 'Enumeration Process'],
|
||||
choices: {
|
||||
vp: OptBoolean.new(['--vulnerable-plugins']),
|
||||
ap: OptBoolean.new(['--all-plugins']),
|
||||
p: OptBoolean.new(['--plugins']),
|
||||
vt: OptBoolean.new(['--vulnerable-themes']),
|
||||
at: OptBoolean.new(['--all-themes']),
|
||||
t: OptBoolean.new(['--themes']),
|
||||
tt: OptBoolean.new(['--timthumbs']),
|
||||
cb: OptBoolean.new(['--config-backups']),
|
||||
vp: OptBoolean.new(['--vulnerable-plugins']),
|
||||
ap: OptBoolean.new(['--all-plugins']),
|
||||
p: OptBoolean.new(['--plugins']),
|
||||
vt: OptBoolean.new(['--vulnerable-themes']),
|
||||
at: OptBoolean.new(['--all-themes']),
|
||||
t: OptBoolean.new(['--themes']),
|
||||
tt: OptBoolean.new(['--timthumbs']),
|
||||
cb: OptBoolean.new(['--config-backups']),
|
||||
dbe: OptBoolean.new(['--db-exports']),
|
||||
u: OptIntegerRange.new(['--users', 'User IDs range. e.g: u1-5'], value_if_empty: '1-10'),
|
||||
m: OptIntegerRange.new(['--medias',
|
||||
'Media IDs range. e.g m1-15',
|
||||
'Note: Permalink setting must be set to "Plain" for those to be detected'],
|
||||
value_if_empty: '1-100')
|
||||
u: OptIntegerRange.new(['--users', 'User IDs range. e.g: u1-5'], value_if_empty: '1-10'),
|
||||
m: OptIntegerRange.new(['--medias',
|
||||
'Media IDs range. e.g m1-15',
|
||||
'Note: Permalink setting must be set to "Plain" for those to be detected'],
|
||||
value_if_empty: '1-100')
|
||||
},
|
||||
value_if_empty: 'vp,vt,tt,cb,dbe,u,m',
|
||||
incompatible: [%i[vp ap p], %i[vt at t]],
|
||||
|
||||
@@ -3,9 +3,10 @@ module WPScan
|
||||
# Enumeration Methods
|
||||
class Enumeration < CMSScanner::Controller::Base
|
||||
# @param [ String ] type (plugins or themes)
|
||||
# @param [ Symbol ] detection_mode
|
||||
#
|
||||
# @return [ String ] The related enumration message depending on the parsed_options and type supplied
|
||||
def enum_message(type)
|
||||
def enum_message(type, detection_mode)
|
||||
return unless %w[plugins themes].include?(type)
|
||||
|
||||
details = if parsed_options[:enumerate][:"vulnerable_#{type}"]
|
||||
@@ -16,7 +17,20 @@ module WPScan
|
||||
'Most Popular'
|
||||
end
|
||||
|
||||
"Enumerating #{details} #{type.capitalize}"
|
||||
"Enumerating #{details} #{type.capitalize} #{enum_detection_message(detection_mode)}"
|
||||
end
|
||||
|
||||
# @param [ Symbol ] detection_mode
|
||||
#
|
||||
# @return [ String ]
|
||||
def enum_detection_message(detection_mode)
|
||||
detection_method = if detection_mode == :mixed
|
||||
'Passive and Aggressive'
|
||||
else
|
||||
detection_mode.to_s.capitalize
|
||||
end
|
||||
|
||||
"(via #{detection_method} Methods)"
|
||||
end
|
||||
|
||||
# @param [ String ] type (plugins, themes etc)
|
||||
@@ -49,12 +63,15 @@ module WPScan
|
||||
sort: true
|
||||
)
|
||||
|
||||
output('@info', msg: enum_message('plugins')) if user_interaction?
|
||||
output('@info', msg: enum_message('plugins', opts[:mode])) if user_interaction?
|
||||
# Enumerate the plugins & find their versions to avoid doing that when #version
|
||||
# is called in the view
|
||||
plugins = target.plugins(opts)
|
||||
|
||||
output('@info', msg: 'Checking Plugin Versions') if user_interaction? && !plugins.empty?
|
||||
if user_interaction? && !plugins.empty?
|
||||
output('@info',
|
||||
msg: "Checking Plugin Versions #{enum_detection_message(opts[:version_detection][:mode])}")
|
||||
end
|
||||
|
||||
plugins.each(&:version)
|
||||
|
||||
@@ -92,12 +109,15 @@ module WPScan
|
||||
sort: true
|
||||
)
|
||||
|
||||
output('@info', msg: enum_message('themes')) if user_interaction?
|
||||
output('@info', msg: enum_message('themes', opts[:mode])) if user_interaction?
|
||||
# Enumerate the themes & find their versions to avoid doing that when #version
|
||||
# is called in the view
|
||||
themes = target.themes(opts)
|
||||
|
||||
output('@info', msg: 'Checking Theme Versions') if user_interaction? && !themes.empty?
|
||||
if user_interaction? && !themes.empty?
|
||||
output('@info',
|
||||
msg: "Checking Theme Versions #{enum_detection_message(opts[:version_detection][:mode])}")
|
||||
end
|
||||
|
||||
themes.each(&:version)
|
||||
|
||||
@@ -125,21 +145,21 @@ module WPScan
|
||||
def enum_timthumbs
|
||||
opts = default_opts('timthumbs').merge(list: parsed_options[:timthumbs_list])
|
||||
|
||||
output('@info', msg: 'Enumerating Timthumbs') if user_interaction?
|
||||
output('@info', msg: "Enumerating Timthumbs #{enum_detection_message(opts[:mode])}") if user_interaction?
|
||||
output('timthumbs', timthumbs: target.timthumbs(opts))
|
||||
end
|
||||
|
||||
def enum_config_backups
|
||||
opts = default_opts('config_backups').merge(list: parsed_options[:config_backups_list])
|
||||
|
||||
output('@info', msg: 'Enumerating Config Backups') if user_interaction?
|
||||
output('@info', msg: "Enumerating Config Backups #{enum_detection_message(opts[:mode])}") if user_interaction?
|
||||
output('config_backups', config_backups: target.config_backups(opts))
|
||||
end
|
||||
|
||||
def enum_db_exports
|
||||
opts = default_opts('db_exports').merge(list: parsed_options[:db_exports_list])
|
||||
|
||||
output('@info', msg: 'Enumerating DB Exports') if user_interaction?
|
||||
output('@info', msg: "Enumerating DB Exports #{enum_detection_message(opts[:mode])}") if user_interaction?
|
||||
output('db_exports', db_exports: target.db_exports(opts))
|
||||
end
|
||||
|
||||
@@ -147,7 +167,9 @@ module WPScan
|
||||
opts = default_opts('medias').merge(range: parsed_options[:enumerate][:medias])
|
||||
|
||||
if user_interaction?
|
||||
output('@info', msg: 'Enumerating Medias (Permalink setting must be set to "Plain" for those to be detected)')
|
||||
output('@info',
|
||||
msg: "Enumerating Medias #{enum_detection_message(opts[:mode])} "\
|
||||
'(Permalink setting must be set to "Plain" for those to be detected)')
|
||||
end
|
||||
|
||||
output('medias', medias: target.medias(opts))
|
||||
@@ -166,7 +188,7 @@ module WPScan
|
||||
list: parsed_options[:users_list]
|
||||
)
|
||||
|
||||
output('@info', msg: 'Enumerating Users') if user_interaction?
|
||||
output('@info', msg: "Enumerating Users #{enum_detection_message(opts[:mode])}") if user_interaction?
|
||||
output('users', users: target.users(opts))
|
||||
end
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ module WPScan
|
||||
|
||||
return unless [200, 403].include?(res.code) && !target.homepage_or_404?(res)
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::BackupDB.new(
|
||||
url,
|
||||
confidence: 70,
|
||||
found_by: DIRECT_ACCESS,
|
||||
|
||||
@@ -9,9 +9,10 @@ module WPScan
|
||||
|
||||
return unless target.debug_log?(path)
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::DebugLog.new(
|
||||
target.url(path),
|
||||
confidence: 100, found_by: DIRECT_ACCESS
|
||||
confidence: 100, found_by: DIRECT_ACCESS,
|
||||
references: { url: 'https://codex.wordpress.org/Debugging_in_WordPress' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -10,7 +10,7 @@ module WPScan
|
||||
|
||||
return unless res.body =~ /DUPLICATOR INSTALL-LOG/
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::DuplicatorInstallerLog.new(
|
||||
url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
|
||||
@@ -10,7 +10,7 @@ module WPScan
|
||||
|
||||
return unless res.code == 200 && !target.homepage_or_404?(res)
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::EmergencyPwdResetScript.new(
|
||||
url,
|
||||
confidence: res.body =~ /password/i ? 100 : 40,
|
||||
found_by: DIRECT_ACCESS,
|
||||
|
||||
@@ -10,11 +10,12 @@ module WPScan
|
||||
|
||||
return if fpd_entries.empty?
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::FullPathDisclosure.new(
|
||||
target.url(path),
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
interesting_entries: fpd_entries
|
||||
interesting_entries: fpd_entries,
|
||||
references: { url: 'https://www.owasp.org/index.php/Full_Path_Disclosure' }
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -12,7 +12,7 @@ module WPScan
|
||||
|
||||
url = target.url('wp-content/mu-plugins/')
|
||||
|
||||
return WPScan::InterestingFinding.new(
|
||||
return WPScan::MuPlugins.new(
|
||||
url,
|
||||
confidence: 70,
|
||||
found_by: 'URLs In Homepage (Passive Detection)',
|
||||
@@ -35,7 +35,7 @@ module WPScan
|
||||
|
||||
target.mu_plugins = true
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::MuPlugins.new(
|
||||
url,
|
||||
confidence: 80,
|
||||
found_by: DIRECT_ACCESS,
|
||||
|
||||
@@ -15,7 +15,7 @@ module WPScan
|
||||
|
||||
target.multisite = true
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::Multisite.new(
|
||||
url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
|
||||
@@ -10,7 +10,7 @@ module WPScan
|
||||
res = Browser.get(url)
|
||||
|
||||
if res.code == 200 && res.body =~ /wordpress/i
|
||||
return WPScan::InterestingFinding.new(url, confidence: 100, found_by: DIRECT_ACCESS)
|
||||
return WPScan::Readme.new(url, confidence: 100, found_by: DIRECT_ACCESS)
|
||||
end
|
||||
end
|
||||
nil
|
||||
|
||||
@@ -18,7 +18,7 @@ module WPScan
|
||||
|
||||
target.registration_enabled = true
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::Registration.new(
|
||||
res.effective_url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
|
||||
@@ -11,7 +11,7 @@ module WPScan
|
||||
|
||||
return unless res.code == 200 && res.headers['Content-Type'] =~ %r{\Aapplication/zip}i
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::TmmDbMigrate.new(
|
||||
url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
|
||||
@@ -11,7 +11,7 @@ module WPScan
|
||||
|
||||
url = target.url(path)
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::UploadDirectoryListing.new(
|
||||
url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS,
|
||||
|
||||
@@ -3,7 +3,7 @@ module WPScan
|
||||
module InterestingFindings
|
||||
# UploadSQLDump finder
|
||||
class UploadSQLDump < CMSScanner::Finders::Finder
|
||||
SQL_PATTERN = /(?:(?:(?:DROP|CREATE) TABLE)|INSERT INTO)/
|
||||
SQL_PATTERN = /(?:(?:(?:DROP|CREATE) TABLE)|INSERT INTO)/.freeze
|
||||
|
||||
# @return [ InterestingFinding ]
|
||||
def aggressive(_opts = {})
|
||||
@@ -12,7 +12,7 @@ module WPScan
|
||||
|
||||
return unless res.code == 200 && res.body =~ SQL_PATTERN
|
||||
|
||||
WPScan::InterestingFinding.new(
|
||||
WPScan::UploadSQLDump.new(
|
||||
url,
|
||||
confidence: 100,
|
||||
found_by: DIRECT_ACCESS
|
||||
|
||||
@@ -3,9 +3,9 @@ module WPScan
|
||||
module MainTheme
|
||||
# From the WooFramework meta generators
|
||||
class WooFrameworkMetaGenerator < CMSScanner::Finders::Finder
|
||||
THEME_PATTERN = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?"\s+/?>}
|
||||
FRAMEWORK_PATTERN = %r{<meta name="generator" content="WooFramework\s?([^"]+)?"\s+/?>}
|
||||
PATTERN = /#{THEME_PATTERN}\s+#{FRAMEWORK_PATTERN}/i
|
||||
THEME_PATTERN = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?"\s+/?>}.freeze
|
||||
FRAMEWORK_PATTERN = %r{<meta name="generator" content="WooFramework\s?([^"]+)?"\s+/?>}.freeze
|
||||
PATTERN = /#{THEME_PATTERN}\s+#{FRAMEWORK_PATTERN}/i.freeze
|
||||
|
||||
def passive(opts = {})
|
||||
return unless target.homepage_res.body =~ PATTERN
|
||||
|
||||
@@ -4,6 +4,7 @@ require_relative 'users/oembed_api'
|
||||
require_relative 'users/rss_generator'
|
||||
require_relative 'users/author_id_brute_forcing'
|
||||
require_relative 'users/login_error_messages'
|
||||
require_relative 'users/yoast_seo_author_sitemap.rb'
|
||||
|
||||
module WPScan
|
||||
module Finders
|
||||
@@ -19,6 +20,7 @@ module WPScan
|
||||
Users::WpJsonApi.new(target) <<
|
||||
Users::OembedApi.new(target) <<
|
||||
Users::RSSGenerator.new(target) <<
|
||||
Users::YoastSeoAuthorSitemap.new(target) <<
|
||||
Users::AuthorIdBruteForcing.new(target) <<
|
||||
Users::LoginErrorMessages.new(target)
|
||||
end
|
||||
|
||||
@@ -14,29 +14,35 @@ module WPScan
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
# TODO: make this code pretty :x
|
||||
#
|
||||
# @return [ Array<User> ]
|
||||
def aggressive(_opts = {})
|
||||
found = []
|
||||
found_by_msg = 'Oembed API - %s (Aggressive Detection)'
|
||||
|
||||
oembed_data = JSON.parse(Browser.get(api_url).body)
|
||||
details = user_details_from_oembed_data(oembed_data)
|
||||
|
||||
return [] unless details
|
||||
|
||||
[CMSScanner::User.new(details[0],
|
||||
found_by: format(found_by_msg, details[1]),
|
||||
confidence: details[2],
|
||||
interesting_entries: [api_url])]
|
||||
rescue JSON::ParserError
|
||||
[]
|
||||
end
|
||||
|
||||
def user_details_from_oembed_data(oembed_data)
|
||||
return unless oembed_data
|
||||
|
||||
if oembed_data['author_url'] =~ %r{/author/([^/]+)/?\z}
|
||||
details = [Regexp.last_match[1], 'Author URL', 90]
|
||||
elsif oembed_data['author_name'] && !oembed_data['author_name'].empty?
|
||||
details = [oembed_data['author_name'].delete(' '), 'Author Name', 70]
|
||||
details = [oembed_data['author_name'], 'Author Name', 70]
|
||||
end
|
||||
|
||||
return unless details
|
||||
details
|
||||
end
|
||||
|
||||
found << CMSScanner::User.new(details[0],
|
||||
found_by: format(found_by_msg, details[1]),
|
||||
confidence: details[2],
|
||||
interesting_entries: [api_url])
|
||||
rescue JSON::ParserError
|
||||
found
|
||||
def found_by_msg
|
||||
'Oembed API - %s (Aggressive Detection)'
|
||||
end
|
||||
|
||||
# @return [ String ] The URL of the API listing the Users
|
||||
|
||||
@@ -4,20 +4,29 @@ module WPScan
|
||||
# WP JSON API
|
||||
#
|
||||
# Since 4.7 - Need more investigation as it seems WP 4.7.1 reduces the exposure, see https://github.com/wpscanteam/wpscan/issues/1038)
|
||||
# For the pagination, see https://github.com/wpscanteam/wpscan/issues/1285
|
||||
#
|
||||
class WpJsonApi < CMSScanner::Finders::Finder
|
||||
MAX_PER_PAGE = 100 # See https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/
|
||||
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
# @return [ Array<User> ]
|
||||
def aggressive(_opts = {})
|
||||
found = []
|
||||
found = []
|
||||
current_page = 0
|
||||
|
||||
JSON.parse(Browser.get(api_url).body)&.each do |user|
|
||||
found << CMSScanner::User.new(user['slug'],
|
||||
id: user['id'],
|
||||
found_by: found_by,
|
||||
confidence: 100,
|
||||
interesting_entries: [api_url])
|
||||
loop do
|
||||
current_page += 1
|
||||
|
||||
res = Typhoeus.get(api_url, params: { per_page: MAX_PER_PAGE, page: current_page })
|
||||
|
||||
total_pages ||= res.headers['X-WP-TotalPages'].to_i
|
||||
|
||||
users_in_page = users_from_response(res)
|
||||
found += users_in_page
|
||||
|
||||
break if current_page >= total_pages || users_in_page.empty?
|
||||
end
|
||||
|
||||
found
|
||||
@@ -25,6 +34,23 @@ module WPScan
|
||||
found
|
||||
end
|
||||
|
||||
# @param [ Typhoeus::Response ] response
|
||||
#
|
||||
# @return [ Array<User> ] The users from the response
|
||||
def users_from_response(response)
|
||||
found = []
|
||||
|
||||
JSON.parse(response.body)&.each do |user|
|
||||
found << CMSScanner::User.new(user['slug'],
|
||||
id: user['id'],
|
||||
found_by: found_by,
|
||||
confidence: 100,
|
||||
interesting_entries: [response.effective_url])
|
||||
end
|
||||
|
||||
found
|
||||
end
|
||||
|
||||
# @return [ String ] The URL of the API listing the Users
|
||||
def api_url
|
||||
@api_url ||= target.url('wp-json/wp/v2/users/')
|
||||
|
||||
34
app/finders/users/yoast_seo_author_sitemap.rb
Normal file
34
app/finders/users/yoast_seo_author_sitemap.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
module WPScan
|
||||
module Finders
|
||||
module Users
|
||||
# The YOAST SEO plugin has an author-sitemap.xml which can leak usernames
|
||||
# See https://github.com/wpscanteam/wpscan/issues/1228
|
||||
class YoastSeoAuthorSitemap < CMSScanner::Finders::Finder
|
||||
# @param [ Hash ] opts
|
||||
#
|
||||
# @return [ Array<User> ]
|
||||
def aggressive(_opts = {})
|
||||
found = []
|
||||
|
||||
Browser.get(sitemap_url).html.xpath('//url/loc').each do |user_tag|
|
||||
username = user_tag.text.to_s[%r{/author/([^\/]+)/}, 1]
|
||||
|
||||
next unless username && !username.strip.empty?
|
||||
|
||||
found << CMSScanner::User.new(username,
|
||||
found_by: found_by,
|
||||
confidence: 100,
|
||||
interesting_entries: [sitemap_url])
|
||||
end
|
||||
|
||||
found
|
||||
end
|
||||
|
||||
# @return [ String ] The URL of the author-sitemap
|
||||
def sitemap_url
|
||||
@sitemap_url ||= target.url('author-sitemap.xml')
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -3,4 +3,43 @@ module WPScan
|
||||
class InterestingFinding < CMSScanner::InterestingFinding
|
||||
include References
|
||||
end
|
||||
|
||||
#
|
||||
# Empty classes for the #type to be correctly displayed (as taken from the self.class from the parent)
|
||||
#
|
||||
class BackupDB < InterestingFinding
|
||||
end
|
||||
|
||||
class DebugLog < InterestingFinding
|
||||
end
|
||||
|
||||
class DuplicatorInstallerLog < InterestingFinding
|
||||
end
|
||||
|
||||
class EmergencyPwdResetScript < InterestingFinding
|
||||
end
|
||||
|
||||
class FullPathDisclosure < InterestingFinding
|
||||
end
|
||||
|
||||
class MuPlugins < InterestingFinding
|
||||
end
|
||||
|
||||
class Multisite < InterestingFinding
|
||||
end
|
||||
|
||||
class Readme < InterestingFinding
|
||||
end
|
||||
|
||||
class Registration < InterestingFinding
|
||||
end
|
||||
|
||||
class TmmDbMigrate < InterestingFinding
|
||||
end
|
||||
|
||||
class UploadDirectoryListing < InterestingFinding
|
||||
end
|
||||
|
||||
class UploadSQLDump < InterestingFinding
|
||||
end
|
||||
end
|
||||
|
||||
@@ -53,7 +53,12 @@ module WPScan
|
||||
|
||||
# @return [ String ]
|
||||
def release_date
|
||||
@release_date ||= db_data['release_date']
|
||||
@release_date ||= db_data['release_date'] || 'Unknown'
|
||||
end
|
||||
|
||||
# @return [ String ]
|
||||
def status
|
||||
@status ||= db_data['status'] || 'Unknown'
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<% if @version -%>
|
||||
<%= info_icon %> WordPress version <%= @version.number %> identified (Released on <%= @version.release_date %>).
|
||||
<%= info_icon %> WordPress version <%= @version.number %> identified (<%= @version.status.capitalize %>, released on <%= @version.release_date %>).
|
||||
<%= render('@finding', item: @version) -%>
|
||||
<% else -%>
|
||||
<%= notice_icon %> The WordPress version could not be detected.
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
"version": {
|
||||
"number": <%= @version.number.to_json %>,
|
||||
"release_date": <%= @version.release_date.to_json %>,
|
||||
"status": <%= @version.status.to_json %>,
|
||||
<%= render('@finding', item: @version) -%>
|
||||
},
|
||||
<% else -%>
|
||||
|
||||
@@ -16,9 +16,7 @@ require 'securerandom'
|
||||
require 'wpscan/helper'
|
||||
require 'wpscan/db'
|
||||
require 'wpscan/version'
|
||||
require 'wpscan/errors/wordpress'
|
||||
require 'wpscan/errors/http'
|
||||
require 'wpscan/errors/update'
|
||||
require 'wpscan/errors'
|
||||
require 'wpscan/browser'
|
||||
require 'wpscan/target'
|
||||
require 'wpscan/finders'
|
||||
|
||||
@@ -60,12 +60,11 @@ module WPScan
|
||||
end
|
||||
|
||||
# @return [ Hash ] The params for Typhoeus::Request
|
||||
# @note Those params can't be overriden by CLI options
|
||||
def request_params
|
||||
{
|
||||
ssl_verifyhost: 2,
|
||||
ssl_verifypeer: true,
|
||||
timeout: 300,
|
||||
connecttimeout: 120,
|
||||
timeout: 600,
|
||||
connecttimeout: 300,
|
||||
accept_encoding: 'gzip, deflate',
|
||||
cache_ttl: 0
|
||||
}
|
||||
|
||||
8
lib/wpscan/errors.rb
Normal file
8
lib/wpscan/errors.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
module WPScan
|
||||
class Error < StandardError
|
||||
end
|
||||
end
|
||||
|
||||
require_relative 'errors/http'
|
||||
require_relative 'errors/update'
|
||||
require_relative 'errors/wordpress'
|
||||
@@ -1,6 +1,6 @@
|
||||
module WPScan
|
||||
# HTTP Error
|
||||
class HTTPError < StandardError
|
||||
class HTTPError < Error
|
||||
attr_reader :response
|
||||
|
||||
# @param [ Typhoeus::Response ] res
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
module WPScan
|
||||
# Error raised when there is a missing DB file and --no-update supplied
|
||||
class MissingDatabaseFile < StandardError
|
||||
class MissingDatabaseFile < Error
|
||||
def to_s
|
||||
'Update required, you can not run a scan if a database file is missing.'
|
||||
end
|
||||
|
||||
@@ -1,20 +1,20 @@
|
||||
module WPScan
|
||||
# WordPress hosted (*.wordpress.com)
|
||||
class WordPressHostedError < StandardError
|
||||
class WordPressHostedError < Error
|
||||
def to_s
|
||||
'Scanning *.wordpress.com hosted blogs is not supported.'
|
||||
end
|
||||
end
|
||||
|
||||
# Not WordPress Error
|
||||
class NotWordPressError < StandardError
|
||||
class NotWordPressError < Error
|
||||
def to_s
|
||||
'The remote website is up, but does not seem to be running WordPress.'
|
||||
end
|
||||
end
|
||||
|
||||
# Invalid Wp Version (used in the WpVersion#new)
|
||||
class InvalidWordPressVersion < StandardError
|
||||
class InvalidWordPressVersion < Error
|
||||
def to_s
|
||||
'The WordPress version is invalid'
|
||||
end
|
||||
|
||||
@@ -9,7 +9,7 @@ module WPScan
|
||||
module WordPress
|
||||
include CMSScanner::Target::Platform::PHP
|
||||
|
||||
WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|(?:mu\-)?plugins|uploads))|wp-includes)/}i
|
||||
WORDPRESS_PATTERN = %r{/(?:(?:wp-content/(?:themes|(?:mu\-)?plugins|uploads))|wp-includes)/}i.freeze
|
||||
|
||||
# These methods are used in the associated interesting_findings finders
|
||||
# to keep the boolean state of the finding rather than re-check the whole thing again
|
||||
@@ -18,10 +18,10 @@ module WPScan
|
||||
alias registration_enabled? registration_enabled
|
||||
alias mu_plugins? mu_plugins
|
||||
|
||||
# @param [ Symbol ] detection_mode
|
||||
#
|
||||
# @return [ Boolean ]
|
||||
def wordpress?
|
||||
# res = Browser.get(url)
|
||||
|
||||
def wordpress?(detection_mode)
|
||||
in_scope_urls(homepage_res) do |url|
|
||||
return true if Addressable::URI.parse(url).path.match(WORDPRESS_PATTERN)
|
||||
end
|
||||
@@ -32,6 +32,14 @@ module WPScan
|
||||
|
||||
return true unless comments_from_page(/wordpress/i, homepage_res).empty?
|
||||
|
||||
if %i[mixed aggressive].include?(detection_mode)
|
||||
%w[wp-admin/install.php wp-login.php].each do |path|
|
||||
in_scope_urls(Browser.get_and_follow_location(url(path))).each do |url|
|
||||
return true if Addressable::URI.parse(url).path.match(WORDPRESS_PATTERN)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
false
|
||||
end
|
||||
|
||||
@@ -41,7 +49,7 @@ module WPScan
|
||||
end
|
||||
|
||||
def wordpress_hosted?
|
||||
uri.host =~ /wordpress.com$/i ? true : false
|
||||
uri.host =~ /\.wordpress\.com$/i ? true : false
|
||||
end
|
||||
|
||||
# @param [ String ] username
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Version
|
||||
module WPScan
|
||||
VERSION = '3.3.2'.freeze
|
||||
VERSION = '3.4.4'.freeze
|
||||
end
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::Aliases do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::Core do
|
||||
subject(:core) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
@@ -167,7 +165,7 @@ describe WPScan::Controller::Core do
|
||||
|
||||
before do
|
||||
expect(core).to receive(:load_server_module)
|
||||
expect(core.target).to receive(:wordpress?).and_return(true)
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
|
||||
end
|
||||
|
||||
it 'calls the formatter when started and finished to update the db' do
|
||||
@@ -210,7 +208,7 @@ describe WPScan::Controller::Core do
|
||||
|
||||
context 'when wordpress' do
|
||||
it 'does not raise an error' do
|
||||
expect(core.target).to receive(:wordpress?).and_return(true)
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
|
||||
|
||||
expect { core.before_scan }.to_not raise_error
|
||||
end
|
||||
@@ -218,7 +216,7 @@ describe WPScan::Controller::Core do
|
||||
|
||||
context 'when not wordpress' do
|
||||
it 'raises an error' do
|
||||
expect(core.target).to receive(:wordpress?).and_return(false)
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false)
|
||||
|
||||
expect { core.before_scan }.to raise_error(WPScan::NotWordPressError)
|
||||
end
|
||||
@@ -239,7 +237,7 @@ describe WPScan::Controller::Core do
|
||||
context 'when wordpress' do
|
||||
before do
|
||||
expect(core).to receive(:load_server_module)
|
||||
expect(core.target).to receive(:wordpress?).and_return(true)
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(true)
|
||||
end
|
||||
|
||||
it 'does not raise any error' do
|
||||
@@ -250,7 +248,7 @@ describe WPScan::Controller::Core do
|
||||
context 'when not wordpress' do
|
||||
before do
|
||||
expect(core).to receive(:load_server_module)
|
||||
expect(core.target).to receive(:wordpress?).and_return(false)
|
||||
expect(core.target).to receive(:wordpress?).with(:mixed).and_return(false)
|
||||
end
|
||||
|
||||
context 'when no --force' do
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::CustomDirectories do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::Enumeration do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://wp.lab/' }
|
||||
@@ -16,10 +14,11 @@ describe WPScan::Controller::Enumeration do
|
||||
end
|
||||
|
||||
describe '#enum_message' do
|
||||
after { expect(controller.enum_message(type)).to eql @expected }
|
||||
after { expect(controller.enum_message(type, detection_mode)).to eql @expected }
|
||||
|
||||
context 'when type argument is incorrect' do
|
||||
let(:type) { 'spec' }
|
||||
let(:type) { 'spec' }
|
||||
let(:detection_mode) { :mixed }
|
||||
|
||||
it 'returns nil' do
|
||||
@expected = nil
|
||||
@@ -28,29 +27,32 @@ describe WPScan::Controller::Enumeration do
|
||||
|
||||
%w[plugins themes].each do |t|
|
||||
context "type = #{t}" do
|
||||
let(:type) { t }
|
||||
let(:type) { t }
|
||||
let(:detection_mode) { :mixed }
|
||||
|
||||
context 'when vulnerable' do
|
||||
let(:cli_args) { "#{super()} -e v#{type[0]}" }
|
||||
|
||||
it 'returns the expected string' do
|
||||
@expected = "Enumerating Vulnerable #{type.capitalize}"
|
||||
@expected = "Enumerating Vulnerable #{type.capitalize} (via Passive and Aggressive Methods)"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when all' do
|
||||
let(:cli_args) { "#{super()} -e a#{type[0]}" }
|
||||
let(:cli_args) { "#{super()} -e a#{type[0]}" }
|
||||
let(:detection_mode) { :passive }
|
||||
|
||||
it 'returns the expected string' do
|
||||
@expected = "Enumerating All #{type.capitalize}"
|
||||
@expected = "Enumerating All #{type.capitalize} (via Passive Methods)"
|
||||
end
|
||||
end
|
||||
|
||||
context 'when most popular' do
|
||||
let(:cli_args) { "#{super()} -e #{type[0]}" }
|
||||
let(:cli_args) { "#{super()} -e #{type[0]}" }
|
||||
let(:detection_mode) { :aggressive }
|
||||
|
||||
it 'returns the expected string' do
|
||||
@expected = "Enumerating Most Popular #{type.capitalize}"
|
||||
@expected = "Enumerating Most Popular #{type.capitalize} (via Aggressive Methods)"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Controller::PasswordAttack do
|
||||
subject(:controller) { described_class.new }
|
||||
let(:target_url) { 'http://ex.lo/' }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
def it_calls_the_formatter_with_the_correct_parameter(version)
|
||||
it 'calls the formatter with the correct parameter' do
|
||||
expect(controller.formatter).to receive(:output)
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::ConfigBackups::KnownFilenames do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::ConfigBackups::Base do
|
||||
subject(:config_backups) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::DbExports::KnownLocations do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::DbExports::Base do
|
||||
subject(:db_exports) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::BackupDB do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
@@ -37,7 +35,7 @@ describe WPScan::Finders::InterestingFindings::BackupDB do
|
||||
after do
|
||||
found = finder.aggressive
|
||||
|
||||
expect(found).to eql WPScan::InterestingFinding.new(
|
||||
expect(found).to eql WPScan::BackupDB.new(
|
||||
dir_url,
|
||||
confidence: 70,
|
||||
found_by: described_class::DIRECT_ACCESS
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::DebugLog do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
@@ -23,7 +21,7 @@ describe WPScan::Finders::InterestingFindings::DebugLog do
|
||||
let(:body) { File.read(File.join(fixtures, 'debug.log')) }
|
||||
|
||||
it 'returns the InterestingFinding' do
|
||||
expect(finder.aggressive).to eql WPScan::InterestingFinding.new(
|
||||
expect(finder.aggressive).to eql WPScan::DebugLog.new(
|
||||
log_url,
|
||||
confidence: 100,
|
||||
found_by: described_class::DIRECT_ACCESS
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
@@ -24,7 +22,7 @@ describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do
|
||||
let(:body) { File.read(File.join(fixtures, filename)) }
|
||||
|
||||
it 'returns the InterestingFinding' do
|
||||
expect(finder.aggressive).to eql WPScan::InterestingFinding.new(
|
||||
expect(finder.aggressive).to eql WPScan::DuplicatorInstallerLog.new(
|
||||
log_url,
|
||||
confidence: 100,
|
||||
found_by: described_class::DIRECT_ACCESS
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::EmergencyPwdResetScript do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::FullPathDisclosure do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
@@ -25,7 +23,7 @@ describe WPScan::Finders::InterestingFindings::FullPathDisclosure do
|
||||
it 'returns the InterestingFinding' do
|
||||
found = finder.aggressive
|
||||
|
||||
expect(found).to eql WPScan::InterestingFinding.new(
|
||||
expect(found).to eql WPScan::FullPathDisclosure.new(
|
||||
file_url,
|
||||
confidence: 100,
|
||||
found_by: described_class::DIRECT_ACCESS
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::MuPlugins do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::Multisite do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::Readme do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
@@ -27,7 +25,7 @@ describe WPScan::Finders::InterestingFindings::Readme do
|
||||
before { stub_request(:get, target.url(file)).to_return(body: readme) }
|
||||
|
||||
it 'returns the expected InterestingFinding' do
|
||||
expected = WPScan::InterestingFinding.new(
|
||||
expected = WPScan::Readme.new(
|
||||
target.url(file),
|
||||
confidence: 100,
|
||||
found_by: described_class::DIRECT_ACCESS
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::Registration do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::TmmDbMigrate do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::UploadDirectoryListing do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::UploadSQLDump do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
@@ -38,7 +36,7 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do
|
||||
let(:fixture) { 'dump.sql' }
|
||||
|
||||
it 'returns the interesting findings' do
|
||||
@expected = WPScan::InterestingFinding.new(
|
||||
@expected = WPScan::UploadSQLDump.new(
|
||||
finder.dump_url,
|
||||
confidence: 100,
|
||||
found_by: described_class::DIRECT_ACCESS
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::InterestingFindings::Base do
|
||||
subject(:files) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::MainTheme::CssStyle do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::MainTheme::UrlsInHomepage do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::MainTheme::WooFrameworkMetaGenerator do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::MainTheme::Base do
|
||||
subject(:main_theme) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Medias::AttachmentBruteForcing do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Medias::Base do
|
||||
subject(:media) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::PluginVersion::Readme do
|
||||
subject(:finder) { described_class.new(plugin) }
|
||||
let(:plugin) { WPScan::Plugin.new('spec', target) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
# If this file is tested alone (rspec path-to-this-file), then there will be an error about
|
||||
# constants not being intilialized. This is due to the Dynamic Finders.
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::BodyPattern do
|
||||
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::Comment do
|
||||
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::ConfigParser do
|
||||
xit
|
||||
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::HeaderPattern do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::JavascriptVar do
|
||||
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::KnownLocations do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::QueryParameter do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::UrlsInHomepage do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::Xpath do
|
||||
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Plugins::Base do
|
||||
subject(:plugins) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::ThemeVersion::Style do
|
||||
subject(:finder) { described_class.new(theme) }
|
||||
let(:theme) { WPScan::Theme.new('spec', target) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::ThemeVersion::WooFrameworkMetaGenerator do
|
||||
subject(:finder) { described_class.new(theme) }
|
||||
let(:theme) { WPScan::Theme.new(slug, target) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::ThemeVersion::Base do
|
||||
subject(:theme_version) { described_class.new(theme) }
|
||||
let(:theme) { WPScan::Plugin.new(slug, target) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Themes::KnownLocations do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Themes::UrlsInHomepage do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Themes::Base do
|
||||
subject(:themes) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::TimthumbVersion::BadRequest do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Timthumb.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::TimthumbVersion::Base do
|
||||
subject(:timthumb_version) { described_class.new(target) }
|
||||
let(:target) { WPScan::Timthumb.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Timthumbs::KnownLocations do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Timthumbs::Base do
|
||||
subject(:timthumb) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Users::AuthorIdBruteForcing do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Users::AuthorPosts do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Users::LoginErrorMessages do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Users::OembedApi do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
@@ -7,6 +5,59 @@ describe WPScan::Finders::Users::OembedApi do
|
||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'users', 'oembed_api') }
|
||||
|
||||
describe '#aggressive' do
|
||||
xit
|
||||
before do
|
||||
allow(target).to receive(:sub_dir).and_return(false)
|
||||
stub_request(:get, finder.api_url).to_return(body: body)
|
||||
end
|
||||
|
||||
context 'when not a JSON response' do
|
||||
let(:body) { '' }
|
||||
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
|
||||
context 'when a JSON response' do
|
||||
context 'when 404' do
|
||||
let(:body) { File.read(File.join(fixtures, '404.json')) }
|
||||
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
|
||||
context 'when 200' do
|
||||
context 'when author_url present' do
|
||||
let(:body) { File.read(File.join(fixtures, '200_author_url.json')) }
|
||||
|
||||
it 'returns the expected array of users' do
|
||||
users = finder.aggressive
|
||||
|
||||
expect(users.size).to eql 1
|
||||
|
||||
user = users.first
|
||||
|
||||
expect(user.username).to eql 'admin'
|
||||
expect(user.confidence).to eql 90
|
||||
expect(user.found_by).to eql 'Oembed API - Author URL (Aggressive Detection)'
|
||||
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/oembed/1.0/embed?url=http://wp.lab/&format=json']
|
||||
end
|
||||
end
|
||||
|
||||
context 'when author_url not present but author_name' do
|
||||
let(:body) { File.read(File.join(fixtures, '200_author_name.json')) }
|
||||
|
||||
it 'returns the expected array of users' do
|
||||
users = finder.aggressive
|
||||
|
||||
expect(users.size).to eql 1
|
||||
|
||||
user = users.first
|
||||
|
||||
expect(user.username).to eql 'admin sa'
|
||||
expect(user.confidence).to eql 70
|
||||
expect(user.found_by).to eql 'Oembed API - Author Name (Aggressive Detection)'
|
||||
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/oembed/1.0/embed?url=http://wp.lab/&format=json']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Users::RSSGenerator do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
|
||||
@@ -1,46 +1,80 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Users::WpJsonApi do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
let(:url) { 'http://wp.lab/' }
|
||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'users', 'wp_json_api') }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('users', 'wp_json_api') }
|
||||
|
||||
describe '#aggressive' do
|
||||
before do
|
||||
# allow(target).to receive(:content_dir).and_return('wp-content')
|
||||
allow(target).to receive(:sub_dir).and_return(false)
|
||||
stub_request(:get, finder.api_url).to_return(body: body)
|
||||
end
|
||||
before { allow(target).to receive(:sub_dir).and_return(false) }
|
||||
|
||||
context 'when not a JSON response' do
|
||||
let(:body) { '' }
|
||||
context 'when only one page of results' do
|
||||
before do
|
||||
stub_request(:get, finder.api_url)
|
||||
.with(query: { page: 1, per_page: 100 })
|
||||
.to_return(body: body, headers: {})
|
||||
end
|
||||
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
|
||||
context 'when a JSON response' do
|
||||
context 'when unauthorised' do
|
||||
let(:body) { File.read(File.join(fixtures, '401.json')) }
|
||||
context 'when not a JSON response' do
|
||||
let(:body) { '' }
|
||||
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
|
||||
context 'when limited exposure (WP >= 4.7.1)' do
|
||||
let(:body) { File.read(File.join(fixtures, '4.7.2.json')) }
|
||||
context 'when a JSON response' do
|
||||
context 'when unauthorised' do
|
||||
let(:body) { File.read(fixtures.join('401.json')) }
|
||||
|
||||
it 'returns the expected array of users' do
|
||||
users = finder.aggressive
|
||||
|
||||
expect(users.size).to eql 1
|
||||
|
||||
user = users.first
|
||||
|
||||
expect(user.id).to eql 1
|
||||
expect(user.username).to eql 'admin'
|
||||
expect(user.confidence).to eql 100
|
||||
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/wp/v2/users/']
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
|
||||
context 'when limited exposure (WP >= 4.7.1)' do
|
||||
let(:body) { File.read(fixtures.join('4.7.2.json')) }
|
||||
|
||||
it 'returns the expected array of users' do
|
||||
users = finder.aggressive
|
||||
|
||||
expect(users.size).to eql 1
|
||||
|
||||
user = users.first
|
||||
|
||||
expect(user.id).to eql 1
|
||||
expect(user.username).to eql 'admin'
|
||||
expect(user.confidence).to eql 100
|
||||
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/wp/v2/users/?page=1&per_page=100']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
context 'when multiple pages of results' do
|
||||
before do
|
||||
stub_request(:get, finder.api_url)
|
||||
.with(query: { page: 1, per_page: 100 })
|
||||
.to_return(body: File.read(fixtures.join('4.7.2.json')), headers: { 'X-WP-TotalPages' => 2 })
|
||||
|
||||
stub_request(:get, finder.api_url)
|
||||
.with(query: { page: 2, per_page: 100 })
|
||||
.to_return(body: File.read(fixtures.join('4.7.2-2.json')), headers: { 'X-WP-TotalPages' => 2 })
|
||||
end
|
||||
|
||||
it 'returns the expected array of users' do
|
||||
users = finder.aggressive
|
||||
|
||||
expect(users.size).to eql 2
|
||||
|
||||
user = users.first
|
||||
|
||||
expect(user.id).to eql 1
|
||||
expect(user.username).to eql 'admin'
|
||||
expect(user.confidence).to eql 100
|
||||
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/wp/v2/users/?page=1&per_page=100']
|
||||
|
||||
user = users.second
|
||||
|
||||
expect(user.id).to eql 20
|
||||
expect(user.username).to eql 'user'
|
||||
expect(user.confidence).to eql 100
|
||||
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/wp/v2/users/?page=2&per_page=100']
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
46
spec/app/finders/users/yoast_seo_author_sitemap_spec.rb
Normal file
46
spec/app/finders/users/yoast_seo_author_sitemap_spec.rb
Normal file
@@ -0,0 +1,46 @@
|
||||
describe WPScan::Finders::Users::YoastSeoAuthorSitemap do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
let(:url) { 'http://wp.lab/' }
|
||||
let(:fixtures) { FINDERS_FIXTURES.join('users', 'yoast_seo_author_sitemap') }
|
||||
|
||||
describe '#aggressive' do
|
||||
before do
|
||||
allow(target).to receive(:sub_dir).and_return(false)
|
||||
|
||||
stub_request(:get, finder.sitemap_url).to_return(body: body)
|
||||
end
|
||||
|
||||
context 'when not an XML response' do
|
||||
let(:body) { '' }
|
||||
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
|
||||
context 'when an XML response' do
|
||||
context 'when no usernames disclosed' do
|
||||
let(:body) { File.read(fixtures.join('no_usernames.xml')) }
|
||||
|
||||
its(:aggressive) { should eql([]) }
|
||||
end
|
||||
|
||||
context 'when usernames disclosed' do
|
||||
let(:body) { File.read(fixtures.join('usernames.xml')) }
|
||||
|
||||
it 'returns the expected array of users' do
|
||||
users = finder.aggressive
|
||||
|
||||
expect(users.size).to eql 2
|
||||
|
||||
expect(users.first.username).to eql 'editor'
|
||||
expect(users.first.confidence).to eql 100
|
||||
expect(users.first.interesting_entries).to eql ['http://wp.lab/author-sitemap.xml']
|
||||
|
||||
expect(users.last.username).to eql 'admin'
|
||||
expect(users.last.confidence).to eql 100
|
||||
expect(users.last.interesting_entries).to eql ['http://wp.lab/author-sitemap.xml']
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::Users::Base do
|
||||
subject(:user) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url) }
|
||||
@@ -8,7 +6,8 @@ describe WPScan::Finders::Users::Base do
|
||||
describe '#finders' do
|
||||
it 'contains the expected finders' do
|
||||
expect(user.finders.map { |f| f.class.to_s.demodulize })
|
||||
.to eq %w[AuthorPosts WpJsonApi OembedApi RSSGenerator AuthorIdBruteForcing LoginErrorMessages]
|
||||
.to eq %w[AuthorPosts WpJsonApi OembedApi RSSGenerator YoastSeoAuthorSitemap
|
||||
AuthorIdBruteForcing LoginErrorMessages]
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::WpVersion::AtomGenerator do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::WpVersion::RDFGenerator do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
@@ -1,5 +1,3 @@
|
||||
require 'spec_helper'
|
||||
|
||||
describe WPScan::Finders::WpVersion::Readme do
|
||||
subject(:finder) { described_class.new(target) }
|
||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user