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.1
|
||||||
- 2.5.2
|
- 2.5.2
|
||||||
- 2.5.3
|
- 2.5.3
|
||||||
|
- 2.6.0
|
||||||
- ruby-head
|
- ruby-head
|
||||||
before_install:
|
before_install:
|
||||||
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
|
||||||
- "gem update --system"
|
- gem update --system
|
||||||
matrix:
|
matrix:
|
||||||
allow_failures:
|
allow_failures:
|
||||||
- rvm: ruby-head
|
- rvm: ruby-head
|
||||||
|
|||||||
6
LICENSE
6
LICENSE
@@ -1,6 +1,6 @@
|
|||||||
WPScan Public Source License
|
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.
|
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.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.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
|
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.
|
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;
|
Free-use Terms and Conditions;
|
||||||
|
|
||||||
3. Redistribution
|
3. Redistribution
|
||||||
|
|||||||
47
README.md
47
README.md
@@ -9,17 +9,22 @@
|
|||||||
|
|
||||||
## Prerequisites:
|
## Prerequisites:
|
||||||
|
|
||||||
|
- (Optional but highly recommended: [RVM](https://rvm.io/rvm/install))
|
||||||
- Ruby >= 2.3 - Recommended: latest
|
- 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
|
- RubyGems - Recommended: latest
|
||||||
|
|
||||||
### From RubyGems:
|
### From RubyGems (Recommended):
|
||||||
|
|
||||||
```
|
```
|
||||||
gem install wpscan
|
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
|
Prerequisites: Git
|
||||||
|
|
||||||
@@ -31,10 +36,27 @@ cd wpscan/
|
|||||||
bundle install && rake install
|
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
|
# Docker
|
||||||
|
|
||||||
Pull the repo with ```docker pull wpscanteam/wpscan```
|
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
|
# 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.
|
```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```
|
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
|
# PROJECT HOME
|
||||||
|
|
||||||
[https://wpscan.org](https://wpscan.org)
|
[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
|
## 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.
|
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.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
|
### 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.
|
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;
|
Free-use Terms and Conditions;
|
||||||
|
|
||||||
### 3. Redistribution
|
### 3. Redistribution
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ module WPScan
|
|||||||
exit(WPScan::ExitCode::VULNERABLE)
|
exit(WPScan::ExitCode::VULNERABLE)
|
||||||
end
|
end
|
||||||
|
|
||||||
raise NotWordPressError unless target.wordpress? || parsed_options[:force]
|
raise NotWordPressError unless target.wordpress?(parsed_options[:detection_mode]) || parsed_options[:force]
|
||||||
end
|
end
|
||||||
|
|
||||||
# Loads the related server module in the target
|
# Loads the related server module in the target
|
||||||
|
|||||||
@@ -3,9 +3,10 @@ module WPScan
|
|||||||
# Enumeration Methods
|
# Enumeration Methods
|
||||||
class Enumeration < CMSScanner::Controller::Base
|
class Enumeration < CMSScanner::Controller::Base
|
||||||
# @param [ String ] type (plugins or themes)
|
# @param [ String ] type (plugins or themes)
|
||||||
|
# @param [ Symbol ] detection_mode
|
||||||
#
|
#
|
||||||
# @return [ String ] The related enumration message depending on the parsed_options and type supplied
|
# @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)
|
return unless %w[plugins themes].include?(type)
|
||||||
|
|
||||||
details = if parsed_options[:enumerate][:"vulnerable_#{type}"]
|
details = if parsed_options[:enumerate][:"vulnerable_#{type}"]
|
||||||
@@ -16,7 +17,20 @@ module WPScan
|
|||||||
'Most Popular'
|
'Most Popular'
|
||||||
end
|
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
|
end
|
||||||
|
|
||||||
# @param [ String ] type (plugins, themes etc)
|
# @param [ String ] type (plugins, themes etc)
|
||||||
@@ -49,12 +63,15 @@ module WPScan
|
|||||||
sort: true
|
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
|
# Enumerate the plugins & find their versions to avoid doing that when #version
|
||||||
# is called in the view
|
# is called in the view
|
||||||
plugins = target.plugins(opts)
|
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)
|
plugins.each(&:version)
|
||||||
|
|
||||||
@@ -92,12 +109,15 @@ module WPScan
|
|||||||
sort: true
|
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
|
# Enumerate the themes & find their versions to avoid doing that when #version
|
||||||
# is called in the view
|
# is called in the view
|
||||||
themes = target.themes(opts)
|
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)
|
themes.each(&:version)
|
||||||
|
|
||||||
@@ -125,21 +145,21 @@ module WPScan
|
|||||||
def enum_timthumbs
|
def enum_timthumbs
|
||||||
opts = default_opts('timthumbs').merge(list: parsed_options[:timthumbs_list])
|
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))
|
output('timthumbs', timthumbs: target.timthumbs(opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
def enum_config_backups
|
def enum_config_backups
|
||||||
opts = default_opts('config_backups').merge(list: parsed_options[:config_backups_list])
|
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))
|
output('config_backups', config_backups: target.config_backups(opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
def enum_db_exports
|
def enum_db_exports
|
||||||
opts = default_opts('db_exports').merge(list: parsed_options[:db_exports_list])
|
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))
|
output('db_exports', db_exports: target.db_exports(opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -147,7 +167,9 @@ module WPScan
|
|||||||
opts = default_opts('medias').merge(range: parsed_options[:enumerate][:medias])
|
opts = default_opts('medias').merge(range: parsed_options[:enumerate][:medias])
|
||||||
|
|
||||||
if user_interaction?
|
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
|
end
|
||||||
|
|
||||||
output('medias', medias: target.medias(opts))
|
output('medias', medias: target.medias(opts))
|
||||||
@@ -166,7 +188,7 @@ module WPScan
|
|||||||
list: parsed_options[:users_list]
|
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))
|
output('users', users: target.users(opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module WPScan
|
|||||||
|
|
||||||
return unless [200, 403].include?(res.code) && !target.homepage_or_404?(res)
|
return unless [200, 403].include?(res.code) && !target.homepage_or_404?(res)
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::BackupDB.new(
|
||||||
url,
|
url,
|
||||||
confidence: 70,
|
confidence: 70,
|
||||||
found_by: DIRECT_ACCESS,
|
found_by: DIRECT_ACCESS,
|
||||||
|
|||||||
@@ -9,9 +9,10 @@ module WPScan
|
|||||||
|
|
||||||
return unless target.debug_log?(path)
|
return unless target.debug_log?(path)
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::DebugLog.new(
|
||||||
target.url(path),
|
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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module WPScan
|
|||||||
|
|
||||||
return unless res.body =~ /DUPLICATOR INSTALL-LOG/
|
return unless res.body =~ /DUPLICATOR INSTALL-LOG/
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::DuplicatorInstallerLog.new(
|
||||||
url,
|
url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: DIRECT_ACCESS,
|
found_by: DIRECT_ACCESS,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module WPScan
|
|||||||
|
|
||||||
return unless res.code == 200 && !target.homepage_or_404?(res)
|
return unless res.code == 200 && !target.homepage_or_404?(res)
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::EmergencyPwdResetScript.new(
|
||||||
url,
|
url,
|
||||||
confidence: res.body =~ /password/i ? 100 : 40,
|
confidence: res.body =~ /password/i ? 100 : 40,
|
||||||
found_by: DIRECT_ACCESS,
|
found_by: DIRECT_ACCESS,
|
||||||
|
|||||||
@@ -10,11 +10,12 @@ module WPScan
|
|||||||
|
|
||||||
return if fpd_entries.empty?
|
return if fpd_entries.empty?
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::FullPathDisclosure.new(
|
||||||
target.url(path),
|
target.url(path),
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: DIRECT_ACCESS,
|
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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ module WPScan
|
|||||||
|
|
||||||
url = target.url('wp-content/mu-plugins/')
|
url = target.url('wp-content/mu-plugins/')
|
||||||
|
|
||||||
return WPScan::InterestingFinding.new(
|
return WPScan::MuPlugins.new(
|
||||||
url,
|
url,
|
||||||
confidence: 70,
|
confidence: 70,
|
||||||
found_by: 'URLs In Homepage (Passive Detection)',
|
found_by: 'URLs In Homepage (Passive Detection)',
|
||||||
@@ -35,7 +35,7 @@ module WPScan
|
|||||||
|
|
||||||
target.mu_plugins = true
|
target.mu_plugins = true
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::MuPlugins.new(
|
||||||
url,
|
url,
|
||||||
confidence: 80,
|
confidence: 80,
|
||||||
found_by: DIRECT_ACCESS,
|
found_by: DIRECT_ACCESS,
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ module WPScan
|
|||||||
|
|
||||||
target.multisite = true
|
target.multisite = true
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::Multisite.new(
|
||||||
url,
|
url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: DIRECT_ACCESS,
|
found_by: DIRECT_ACCESS,
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ module WPScan
|
|||||||
res = Browser.get(url)
|
res = Browser.get(url)
|
||||||
|
|
||||||
if res.code == 200 && res.body =~ /wordpress/i
|
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
|
||||||
end
|
end
|
||||||
nil
|
nil
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ module WPScan
|
|||||||
|
|
||||||
target.registration_enabled = true
|
target.registration_enabled = true
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::Registration.new(
|
||||||
res.effective_url,
|
res.effective_url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: DIRECT_ACCESS,
|
found_by: DIRECT_ACCESS,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module WPScan
|
|||||||
|
|
||||||
return unless res.code == 200 && res.headers['Content-Type'] =~ %r{\Aapplication/zip}i
|
return unless res.code == 200 && res.headers['Content-Type'] =~ %r{\Aapplication/zip}i
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::TmmDbMigrate.new(
|
||||||
url,
|
url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: DIRECT_ACCESS,
|
found_by: DIRECT_ACCESS,
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ module WPScan
|
|||||||
|
|
||||||
url = target.url(path)
|
url = target.url(path)
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::UploadDirectoryListing.new(
|
||||||
url,
|
url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: DIRECT_ACCESS,
|
found_by: DIRECT_ACCESS,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ module WPScan
|
|||||||
module InterestingFindings
|
module InterestingFindings
|
||||||
# UploadSQLDump finder
|
# UploadSQLDump finder
|
||||||
class UploadSQLDump < CMSScanner::Finders::Finder
|
class UploadSQLDump < CMSScanner::Finders::Finder
|
||||||
SQL_PATTERN = /(?:(?:(?:DROP|CREATE) TABLE)|INSERT INTO)/
|
SQL_PATTERN = /(?:(?:(?:DROP|CREATE) TABLE)|INSERT INTO)/.freeze
|
||||||
|
|
||||||
# @return [ InterestingFinding ]
|
# @return [ InterestingFinding ]
|
||||||
def aggressive(_opts = {})
|
def aggressive(_opts = {})
|
||||||
@@ -12,7 +12,7 @@ module WPScan
|
|||||||
|
|
||||||
return unless res.code == 200 && res.body =~ SQL_PATTERN
|
return unless res.code == 200 && res.body =~ SQL_PATTERN
|
||||||
|
|
||||||
WPScan::InterestingFinding.new(
|
WPScan::UploadSQLDump.new(
|
||||||
url,
|
url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: DIRECT_ACCESS
|
found_by: DIRECT_ACCESS
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ module WPScan
|
|||||||
module MainTheme
|
module MainTheme
|
||||||
# From the WooFramework meta generators
|
# From the WooFramework meta generators
|
||||||
class WooFrameworkMetaGenerator < CMSScanner::Finders::Finder
|
class WooFrameworkMetaGenerator < CMSScanner::Finders::Finder
|
||||||
THEME_PATTERN = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?"\s+/?>}
|
THEME_PATTERN = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?"\s+/?>}.freeze
|
||||||
FRAMEWORK_PATTERN = %r{<meta name="generator" content="WooFramework\s?([^"]+)?"\s+/?>}
|
FRAMEWORK_PATTERN = %r{<meta name="generator" content="WooFramework\s?([^"]+)?"\s+/?>}.freeze
|
||||||
PATTERN = /#{THEME_PATTERN}\s+#{FRAMEWORK_PATTERN}/i
|
PATTERN = /#{THEME_PATTERN}\s+#{FRAMEWORK_PATTERN}/i.freeze
|
||||||
|
|
||||||
def passive(opts = {})
|
def passive(opts = {})
|
||||||
return unless target.homepage_res.body =~ PATTERN
|
return unless target.homepage_res.body =~ PATTERN
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ require_relative 'users/oembed_api'
|
|||||||
require_relative 'users/rss_generator'
|
require_relative 'users/rss_generator'
|
||||||
require_relative 'users/author_id_brute_forcing'
|
require_relative 'users/author_id_brute_forcing'
|
||||||
require_relative 'users/login_error_messages'
|
require_relative 'users/login_error_messages'
|
||||||
|
require_relative 'users/yoast_seo_author_sitemap.rb'
|
||||||
|
|
||||||
module WPScan
|
module WPScan
|
||||||
module Finders
|
module Finders
|
||||||
@@ -19,6 +20,7 @@ module WPScan
|
|||||||
Users::WpJsonApi.new(target) <<
|
Users::WpJsonApi.new(target) <<
|
||||||
Users::OembedApi.new(target) <<
|
Users::OembedApi.new(target) <<
|
||||||
Users::RSSGenerator.new(target) <<
|
Users::RSSGenerator.new(target) <<
|
||||||
|
Users::YoastSeoAuthorSitemap.new(target) <<
|
||||||
Users::AuthorIdBruteForcing.new(target) <<
|
Users::AuthorIdBruteForcing.new(target) <<
|
||||||
Users::LoginErrorMessages.new(target)
|
Users::LoginErrorMessages.new(target)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,29 +14,35 @@ module WPScan
|
|||||||
|
|
||||||
# @param [ Hash ] opts
|
# @param [ Hash ] opts
|
||||||
#
|
#
|
||||||
# TODO: make this code pretty :x
|
|
||||||
#
|
|
||||||
# @return [ Array<User> ]
|
# @return [ Array<User> ]
|
||||||
def aggressive(_opts = {})
|
def aggressive(_opts = {})
|
||||||
found = []
|
|
||||||
found_by_msg = 'Oembed API - %s (Aggressive Detection)'
|
|
||||||
|
|
||||||
oembed_data = JSON.parse(Browser.get(api_url).body)
|
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}
|
if oembed_data['author_url'] =~ %r{/author/([^/]+)/?\z}
|
||||||
details = [Regexp.last_match[1], 'Author URL', 90]
|
details = [Regexp.last_match[1], 'Author URL', 90]
|
||||||
elsif oembed_data['author_name'] && !oembed_data['author_name'].empty?
|
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
|
end
|
||||||
|
|
||||||
return unless details
|
details
|
||||||
|
end
|
||||||
|
|
||||||
found << CMSScanner::User.new(details[0],
|
def found_by_msg
|
||||||
found_by: format(found_by_msg, details[1]),
|
'Oembed API - %s (Aggressive Detection)'
|
||||||
confidence: details[2],
|
|
||||||
interesting_entries: [api_url])
|
|
||||||
rescue JSON::ParserError
|
|
||||||
found
|
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [ String ] The URL of the API listing the Users
|
# @return [ String ] The URL of the API listing the Users
|
||||||
|
|||||||
@@ -4,20 +4,29 @@ module WPScan
|
|||||||
# WP JSON API
|
# 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)
|
# 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
|
class WpJsonApi < CMSScanner::Finders::Finder
|
||||||
|
MAX_PER_PAGE = 100 # See https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/
|
||||||
|
|
||||||
# @param [ Hash ] opts
|
# @param [ Hash ] opts
|
||||||
#
|
#
|
||||||
# @return [ Array<User> ]
|
# @return [ Array<User> ]
|
||||||
def aggressive(_opts = {})
|
def aggressive(_opts = {})
|
||||||
found = []
|
found = []
|
||||||
|
current_page = 0
|
||||||
|
|
||||||
JSON.parse(Browser.get(api_url).body)&.each do |user|
|
loop do
|
||||||
found << CMSScanner::User.new(user['slug'],
|
current_page += 1
|
||||||
id: user['id'],
|
|
||||||
found_by: found_by,
|
res = Typhoeus.get(api_url, params: { per_page: MAX_PER_PAGE, page: current_page })
|
||||||
confidence: 100,
|
|
||||||
interesting_entries: [api_url])
|
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
|
end
|
||||||
|
|
||||||
found
|
found
|
||||||
@@ -25,6 +34,23 @@ module WPScan
|
|||||||
found
|
found
|
||||||
end
|
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
|
# @return [ String ] The URL of the API listing the Users
|
||||||
def api_url
|
def api_url
|
||||||
@api_url ||= target.url('wp-json/wp/v2/users/')
|
@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
|
class InterestingFinding < CMSScanner::InterestingFinding
|
||||||
include References
|
include References
|
||||||
end
|
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
|
end
|
||||||
|
|||||||
@@ -53,7 +53,12 @@ module WPScan
|
|||||||
|
|
||||||
# @return [ String ]
|
# @return [ String ]
|
||||||
def release_date
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<% if @version -%>
|
<% 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) -%>
|
<%= render('@finding', item: @version) -%>
|
||||||
<% else -%>
|
<% else -%>
|
||||||
<%= notice_icon %> The WordPress version could not be detected.
|
<%= notice_icon %> The WordPress version could not be detected.
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
"version": {
|
"version": {
|
||||||
"number": <%= @version.number.to_json %>,
|
"number": <%= @version.number.to_json %>,
|
||||||
"release_date": <%= @version.release_date.to_json %>,
|
"release_date": <%= @version.release_date.to_json %>,
|
||||||
|
"status": <%= @version.status.to_json %>,
|
||||||
<%= render('@finding', item: @version) -%>
|
<%= render('@finding', item: @version) -%>
|
||||||
},
|
},
|
||||||
<% else -%>
|
<% else -%>
|
||||||
|
|||||||
@@ -16,9 +16,7 @@ require 'securerandom'
|
|||||||
require 'wpscan/helper'
|
require 'wpscan/helper'
|
||||||
require 'wpscan/db'
|
require 'wpscan/db'
|
||||||
require 'wpscan/version'
|
require 'wpscan/version'
|
||||||
require 'wpscan/errors/wordpress'
|
require 'wpscan/errors'
|
||||||
require 'wpscan/errors/http'
|
|
||||||
require 'wpscan/errors/update'
|
|
||||||
require 'wpscan/browser'
|
require 'wpscan/browser'
|
||||||
require 'wpscan/target'
|
require 'wpscan/target'
|
||||||
require 'wpscan/finders'
|
require 'wpscan/finders'
|
||||||
|
|||||||
@@ -60,12 +60,11 @@ module WPScan
|
|||||||
end
|
end
|
||||||
|
|
||||||
# @return [ Hash ] The params for Typhoeus::Request
|
# @return [ Hash ] The params for Typhoeus::Request
|
||||||
|
# @note Those params can't be overriden by CLI options
|
||||||
def request_params
|
def request_params
|
||||||
{
|
{
|
||||||
ssl_verifyhost: 2,
|
timeout: 600,
|
||||||
ssl_verifypeer: true,
|
connecttimeout: 300,
|
||||||
timeout: 300,
|
|
||||||
connecttimeout: 120,
|
|
||||||
accept_encoding: 'gzip, deflate',
|
accept_encoding: 'gzip, deflate',
|
||||||
cache_ttl: 0
|
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
|
module WPScan
|
||||||
# HTTP Error
|
# HTTP Error
|
||||||
class HTTPError < StandardError
|
class HTTPError < Error
|
||||||
attr_reader :response
|
attr_reader :response
|
||||||
|
|
||||||
# @param [ Typhoeus::Response ] res
|
# @param [ Typhoeus::Response ] res
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
module WPScan
|
module WPScan
|
||||||
# Error raised when there is a missing DB file and --no-update supplied
|
# Error raised when there is a missing DB file and --no-update supplied
|
||||||
class MissingDatabaseFile < StandardError
|
class MissingDatabaseFile < Error
|
||||||
def to_s
|
def to_s
|
||||||
'Update required, you can not run a scan if a database file is missing.'
|
'Update required, you can not run a scan if a database file is missing.'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,20 +1,20 @@
|
|||||||
module WPScan
|
module WPScan
|
||||||
# WordPress hosted (*.wordpress.com)
|
# WordPress hosted (*.wordpress.com)
|
||||||
class WordPressHostedError < StandardError
|
class WordPressHostedError < Error
|
||||||
def to_s
|
def to_s
|
||||||
'Scanning *.wordpress.com hosted blogs is not supported.'
|
'Scanning *.wordpress.com hosted blogs is not supported.'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Not WordPress Error
|
# Not WordPress Error
|
||||||
class NotWordPressError < StandardError
|
class NotWordPressError < Error
|
||||||
def to_s
|
def to_s
|
||||||
'The remote website is up, but does not seem to be running WordPress.'
|
'The remote website is up, but does not seem to be running WordPress.'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# Invalid Wp Version (used in the WpVersion#new)
|
# Invalid Wp Version (used in the WpVersion#new)
|
||||||
class InvalidWordPressVersion < StandardError
|
class InvalidWordPressVersion < Error
|
||||||
def to_s
|
def to_s
|
||||||
'The WordPress version is invalid'
|
'The WordPress version is invalid'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ module WPScan
|
|||||||
module WordPress
|
module WordPress
|
||||||
include CMSScanner::Target::Platform::PHP
|
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
|
# 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
|
# 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 registration_enabled? registration_enabled
|
||||||
alias mu_plugins? mu_plugins
|
alias mu_plugins? mu_plugins
|
||||||
|
|
||||||
|
# @param [ Symbol ] detection_mode
|
||||||
|
#
|
||||||
# @return [ Boolean ]
|
# @return [ Boolean ]
|
||||||
def wordpress?
|
def wordpress?(detection_mode)
|
||||||
# res = Browser.get(url)
|
|
||||||
|
|
||||||
in_scope_urls(homepage_res) do |url|
|
in_scope_urls(homepage_res) do |url|
|
||||||
return true if Addressable::URI.parse(url).path.match(WORDPRESS_PATTERN)
|
return true if Addressable::URI.parse(url).path.match(WORDPRESS_PATTERN)
|
||||||
end
|
end
|
||||||
@@ -32,6 +32,14 @@ module WPScan
|
|||||||
|
|
||||||
return true unless comments_from_page(/wordpress/i, homepage_res).empty?
|
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
|
false
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -41,7 +49,7 @@ module WPScan
|
|||||||
end
|
end
|
||||||
|
|
||||||
def wordpress_hosted?
|
def wordpress_hosted?
|
||||||
uri.host =~ /wordpress.com$/i ? true : false
|
uri.host =~ /\.wordpress\.com$/i ? true : false
|
||||||
end
|
end
|
||||||
|
|
||||||
# @param [ String ] username
|
# @param [ String ] username
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
# Version
|
# Version
|
||||||
module WPScan
|
module WPScan
|
||||||
VERSION = '3.3.2'.freeze
|
VERSION = '3.4.4'.freeze
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Controller::Aliases do
|
describe WPScan::Controller::Aliases do
|
||||||
subject(:controller) { described_class.new }
|
subject(:controller) { described_class.new }
|
||||||
let(:target_url) { 'http://ex.lo/' }
|
let(:target_url) { 'http://ex.lo/' }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Controller::Core do
|
describe WPScan::Controller::Core do
|
||||||
subject(:core) { described_class.new }
|
subject(:core) { described_class.new }
|
||||||
let(:target_url) { 'http://ex.lo/' }
|
let(:target_url) { 'http://ex.lo/' }
|
||||||
@@ -167,7 +165,7 @@ describe WPScan::Controller::Core do
|
|||||||
|
|
||||||
before do
|
before do
|
||||||
expect(core).to receive(:load_server_module)
|
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
|
end
|
||||||
|
|
||||||
it 'calls the formatter when started and finished to update the db' do
|
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
|
context 'when wordpress' do
|
||||||
it 'does not raise an error' 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
|
expect { core.before_scan }.to_not raise_error
|
||||||
end
|
end
|
||||||
@@ -218,7 +216,7 @@ describe WPScan::Controller::Core do
|
|||||||
|
|
||||||
context 'when not wordpress' do
|
context 'when not wordpress' do
|
||||||
it 'raises an error' 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)
|
expect { core.before_scan }.to raise_error(WPScan::NotWordPressError)
|
||||||
end
|
end
|
||||||
@@ -239,7 +237,7 @@ describe WPScan::Controller::Core do
|
|||||||
context 'when wordpress' do
|
context 'when wordpress' do
|
||||||
before do
|
before do
|
||||||
expect(core).to receive(:load_server_module)
|
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
|
end
|
||||||
|
|
||||||
it 'does not raise any error' do
|
it 'does not raise any error' do
|
||||||
@@ -250,7 +248,7 @@ describe WPScan::Controller::Core do
|
|||||||
context 'when not wordpress' do
|
context 'when not wordpress' do
|
||||||
before do
|
before do
|
||||||
expect(core).to receive(:load_server_module)
|
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
|
end
|
||||||
|
|
||||||
context 'when no --force' do
|
context 'when no --force' do
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Controller::CustomDirectories do
|
describe WPScan::Controller::CustomDirectories do
|
||||||
subject(:controller) { described_class.new }
|
subject(:controller) { described_class.new }
|
||||||
let(:target_url) { 'http://ex.lo/' }
|
let(:target_url) { 'http://ex.lo/' }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Controller::Enumeration do
|
describe WPScan::Controller::Enumeration do
|
||||||
subject(:controller) { described_class.new }
|
subject(:controller) { described_class.new }
|
||||||
let(:target_url) { 'http://wp.lab/' }
|
let(:target_url) { 'http://wp.lab/' }
|
||||||
@@ -16,10 +14,11 @@ describe WPScan::Controller::Enumeration do
|
|||||||
end
|
end
|
||||||
|
|
||||||
describe '#enum_message' do
|
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
|
context 'when type argument is incorrect' do
|
||||||
let(:type) { 'spec' }
|
let(:type) { 'spec' }
|
||||||
|
let(:detection_mode) { :mixed }
|
||||||
|
|
||||||
it 'returns nil' do
|
it 'returns nil' do
|
||||||
@expected = nil
|
@expected = nil
|
||||||
@@ -29,28 +28,31 @@ describe WPScan::Controller::Enumeration do
|
|||||||
%w[plugins themes].each do |t|
|
%w[plugins themes].each do |t|
|
||||||
context "type = #{t}" do
|
context "type = #{t}" do
|
||||||
let(:type) { t }
|
let(:type) { t }
|
||||||
|
let(:detection_mode) { :mixed }
|
||||||
|
|
||||||
context 'when vulnerable' do
|
context 'when vulnerable' do
|
||||||
let(:cli_args) { "#{super()} -e v#{type[0]}" }
|
let(:cli_args) { "#{super()} -e v#{type[0]}" }
|
||||||
|
|
||||||
it 'returns the expected string' do
|
it 'returns the expected string' do
|
||||||
@expected = "Enumerating Vulnerable #{type.capitalize}"
|
@expected = "Enumerating Vulnerable #{type.capitalize} (via Passive and Aggressive Methods)"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when all' do
|
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
|
it 'returns the expected string' do
|
||||||
@expected = "Enumerating All #{type.capitalize}"
|
@expected = "Enumerating All #{type.capitalize} (via Passive Methods)"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when most popular' do
|
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
|
it 'returns the expected string' do
|
||||||
@expected = "Enumerating Most Popular #{type.capitalize}"
|
@expected = "Enumerating Most Popular #{type.capitalize} (via Aggressive Methods)"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Controller::PasswordAttack do
|
describe WPScan::Controller::PasswordAttack do
|
||||||
subject(:controller) { described_class.new }
|
subject(:controller) { described_class.new }
|
||||||
let(:target_url) { 'http://ex.lo/' }
|
let(:target_url) { 'http://ex.lo/' }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
def it_calls_the_formatter_with_the_correct_parameter(version)
|
def it_calls_the_formatter_with_the_correct_parameter(version)
|
||||||
it 'calls the formatter with the correct parameter' do
|
it 'calls the formatter with the correct parameter' do
|
||||||
expect(controller.formatter).to receive(:output)
|
expect(controller.formatter).to receive(:output)
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::ConfigBackups::KnownFilenames do
|
describe WPScan::Finders::ConfigBackups::KnownFilenames do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::ConfigBackups::Base do
|
describe WPScan::Finders::ConfigBackups::Base do
|
||||||
subject(:config_backups) { described_class.new(target) }
|
subject(:config_backups) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::DbExports::KnownLocations do
|
describe WPScan::Finders::DbExports::KnownLocations do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::DbExports::Base do
|
describe WPScan::Finders::DbExports::Base do
|
||||||
subject(:db_exports) { described_class.new(target) }
|
subject(:db_exports) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::BackupDB do
|
describe WPScan::Finders::InterestingFindings::BackupDB do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
@@ -37,7 +35,7 @@ describe WPScan::Finders::InterestingFindings::BackupDB do
|
|||||||
after do
|
after do
|
||||||
found = finder.aggressive
|
found = finder.aggressive
|
||||||
|
|
||||||
expect(found).to eql WPScan::InterestingFinding.new(
|
expect(found).to eql WPScan::BackupDB.new(
|
||||||
dir_url,
|
dir_url,
|
||||||
confidence: 70,
|
confidence: 70,
|
||||||
found_by: described_class::DIRECT_ACCESS
|
found_by: described_class::DIRECT_ACCESS
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::DebugLog do
|
describe WPScan::Finders::InterestingFindings::DebugLog do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
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')) }
|
let(:body) { File.read(File.join(fixtures, 'debug.log')) }
|
||||||
|
|
||||||
it 'returns the InterestingFinding' do
|
it 'returns the InterestingFinding' do
|
||||||
expect(finder.aggressive).to eql WPScan::InterestingFinding.new(
|
expect(finder.aggressive).to eql WPScan::DebugLog.new(
|
||||||
log_url,
|
log_url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: described_class::DIRECT_ACCESS
|
found_by: described_class::DIRECT_ACCESS
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do
|
describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
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)) }
|
let(:body) { File.read(File.join(fixtures, filename)) }
|
||||||
|
|
||||||
it 'returns the InterestingFinding' do
|
it 'returns the InterestingFinding' do
|
||||||
expect(finder.aggressive).to eql WPScan::InterestingFinding.new(
|
expect(finder.aggressive).to eql WPScan::DuplicatorInstallerLog.new(
|
||||||
log_url,
|
log_url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: described_class::DIRECT_ACCESS
|
found_by: described_class::DIRECT_ACCESS
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::EmergencyPwdResetScript do
|
describe WPScan::Finders::InterestingFindings::EmergencyPwdResetScript do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::FullPathDisclosure do
|
describe WPScan::Finders::InterestingFindings::FullPathDisclosure do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
@@ -25,7 +23,7 @@ describe WPScan::Finders::InterestingFindings::FullPathDisclosure do
|
|||||||
it 'returns the InterestingFinding' do
|
it 'returns the InterestingFinding' do
|
||||||
found = finder.aggressive
|
found = finder.aggressive
|
||||||
|
|
||||||
expect(found).to eql WPScan::InterestingFinding.new(
|
expect(found).to eql WPScan::FullPathDisclosure.new(
|
||||||
file_url,
|
file_url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: described_class::DIRECT_ACCESS
|
found_by: described_class::DIRECT_ACCESS
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::MuPlugins do
|
describe WPScan::Finders::InterestingFindings::MuPlugins do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::Multisite do
|
describe WPScan::Finders::InterestingFindings::Multisite do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::Readme do
|
describe WPScan::Finders::InterestingFindings::Readme do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
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) }
|
before { stub_request(:get, target.url(file)).to_return(body: readme) }
|
||||||
|
|
||||||
it 'returns the expected InterestingFinding' do
|
it 'returns the expected InterestingFinding' do
|
||||||
expected = WPScan::InterestingFinding.new(
|
expected = WPScan::Readme.new(
|
||||||
target.url(file),
|
target.url(file),
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: described_class::DIRECT_ACCESS
|
found_by: described_class::DIRECT_ACCESS
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::Registration do
|
describe WPScan::Finders::InterestingFindings::Registration do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::TmmDbMigrate do
|
describe WPScan::Finders::InterestingFindings::TmmDbMigrate do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::UploadDirectoryListing do
|
describe WPScan::Finders::InterestingFindings::UploadDirectoryListing do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::UploadSQLDump do
|
describe WPScan::Finders::InterestingFindings::UploadSQLDump do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
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' }
|
let(:fixture) { 'dump.sql' }
|
||||||
|
|
||||||
it 'returns the interesting findings' do
|
it 'returns the interesting findings' do
|
||||||
@expected = WPScan::InterestingFinding.new(
|
@expected = WPScan::UploadSQLDump.new(
|
||||||
finder.dump_url,
|
finder.dump_url,
|
||||||
confidence: 100,
|
confidence: 100,
|
||||||
found_by: described_class::DIRECT_ACCESS
|
found_by: described_class::DIRECT_ACCESS
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::InterestingFindings::Base do
|
describe WPScan::Finders::InterestingFindings::Base do
|
||||||
subject(:files) { described_class.new(target) }
|
subject(:files) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::MainTheme::CssStyle do
|
describe WPScan::Finders::MainTheme::CssStyle do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::MainTheme::UrlsInHomepage do
|
describe WPScan::Finders::MainTheme::UrlsInHomepage do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::MainTheme::WooFrameworkMetaGenerator do
|
describe WPScan::Finders::MainTheme::WooFrameworkMetaGenerator do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::MainTheme::Base do
|
describe WPScan::Finders::MainTheme::Base do
|
||||||
subject(:main_theme) { described_class.new(target) }
|
subject(:main_theme) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Medias::AttachmentBruteForcing do
|
describe WPScan::Finders::Medias::AttachmentBruteForcing do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Medias::Base do
|
describe WPScan::Finders::Medias::Base do
|
||||||
subject(:media) { described_class.new(target) }
|
subject(:media) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::PluginVersion::Readme do
|
describe WPScan::Finders::PluginVersion::Readme do
|
||||||
subject(:finder) { described_class.new(plugin) }
|
subject(:finder) { described_class.new(plugin) }
|
||||||
let(:plugin) { WPScan::Plugin.new('spec', target) }
|
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
|
# 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.
|
# constants not being intilialized. This is due to the Dynamic Finders.
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::BodyPattern do
|
describe WPScan::Finders::Plugins::BodyPattern do
|
||||||
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::Comment do
|
describe WPScan::Finders::Plugins::Comment do
|
||||||
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::ConfigParser do
|
describe WPScan::Finders::Plugins::ConfigParser do
|
||||||
xit
|
xit
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::HeaderPattern do
|
describe WPScan::Finders::Plugins::HeaderPattern do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::JavascriptVar do
|
describe WPScan::Finders::Plugins::JavascriptVar do
|
||||||
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::KnownLocations do
|
describe WPScan::Finders::Plugins::KnownLocations do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::QueryParameter do
|
describe WPScan::Finders::Plugins::QueryParameter do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::UrlsInHomepage do
|
describe WPScan::Finders::Plugins::UrlsInHomepage do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::Xpath do
|
describe WPScan::Finders::Plugins::Xpath do
|
||||||
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
it_behaves_like WPScan::Finders::DynamicFinder::WpItems::Finder do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::Base do
|
describe WPScan::Finders::Plugins::Base do
|
||||||
subject(:plugins) { described_class.new(target) }
|
subject(:plugins) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::ThemeVersion::Style do
|
describe WPScan::Finders::ThemeVersion::Style do
|
||||||
subject(:finder) { described_class.new(theme) }
|
subject(:finder) { described_class.new(theme) }
|
||||||
let(:theme) { WPScan::Theme.new('spec', target) }
|
let(:theme) { WPScan::Theme.new('spec', target) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::ThemeVersion::WooFrameworkMetaGenerator do
|
describe WPScan::Finders::ThemeVersion::WooFrameworkMetaGenerator do
|
||||||
subject(:finder) { described_class.new(theme) }
|
subject(:finder) { described_class.new(theme) }
|
||||||
let(:theme) { WPScan::Theme.new(slug, target) }
|
let(:theme) { WPScan::Theme.new(slug, target) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::ThemeVersion::Base do
|
describe WPScan::Finders::ThemeVersion::Base do
|
||||||
subject(:theme_version) { described_class.new(theme) }
|
subject(:theme_version) { described_class.new(theme) }
|
||||||
let(:theme) { WPScan::Plugin.new(slug, target) }
|
let(:theme) { WPScan::Plugin.new(slug, target) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Themes::KnownLocations do
|
describe WPScan::Finders::Themes::KnownLocations do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Themes::UrlsInHomepage do
|
describe WPScan::Finders::Themes::UrlsInHomepage do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Themes::Base do
|
describe WPScan::Finders::Themes::Base do
|
||||||
subject(:themes) { described_class.new(target) }
|
subject(:themes) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::TimthumbVersion::BadRequest do
|
describe WPScan::Finders::TimthumbVersion::BadRequest do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Timthumb.new(url) }
|
let(:target) { WPScan::Timthumb.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::TimthumbVersion::Base do
|
describe WPScan::Finders::TimthumbVersion::Base do
|
||||||
subject(:timthumb_version) { described_class.new(target) }
|
subject(:timthumb_version) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Timthumb.new(url) }
|
let(:target) { WPScan::Timthumb.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Timthumbs::KnownLocations do
|
describe WPScan::Finders::Timthumbs::KnownLocations do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Timthumbs::Base do
|
describe WPScan::Finders::Timthumbs::Base do
|
||||||
subject(:timthumb) { described_class.new(target) }
|
subject(:timthumb) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Users::AuthorIdBruteForcing do
|
describe WPScan::Finders::Users::AuthorIdBruteForcing do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Users::AuthorPosts do
|
describe WPScan::Finders::Users::AuthorPosts do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Users::LoginErrorMessages do
|
describe WPScan::Finders::Users::LoginErrorMessages do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Users::OembedApi do
|
describe WPScan::Finders::Users::OembedApi do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
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') }
|
let(:fixtures) { File.join(FINDERS_FIXTURES, 'users', 'oembed_api') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Users::RSSGenerator do
|
describe WPScan::Finders::Users::RSSGenerator do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
|||||||
@@ -1,16 +1,17 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Users::WpJsonApi do
|
describe WPScan::Finders::Users::WpJsonApi do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
let(:url) { 'http://wp.lab/' }
|
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
|
describe '#aggressive' do
|
||||||
|
before { allow(target).to receive(:sub_dir).and_return(false) }
|
||||||
|
|
||||||
|
context 'when only one page of results' do
|
||||||
before do
|
before do
|
||||||
# allow(target).to receive(:content_dir).and_return('wp-content')
|
stub_request(:get, finder.api_url)
|
||||||
allow(target).to receive(:sub_dir).and_return(false)
|
.with(query: { page: 1, per_page: 100 })
|
||||||
stub_request(:get, finder.api_url).to_return(body: body)
|
.to_return(body: body, headers: {})
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when not a JSON response' do
|
context 'when not a JSON response' do
|
||||||
@@ -21,13 +22,13 @@ describe WPScan::Finders::Users::WpJsonApi do
|
|||||||
|
|
||||||
context 'when a JSON response' do
|
context 'when a JSON response' do
|
||||||
context 'when unauthorised' do
|
context 'when unauthorised' do
|
||||||
let(:body) { File.read(File.join(fixtures, '401.json')) }
|
let(:body) { File.read(fixtures.join('401.json')) }
|
||||||
|
|
||||||
its(:aggressive) { should eql([]) }
|
its(:aggressive) { should eql([]) }
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when limited exposure (WP >= 4.7.1)' do
|
context 'when limited exposure (WP >= 4.7.1)' do
|
||||||
let(:body) { File.read(File.join(fixtures, '4.7.2.json')) }
|
let(:body) { File.read(fixtures.join('4.7.2.json')) }
|
||||||
|
|
||||||
it 'returns the expected array of users' do
|
it 'returns the expected array of users' do
|
||||||
users = finder.aggressive
|
users = finder.aggressive
|
||||||
@@ -39,9 +40,42 @@ describe WPScan::Finders::Users::WpJsonApi do
|
|||||||
expect(user.id).to eql 1
|
expect(user.id).to eql 1
|
||||||
expect(user.username).to eql 'admin'
|
expect(user.username).to eql 'admin'
|
||||||
expect(user.confidence).to eql 100
|
expect(user.confidence).to eql 100
|
||||||
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/wp/v2/users/']
|
expect(user.interesting_entries).to eql ['http://wp.lab/wp-json/wp/v2/users/?page=1&per_page=100']
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
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
|
||||||
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
|
describe WPScan::Finders::Users::Base do
|
||||||
subject(:user) { described_class.new(target) }
|
subject(:user) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url) }
|
let(:target) { WPScan::Target.new(url) }
|
||||||
@@ -8,7 +6,8 @@ describe WPScan::Finders::Users::Base do
|
|||||||
describe '#finders' do
|
describe '#finders' do
|
||||||
it 'contains the expected finders' do
|
it 'contains the expected finders' do
|
||||||
expect(user.finders.map { |f| f.class.to_s.demodulize })
|
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
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::WpVersion::AtomGenerator do
|
describe WPScan::Finders::WpVersion::AtomGenerator do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::WpVersion::RDFGenerator do
|
describe WPScan::Finders::WpVersion::RDFGenerator do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::WpVersion::Readme do
|
describe WPScan::Finders::WpVersion::Readme do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::WpVersion::RSSGenerator do
|
describe WPScan::Finders::WpVersion::RSSGenerator do
|
||||||
subject(:finder) { described_class.new(target) }
|
subject(:finder) { described_class.new(target) }
|
||||||
let(:target) { WPScan::Target.new(url).extend(CMSScanner::Target::Server::Apache) }
|
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