Compare commits
111 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 | ||
|
|
41cca5fb8a | ||
|
|
498da1a06b | ||
|
|
48dab90313 | ||
|
|
d1ff642957 | ||
|
|
2b5613d84a | ||
|
|
09d28fae26 | ||
|
|
7517e247d9 | ||
|
|
998951e629 | ||
|
|
d89fcbb68a | ||
|
|
d3e0ff1e66 | ||
|
|
804a8c34c6 | ||
|
|
57942e1826 | ||
|
|
5657735b55 | ||
|
|
791fce2424 | ||
|
|
c34fa45875 | ||
|
|
e0fd79f800 | ||
|
|
f9d9cda4a4 | ||
|
|
d6f44b2f42 | ||
|
|
bd90da7ed2 | ||
|
|
3a1a976e35 | ||
|
|
db1309af83 | ||
|
|
0e47441a36 | ||
|
|
375bea9a8b | ||
|
|
3a42772879 | ||
|
|
e9956593dc | ||
|
|
fda6000c4c | ||
|
|
99b4eb969d | ||
|
|
dadd55ba32 | ||
|
|
b40e06b2ea | ||
|
|
3f20edc41f | ||
|
|
baaa11bb64 | ||
|
|
44e1179ce4 | ||
|
|
808521fb70 | ||
|
|
ad8e97f432 |
@@ -8,6 +8,7 @@ spec/
|
|||||||
.*
|
.*
|
||||||
**/*.md
|
**/*.md
|
||||||
*.md
|
*.md
|
||||||
|
!README.md
|
||||||
Dockerfile
|
Dockerfile
|
||||||
**/*.orig
|
**/*.orig
|
||||||
*.orig
|
*.orig
|
||||||
|
|||||||
9
.gitignore
vendored
9
.gitignore
vendored
@@ -12,3 +12,12 @@ Gemfile.lock
|
|||||||
_yardoc
|
_yardoc
|
||||||
doc/
|
doc/
|
||||||
.wpscan/
|
.wpscan/
|
||||||
|
|
||||||
|
.ash_history
|
||||||
|
.DS_Store
|
||||||
|
.DS_Store?
|
||||||
|
.idea/
|
||||||
|
|
||||||
|
# Old files from v2
|
||||||
|
cache/
|
||||||
|
data/
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
2.5.0
|
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
|
||||||
@@ -10,16 +10,21 @@ rvm:
|
|||||||
- 2.3.5
|
- 2.3.5
|
||||||
- 2.3.6
|
- 2.3.6
|
||||||
- 2.3.7
|
- 2.3.7
|
||||||
|
- 2.3.8
|
||||||
- 2.4.1
|
- 2.4.1
|
||||||
- 2.4.2
|
- 2.4.2
|
||||||
- 2.4.3
|
- 2.4.3
|
||||||
- 2.4.4
|
- 2.4.4
|
||||||
|
- 2.4.5
|
||||||
- 2.5.0
|
- 2.5.0
|
||||||
- 2.5.1
|
- 2.5.1
|
||||||
|
- 2.5.2
|
||||||
|
- 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
|
||||||
|
|||||||
33
Dockerfile
33
Dockerfile
@@ -1,27 +1,38 @@
|
|||||||
FROM ruby:2.5-alpine
|
FROM ruby:2.5.1-alpine AS builder
|
||||||
MAINTAINER WPScan Team <team@wpscan.org>
|
LABEL maintainer="WPScan Team <team@wpscan.org>"
|
||||||
|
|
||||||
ARG BUNDLER_ARGS="--jobs=8 --without test development"
|
ARG BUNDLER_ARGS="--jobs=8 --without test development"
|
||||||
|
|
||||||
RUN adduser -h /wpscan -g WPScan -D wpscan
|
|
||||||
RUN echo "gem: --no-ri --no-rdoc" > /etc/gemrc
|
RUN echo "gem: --no-ri --no-rdoc" > /etc/gemrc
|
||||||
|
|
||||||
COPY . /wpscan
|
COPY . /wpscan
|
||||||
RUN chown -R wpscan:wpscan /wpscan
|
|
||||||
|
|
||||||
# runtime dependencies
|
RUN apk add --no-cache git libcurl ruby-dev libffi-dev make gcc musl-dev zlib-dev procps sqlite-dev && \
|
||||||
RUN apk add --no-cache libcurl procps sqlite-libs && \
|
bundle install --system --clean --no-cache --gemfile=/wpscan/Gemfile $BUNDLER_ARGS && \
|
||||||
# build dependencies
|
# temp fix for https://github.com/bundler/bundler/issues/6680
|
||||||
apk add --no-cache --virtual build-deps git libcurl ruby-dev libffi-dev make gcc musl-dev zlib-dev procps sqlite-dev && \
|
rm -rf /usr/local/bundle/cache
|
||||||
bundle install --system --gemfile=/wpscan/Gemfile $BUNDLER_ARGS && \
|
|
||||||
apk del --no-cache build-deps
|
|
||||||
|
|
||||||
WORKDIR /wpscan
|
WORKDIR /wpscan
|
||||||
RUN rake install --trace
|
RUN rake install --trace
|
||||||
|
|
||||||
|
# needed so non superusers can read gems
|
||||||
|
RUN chmod -R a+r /usr/local/bundle
|
||||||
|
|
||||||
|
|
||||||
|
FROM ruby:2.5-alpine
|
||||||
|
LABEL maintainer="WPScan Team <team@wpscan.org>"
|
||||||
|
|
||||||
|
RUN adduser -h /wpscan -g WPScan -D wpscan
|
||||||
|
|
||||||
|
COPY --from=builder /usr/local/bundle /usr/local/bundle
|
||||||
|
RUN chown -R wpscan:wpscan /wpscan
|
||||||
|
|
||||||
|
# runtime dependencies
|
||||||
|
RUN apk add --no-cache libcurl procps sqlite-libs
|
||||||
|
|
||||||
|
|
||||||
USER wpscan
|
USER wpscan
|
||||||
RUN /usr/local/bundle/bin/wpscan --update --verbose
|
RUN /usr/local/bundle/bin/wpscan --update --verbose
|
||||||
|
|
||||||
ENTRYPOINT ["/usr/local/bundle/bin/wpscan"]
|
ENTRYPOINT ["/usr/local/bundle/bin/wpscan"]
|
||||||
CMD ["--help"]
|
CMD ["--help"]
|
||||||
|
|
||||||
|
|||||||
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
|
||||||
|
|
||||||
|
|||||||
97
README.md
97
README.md
@@ -1,29 +1,34 @@
|
|||||||

|

|
||||||
|
|
||||||
[](https://badge.fury.io/rb/wpscan)
|
[](https://badge.fury.io/rb/wpscan)
|
||||||
[](https://travis-ci.org/wpscanteam/wpscan-v3)
|
[](https://travis-ci.org/wpscanteam/wpscan)
|
||||||
[](https://codeclimate.com/github/wpscanteam/wpscan)
|
[](https://codeclimate.com/github/wpscanteam/wpscan)
|
||||||
[](https://www.patreon.com/wpscan)
|
[](https://www.patreon.com/wpscan)
|
||||||
|
|
||||||
# INSTALL
|
# INSTALL
|
||||||
|
|
||||||
## Prerequisites:
|
## Prerequisites
|
||||||
|
|
||||||
- Ruby >= 2.2.2 - Recommended: 2.3.3
|
- (Optional but highly recommended: [RVM](https://rvm.io/rvm/install))
|
||||||
- Curl >= 7.21 - Recommended: latest - FYI the 7.29 has a segfault
|
- Ruby >= 2.3 - Recommended: latest
|
||||||
|
- 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
|
||||||
|
|
||||||
@@ -99,30 +140,28 @@ A commercial use is one intended for commercial advantage or monetary compensati
|
|||||||
|
|
||||||
Example cases of commercialization are:
|
Example cases of commercialization are:
|
||||||
|
|
||||||
- Using WPScan to provide commercial managed/Software-as-a-Service services.
|
- Using WPScan to provide commercial managed/Software-as-a-Service services.
|
||||||
- Distributing WPScan as a commercial product or as part of one.
|
- Distributing WPScan as a commercial product or as part of one.
|
||||||
- Using WPScan as a value added service/product.
|
- Using WPScan as a value added service/product.
|
||||||
|
|
||||||
Example cases which do not require a commercial license, and thus fall under the terms set out below, include (but are not limited to):
|
Example cases which do not require a commercial license, and thus fall under the terms set out below, include (but are not limited to):
|
||||||
|
|
||||||
- Penetration testers (or penetration testing organizations) using WPScan as part of their assessment toolkit.
|
- Penetration testers (or penetration testing organizations) using WPScan as part of their assessment toolkit.
|
||||||
- Penetration Testing Linux Distributions including but not limited to Kali Linux, SamuraiWTF, BackBox Linux.
|
- Penetration Testing Linux Distributions including but not limited to Kali Linux, SamuraiWTF, BackBox Linux.
|
||||||
- Using WPScan to test your own systems.
|
- Using WPScan to test your own systems.
|
||||||
- Any non-commercial use of WPScan.
|
- Any non-commercial use of WPScan.
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
Redistribution is permitted under the following conditions:
|
Redistribution is permitted under the following conditions:
|
||||||
|
|
||||||
- Unmodified License is provided with WPScan.
|
- Unmodified License is provided with WPScan.
|
||||||
- Unmodified Copyright notices are provided with WPScan.
|
- Unmodified Copyright notices are provided with WPScan.
|
||||||
- Does not conflict with the commercialization clause.
|
- Does not conflict with the commercialization clause.
|
||||||
|
|
||||||
### 4. Copying
|
### 4. Copying
|
||||||
|
|
||||||
|
|||||||
@@ -5,15 +5,15 @@ module WPScan
|
|||||||
# @return [ Array<OptParseValidator::Opt> ]
|
# @return [ Array<OptParseValidator::Opt> ]
|
||||||
def cli_options
|
def cli_options
|
||||||
[OptURL.new(['--url URL', 'The URL of the blog to scan'],
|
[OptURL.new(['--url URL', 'The URL of the blog to scan'],
|
||||||
required_unless: %i[update help version], default_protocol: 'http')] +
|
required_unless: %i[update help hh version], default_protocol: 'http')] +
|
||||||
super.drop(1) + # delete the --url from CMSScanner
|
super.drop(1) + # delete the --url from CMSScanner
|
||||||
[
|
[
|
||||||
OptChoice.new(['--server SERVER', 'Force the supplied server module to be loaded'],
|
OptChoice.new(['--server SERVER', 'Force the supplied server module to be loaded'],
|
||||||
choices: %w[apache iis nginx],
|
choices: %w[apache iis nginx],
|
||||||
normalize: %i[downcase to_sym]),
|
normalize: %i[downcase to_sym],
|
||||||
|
advanced: true),
|
||||||
OptBoolean.new(['--force', 'Do not check if the target is running WordPress']),
|
OptBoolean.new(['--force', 'Do not check if the target is running WordPress']),
|
||||||
OptBoolean.new(['--[no-]update', 'Wether or not to update the Database'],
|
OptBoolean.new(['--[no-]update', 'Whether or not to update the Database'])
|
||||||
required_unless: %i[url help version])
|
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -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
|
||||||
|
|||||||
@@ -13,19 +13,22 @@ module WPScan
|
|||||||
def cli_enum_choices
|
def cli_enum_choices
|
||||||
[
|
[
|
||||||
OptMultiChoices.new(
|
OptMultiChoices.new(
|
||||||
['--enumerate [OPTS]', '-e', 'Enumeration Process'],
|
['-e', '--enumerate [OPTS]', 'Enumeration Process'],
|
||||||
choices: {
|
choices: {
|
||||||
vp: OptBoolean.new(['--vulnerable-plugins']),
|
vp: OptBoolean.new(['--vulnerable-plugins']),
|
||||||
ap: OptBoolean.new(['--all-plugins']),
|
ap: OptBoolean.new(['--all-plugins']),
|
||||||
p: OptBoolean.new(['--plugins']),
|
p: OptBoolean.new(['--plugins']),
|
||||||
vt: OptBoolean.new(['--vulnerable-themes']),
|
vt: OptBoolean.new(['--vulnerable-themes']),
|
||||||
at: OptBoolean.new(['--all-themes']),
|
at: OptBoolean.new(['--all-themes']),
|
||||||
t: OptBoolean.new(['--themes']),
|
t: OptBoolean.new(['--themes']),
|
||||||
tt: OptBoolean.new(['--timthumbs']),
|
tt: OptBoolean.new(['--timthumbs']),
|
||||||
cb: OptBoolean.new(['--config-backups']),
|
cb: OptBoolean.new(['--config-backups']),
|
||||||
dbe: OptBoolean.new(['--db-exports']),
|
dbe: OptBoolean.new(['--db-exports']),
|
||||||
u: OptIntegerRange.new(['--users', 'User IDs range. e.g: u1-5'], value_if_empty: '1-10'),
|
u: OptIntegerRange.new(['--users', 'User IDs range. e.g: u1-5'], value_if_empty: '1-10'),
|
||||||
m: OptIntegerRange.new(['--medias', 'Media IDs range. e.g m1-15'], value_if_empty: '1-100')
|
m: OptIntegerRange.new(['--medias',
|
||||||
|
'Media IDs range. e.g m1-15',
|
||||||
|
'Note: Permalink setting must be set to "Plain" for those to be detected'],
|
||||||
|
value_if_empty: '1-100')
|
||||||
},
|
},
|
||||||
value_if_empty: 'vp,vt,tt,cb,dbe,u,m',
|
value_if_empty: 'vp,vt,tt,cb,dbe,u,m',
|
||||||
incompatible: [%i[vp ap p], %i[vt at t]],
|
incompatible: [%i[vp ap p], %i[vt at t]],
|
||||||
@@ -45,7 +48,7 @@ module WPScan
|
|||||||
# @return [ Array<OptParseValidator::OptBase> ]
|
# @return [ Array<OptParseValidator::OptBase> ]
|
||||||
def cli_plugins_opts
|
def cli_plugins_opts
|
||||||
[
|
[
|
||||||
OptSmartList.new(['--plugins-list LIST', 'List of plugins to enumerate']),
|
OptSmartList.new(['--plugins-list LIST', 'List of plugins to enumerate'], advanced: true),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--plugins-detection MODE',
|
['--plugins-detection MODE',
|
||||||
'Use the supplied mode to enumerate Plugins, instead of the global (--detection-mode) mode.'],
|
'Use the supplied mode to enumerate Plugins, instead of the global (--detection-mode) mode.'],
|
||||||
@@ -54,7 +57,8 @@ module WPScan
|
|||||||
OptBoolean.new(
|
OptBoolean.new(
|
||||||
['--plugins-version-all',
|
['--plugins-version-all',
|
||||||
'Check all the plugins version locations according to the choosen mode (--detection-mode, ' \
|
'Check all the plugins version locations according to the choosen mode (--detection-mode, ' \
|
||||||
'--plugins-detection and --plugins-version-detection)']
|
'--plugins-detection and --plugins-version-detection)'],
|
||||||
|
advanced: true
|
||||||
),
|
),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--plugins-version-detection MODE',
|
['--plugins-version-detection MODE',
|
||||||
@@ -68,22 +72,23 @@ module WPScan
|
|||||||
# @return [ Array<OptParseValidator::OptBase> ]
|
# @return [ Array<OptParseValidator::OptBase> ]
|
||||||
def cli_themes_opts
|
def cli_themes_opts
|
||||||
[
|
[
|
||||||
OptSmartList.new(['--themes-list LIST', 'List of themes to enumerate']),
|
OptSmartList.new(['--themes-list LIST', 'List of themes to enumerate'], advanced: true),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--themes-detection MODE',
|
['--themes-detection MODE',
|
||||||
'Use the supplied mode to enumerate Themes, instead of the global (--detection-mode) mode.'],
|
'Use the supplied mode to enumerate Themes, instead of the global (--detection-mode) mode.'],
|
||||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
),
|
),
|
||||||
OptBoolean.new(
|
OptBoolean.new(
|
||||||
['--themes-version-all',
|
['--themes-version-all',
|
||||||
'Check all the themes version locations according to the choosen mode (--detection-mode, ' \
|
'Check all the themes version locations according to the choosen mode (--detection-mode, ' \
|
||||||
'--themes-detection and --themes-version-detection)']
|
'--themes-detection and --themes-version-detection)'],
|
||||||
|
advanced: true
|
||||||
),
|
),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--themes-version-detection MODE',
|
['--themes-version-detection MODE',
|
||||||
'Use the supplied mode to check themes versions instead of the --detection-mode ' \
|
'Use the supplied mode to check themes versions instead of the --detection-mode ' \
|
||||||
'or --themes-detection modes.'],
|
'or --themes-detection modes.'],
|
||||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@@ -93,12 +98,12 @@ 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')
|
exists: true, default: DB_DIR.join('timthumbs-v3.txt').to_s, advanced: true
|
||||||
),
|
),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--timthumbs-detection MODE',
|
['--timthumbs-detection MODE',
|
||||||
'Use the supplied mode to enumerate Timthumbs, instead of the global (--detection-mode) mode.'],
|
'Use the supplied mode to enumerate Timthumbs, instead of the global (--detection-mode) mode.'],
|
||||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@@ -108,12 +113,12 @@ 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')
|
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',
|
||||||
'Use the supplied mode to enumerate Config Backups, instead of the global (--detection-mode) mode.'],
|
'Use the supplied mode to enumerate Config Backups, instead of the global (--detection-mode) mode.'],
|
||||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@@ -123,12 +128,12 @@ 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')
|
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',
|
||||||
'Use the supplied mode to enumerate DB Exports, instead of the global (--detection-mode) mode.'],
|
'Use the supplied mode to enumerate DB Exports, instead of the global (--detection-mode) mode.'],
|
||||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@@ -139,7 +144,7 @@ module WPScan
|
|||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--medias-detection MODE',
|
['--medias-detection MODE',
|
||||||
'Use the supplied mode to enumerate Medias, instead of the global (--detection-mode) mode.'],
|
'Use the supplied mode to enumerate Medias, instead of the global (--detection-mode) mode.'],
|
||||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
@@ -149,12 +154,13 @@ module WPScan
|
|||||||
[
|
[
|
||||||
OptSmartList.new(
|
OptSmartList.new(
|
||||||
['--users-list LIST',
|
['--users-list LIST',
|
||||||
'List of users to check during the users enumeration from the Login Error Messages']
|
'List of users to check during the users enumeration from the Login Error Messages'],
|
||||||
|
advanced: true
|
||||||
),
|
),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--users-detection MODE',
|
['--users-detection MODE',
|
||||||
'Use the supplied mode to enumerate Users, instead of the global (--detection-mode) mode.'],
|
'Use the supplied mode to enumerate Users, instead of the global (--detection-mode) mode.'],
|
||||||
choices: %w[mixed passive aggressive], normalize: :to_sym
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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,28 +145,33 @@ 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
|
||||||
|
|
||||||
def enum_medias
|
def enum_medias
|
||||||
opts = default_opts('medias').merge(range: parsed_options[:enumerate][:medias])
|
opts = default_opts('medias').merge(range: parsed_options[:enumerate][:medias])
|
||||||
|
|
||||||
output('@info', msg: 'Enumerating Medias') if user_interaction?
|
if user_interaction?
|
||||||
|
output('@info',
|
||||||
|
msg: "Enumerating Medias #{enum_detection_message(opts[:mode])} "\
|
||||||
|
'(Permalink setting must be set to "Plain" for those to be detected)')
|
||||||
|
end
|
||||||
|
|
||||||
output('medias', medias: target.medias(opts))
|
output('medias', medias: target.medias(opts))
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -163,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
|
||||||
|
|
||||||
|
|||||||
@@ -7,8 +7,7 @@ module WPScan
|
|||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--main-theme-detection MODE',
|
['--main-theme-detection MODE',
|
||||||
'Use the supplied mode for the Main theme detection, instead of the global (--detection-mode) mode.'],
|
'Use the supplied mode for the Main theme detection, instead of the global (--detection-mode) mode.'],
|
||||||
choices: %w[mixed passive aggressive],
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
normalize: :to_sym
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
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
|
||||||
|
|||||||
@@ -4,13 +4,12 @@ module WPScan
|
|||||||
class WpVersion < CMSScanner::Controller::Base
|
class WpVersion < CMSScanner::Controller::Base
|
||||||
def cli_options
|
def cli_options
|
||||||
[
|
[
|
||||||
OptBoolean.new(['--wp-version-all', 'Check all the version locations']),
|
OptBoolean.new(['--wp-version-all', 'Check all the version locations'], advanced: true),
|
||||||
OptChoice.new(
|
OptChoice.new(
|
||||||
['--wp-version-detection MODE',
|
['--wp-version-detection MODE',
|
||||||
'Use the supplied mode for the WordPress version detection, ' \
|
'Use the supplied mode for the WordPress version detection, ' \
|
||||||
'instead of the global (--detection-mode) mode.'],
|
'instead of the global (--detection-mode) mode.'],
|
||||||
choices: %w[mixed passive aggressive],
|
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
|
||||||
normalize: :to_sym
|
|
||||||
)
|
)
|
||||||
]
|
]
|
||||||
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
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
module WPScan
|
module WPScan
|
||||||
module Finders
|
module Finders
|
||||||
module Medias
|
module Medias
|
||||||
# Medias Finder
|
# Medias Finder, see https://github.com/wpscanteam/wpscan/issues/172
|
||||||
class AttachmentBruteForcing < CMSScanner::Finders::Finder
|
class AttachmentBruteForcing < CMSScanner::Finders::Finder
|
||||||
include CMSScanner::Finders::Finder::Enumerator
|
include CMSScanner::Finders::Finder::Enumerator
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -17,7 +17,13 @@ module WPScan
|
|||||||
|
|
||||||
begin
|
begin
|
||||||
res.xml.xpath('//item/dc:creator').each do |node|
|
res.xml.xpath('//item/dc:creator').each do |node|
|
||||||
potential_usernames << node.text.to_s unless node.text.to_s.length > 40
|
potential_username = node.text.to_s
|
||||||
|
|
||||||
|
# Ignoring potential username longer than 60 characters and containing accents
|
||||||
|
# as they are considered invalid. See https://github.com/wpscanteam/wpscan/issues/1215
|
||||||
|
next if potential_username.length > 60 || potential_username =~ /[^\x00-\x7F]/
|
||||||
|
|
||||||
|
potential_usernames << potential_username
|
||||||
end
|
end
|
||||||
rescue Nokogiri::XML::XPath::SyntaxError
|
rescue Nokogiri::XML::XPath::SyntaxError
|
||||||
next
|
next
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -50,5 +50,15 @@ module WPScan
|
|||||||
|
|
||||||
@vulnerabilities
|
@vulnerabilities
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# @return [ String ]
|
||||||
|
def release_date
|
||||||
|
@release_date ||= db_data['release_date'] || 'Unknown'
|
||||||
|
end
|
||||||
|
|
||||||
|
# @return [ String ]
|
||||||
|
def status
|
||||||
|
@status ||= db_data['status'] || 'Unknown'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
<% if @version -%>
|
<% if @version -%>
|
||||||
<%= info_icon %> WordPress version <%= @version.number %> identified.
|
<%= 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.
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
<% if @version -%>
|
<% if @version -%>
|
||||||
"version": {
|
"version": {
|
||||||
"number": <%= @version.number.to_json %>,
|
"number": <%= @version.number.to_json %>,
|
||||||
|
"release_date": <%= @version.release_date.to_json %>,
|
||||||
|
"status": <%= @version.status.to_json %>,
|
||||||
<%= render('@finding', item: @version) -%>
|
<%= render('@finding', item: @version) -%>
|
||||||
},
|
},
|
||||||
<% else -%>
|
<% else -%>
|
||||||
|
|||||||
@@ -9,6 +9,6 @@ done
|
|||||||
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
||||||
|
|
||||||
cd $DIR/../
|
cd $DIR/../
|
||||||
docker build -q -t wpscanv3:git .
|
docker build -q -t wpscan:git .
|
||||||
docker run -it --rm wpscanv3:git "$@"
|
docker run -it --rm wpscan:git "$@"
|
||||||
|
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
|
|||||||
|
|
||||||
cd $DIR/../
|
cd $DIR/../
|
||||||
if [[ -n "$WPSCAN_BUILD" ]]; then
|
if [[ -n "$WPSCAN_BUILD" ]]; then
|
||||||
docker build -q -t wpscanv3:git .
|
docker build -q -t wpscan:git .
|
||||||
fi
|
fi
|
||||||
docker run -it --rm -v $DIR/../:/wpscan wpscanv3:git "$@"
|
docker run -it --rm -v $DIR/../:/wpscan wpscan:git "$@"
|
||||||
|
|
||||||
|
|||||||
@@ -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.0'.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/' }
|
||||||
@@ -22,7 +20,7 @@ describe WPScan::Controller::Core do
|
|||||||
|
|
||||||
# Ensures the :url is the first one and is correctly setup
|
# Ensures the :url is the first one and is correctly setup
|
||||||
expect(cli_options.first.to_sym).to eql :url
|
expect(cli_options.first.to_sym).to eql :url
|
||||||
expect(cli_options.first.required_unless).to match_array %i[update help version]
|
expect(cli_options.first.required_unless).to match_array %i[update help hh version]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -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
|
||||||
@@ -28,29 +27,32 @@ 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,25 +66,49 @@ describe WPScan::Controller::PasswordAttack do
|
|||||||
end
|
end
|
||||||
|
|
||||||
context 'when xmlrpc' do
|
context 'when xmlrpc' do
|
||||||
before do
|
context 'when xmlrpc not detected on target' do
|
||||||
expect(controller.target).to receive(:xmlrpc).and_return(WPScan::XMLRPC.new("#{target_url}/xmlrpc.php"))
|
before do
|
||||||
end
|
expect(controller.target).to receive(:xmlrpc).and_return(nil)
|
||||||
|
end
|
||||||
|
|
||||||
context 'when single xmlrpc' do
|
context 'when single xmlrpc' do
|
||||||
let(:attack) { 'xmlrpc' }
|
let(:attack) { 'xmlrpc' }
|
||||||
|
|
||||||
it 'returns the correct object' do
|
it 'raises an error' do
|
||||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPC
|
expect { controller.attacker }.to raise_error(WPScan::XMLRPCNotDetected)
|
||||||
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
context 'when xmlrpc-multicall' do
|
context 'when xmlrpc detected on target' do
|
||||||
let(:attack) { 'xmlrpc-multicall' }
|
before do
|
||||||
|
expect(controller.target).to receive(:xmlrpc).and_return(WPScan::XMLRPC.new("#{target_url}/xmlrpc.php"))
|
||||||
|
end
|
||||||
|
|
||||||
it 'returns the correct object' do
|
context 'when single xmlrpc' do
|
||||||
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPCMulticall
|
let(:attack) { 'xmlrpc' }
|
||||||
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
|
||||||
|
it 'returns the correct object' do
|
||||||
|
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPC
|
||||||
|
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when xmlrpc-multicall' do
|
||||||
|
let(:attack) { 'xmlrpc-multicall' }
|
||||||
|
|
||||||
|
it 'returns the correct object' do
|
||||||
|
expect(controller.attacker).to be_a WPScan::Finders::Passwords::XMLRPCMulticall
|
||||||
|
expect(controller.attacker.target).to be_a WPScan::XMLRPC
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user