Compare commits
78 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
adff971d62 | ||
|
|
23b22f71b8 | ||
|
|
fee3671e32 | ||
|
|
26c6be7268 | ||
|
|
01c5bcf2be | ||
|
|
1ab8a5ab98 | ||
|
|
b54aaca28a | ||
|
|
86a29ae000 | ||
|
|
a5dbee93ff | ||
|
|
e0465e6e10 | ||
|
|
7da48b9dd1 | ||
|
|
a64895c3a6 | ||
|
|
21f1a5d4c4 | ||
|
|
d60f79ca33 | ||
|
|
2d5cea5033 | ||
|
|
b0615215fe | ||
|
|
7a0f98b2cb | ||
|
|
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
|
||||||
|
|||||||
10
LICENSE
10
LICENSE
@@ -1,14 +1,14 @@
|
|||||||
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.
|
||||||
|
|
||||||
1. Definitions
|
1. Definitions
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -59,7 +59,7 @@ WPScan is provided under an AS-IS basis and without any support, updates or main
|
|||||||
|
|
||||||
8. Disclaimer of Warranty
|
8. Disclaimer of Warranty
|
||||||
|
|
||||||
WPScan is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the WPScan is free of defects, merchantable, fit for a particular purpose or non-infringing.
|
WPScan is provided under this License on an "as is" basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the WPScan is free of defects, merchantable, fit for a particular purpose or non-infringing.
|
||||||
|
|
||||||
9. Limitation of Liability
|
9. Limitation of Liability
|
||||||
|
|
||||||
|
|||||||
71
README.md
71
README.md
@@ -7,23 +7,28 @@
|
|||||||
|
|
||||||
# INSTALL
|
# INSTALL
|
||||||
|
|
||||||
## 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)
|
||||||
|
|
||||||
```
|
```shell
|
||||||
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
|
||||||
|
|
||||||
```
|
```shell
|
||||||
git clone https://github.com/wpscanteam/wpscan
|
git clone https://github.com/wpscanteam/wpscan
|
||||||
|
|
||||||
cd wpscan/
|
cd wpscan/
|
||||||
@@ -31,10 +36,30 @@ 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
|
||||||
|
|
||||||
|
```shell
|
||||||
|
docker run -it --rm wpscanteam/wpscan --url https://target.tld/ --enumerate u
|
||||||
|
```
|
||||||
|
|
||||||
|
Enumerating a range of usernames
|
||||||
|
|
||||||
|
```shell
|
||||||
|
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.
|
||||||
@@ -46,29 +71,45 @@ The DB is located at ~/.wpscan/db
|
|||||||
|
|
||||||
WPScan can load all options (including the --url) from configuration files, the following locations are checked (order: first to last):
|
WPScan can load all options (including the --url) from configuration files, the following locations are checked (order: first to last):
|
||||||
|
|
||||||
* ~/.wpscan/cli_options.json
|
- ~/.wpscan/cli_options.json
|
||||||
* ~/.wpscan/cli_options.yml
|
- ~/.wpscan/cli_options.yml
|
||||||
* pwd/.wpscan/cli_options.json
|
- pwd/.wpscan/cli_options.json
|
||||||
* pwd/.wpscan/cli_options.yml
|
- pwd/.wpscan/cli_options.yml
|
||||||
|
|
||||||
If those files exist, options from them will be loaded and overridden if found twice.
|
If those files exist, options from them will be loaded and overridden if found twice.
|
||||||
|
|
||||||
e.g:
|
e.g:
|
||||||
|
|
||||||
~/.wpscan/cli_options.yml:
|
~/.wpscan/cli_options.yml:
|
||||||
```
|
|
||||||
|
```yml
|
||||||
proxy: 'http://127.0.0.1:8080'
|
proxy: 'http://127.0.0.1:8080'
|
||||||
verbose: true
|
verbose: true
|
||||||
```
|
```
|
||||||
|
|
||||||
pwd/.wpscan/cli_options.yml:
|
pwd/.wpscan/cli_options.yml:
|
||||||
```
|
|
||||||
|
```yml
|
||||||
proxy: 'socks5://127.0.0.1:9090'
|
proxy: 'socks5://127.0.0.1:9090'
|
||||||
url: 'http://target.tld'
|
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
|
||||||
|
|
||||||
|
```shell
|
||||||
|
wpscan --url https://target.tld/ --enumerate u
|
||||||
|
```
|
||||||
|
|
||||||
|
Enumerating a range of usernames
|
||||||
|
|
||||||
|
```shell
|
||||||
|
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 +122,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 +132,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 +153,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
|
||||||
|
|||||||
@@ -98,7 +98,7 @@ module WPScan
|
|||||||
[
|
[
|
||||||
OptFilePath.new(
|
OptFilePath.new(
|
||||||
['--timthumbs-list FILE-PATH', 'List of timthumbs\' location to use'],
|
['--timthumbs-list FILE-PATH', 'List of timthumbs\' location to use'],
|
||||||
exists: true, default: File.join(DB_DIR, 'timthumbs-v3.txt'), advanced: true
|
exists: true, default: DB_DIR.join('timthumbs-v3.txt').to_s, advanced: true
|
||||||
),
|
),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--timthumbs-detection MODE',
|
['--timthumbs-detection MODE',
|
||||||
@@ -113,7 +113,7 @@ module WPScan
|
|||||||
[
|
[
|
||||||
OptFilePath.new(
|
OptFilePath.new(
|
||||||
['--config-backups-list FILE-PATH', 'List of config backups\' filenames to use'],
|
['--config-backups-list FILE-PATH', 'List of config backups\' filenames to use'],
|
||||||
exists: true, default: File.join(DB_DIR, 'config_backups.txt'), advanced: true
|
exists: true, default: DB_DIR.join('config_backups.txt').to_s, advanced: true
|
||||||
),
|
),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--config-backups-detection MODE',
|
['--config-backups-detection MODE',
|
||||||
@@ -128,7 +128,7 @@ module WPScan
|
|||||||
[
|
[
|
||||||
OptFilePath.new(
|
OptFilePath.new(
|
||||||
['--db-exports-list FILE-PATH', 'List of DB exports\' paths to use'],
|
['--db-exports-list FILE-PATH', 'List of DB exports\' paths to use'],
|
||||||
exists: true, default: File.join(DB_DIR, 'db_exports.txt'), advanced: true
|
exists: true, default: DB_DIR.join('db_exports.txt').to_s, advanced: true
|
||||||
),
|
),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--db-exports-detection MODE',
|
['--db-exports-detection MODE',
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
@@ -65,8 +65,12 @@ module WPScan
|
|||||||
when :wp_login
|
when :wp_login
|
||||||
WPScan::Finders::Passwords::WpLogin.new(target)
|
WPScan::Finders::Passwords::WpLogin.new(target)
|
||||||
when :xmlrpc
|
when :xmlrpc
|
||||||
|
raise XMLRPCNotDetected unless xmlrpc
|
||||||
|
|
||||||
WPScan::Finders::Passwords::XMLRPC.new(xmlrpc)
|
WPScan::Finders::Passwords::XMLRPC.new(xmlrpc)
|
||||||
when :xmlrpc_multicall
|
when :xmlrpc_multicall
|
||||||
|
raise XMLRPCNotDetected unless xmlrpc
|
||||||
|
|
||||||
WPScan::Finders::Passwords::XMLRPCMulticall.new(xmlrpc)
|
WPScan::Finders::Passwords::XMLRPCMulticall.new(xmlrpc)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
require_relative 'interesting_findings/readme'
|
require_relative 'interesting_findings/readme'
|
||||||
|
require_relative 'interesting_findings/wp_cron'
|
||||||
require_relative 'interesting_findings/multisite'
|
require_relative 'interesting_findings/multisite'
|
||||||
require_relative 'interesting_findings/debug_log'
|
require_relative 'interesting_findings/debug_log'
|
||||||
require_relative 'interesting_findings/backup_db'
|
require_relative 'interesting_findings/backup_db'
|
||||||
@@ -23,7 +24,7 @@ module WPScan
|
|||||||
%w[
|
%w[
|
||||||
Readme DebugLog FullPathDisclosure BackupDB DuplicatorInstallerLog
|
Readme DebugLog FullPathDisclosure BackupDB DuplicatorInstallerLog
|
||||||
Multisite MuPlugins Registration UploadDirectoryListing TmmDbMigrate
|
Multisite MuPlugins Registration UploadDirectoryListing TmmDbMigrate
|
||||||
UploadSQLDump EmergencyPwdResetScript
|
UploadSQLDump EmergencyPwdResetScript WPCron
|
||||||
].each do |f|
|
].each do |f|
|
||||||
finders << InterestingFindings.const_get(f).new(target)
|
finders << InterestingFindings.const_get(f).new(target)
|
||||||
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
|
||||||
|
|||||||
31
app/finders/interesting_findings/wp_cron.rb
Normal file
31
app/finders/interesting_findings/wp_cron.rb
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
module WPScan
|
||||||
|
module Finders
|
||||||
|
module InterestingFindings
|
||||||
|
# wp-cron.php finder
|
||||||
|
class WPCron < CMSScanner::Finders::Finder
|
||||||
|
# @return [ InterestingFinding ]
|
||||||
|
def aggressive(_opts = {})
|
||||||
|
res = Browser.get(wp_cron_url)
|
||||||
|
|
||||||
|
return unless res.code == 200
|
||||||
|
|
||||||
|
WPScan::WPCron.new(
|
||||||
|
wp_cron_url,
|
||||||
|
confidence: 60,
|
||||||
|
found_by: DIRECT_ACCESS,
|
||||||
|
references: {
|
||||||
|
url: [
|
||||||
|
'https://www.iplocation.net/defend-wordpress-from-ddos',
|
||||||
|
'https://github.com/wpscanteam/wpscan/issues/1299'
|
||||||
|
]
|
||||||
|
}
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def wp_cron_url
|
||||||
|
@wp_cron_url ||= target.url('wp-cron.php')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -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,46 @@ 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
|
||||||
|
|
||||||
|
class WPCron < 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'
|
||||||
@@ -35,7 +33,7 @@ module WPScan
|
|||||||
include CMSScanner
|
include CMSScanner
|
||||||
|
|
||||||
APP_DIR = Pathname.new(__FILE__).dirname.join('..', 'app').expand_path
|
APP_DIR = Pathname.new(__FILE__).dirname.join('..', 'app').expand_path
|
||||||
DB_DIR = File.join(Dir.home, '.wpscan', 'db')
|
DB_DIR = Pathname.new(Dir.home).join('.wpscan', 'db')
|
||||||
|
|
||||||
# Override, otherwise it would be returned as 'wp_scan'
|
# Override, otherwise it would be returned as 'wp_scan'
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ module WPScan
|
|||||||
|
|
||||||
# @return [ String ] The path to the user agents list
|
# @return [ String ] The path to the user agents list
|
||||||
def user_agents_list
|
def user_agents_list
|
||||||
@user_agents_list ||= File.join(DB_DIR, 'user-agents.txt')
|
@user_agents_list ||= DB_DIR.join('user-agents.txt').to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [ String ]
|
# @return [ String ]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module WPScan
|
|||||||
class Base
|
class Base
|
||||||
# @return [ String ]
|
# @return [ String ]
|
||||||
def self.db_file
|
def self.db_file
|
||||||
@db_file ||= File.join(DB_DIR, 'dynamic_finders.yml')
|
@db_file ||= DB_DIR.join('dynamic_finders.yml').to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [ Hash ]
|
# @return [ Hash ]
|
||||||
|
|||||||
@@ -33,7 +33,7 @@ module WPScan
|
|||||||
|
|
||||||
# @return [ String ]
|
# @return [ String ]
|
||||||
def self.wp_fingerprints_path
|
def self.wp_fingerprints_path
|
||||||
@wp_fingerprints_path ||= File.join(DB_DIR, 'wp_fingerprints.json')
|
@wp_fingerprints_path ||= DB_DIR.join('wp_fingerprints.json').to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [ Hash ]
|
# @return [ Hash ]
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module WPScan
|
|||||||
class Plugin < WpItem
|
class Plugin < WpItem
|
||||||
# @return [ String ]
|
# @return [ String ]
|
||||||
def self.db_file
|
def self.db_file
|
||||||
@db_file ||= File.join(DB_DIR, 'plugins.json')
|
@db_file ||= DB_DIR.join('plugins.json').to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module WPScan
|
|||||||
class Theme < WpItem
|
class Theme < WpItem
|
||||||
# @return [ String ]
|
# @return [ String ]
|
||||||
def self.db_file
|
def self.db_file
|
||||||
@db_file ||= File.join(DB_DIR, 'themes.json')
|
@db_file ||= DB_DIR.join('themes.json').to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ module WPScan
|
|||||||
attr_reader :repo_directory
|
attr_reader :repo_directory
|
||||||
|
|
||||||
def initialize(repo_directory)
|
def initialize(repo_directory)
|
||||||
@repo_directory = repo_directory
|
@repo_directory = Pathname.new(repo_directory).expand_path
|
||||||
|
|
||||||
FileUtils.mkdir_p(repo_directory) unless Dir.exist?(repo_directory)
|
FileUtils.mkdir_p(repo_directory.to_s) unless Dir.exist?(repo_directory.to_s)
|
||||||
|
|
||||||
raise "#{repo_directory} is not writable" unless Pathname.new(repo_directory).writable?
|
raise "#{repo_directory} is not writable" unless repo_directory.writable?
|
||||||
|
|
||||||
delete_old_files
|
delete_old_files
|
||||||
end
|
end
|
||||||
@@ -41,7 +41,7 @@ module WPScan
|
|||||||
|
|
||||||
# @return [ String ]
|
# @return [ String ]
|
||||||
def last_update_file
|
def last_update_file
|
||||||
@last_update_file ||= File.join(repo_directory, '.last_update')
|
@last_update_file ||= repo_directory.join('.last_update').to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
# @return [ Boolean ]
|
# @return [ Boolean ]
|
||||||
@@ -54,18 +54,17 @@ module WPScan
|
|||||||
# @return [ Boolean ]
|
# @return [ Boolean ]
|
||||||
def missing_files?
|
def missing_files?
|
||||||
FILES.each do |file|
|
FILES.each do |file|
|
||||||
return true unless File.exist?(File.join(repo_directory, file))
|
return true unless File.exist?(repo_directory.join(file))
|
||||||
end
|
end
|
||||||
false
|
false
|
||||||
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
|
||||||
}
|
}
|
||||||
@@ -86,16 +85,18 @@ module WPScan
|
|||||||
res.body.chomp
|
res.body.chomp
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @return [ String ]
|
||||||
def local_file_path(filename)
|
def local_file_path(filename)
|
||||||
File.join(repo_directory, filename.to_s)
|
repo_directory.join(filename.to_s).to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def local_file_checksum(filename)
|
def local_file_checksum(filename)
|
||||||
Digest::SHA512.file(local_file_path(filename)).hexdigest
|
Digest::SHA512.file(local_file_path(filename)).hexdigest
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @return [ String ]
|
||||||
def backup_file_path(filename)
|
def backup_file_path(filename)
|
||||||
File.join(repo_directory, "#{filename}.back")
|
repo_directory.join("#{filename}.back").to_s
|
||||||
end
|
end
|
||||||
|
|
||||||
def create_backup(filename)
|
def create_backup(filename)
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module WPScan
|
|||||||
class Version < WpItem
|
class Version < WpItem
|
||||||
# @return [ String ]
|
# @return [ String ]
|
||||||
def self.db_file
|
def self.db_file
|
||||||
@db_file ||= File.join(DB_DIR, 'wordpresses.json')
|
@db_file ||= DB_DIR.join('wordpresses.json').to_s
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
9
lib/wpscan/errors.rb
Normal file
9
lib/wpscan/errors.rb
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
module WPScan
|
||||||
|
class Error < StandardError
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
require_relative 'errors/http'
|
||||||
|
require_relative 'errors/update'
|
||||||
|
require_relative 'errors/wordpress'
|
||||||
|
require_relative 'errors/xmlrpc'
|
||||||
@@ -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
|
||||||
|
|||||||
8
lib/wpscan/errors/xmlrpc.rb
Normal file
8
lib/wpscan/errors/xmlrpc.rb
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module WPScan
|
||||||
|
# XML-RPC Not Detected
|
||||||
|
class XMLRPCNotDetected < Error
|
||||||
|
def to_s
|
||||||
|
'The XML-RPC Interface was not detected.'
|
||||||
|
end
|
||||||
|
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.5'.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/' }
|
||||||
@@ -68,6 +66,29 @@ describe WPScan::Controller::PasswordAttack do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when xmlrpc' do
|
context 'when xmlrpc' do
|
||||||
|
context 'when xmlrpc not detected on target' do
|
||||||
|
before do
|
||||||
|
expect(controller.target).to receive(:xmlrpc).and_return(nil)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when single xmlrpc' do
|
||||||
|
let(:attack) { 'xmlrpc' }
|
||||||
|
|
||||||
|
it 'raises an error' do
|
||||||
|
expect { controller.attacker }.to raise_error(WPScan::XMLRPCNotDetected)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when xmlrpc-multicall' do
|
||||||
|
let(:attack) { 'xmlrpc-multicall' }
|
||||||
|
|
||||||
|
it 'raises an error' do
|
||||||
|
expect { controller.attacker }.to raise_error(WPScan::XMLRPCNotDetected)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when xmlrpc detected on target' do
|
||||||
before do
|
before do
|
||||||
expect(controller.target).to receive(:xmlrpc).and_return(WPScan::XMLRPC.new("#{target_url}/xmlrpc.php"))
|
expect(controller.target).to receive(:xmlrpc).and_return(WPScan::XMLRPC.new("#{target_url}/xmlrpc.php"))
|
||||||
end
|
end
|
||||||
@@ -91,6 +112,7 @@ describe WPScan::Controller::PasswordAttack do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
context 'when automatic detection' do
|
context 'when automatic detection' do
|
||||||
before { expect(controller.target).to receive(:xmlrpc).and_return(xmlrpc) }
|
before { expect(controller.target).to receive(:xmlrpc).and_return(xmlrpc) }
|
||||||
|
|||||||
@@ -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,11 +1,9 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'config_backups') }
|
let(:fixtures) { FINDERS_FIXTURES.join('config_backups') }
|
||||||
let(:opts) { { list: File.join(WPScan::DB_DIR, 'config_backups.txt') } }
|
let(:opts) { { list: WPScan::DB_DIR.join('config_backups.txt').to_s } }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
before do
|
before do
|
||||||
@@ -25,7 +23,7 @@ describe WPScan::Finders::ConfigBackups::KnownFilenames do
|
|||||||
|
|
||||||
context 'when some files exist' do
|
context 'when some files exist' do
|
||||||
let(:files) { ['%23wp-config.php%23', 'wp-config.bak'] }
|
let(:files) { ['%23wp-config.php%23', 'wp-config.bak'] }
|
||||||
let(:config_backup) { File.read(File.join(fixtures, 'wp-config.php')) }
|
let(:config_backup) { File.read(fixtures.join('wp-config.php')) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
files.each do |file|
|
files.each do |file|
|
||||||
|
|||||||
@@ -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,11 +1,9 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/aa/' }
|
let(:url) { 'http://ex.lo/aa/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'db_exports') }
|
let(:fixtures) { FINDERS_FIXTURES.join('db_exports') }
|
||||||
let(:opts) { { list: File.join(WPScan::DB_DIR, 'db_exports.txt') } }
|
let(:opts) { { list: WPScan::DB_DIR.join('db_exports.txt').to_s } }
|
||||||
|
|
||||||
describe '#potential_urls' do
|
describe '#potential_urls' do
|
||||||
before do
|
before do
|
||||||
@@ -42,7 +40,7 @@ describe WPScan::Finders::DbExports::KnownLocations do
|
|||||||
|
|
||||||
context 'when some files exist' do
|
context 'when some files exist' do
|
||||||
let(:files) { %w[ex.sql backups/db_backup.sql] }
|
let(:files) { %w[ex.sql backups/db_backup.sql] }
|
||||||
let(:db_export) { File.read(File.join(fixtures, 'dump.sql')) }
|
let(:db_export) { File.read(fixtures.join('dump.sql')) }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
files.each do |file|
|
files.each do |file|
|
||||||
|
|||||||
@@ -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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'backup_db') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'backup_db') }
|
||||||
let(:wp_content) { 'wp-content' }
|
let(:wp_content) { 'wp-content' }
|
||||||
let(:dir_url) { target.url("#{wp_content}/backup-db/") }
|
let(:dir_url) { target.url("#{wp_content}/backup-db/") }
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -53,7 +51,7 @@ describe WPScan::Finders::InterestingFindings::BackupDB do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when directory listing enabled' do
|
context 'when directory listing enabled' do
|
||||||
let(:body) { File.read(File.join(fixtures, 'dir_listing.html')) }
|
let(:body) { File.read(fixtures.join('dir_listing.html')) }
|
||||||
|
|
||||||
it 'returns the expected interesting_findings attribute' do
|
it 'returns the expected interesting_findings attribute' do
|
||||||
@expected_entries = %w[sqldump.sql test.txt]
|
@expected_entries = %w[sqldump.sql test.txt]
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'debug_log') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'debug_log') }
|
||||||
let(:wp_content) { 'wp-content' }
|
let(:wp_content) { 'wp-content' }
|
||||||
let(:log_url) { target.url("#{wp_content}/debug.log") }
|
let(:log_url) { target.url("#{wp_content}/debug.log") }
|
||||||
|
|
||||||
@@ -20,10 +18,10 @@ describe WPScan::Finders::InterestingFindings::DebugLog do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when a log file' do
|
context 'when a log file' do
|
||||||
let(:body) { File.read(File.join(fixtures, 'debug.log')) }
|
let(:body) { File.read(fixtures.join('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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'duplicator_installer_log') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'duplicator_installer_log') }
|
||||||
let(:filename) { 'installer-log.txt' }
|
let(:filename) { 'installer-log.txt' }
|
||||||
let(:log_url) { target.url(filename) }
|
let(:log_url) { target.url(filename) }
|
||||||
|
|
||||||
@@ -21,10 +19,10 @@ describe WPScan::Finders::InterestingFindings::DuplicatorInstallerLog do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when the body matches' do
|
context 'when the body matches' do
|
||||||
let(:body) { File.read(File.join(fixtures, filename)) }
|
let(:body) { File.read(fixtures.join(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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'emergency_pwd_reset_script') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'emergency_pwd_reset_script') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'fpd') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'fpd') }
|
||||||
let(:file_url) { target.url('wp-includes/rss-functions.php') }
|
let(:file_url) { target.url('wp-includes/rss-functions.php') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
@@ -20,12 +18,12 @@ describe WPScan::Finders::InterestingFindings::FullPathDisclosure do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when a log file' do
|
context 'when a log file' do
|
||||||
let(:body) { File.read(File.join(fixtures, 'rss_functions.php')) }
|
let(:body) { File.read(fixtures.join('rss_functions.php')) }
|
||||||
|
|
||||||
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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'mu_plugins') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'mu_plugins') }
|
||||||
|
|
||||||
describe '#passive' do
|
describe '#passive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'multisite') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'multisite') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'readme') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'readme') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
before do
|
before do
|
||||||
@@ -22,12 +20,12 @@ describe WPScan::Finders::InterestingFindings::Readme do
|
|||||||
# TODO: case when multiple files are present ? (should return only the first one found)
|
# TODO: case when multiple files are present ? (should return only the first one found)
|
||||||
context 'when a file exists' do
|
context 'when a file exists' do
|
||||||
let(:file) { finder.potential_files.sample }
|
let(:file) { finder.potential_files.sample }
|
||||||
let(:readme) { File.read(File.join(fixtures, 'readme-3.9.2.html')) }
|
let(:readme) { File.read(fixtures.join('readme-3.9.2.html')) }
|
||||||
|
|
||||||
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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'registration') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'registration') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'tmm_db_migrate') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'tmm_db_migrate') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'upload_directory_listing') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'upload_directory_listing') }
|
||||||
let(:wp_content) { 'wp-content' }
|
let(:wp_content) { 'wp-content' }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'interesting_findings', 'upload_sql_dump') }
|
let(:fixtures) { FINDERS_FIXTURES.join('interesting_findings', 'upload_sql_dump') }
|
||||||
let(:wp_content) { 'wp-content' }
|
let(:wp_content) { 'wp-content' }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
@@ -23,7 +21,7 @@ describe WPScan::Finders::InterestingFindings::UploadSQLDump do
|
|||||||
context 'when a 200' do
|
context 'when a 200' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, finder.dump_url)
|
stub_request(:get, finder.dump_url)
|
||||||
.to_return(status: 200, body: File.read(File.join(fixtures, fixture)))
|
.to_return(status: 200, body: File.read(fixtures.join(fixture)))
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when the body does not match a SQL dump' do
|
context 'when the body does not match a SQL dump' do
|
||||||
@@ -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
|
||||||
|
|||||||
30
spec/app/finders/interesting_findings/wp_cron_spec.rb
Normal file
30
spec/app/finders/interesting_findings/wp_cron_spec.rb
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
describe WPScan::Finders::InterestingFindings::WPCron do
|
||||||
|
subject(:finder) { described_class.new(target) }
|
||||||
|
let(:target) { WPScan::Target.new(url) }
|
||||||
|
let(:url) { 'http://ex.lo/' }
|
||||||
|
let(:wp_content) { 'wp-content' }
|
||||||
|
|
||||||
|
before { expect(target).to receive(:sub_dir).at_least(1).and_return(false) }
|
||||||
|
|
||||||
|
describe '#aggressive' do
|
||||||
|
before { stub_request(:get, finder.wp_cron_url).to_return(status: status) }
|
||||||
|
|
||||||
|
context 'when 200' do
|
||||||
|
let(:status) { 200 }
|
||||||
|
|
||||||
|
it 'returns the InterestingFinding' do
|
||||||
|
expect(finder.aggressive).to eql WPScan::WPCron.new(
|
||||||
|
finder.wp_cron_url,
|
||||||
|
confidence: 60,
|
||||||
|
found_by: described_class::DIRECT_ACCESS
|
||||||
|
)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'otherwise' do
|
||||||
|
let(:status) { 403 }
|
||||||
|
|
||||||
|
its(:aggressive) { should be_nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
@@ -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,14 +1,12 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://wp.lab/' }
|
let(:url) { 'http://wp.lab/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'main_theme', 'css_style') }
|
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'css_style') }
|
||||||
|
|
||||||
describe '#passive' do
|
describe '#passive' do
|
||||||
after do
|
after do
|
||||||
stub_request(:get, url).to_return(body: File.read(File.join(fixtures, fixture)))
|
stub_request(:get, url).to_return(body: File.read(fixtures.join(fixture)))
|
||||||
expect(finder.passive).to eql @expected
|
expect(finder.passive).to eql @expected
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://wp.lab/' }
|
let(:url) { 'http://wp.lab/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'main_theme', 'urls_in_homepage') }
|
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'urls_in_homepage') }
|
||||||
|
|
||||||
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
||||||
let(:type) { 'themes' }
|
let(:type) { 'themes' }
|
||||||
@@ -17,7 +15,7 @@ describe WPScan::Finders::MainTheme::UrlsInHomepage do
|
|||||||
describe '#passive' do
|
describe '#passive' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, /.*.css/)
|
stub_request(:get, /.*.css/)
|
||||||
stub_request(:get, target.url).to_return(body: File.read(File.join(fixtures, 'found.html')))
|
stub_request(:get, target.url).to_return(body: File.read(fixtures.join('found.html')))
|
||||||
end
|
end
|
||||||
|
|
||||||
it 'returns the expected Themes' do
|
it 'returns the expected Themes' do
|
||||||
|
|||||||
@@ -1,14 +1,12 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://wp.lab/' }
|
let(:url) { 'http://wp.lab/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'main_theme', 'woo_framework_meta_generator') }
|
let(:fixtures) { FINDERS_FIXTURES.join('main_theme', 'woo_framework_meta_generator') }
|
||||||
|
|
||||||
describe '#passive' do
|
describe '#passive' do
|
||||||
after do
|
after do
|
||||||
stub_request(:get, url).to_return(body: File.read(File.join(fixtures, @file)))
|
stub_request(:get, url).to_return(body: File.read(fixtures.join(@file)))
|
||||||
|
|
||||||
expect(finder.passive).to eql @expected
|
expect(finder.passive).to eql @expected
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'medias', 'attachment_brute_forcing') }
|
let(:fixtures) { FINDERS_FIXTURES.join('medias', 'attachment_brute_forcing') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:target) { WPScan::Target.new('http://wp.lab/') }
|
let(:target) { WPScan::Target.new('http://wp.lab/') }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'plugin_version', 'readme') }
|
let(:fixtures) { FINDERS_FIXTURES.join('plugin_version', 'readme') }
|
||||||
|
|
||||||
def version(number, found_by, confidence)
|
def version(number, found_by, confidence)
|
||||||
WPScan::Version.new(
|
WPScan::Version.new(
|
||||||
@@ -28,7 +26,7 @@ describe WPScan::Finders::PluginVersion::Readme do
|
|||||||
|
|
||||||
after do
|
after do
|
||||||
stub_request(:get, /.*/).to_return(status: 404)
|
stub_request(:get, /.*/).to_return(status: 404)
|
||||||
stub_request(:get, readme_url).to_return(body: File.read(File.join(fixtures, @file)))
|
stub_request(:get, readme_url).to_return(body: File.read(fixtures.join(@file)))
|
||||||
|
|
||||||
expect(finder.aggressive).to eql @expected
|
expect(finder.aggressive).to eql @expected
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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,11 +1,9 @@
|
|||||||
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) }
|
||||||
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(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
|
let(:fixtures) { DYNAMIC_FINDERS_FIXTURES.join('plugin_version') }
|
||||||
|
|
||||||
let(:expected_all) { df_expected_all['plugins'] }
|
let(:expected_all) { df_expected_all['plugins'] }
|
||||||
let(:item_class) { WPScan::Plugin }
|
let(:item_class) { WPScan::Plugin }
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
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) }
|
||||||
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(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
|
let(:fixtures) { DYNAMIC_FINDERS_FIXTURES.join('plugin_version') }
|
||||||
|
|
||||||
let(:expected_all) { df_expected_all['plugins'] }
|
let(:expected_all) { df_expected_all['plugins'] }
|
||||||
let(:item_class) { WPScan::Plugin }
|
let(:item_class) { WPScan::Plugin }
|
||||||
|
|||||||
@@ -1,5 +1,3 @@
|
|||||||
require 'spec_helper'
|
|
||||||
|
|
||||||
describe WPScan::Finders::Plugins::ConfigParser do
|
describe WPScan::Finders::Plugins::ConfigParser do
|
||||||
xit
|
xit
|
||||||
|
|
||||||
@@ -7,7 +5,7 @@ describe WPScan::Finders::Plugins::ConfigParser 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(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
|
# let(:fixtures) { DYNAMIC_FINDERS_FIXTURES.join('plugin_version') }
|
||||||
#
|
#
|
||||||
# let(:expected_all) { df_expected_all['plugins'] }
|
# let(:expected_all) { df_expected_all['plugins'] }
|
||||||
# let(:item_class) { WPScan::Plugin }
|
# let(:item_class) { WPScan::Plugin }
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://wp.lab/' }
|
let(:url) { 'http://wp.lab/' }
|
||||||
let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
|
let(:fixtures) { DYNAMIC_FINDERS_FIXTURES.join('plugin_version') }
|
||||||
|
|
||||||
def plugin(slug)
|
def plugin(slug)
|
||||||
WPScan::Plugin.new(slug, target)
|
WPScan::Plugin.new(slug, target)
|
||||||
@@ -31,7 +29,7 @@ describe WPScan::Finders::Plugins::HeaderPattern do
|
|||||||
context 'when headers' do
|
context 'when headers' do
|
||||||
before { expect(target).to receive(:content_dir).and_return('wp-content') }
|
before { expect(target).to receive(:content_dir).and_return('wp-content') }
|
||||||
|
|
||||||
let(:headers) { JSON.parse(File.read(File.join(fixtures, 'header_pattern_passive_all.html'))) }
|
let(:headers) { JSON.parse(File.read(fixtures.join('header_pattern_passive_all.html'))) }
|
||||||
|
|
||||||
it 'returns the expected plugins' do
|
it 'returns the expected plugins' do
|
||||||
@expected = []
|
@expected = []
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
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) }
|
||||||
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(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
|
let(:fixtures) { DYNAMIC_FINDERS_FIXTURES.join('plugin_version') }
|
||||||
|
|
||||||
let(:expected_all) { df_expected_all['plugins'] }
|
let(:expected_all) { df_expected_all['plugins'] }
|
||||||
let(:item_class) { WPScan::Plugin }
|
let(:item_class) { WPScan::Plugin }
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'plugins', 'known_locations') }
|
let(:fixtures) { FINDERS_FIXTURES.join('plugins', 'known_locations') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://wp.lab/' }
|
let(:url) { 'http://wp.lab/' }
|
||||||
let(:fixtures) { File.join(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
|
let(:fixtures) { DYNAMIC_FINDERS_FIXTURES.join('plugin_version') }
|
||||||
|
|
||||||
describe '#passive' do
|
describe '#passive' do
|
||||||
its(:passive) { should be nil }
|
its(:passive) { should be nil }
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://wp.lab/' }
|
let(:url) { 'http://wp.lab/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'plugins', 'urls_in_homepage') }
|
let(:fixtures) { FINDERS_FIXTURES.join('plugins', 'urls_in_homepage') }
|
||||||
|
|
||||||
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
||||||
let(:type) { 'plugins' }
|
let(:type) { 'plugins' }
|
||||||
@@ -17,7 +15,7 @@ describe WPScan::Finders::Plugins::UrlsInHomepage do
|
|||||||
describe '#passive' do
|
describe '#passive' do
|
||||||
before do
|
before do
|
||||||
stub_request(:get, finder.target.url)
|
stub_request(:get, finder.target.url)
|
||||||
.to_return(body: File.read(File.join(fixtures, 'found.html')))
|
.to_return(body: File.read(fixtures.join('found.html')))
|
||||||
|
|
||||||
expect(finder.target).to receive(:content_dir).at_least(1).and_return('wp-content')
|
expect(finder.target).to receive(:content_dir).at_least(1).and_return('wp-content')
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,11 +1,9 @@
|
|||||||
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) }
|
||||||
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(DYNAMIC_FINDERS_FIXTURES, 'plugin_version') }
|
let(:fixtures) { DYNAMIC_FINDERS_FIXTURES.join('plugin_version') }
|
||||||
|
|
||||||
let(:expected_all) { df_expected_all['plugins'] }
|
let(:expected_all) { df_expected_all['plugins'] }
|
||||||
let(:item_class) { WPScan::Plugin }
|
let(:item_class) { WPScan::Plugin }
|
||||||
|
|||||||
@@ -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,13 +1,11 @@
|
|||||||
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) }
|
||||||
let(:target) { WPScan::Target.new('http://wp.lab/') }
|
let(:target) { WPScan::Target.new('http://wp.lab/') }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'theme_version', 'style') }
|
let(:fixtures) { FINDERS_FIXTURES.join('theme_version', 'style') }
|
||||||
|
|
||||||
before :all do
|
before :all do
|
||||||
Typhoeus::Config.cache = WPScan::Cache::Typhoeus.new(File.join(SPECS, 'cache'))
|
Typhoeus::Config.cache = WPScan::Cache::Typhoeus.new(SPECS.join('cache'))
|
||||||
end
|
end
|
||||||
|
|
||||||
before do
|
before do
|
||||||
@@ -79,7 +77,7 @@ describe WPScan::Finders::ThemeVersion::Style do
|
|||||||
'no_version' => nil
|
'no_version' => nil
|
||||||
}.each do |file, expected_version|
|
}.each do |file, expected_version|
|
||||||
context "when #{file}" do
|
context "when #{file}" do
|
||||||
let(:style_body) { File.new(File.join(fixtures, "#{file}.css")) }
|
let(:style_body) { File.new(fixtures.join("#{file}.css")) }
|
||||||
|
|
||||||
it 'returns the expected version' do
|
it 'returns the expected version' do
|
||||||
expected = if expected_version
|
expected = if expected_version
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:target) { WPScan::Target.new('http://wp.lab/') }
|
let(:target) { WPScan::Target.new('http://wp.lab/') }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'theme_version', 'woo_framework_meta_generator') }
|
let(:fixtures) { FINDERS_FIXTURES.join('theme_version', 'woo_framework_meta_generator') }
|
||||||
|
|
||||||
before do
|
before do
|
||||||
expect(target).to receive(:content_dir).and_return('wp-content')
|
expect(target).to receive(:content_dir).and_return('wp-content')
|
||||||
@@ -13,7 +11,7 @@ describe WPScan::Finders::ThemeVersion::WooFrameworkMetaGenerator do
|
|||||||
|
|
||||||
describe '#passive' do
|
describe '#passive' do
|
||||||
after do
|
after do
|
||||||
stub_request(:get, target.url).to_return(body: File.read(File.join(fixtures, 'editorial-1.3.5.html')))
|
stub_request(:get, target.url).to_return(body: File.read(fixtures.join('editorial-1.3.5.html')))
|
||||||
|
|
||||||
expect(finder.passive).to eql @expected
|
expect(finder.passive).to eql @expected
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'themes', 'known_locations') }
|
let(:fixtures) { FINDERS_FIXTURES.join('themes', 'known_locations') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -1,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://wp.lab/' }
|
let(:url) { 'http://wp.lab/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'themes', 'urls_in_homepage') }
|
let(:fixtures) { FINDERS_FIXTURES.join('themes', 'urls_in_homepage') }
|
||||||
|
|
||||||
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
it_behaves_like 'App::Finders::WpItems::URLsInHomepage' do
|
||||||
let(:type) { 'themes' }
|
let(:type) { 'themes' }
|
||||||
|
|||||||
@@ -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,13 +1,11 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/timthumb.php' }
|
let(:url) { 'http://ex.lo/timthumb.php' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'timthumb_version', 'bad_request') }
|
let(:fixtures) { FINDERS_FIXTURES.join('timthumb_version', 'bad_request') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
before { stub_request(:get, url).to_return(body: File.read(File.join(fixtures, file))) }
|
before { stub_request(:get, url).to_return(body: File.read(fixtures.join(file))) }
|
||||||
after { expect(finder.aggressive).to eql @expected }
|
after { expect(finder.aggressive).to eql @expected }
|
||||||
|
|
||||||
context 'when no version' do
|
context 'when no version' do
|
||||||
|
|||||||
@@ -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,10 +1,8 @@
|
|||||||
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) }
|
||||||
let(:url) { 'http://ex.lo/' }
|
let(:url) { 'http://ex.lo/' }
|
||||||
let(:fixtures) { File.join(FINDERS_FIXTURES, 'timthumbs', 'known_locations') }
|
let(:fixtures) { FINDERS_FIXTURES.join('timthumbs', 'known_locations') }
|
||||||
|
|
||||||
describe '#aggressive' do
|
describe '#aggressive' do
|
||||||
xit
|
xit
|
||||||
|
|||||||
@@ -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) }
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user