Compare commits

...

346 Commits
v2 ... v3.7.1

Author SHA1 Message Date
erwanlr
1994826af8 Bumps version 2019-09-16 13:14:27 +01:00
erwanlr
ab950d6ffc Do not cache login requests - Fixes #1395 2019-09-16 10:37:43 +01:00
erwanlr
b77e611a90 Adds DFs 2019-09-14 10:35:22 +01:00
erwanlr
86f0284894 Updates help to reflect enumeration of popular plugins and themes 2019-09-13 18:10:33 +01:00
erwanlr
9bbe014dfe Merge branch 'master' of github.com:wpscanteam/wpscan 2019-09-13 17:23:19 +01:00
erwanlr
ad92c95500 Fixes crash when API returns HTML data rather than JSON in edge cases 2019-09-13 17:22:26 +01:00
Erwan
d360190382 Adds section for username enumeration in the Readme 2019-09-13 11:31:32 +02:00
ethicalhack3r
1737c8a7f6 Update readme 2019-09-13 11:02:12 +02:00
ethicalhack3r
cde262fd66 Add wpvulndb api info to readme 2019-09-13 10:49:05 +02:00
erwanlr
bd74689079 Bumps version 2019-09-13 08:34:19 +01:00
Erwan
248942bdea Updates Readme (adds link, fixes typo) 2019-09-11 11:29:45 +02:00
erwanlr
d9f203300b Updates deps 2019-09-11 10:19:48 +01:00
erwanlr
aceabc969f Merge branch 'master' into 3.7.0 2019-09-11 10:18:28 +01:00
erwanlr
dedc24d3a7 Adds DFs 2019-09-07 11:55:53 +01:00
erwanlr
6e583e78e8 Gets Sponsor text from db file 2019-09-05 21:47:26 +01:00
erwanlr
c012e83355 Merge branch 'master' into 3.7.0-merged-master 2019-09-05 19:46:16 +01:00
erwanlr
264355d185 Ignores 404 with BodyPattern DF - Ref #1386 2019-09-05 19:41:24 +01:00
erwanlr
fdbfd1ec60 Ref #1386 2019-09-03 12:03:12 +01:00
erwanlr
7a8b27a255 Fixes #1386 2019-09-02 22:09:28 +01:00
erwanlr
ec4bfac98b Adds DFs 2019-09-01 11:38:57 +01:00
erwanlr
c63ffe37c9 Updates deps and Readme 2019-08-30 18:22:25 +01:00
erwanlr
d2f3ce82c9 Fixes specs 2019-08-30 09:28:47 +01:00
erwanlr
3e24a0b0a4 Merge with master 2019-08-30 09:03:31 +01:00
Erwan
1a07e29ff4 Merge pull request #1383 from wpscanteam/dependabot/bundler/webmock-tw-3.7.0
Update webmock requirement from ~> 3.6.0 to ~> 3.7.0
2019-08-28 14:29:22 +02:00
dependabot-preview[bot]
1aa46a8928 Update webmock requirement from ~> 3.6.0 to ~> 3.7.0
Updates the requirements on [webmock](https://github.com/bblimke/webmock) to permit the latest version.
- [Release notes](https://github.com/bblimke/webmock/releases)
- [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bblimke/webmock/compare/v3.6.0...v3.7.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-28 09:01:28 +00:00
erwanlr
d9083f8b5f Fixes spec related to latest changes 2019-08-24 15:17:18 +01:00
erwanlr
23d558a6d7 Updates to CMSScanner 0.5.8 2019-08-24 14:49:56 +01:00
erwanlr
665a5b7b12 Adds DFs 2019-08-24 14:06:52 +01:00
erwanlr
1d73418969 Adds DFs 2019-08-17 10:36:18 +01:00
erwanlr
f67b5e4cc4 Updates deps again 2019-08-13 11:55:57 +01:00
erwanlr
ae2515444f Updates deps 2019-08-13 11:03:34 +01:00
erwanlr
463e77f0a5 VulnAPI Implementation 2019-08-13 10:03:01 +01:00
erwanlr
d7b796b1a7 Adds DFs 2019-08-10 12:22:38 +01:00
erwanlr
9b07d53077 Bumps version 2019-08-06 16:10:21 +01:00
erwanlr
8ee9b2bc31 Fixes #1378 2019-08-06 13:01:22 +01:00
erwanlr
c5989477a4 Adds DFs 2019-08-03 10:56:22 +01:00
Erwan
96d8a4e4f8 Merge pull request #1377 from wpscanteam/dependabot/bundler/rubocop-tw-0.74.0
Update rubocop requirement from ~> 0.73.0 to ~> 0.74.0
2019-08-03 10:19:49 +02:00
dependabot-preview[bot]
e865e11731 Update rubocop requirement from ~> 0.73.0 to ~> 0.74.0
Updates the requirements on [rubocop](https://github.com/rubocop-hq/rubocop) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.73.0...v0.74.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-08-01 05:31:24 +00:00
erwanlr
f0997bfe0d Bumps version 2019-07-31 15:46:59 +01:00
erwanlr
8b67dad456 Fixes regexp perf 2019-07-31 14:54:57 +01:00
erwanlr
53fdac1038 Fixes #1376 2019-07-31 14:53:11 +01:00
erwanlr
534a7602e6 Adds DFs 2019-07-27 18:36:53 +01:00
erwanlr
30f329fe43 Bumps version 2019-07-23 18:27:09 +01:00
erwanlr
4ce39951a9 Additional specs for #1374 2019-07-23 16:33:09 +01:00
ethicalhack3r
0e9eb34626 Remove Patreon link 2019-07-23 12:09:04 +02:00
erwanlr
0ff299c425 Updates UA used when updating the DB 2019-07-22 12:13:01 +01:00
erwanlr
6366258ce9 Merge branch 'df' 2019-07-20 19:11:06 +01:00
erwanlr
bca69a026e Adds DFs 2019-07-20 19:10:47 +01:00
Christian Mehlmauer
adc26ea42a ruby 2.6.3 2019-07-19 09:16:56 +02:00
erwanlr
84422b10c8 Changes db_data to metadata 2019-07-18 18:52:52 +01:00
erwanlr
d05ad0f8f4 Adds an Api Token controller 2019-07-18 17:40:27 +01:00
erwanlr
3f70ddaffa Switching to dev 2019-07-18 17:31:02 +01:00
Erwan
b16e8d84d7 Merge pull request #1369 from wpscanteam/dependabot/bundler/rubocop-tw-0.73.0
Update rubocop requirement from ~> 0.72.0 to ~> 0.73.0
2019-07-17 11:38:45 +02:00
dependabot-preview[bot]
5ee405d5a0 Update rubocop requirement from ~> 0.72.0 to ~> 0.73.0
Updates the requirements on [rubocop](https://github.com/rubocop-hq/rubocop) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.72.0...v0.73.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-07-17 05:28:25 +00:00
erwanlr
a5b9470636 Adds DFs 2019-07-13 11:57:18 +01:00
erwanlr
16a3d54cb6 Bumps version 2019-07-11 17:50:46 +01:00
erwanlr
9677dcd978 Makes sure the sub_dir is only checked once 2019-07-10 18:35:46 +01:00
erwanlr
17ea42f918 Updates cms_scanner dep 2019-07-10 09:17:49 +01:00
erwanlr
bd8915918d Switcing back to master 2019-07-09 15:07:42 +01:00
erwanlr
91db6773a0 Reduces --themes-threshold 2019-07-09 14:37:30 +01:00
erwanlr
f50680b61f Adds a --plugins-threshold and --themes-threshold options 2019-07-08 19:47:46 +01:00
erwanlr
3fb5d33333 Switching to dev 2019-07-08 17:34:13 +01:00
erwanlr
f70bbb2660 Switching to master 2019-07-08 14:02:38 +01:00
erwanlr
589c1ac9bb Only create Versions DF when needed 2019-07-08 13:02:29 +01:00
erwanlr
d458fa1b89 Switching to dev 2019-07-08 10:23:42 +01:00
erwanlr
dc2c99434f Switching to master 2019-07-07 12:19:05 +01:00
erwanlr
bbf36562d0 Fixes specs 2019-07-07 09:57:54 +01:00
erwanlr
c458edf3e4 Adds a note about the Readme DF 2019-07-07 08:51:29 +01:00
erwanlr
99c2aaef7a Changes some DF method names to avoid confusion with db ones 2019-07-07 08:35:41 +01:00
erwanlr
921096ca10 Adds DFs 2019-07-07 08:09:22 +01:00
erwanlr
b0fbd6fa36 Removes empty expected DF 2019-07-06 15:58:23 +01:00
erwanlr
21bd67c44f Switching to minor release 2019-07-06 15:53:00 +01:00
erwanlr
4f142985a2 Fixes #1364 2019-07-06 15:32:42 +01:00
erwanlr
bfa89b44bc Switching to dev 2019-07-06 13:04:38 +01:00
erwanlr
eba876e72b Adds DFs 2019-07-06 11:05:22 +01:00
erwanlr
f1a7413e20 Adds Theme DFs 2019-07-05 09:34:13 +01:00
erwanlr
4d32749489 Updates deps and bump version 2019-07-04 17:06:28 +01:00
erwanlr
d911a16684 Removes useless WPScan namespace 2019-07-04 16:46:33 +01:00
erwanlr
d7193bc755 Ref #1364 2019-07-04 16:33:14 +01:00
erwanlr
aee9ffdb9c Fixes #1365 2019-07-04 15:45:01 +01:00
erwanlr
1f627d5e49 Adds DFs 2019-06-29 10:51:03 +01:00
ethicalhack3r
bb67626d09 Change thimthub enum icon back to info 2019-06-28 15:04:30 +02:00
ethicalhack3r
4e0153e94a Change some enum icons to critical 2019-06-28 15:00:05 +02:00
erwanlr
065142ff19 Updates Rubocop dep 2019-06-27 08:15:54 +01:00
erwanlr
8bb6fae52f Adds DFs 2019-06-22 11:31:28 +01:00
Erwan
8cb7b81903 Merge pull request #1359 from wpscanteam/dependabot/bundler/rubocop-performance-tw-1.4.0
Update rubocop-performance requirement from ~> 1.3.0 to ~> 1.4.0
2019-06-21 13:02:00 +02:00
dependabot-preview[bot]
cb214ccda9 Update rubocop-performance requirement from ~> 1.3.0 to ~> 1.4.0
Updates the requirements on [rubocop-performance](https://github.com/rubocop-hq/rubocop-performance) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop-performance/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop-performance/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop-performance/compare/v1.3.0...v1.4.0)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2019-06-21 05:41:30 +00:00
erwanlr
3fa7b96f27 Bumps version 2019-06-17 18:11:37 +01:00
erwanlr
7c8e259072 Adds DFs 2019-06-15 16:28:14 +01:00
erwanlr
743d067042 Adds DFs 2019-06-08 12:11:24 +01:00
Erwan
50ea410718 Merge pull request #1353 from wpscanteam/dependabot/bundler/webmock-tw-3.6.0
Update webmock requirement from ~> 3.5.1 to ~> 3.6.0
2019-06-05 12:50:44 +02:00
dependabot-preview[bot]
e71182aed2 Update webmock requirement from ~> 3.5.1 to ~> 3.6.0
Updates the requirements on [webmock](https://github.com/bblimke/webmock) to permit the latest version.
- [Release notes](https://github.com/bblimke/webmock/releases)
- [Changelog](https://github.com/bblimke/webmock/blob/master/CHANGELOG.md)
- [Commits](https://github.com/bblimke/webmock/compare/v3.5.1...v3.6.0)
2019-06-05 07:53:59 +00:00
erwanlr
97f7963e0b Adds DFs 2019-06-02 14:05:44 +01:00
Erwan
6cea6a10bd Merge pull request #1352 from wpscanteam/dependabot/bundler/rubocop-tw-0.71.0
Update rubocop requirement from ~> 0.70.0 to ~> 0.71.0
2019-05-31 14:24:27 +02:00
dependabot-preview[bot]
344d41e365 Update rubocop requirement from ~> 0.70.0 to ~> 0.71.0
Updates the requirements on [rubocop](https://github.com/rubocop-hq/rubocop) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.70.0...v0.71.0)
2019-05-31 08:04:55 +00:00
erwanlr
597a8adfed Removes FP DF 2019-05-24 11:16:52 +01:00
erwanlr
5682e5483a Adds DFs 2019-05-24 11:06:50 +01:00
Erwan
18779edd7d Merge pull request #1349 from wpscanteam/dependabot/bundler/rubocop-tw-0.70.0
Update rubocop requirement from ~> 0.69.0 to ~> 0.70.0
2019-05-22 14:23:49 +02:00
dependabot[bot]
63aeaea77a Update rubocop requirement from ~> 0.69.0 to ~> 0.70.0
Updates the requirements on [rubocop](https://github.com/rubocop-hq/rubocop) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.69.0...v0.70.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-22 06:25:23 +00:00
Erwan
f51e48cb40 Merge pull request #1347 from wpscanteam/dependabot/bundler/rubocop-tw-0.69.0
Update rubocop requirement from ~> 0.68.0 to ~> 0.69.0
2019-05-14 17:50:34 +02:00
Erwan
193372c79c Adds a note about Nokogiri in the Readme 2019-05-14 14:12:28 +02:00
dependabot[bot]
34d0afe7e5 Update rubocop requirement from ~> 0.68.0 to ~> 0.69.0
Updates the requirements on [rubocop](https://github.com/rubocop-hq/rubocop) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.68.0...v0.69.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-14 11:26:28 +00:00
Erwan
d33a9dd56d Merge pull request #1346 from wpscanteam/dependabot/bundler/rubocop-performance-tw-1.3.0
Update rubocop-performance requirement from ~> 1.2.0 to ~> 1.3.0
2019-05-14 13:19:26 +02:00
dependabot[bot]
af2be90176 Update rubocop-performance requirement from ~> 1.2.0 to ~> 1.3.0
Updates the requirements on [rubocop-performance](https://github.com/rubocop-hq/rubocop-performance) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop-performance/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop-performance/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop-performance/compare/v1.2.0...v1.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-14 06:21:57 +00:00
erwanlr
701fb21544 Adds DFs 2019-05-11 11:34:47 +01:00
erwanlr
c8f010d9a6 Ref #1344 2019-05-08 18:17:25 +01:00
Erwan
c1ca7580e2 Merge pull request #1343 from wpscanteam/dependabot/bundler/rubocop-performance-tw-1.2.0
Update rubocop-performance requirement from ~> 1.1.0 to ~> 1.2.0
2019-05-08 18:56:36 +02:00
dependabot[bot]
11d3c2cbf1 Update rubocop-performance requirement from ~> 1.1.0 to ~> 1.2.0
Updates the requirements on [rubocop-performance](https://github.com/rubocop-hq/rubocop-performance) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop-performance/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop-performance/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop-performance/compare/v1.1.0...v1.2.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-05-06 06:12:47 +00:00
erwanlr
412f576aee Adds DFs 2019-05-03 11:54:25 +01:00
erwanlr
ff98a7b23b Fixes #1341 2019-05-01 19:50:43 +01:00
erwanlr
507bac8542 Merge branch 'master' of github.com:wpscanteam/wpscan 2019-04-29 15:48:07 +01:00
erwanlr
3bd6cf4805 Adds Ruby 2.6.3 to Travis 2019-04-29 15:47:55 +01:00
erwanlr
5712b31869 Updates Rubocop dep 2019-04-29 15:47:33 +01:00
Erwan
b0f9a0b18f Update issue templates 2019-04-29 15:24:22 +02:00
Erwan
f7665b460e Update issue templates 2019-04-29 15:20:44 +02:00
Erwan
100029b640 Delete old issue template 2019-04-29 15:18:10 +02:00
Erwan
2b89bddf0f Update issue templates 2019-04-29 15:17:39 +02:00
erwanlr
ca46bad8ec Bumps version 2019-04-26 11:53:00 +01:00
erwanlr
1ecd2600a3 Adds DFs 2019-04-26 10:56:26 +01:00
erwanlr
28306b126b Adds DFs 2019-04-24 17:32:25 +01:00
erwanlr
5c842e192b Updates deps 2019-04-24 12:42:18 +01:00
erwanlr
f9f307118d Adds DFs 2019-04-19 10:18:52 +01:00
erwanlr
2266fa4f4b Removes useless comment 2019-04-18 14:43:21 +01:00
erwanlr
6df2564d1a Improves Target#wordpress_hosted? 2019-04-18 14:17:00 +01:00
erwanlr
b2a62ebd26 Fixes #1335 2019-04-18 12:26:47 +01:00
erwanlr
2fca30752a Improves wp-content detection 2019-04-18 12:13:56 +01:00
erwanlr
210eced369 Typo in comments 2019-04-17 17:39:20 +01:00
erwanlr
08c574aff8 Improves detection of wp-content folder 2019-04-17 15:52:06 +01:00
Christian Mehlmauer
f4db2d65f1 fix #1309 2019-04-16 06:42:26 +02:00
erwanlr
23b02ade96 Adds DFs 2019-04-13 14:29:24 +01:00
erwanlr
71d35b16ac Adds DFs 2019-04-13 14:22:42 +01:00
erwanlr
200058c52a Adds DFs 2019-04-13 10:37:39 +01:00
erwanlr
edb5fb202a Removes check for 301 when enumerating plugins and themes 2019-04-13 08:13:38 +01:00
erwanlr
d114c25cdb Typo 2019-04-12 14:52:39 +01:00
erwanlr
64e469568b Adds message help for --wp-content-dir and --wp-plugins-dir options 2019-04-12 14:07:28 +01:00
erwanlr
c63d777372 Fixes version wrongly bumped 2019-04-12 14:00:39 +01:00
erwanlr
ae343b8cb0 Checks for wp-content directly (depends on detection-mode) when not identified passively 2019-04-12 13:55:40 +01:00
Erwan
86eb5d2d57 Merge pull request #1332 from wpscanteam/dependabot/bundler/rspec-its-tw-1.3.0
Update rspec-its requirement from ~> 1.2.0 to ~> 1.3.0
2019-04-10 10:33:27 +02:00
dependabot[bot]
b562d241db Update rspec-its requirement from ~> 1.2.0 to ~> 1.3.0
Updates the requirements on [rspec-its](https://github.com/rspec/rspec-its) to permit the latest version.
- [Release notes](https://github.com/rspec/rspec-its/releases)
- [Changelog](https://github.com/rspec/rspec-its/blob/master/Changelog.md)
- [Commits](https://github.com/rspec/rspec-its/compare/v1.2.0...v1.3.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-10 06:07:39 +00:00
erwanlr
49b1829b78 Bumps version 2019-04-08 16:58:26 +01:00
erwanlr
1a5bf4035c Update deps 2019-04-08 09:39:07 +01:00
erwanlr
f3810a1504 Bumps version 2019-04-07 17:45:29 +01:00
erwanlr
4831760c11 Merge branch '3.5.1' 2019-04-07 17:42:51 +01:00
erwanlr
f375d8991e Update deps 2019-04-07 17:35:18 +01:00
erwanlr
8145a4a3a6 Fixes #1330 2019-04-07 17:06:19 +01:00
erwanlr
12c9b49d4c Adds DFs 2019-04-06 11:34:23 +01:00
erwanlr
c8eb81161e Uses https rather than git protocols for CMSScanner dep 2019-04-05 19:53:29 +01:00
erwanlr
8ab246a66c Uses CMSScanner git dep 2019-04-05 19:48:22 +01:00
erwanlr
8dfc4797fa Handles default user_agent_list via CLI option (in CMSScanner) 2019-04-05 19:30:53 +01:00
erwanlr
7888fe1176 Uses ParsedCli 2019-04-05 16:47:14 +01:00
Erwan
8a6f3056a3 Merge pull request #1329 from wpscanteam/dependabot/bundler/rubocop-tw-0.67.1
Update rubocop requirement from ~> 0.66.0 to ~> 0.67.1
2019-04-05 11:37:00 +02:00
dependabot[bot]
5fbdf9e013 Update rubocop requirement from ~> 0.66.0 to ~> 0.67.1
Updates the requirements on [rubocop](https://github.com/rubocop-hq/rubocop) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/compare/v0.66.0...v0.67.1)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-04-05 06:16:13 +00:00
erwanlr
1da2f5e823 Sets the Target#mu_plugind to true when detected passively 2019-04-04 17:25:58 +01:00
erwanlr
888779f81b Support of Ruby 2.3 removed as its life ended 2019-04-04 15:40:21 +01:00
erwanlr
352286e497 Adds a #maybe_add_cookies to handle website requiring a specific cookie 2019-04-03 19:08:52 +01:00
erwanlr
025ce37c05 Bumps version 2019-04-03 12:32:07 +01:00
erwanlr
d6c2c63679 Updates deps 2019-04-03 10:14:28 +01:00
erwanlr
49efbf25ea Adds detection of Plugin/Theme via errors 500 and custom 401/403 - Fixes #1090 2019-04-03 08:22:31 +01:00
erwanlr
02cdee2776 Retains db_data for Plugin, Theme and WpVersion models 2019-04-02 17:10:07 +01:00
erwanlr
7c9d4d5b05 Updates deps 2019-04-02 11:56:59 +01:00
erwanlr
609b7551f8 Forces GC to start only after Plugin/Theme DF generation 2019-04-02 09:47:16 +01:00
erwanlr
e8f215ae00 Forces the Garbage Collector to run after creating the DFs 2019-04-01 19:39:40 +01:00
erwanlr
2e00aea16e Mem tests 2019-04-01 12:19:40 +01:00
erwanlr
dd274d77f5 Updates deps 2019-04-01 11:15:02 +01:00
Erwan
58171a7b8c Fixes CodeClimate URL 2019-03-30 16:00:32 +01:00
erwanlr
8b05179401 Adds DFs 2019-03-30 14:17:09 +00:00
erwanlr
51d61a7e88 Adds DFs 2019-03-30 12:15:08 +00:00
erwanlr
d653ce4e0e Adds DFs 2019-03-30 11:11:27 +00:00
erwanlr
07b3826806 Adds DFs 2019-03-30 07:22:14 +00:00
erwanlr
1baa3e23b2 Fixes #1326 2019-03-29 08:27:18 +00:00
erwanlr
0aa1f20d47 Removes Changelog detection 2019-03-28 13:40:58 +00:00
erwanlr
1cf330b389 Merge branch 'master' into 3.5.0 2019-03-28 06:45:48 +00:00
erwanlr
1771c4b346 Updates Ruby version 2019-03-27 17:44:47 +00:00
erwanlr
4c053b4873 Updates dockerignore to ignore profiling executables as well 2019-03-27 14:25:58 +00:00
erwanlr
743ba0541b Updates finders to use new methods 2019-03-26 21:10:14 +00:00
erwanlr
cfab2a9cd7 Uses the new CMSScanner Enumerator module 2019-03-26 17:05:19 +00:00
erwanlr
32270efd65 Updates plugin version detection via Readme 2019-03-26 09:02:23 +00:00
erwanlr
7ea1acb7c1 Fixes non detection of plugin/theme readme and changelog files due to changes in CMSSCanner 2019-03-25 21:25:00 +00:00
erwanlr
bf91f60242 Uses the new Browser#forge_request method 2019-03-25 20:42:43 +00:00
Ryan Dewhurst
660885c0b1 Try to resolve weird char after readme conversion 2019-03-25 09:49:03 +01:00
erwanlr
15fd3b969f Uses head_and_get to check for Readme and Changelog locations 2019-03-24 22:01:19 +00:00
erwanlr
f1d15ca7f2 Updates spec for latest changes 2019-03-24 20:24:14 +00:00
erwanlr
6f4f4a5924 Typo 2019-03-24 20:15:43 +00:00
erwanlr
9af0520701 Delegates #head_and_get to #blog in WpItem models 2019-03-24 20:06:03 +00:00
erwanlr
2edeab558e Adds ruby frozen_string_literal comment to profiling bins 2019-03-24 19:57:59 +00:00
erwanlr
87bf59f50b Merge branch 'master' of github.com:wpscanteam/wpscan 2019-03-24 14:38:25 +00:00
erwanlr
eeb69e63f7 Adds DFs 2019-03-24 14:38:01 +00:00
erwanlr
f9435906e7 Merges with Master (and solves conflicts) 2019-03-24 13:01:29 +00:00
Ryan Dewhurst
6c8adbe50e Remove strange char when converted to html 2019-03-23 10:37:05 +01:00
Ryan Dewhurst
23bdb6c579 Open readme links in new tab 2019-03-23 10:14:51 +01:00
Ryan Dewhurst
264411bfb9 Update README.md 2019-03-23 10:00:50 +01:00
Ryan Dewhurst
2104237584 Update README.md 2019-03-23 09:57:50 +01:00
Ryan Dewhurst
0ae2525737 Update README.md 2019-03-23 09:57:33 +01:00
Ryan Dewhurst
b12973a837 Add projects links to the top of Readme 2019-03-23 09:41:14 +01:00
erwanlr
fa0582ce0b Uses head or get method to enumerate config backups 2019-03-22 20:35:22 +00:00
erwanlr
231f5157bf Fixes #1322 2019-03-22 20:20:07 +00:00
erwanlr
8b18204a69 Updates memory_profiler dep, revert changes to memory allocated commit (increased retained memory too much) 2019-03-22 06:56:10 +00:00
erwanlr
95eb6a732c Memprofiling - Increases the top to be displayed to 15 2019-03-21 20:50:57 +00:00
erwanlr
047a188b34 Uses the frozen_string_literal magic comment (will be the default in Ruby 3) 2019-03-21 17:41:29 +00:00
erwanlr
d407815c30 Adds comment about scale_bytes in memory_profiler 2019-03-21 16:54:06 +00:00
erwanlr
1f0f87633b Reduces memory allocation with creating DFs 2019-03-21 13:52:34 +00:00
erwanlr
c15ff4e32e Adds memprof binary - Ref #1321 2019-03-21 12:45:44 +00:00
erwanlr
72bddca314 Adds profiling binary for dev [WIP] - Ref #1321 2019-03-20 21:12:53 +00:00
erwanlr
496fc4ebee Typo 2019-03-20 20:12:18 +00:00
erwanlr
f414e6eeb7 Better code for WpVersion#all 2019-03-20 20:10:30 +00:00
erwanlr
f09606cfa3 Fixes #1319 2019-03-20 15:42:05 +00:00
erwanlr
6304fe4c19 Fixes #1318 2019-03-20 08:41:39 +00:00
erwanlr
5f2b8f8a2e Fixes #1317 2019-03-20 07:47:28 +00:00
erwanlr
898e8d4546 Moves Models into their own namespace - Ref #1315 2019-03-19 21:07:53 +00:00
erwanlr
f1657164d5 Errors moved into their own namespace - Ref #1315 2019-03-19 19:09:16 +00:00
erwanlr
357e13be2b Updates cms_scanner dep 2019-03-19 18:52:18 +00:00
erwanlr
9685568c75 Updates deps 2019-03-19 10:55:50 +00:00
erwanlr
b316940790 Merge branch 'enum-head' 2019-03-18 20:40:36 +00:00
erwanlr
2ced489e1e Updates deps 2019-03-18 20:37:24 +00:00
erwanlr
5969fe08d8 Revert changes related to the unexpected return - Ref #1314 2019-03-18 19:24:02 +00:00
erwanlr
4a427f1ff6 Adds a custom temporary Enumerator for Plugins,Themes and Timthumbs 2019-03-18 19:15:43 +00:00
erwanlr
9a3db275f3 Merge branch 'master' of github.com:wpscanteam/wpscan 2019-03-17 07:25:09 +00:00
erwanlr
475dd4d1ff Ref #1314 2019-03-17 07:24:49 +00:00
erwanlr
57c99c4a34 Fixes #1313 2019-03-17 06:59:44 +00:00
Christian Mehlmauer
966f5691a2 update image 2019-03-16 19:48:47 +01:00
erwanlr
5088ece8a1 Updates deps 2019-03-16 12:35:19 +00:00
erwanlr
943d87fe17 Updates deps 2019-03-16 09:31:01 +00:00
erwanlr
b5363b2689 Adds DFs 2019-03-16 08:38:07 +00:00
erwanlr
c15cb16ca8 Update deps 2019-03-15 14:09:31 +00:00
erwanlr
18b7f088fc Adds ruby versions to Travis 2019-03-15 12:47:06 +00:00
erwanlr
4f9822743c Improves Password Attack against wp-login.php to avoid FP 2019-03-14 19:21:39 +00:00
erwanlr
e7925de5bc Check the wp-login.php for potential redirection before using it 2019-03-14 18:06:32 +00:00
erwanlr
27fc6a7279 Updates cms_scanner dep 2019-03-14 11:55:20 +00:00
erwanlr
ab5f46e955 Adds detection of wp-content from raw JS 2019-03-14 09:14:55 +00:00
erwanlr
d30d212cc5 Updates WP DF (also check non minified file paths) - Ref #1311 2019-03-12 07:55:32 +00:00
erwanlr
adff971d62 Bumps version 2019-03-10 09:47:41 +00:00
erwanlr
23b22f71b8 Reduces confidence of wp-cron detection 2019-03-10 08:02:51 +00:00
erwanlr
fee3671e32 Adds wp-cron.php detection - Fixes #1299 2019-03-10 07:53:12 +00:00
erwanlr
26c6be7268 Fixes #1307 2019-03-10 07:11:48 +00:00
erwanlr
01c5bcf2be Adds DFs 2019-03-09 16:19:25 +00:00
erwanlr
1ab8a5ab98 Updates deps 2019-03-07 19:37:01 +00:00
erwanlr
b54aaca28a Adds missing lines 2019-03-04 07:40:45 +00:00
erwanlr
86a29ae000 Adds DF 2019-03-04 07:35:21 +00:00
erwanlr
a5dbee93ff Adds DFs 2019-03-02 10:43:45 +00:00
Christian Mehlmauer
e0465e6e10 remove line 2019-02-28 08:41:19 +01:00
Christian Mehlmauer
7da48b9dd1 readme linting 2019-02-28 08:18:01 +01:00
Christian Mehlmauer
a64895c3a6 remove UTF characters from license 2019-02-28 08:13:42 +01:00
erwanlr
21f1a5d4c4 Adds DFs 2019-02-23 08:27:27 +00:00
erwanlr
d60f79ca33 Adds DFs 2019-02-16 13:20:51 +00:00
Erwan
2d5cea5033 Adds missing #to_s calls again 2019-02-11 21:14:40 +01:00
erwanlr
b0615215fe Adds missing #to_s calls 2019-02-11 20:03:05 +00:00
erwanlr
7a0f98b2cb Uses Pathname#join rather than File#join when possible 2019-02-11 19:56:07 +00:00
erwanlr
cdc1dab4a6 Bumps version 2019-02-11 11:48:49 +00:00
erwanlr
431739ab19 Updates Rubocop dep 2019-02-11 10:44:29 +00:00
erwanlr
1780399050 Fixes #1277 2019-02-10 15:32:30 +00:00
erwanlr
eb75d38716 Fixes #1284 2019-02-10 13:47:19 +00:00
erwanlr
06f82d78f4 Ref #1285 - Adds comment about the pagination 2019-02-10 10:49:03 +00:00
erwanlr
dee4da1c0e Fixes #1285 2019-02-10 10:45:54 +00:00
erwanlr
e341ec7c60 Adds DFs 2019-02-10 09:44:17 +00:00
Erwan
9146609e4a Update Readme, Fixes #1286 2019-02-03 20:46:03 +01:00
erwanlr
f90615ca41 Adds DF 2019-02-03 07:08:05 +00:00
erwanlr
8a2a6a05ff Adds DFs 2019-01-27 10:54:13 +00:00
Erwan
5a787f8ed5 Adds a note about bug in Ruby 2.5.x, Ref #1283 2019-01-25 20:14:14 +00:00
erwanlr
a904053002 Adds DFs 2019-01-20 17:04:32 +00:00
Erwan
70ecd30dcc Merge pull request #1276 from wpscanteam/dependabot/bundler/rubocop-tw-0.63.0
Update rubocop requirement from ~> 0.62.0 to ~> 0.63.0
2019-01-17 09:32:24 +00:00
dependabot[bot]
b0976d7e47 Update rubocop requirement from ~> 0.62.0 to ~> 0.63.0
Updates the requirements on [rubocop](https://github.com/rubocop-hq/rubocop) to permit the latest version.
- [Release notes](https://github.com/rubocop-hq/rubocop/releases)
- [Changelog](https://github.com/rubocop-hq/rubocop/blob/master/CHANGELOG.md)
- [Commits](https://github.com/rubocop-hq/rubocop/commits/v0.63.0)

Signed-off-by: dependabot[bot] <support@dependabot.com>
2019-01-17 05:54:18 +00:00
erwanlr
bb5e55016c Adds DFs 2019-01-13 16:56:13 +00:00
erwanlr
abdf285c69 Bumps version 2019-01-11 11:53:11 +00:00
erwanlr
fd4da23d4f Creates simplecov exetrnal config 2019-01-11 11:13:49 +00:00
erwanlr
bb8f58c83b Updates deps 2019-01-11 11:12:34 +00:00
erwanlr
077da6ae86 Moves require spec_helper to config file 2019-01-11 11:11:56 +00:00
erwanlr
d5222d7e9a Adds DFs 2019-01-07 14:58:03 +00:00
erwanlr
01702c127b Tries to fix Travis again 2019-01-07 11:47:58 +00:00
Erwan
87902cbfb4 Tries to fix Travis builds 2019-01-07 10:54:05 +00:00
ethicalhack3r
fcaa393ffe Update license 2019-01-07 10:54:24 +01:00
ethicalhack3r
18bac6e792 Update to Ruby 2.6.0 2019-01-07 10:16:32 +01:00
erwanlr
9a21efebe3 Updates DFs 2018-12-28 22:50:05 +00:00
erwanlr
357182ef17 Adds DFs 2018-12-28 22:43:41 +00:00
erwanlr
5fad540a4c Bumps version 2018-12-28 13:35:01 +00:00
erwanlr
c1fc153420 Updates Deps, ref #1266 2018-12-28 11:17:37 +00:00
erwanlr
73a1974f85 Bumps version 2018-12-13 22:16:45 +00:00
erwanlr
dec73c21b6 Fixes #1264 2018-12-13 22:11:37 +00:00
erwanlr
46a00cc864 Adds DFs 2018-12-07 14:59:03 +00:00
erwanlr
62455be165 Deletes useless specs 2018-12-06 22:54:17 +00:00
erwanlr
17ef5ef918 Reverts spec changes 2018-12-06 22:52:10 +00:00
erwanlr
922b6fffd0 Fixes specs 2018-12-06 21:46:13 +00:00
erwanlr
b47bf006d0 Removes useless spec 2018-12-06 21:44:54 +00:00
erwanlr
d60269f4bc Adds DFs 2018-12-06 21:41:00 +00:00
erwanlr
1ce057a78e Adds DFs 2018-12-06 15:54:15 +00:00
erwanlr
a0fe04b990 Fixes #1260 2018-12-06 02:51:23 +00:00
erwanlr
31c9172e19 Removes false positive DFs 2018-12-03 15:37:09 +00:00
erwanlr
7f23cbef71 Adds DFs 2018-12-03 15:08:56 +00:00
Ryan Dewhurst
4884defaed Add some references to interesting findings 2018-11-22 15:04:43 +01:00
erwanlr
3039218c40 Adds DFs 2018-11-18 11:45:58 +00:00
erwanlr
8bbc2f32ae Bumps version 2018-11-12 16:11:14 +00:00
erwanlr
4ca46ab3ba Fixes #1241 2018-11-12 15:57:17 +00:00
erwanlr
7442c72d01 Fixes #1244 2018-11-08 20:28:24 +00:00
erwanlr
01cd8350bc Fixes 1242 2018-11-08 19:16:47 +00:00
erwanlr
8b5ea589db Ref #1241 2018-11-08 19:04:40 +00:00
Erwan
3555ca1d1e Merge pull request #1223 from taha-abbasi/patch-1
Added username enumeration instructions
2018-11-07 11:40:41 +00:00
erwanlr
ae034a47ed Removes FP DFs 2018-11-03 19:36:55 +00:00
erwanlr
ec3862c930 Adds DFs 2018-11-03 19:27:52 +00:00
erwanlr
c63804d1c5 Bumps version 2018-11-02 19:51:57 +00:00
erwanlr
c5e6752f75 Fixes #1232 2018-11-02 19:33:38 +00:00
erwanlr
e4f3e9d11c Fixes spec 2018-11-02 17:52:43 +00:00
erwanlr
f3713536b9 Adds missing spec files 2018-11-02 16:36:10 +00:00
erwanlr
fb751c0a51 Fixes #1228 2018-11-02 13:40:46 +00:00
erwanlr
9d3464055a Updates deps 2018-11-02 08:36:22 +00:00
erwanlr
0fea814f5d Fixes #1237 2018-11-02 08:33:21 +00:00
Ryan Dewhurst
ae70a6df9d Merge pull request #1233 from FenrirSec/fix_wordpress_hosted
Fixed pattern matching on target.wordpress_hosted
2018-10-29 13:46:50 +01:00
lp1
4afc756ccd Added spec for the new regex 2018-10-29 12:11:28 +01:00
lp1
adc5841261 Fixed too restrictive pattern matching on target.wordpress_hosted attribute 2018-10-25 18:09:04 +02:00
erwanlr
41cca5fb8a Bumps version 2018-10-20 13:43:20 +01:00
erwanlr
498da1a06b Merge branch 'advanced_help' 2018-10-20 13:41:17 +01:00
erwanlr
48dab90313 Displays the release date of the detected WP version 2018-10-20 12:37:46 +01:00
erwanlr
d1ff642957 Adds DFs 2018-10-20 11:56:47 +01:00
Erwan
2b5613d84a Update .travis.yml 2018-10-19 21:15:03 +01:00
Ryan Dewhurst
09d28fae26 Update Ruby 2018-10-19 09:47:02 +02:00
Ryan Dewhurst
7517e247d9 Update readme ruby version 2018-10-19 09:45:39 +02:00
erwanlr
998951e629 Re-enables rspec on build 2018-10-18 16:15:36 +01:00
erwanlr
d89fcbb68a Ref #1225 - Adds notes related to Medias enumeration 2018-10-18 16:15:04 +01:00
erwanlr
d3e0ff1e66 Adds simple and full help options 2018-10-18 16:01:28 +01:00
Taha Abbasi
804a8c34c6 Added username enumeration instructions
Added username enumeration instructions, and username enumeration with range instructions for use with Docker and without.
2018-10-08 13:39:11 -04:00
erwanlr
57942e1826 Adds DFs 2018-10-07 15:58:56 +01:00
Christian Mehlmauer
5657735b55 reduce image size 2018-10-04 16:28:21 +02:00
Christian Mehlmauer
791fce2424 smaller image 2018-10-03 07:36:06 +02:00
Christian Mehlmauer
c34fa45875 ruby 2018-10-03 07:17:44 +02:00
Christian Mehlmauer
e0fd79f800 fix docker build 2018-10-02 17:12:39 +02:00
Christian Mehlmauer
f9d9cda4a4 Merge pull request #1218 from mostafahussein/dockerfile-enhancements
Use LABEL and Make use of multi-stage build
2018-10-02 17:10:49 +02:00
Mostafa Hussein
d6f44b2f42 Remove unnecessary commands 2018-10-02 15:55:35 +02:00
Mostafa Hussein
bd90da7ed2 Remove runtime dependencies from build stage 2018-10-02 14:43:38 +02:00
Mostafa Hussein
3a1a976e35 Update Maintainers 2018-10-02 13:29:10 +02:00
Mostafa Hussein
db1309af83 Use LABEL and Make use of multistage build
Maintainer keyword should be replaced with LABEL, and Also using multistage build decreases the image from 139MB to 117MB

Signed-off-by: Mostafa Hussein <mostafa.hussein91@gmail.com>
2018-10-02 08:45:35 +02:00
Christian Mehlmauer
0e47441a36 dockerignore 2018-10-01 22:03:13 +02:00
Ryan Dewhurst
375bea9a8b Update README.md 2018-10-01 20:06:41 +02:00
erwanlr
3a42772879 Adds missing spec files 2018-09-30 13:57:46 +01:00
erwanlr
e9956593dc Adds DFs 2018-09-30 13:16:58 +01:00
erwanlr
fda6000c4c Merge branch 'master' of github.com:wpscanteam/wpscan 2018-09-30 11:23:26 +01:00
erwanlr
99b4eb969d Adds License and Readme files to gem 2018-09-30 11:20:28 +01:00
Christian Mehlmauer
dadd55ba32 another reference 2018-09-30 11:18:29 +02:00
Christian Mehlmauer
b40e06b2ea remove v3 references 2018-09-30 11:17:20 +02:00
Christian Mehlmauer
3f20edc41f gitignore 2018-09-30 11:15:48 +02:00
erwanlr
baaa11bb64 Bumps version 2018-09-28 10:57:21 +01:00
erwanlr
44e1179ce4 Fixes #1215 2018-09-28 10:33:19 +01:00
erwanlr
808521fb70 Updates deps 2018-09-28 09:20:14 +01:00
Erwan
ad8e97f432 Update README.md 2018-09-26 20:49:13 +01:00
Ryan Dewhurst
3c47652cc0 Add missing hidden files 2018-09-26 21:17:43 +02:00
Ryan Dewhurst
220ff0e3f7 Update readme 2018-09-26 21:17:02 +02:00
Ryan Dewhurst
d268a86795 HELLO v3!!! 2018-09-26 21:12:01 +02:00
Ryan Dewhurst
28b9c15256 So long hidden files! 2018-09-26 21:03:08 +02:00
Ryan Dewhurst
4f594d59cc So long hombre 2018-09-26 21:00:28 +02:00
3327 changed files with 1306936 additions and 21946 deletions

View File

@@ -1,21 +1,16 @@
.*
bin/
dev/
spec/
*.md
Dockerfile
## TEMP
git/
bundle/
.idea/
.yardoc/
bundle/
cache/
coverage/
git/
spec/
.*
**/*.md
*.md
!README.md
Dockerfile
**/*.orig
*.orig
CREDITS
data.zip
DISCLAIMER.txt
example.conf.json
bin/wpscan-*
.wpscan/

5
.github/CONTRIBUTING.md vendored Normal file
View File

@@ -0,0 +1,5 @@
# Contributing to WPScan
## Licensing
By submitting code contributions to the WPScan development team via Github Pull Requests, or any other method, it is understood that the contributor is offering the WPScan company (company number 83421476900012), which is registered in France, the unlimited, non-exclusive right to reuse, modify, and relicense the code.

38
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,38 @@
---
name: Bug report
about: Create a report to help us improve
title: ''
labels: ''
assignees: ''
---
Before submitting an issue, please make sure you fully read any potential error messages output and did some research on your own.
### Subject of the issue
Describe your issue here.
### Your environment
* Version of WPScan:
* Version of Ruby:
* Operating System (OS):
### Steps to reproduce
Tell us how to reproduce this issue.
### Expected behavior
Tell us what should happen.
### Actual behavior
Tell us what happens instead.
### What have you already tried
Tell us what you have already tried to do to fix the issue you are having.
Things you have tried (where relevant):
* Update WPScan to the latest version [ ]
* Update Ruby to the latest version [ ]
* Ensure you can reach the target site using cURL [ ]
* Proxied WPScan through a HTTP proxy to view the raw traffic [ ]
* Ensure you are using a supported Operating System (Linux and macOS) [ ]

View File

@@ -0,0 +1,20 @@
---
name: Feature request
about: Suggest an idea for this project
title: ''
labels: ''
assignees: ''
---
**Is your feature request related to a problem? Please describe.**
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
**Describe the solution you'd like**
A clear and concise description of what you want to happen.
**Describe alternatives you've considered**
A clear and concise description of any alternative solutions or features you've considered.
**Additional context**
Add any other context or screenshots about the feature request here.

10
.github/ISSUE_TEMPLATE/other-issue.md vendored Normal file
View File

@@ -0,0 +1,10 @@
---
name: Other Issue
about: Create a report which is not a related to a Bug or Feature
title: ''
labels: ''
assignees: ''
---
Before submitting an issue, please make sure you fully read any potential error messages output and did some research on your own.

3
.github/PULL_REQUEST_TEMPLATE.md vendored Normal file
View File

@@ -0,0 +1,3 @@
## Licensing
By submitting code contributions to the WPScan development team via Github Pull Requests, or any other method, it is understood that the contributor is offering the WPScan company (company number 83421476900012), which is registered in France, the unlimited, non-exclusive right to reuse, modify, and relicense the code.

41
.gitignore vendored
View File

@@ -1,21 +1,26 @@
# WPScan (If not using ~/.wpscan/)
cache/
data/
log.txt
output.txt
# WPScan (Deployment)
debug.log
rspec_results.html
wordlist.txt
# OS/IDE Rubbish
coverage/
.yardoc/
.idea/
*.sublime-*
.*.swp
.ash_history
*.gem
*.rbc
.bundle
.config
coverage
pkg
rdoc
Gemfile.lock
# YARD artifacts
.yardoc
_yardoc
doc/
.wpscan/
.ash_history
.DS_Store
.DS_Store?
.idea/
# Old files from v2
cache/
data/
# Profiling reports
bin/memprof*.report

1
.rspec
View File

@@ -1,2 +1,3 @@
--color
--fail-fast
--require spec_helper

34
.rubocop.yml Normal file
View File

@@ -0,0 +1,34 @@
require: rubocop-performance
AllCops:
TargetRubyVersion: 2.4
Exclude:
- '*.gemspec'
- 'vendor/**/*'
ClassVars:
Enabled: false
LineLength:
Max: 120
Lint/UriEscapeUnescape:
Enabled: false
MethodLength:
Max: 20
Exclude:
- 'app/controllers/enumeration/cli_options.rb'
Metrics/AbcSize:
Max: 25
Metrics/BlockLength:
Exclude:
- 'spec/**/*'
Metrics/ClassLength:
Max: 150
Exclude:
- 'app/controllers/enumeration/cli_options.rb'
Metrics/CyclomaticComplexity:
Max: 8
Style/Documentation:
Enabled: false
Style/FormatStringToken:
Enabled: false
Style/NumericPredicate:
Exclude:
- 'app/controllers/vuln_api.rb'

View File

@@ -1 +1 @@
wpscan
wpscanv3

View File

@@ -1 +1 @@
2.5.1
2.6.2

View File

@@ -1,8 +1,4 @@
SimpleCov.start do
add_filter "/spec/"
add_filter "_helper.rb"
add_filter "environment.rb"
add_filter "_plugin.rb"
add_filter "hacks.rb"
add_filter "output.rb"
add_filter '/spec/'
add_filter 'helper'
end

View File

@@ -2,35 +2,32 @@ language: ruby
sudo: false
cache: bundler
rvm:
- 2.1.9
- 2.2.0
- 2.2.1
- 2.2.2
- 2.2.3
- 2.2.4
- 2.3.0
- 2.3.1
- 2.3.2
- 2.3.3
- 2.4.1
- 2.4.2
- 2.4.3
- 2.4.4
- 2.4.5
- 2.4.6
- 2.5.0
- 2.5.1
- 2.5.2
- 2.5.3
- 2.5.4
- 2.5.5
- 2.6.0
- 2.6.1
- 2.6.2
- 2.6.3
- ruby-head
before_install:
- "env"
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
- "gem install bundler"
- "gem regenerate_binstubs"
- "bundle --version"
before_script:
- "unzip -o $TRAVIS_BUILD_DIR/data.zip -d $HOME/.wpscan/"
- gem update --system
matrix:
allow_failures:
- rvm: ruby-head
script:
- "bundle exec rspec"
- bundle exec rubocop
- bundle exec rspec
notifications:
email:
- team@wpscan.org
# do not build gh-pages branch
branches:
except:
- gh-pages

View File

@@ -1,587 +0,0 @@
# Changelog
## Master
[Work in progress](https://github.com/wpscanteam/wpscan/compare/2.9.4...master)
## Version 2.9.4
Released: 2018-06-15
* Updated dependencies and required ruby version
* Improved CLI output
* Only show readme.html output when wp <= 4.8 #1127
* Cleanup README.md
* Fix bug "undefined method 'identifier' for nil:NilClass" #1149
* Since WP 4.7 readme.html only shows major version #1152
* Add checks for humans.txt and security.text (Thank you @g0tmi1k!)
* Add offline database update support (Thank you @g0tmi1k!)
* Check for API access and /wp-json/'s users output (Thank you @g0tmi1k!)
* Add RSS author information (Thank you @g0tmi1k!)
* Check HTTP status of each value in /robots.txt (Thank you @g0tmi1k!)
* Follow any redirections (e.g. http -> https) (Thank you @g0tmi1k!)
* Lots of other enhancements by @g0tmi1k & WPScan Team
* Database export file enumeration.
WPScan Database Statistics:
* Total tracked wordpresses: 319
* Total tracked plugins: 74896
* Total tracked themes: 16666
* Total vulnerable wordpresses: 305
* Total vulnerable plugins: 1645
* Total vulnerable themes: 286
* Total wordpress vulnerabilities: 8327
* Total plugin vulnerabilities: 2603
* Total theme vulnerabilities: 352
## Version 2.9.3
Released: 2017-07-19
* Updated dependencies and required ruby version
* Made some changes so wpscan works in ruby 2.4
* Added a Gemfile.lock to lock all dependencies
* You can now pass a wordlist from stdin via "--wordlist -"
* Improved version detection regexes
* Added an optional paramter to --log to specify a filename
WPScan Database Statistics:
* Total tracked wordpresses: 251
* Total tracked plugins: 68818
* Total tracked themes: 15132
* Total vulnerable wordpresses: 243
* Total vulnerable plugins: 1527
* Total vulnerable themes: 280
* Total wordpress vulnerabilities: 5263
* Total plugin vulnerabilities: 2406
* Total theme vulnerabilities: 349
## Version 2.9.2
Released: 2016-11-15
* Fixed error when detecting plugins with UTF-8 characters
* Use all possible finders to verify a detected version
* Fix error when detecting a WordPress version not in our database
* Added some additional clarification on error messages
* Upgrade terminal-table gem
* Add --cache-dir option
* Add --disable-tls-checks options
* Improve/add additional plugin passive detections
* Remove scripts when calculating page hashes
* Many other small bug fixes.
WPScan Database Statistics:
* Total tracked wordpresses: 194
* Total tracked plugins: 63703
* Total tracked themes: 13835
* Total vulnerable wordpresses: 177
* Total vulnerable plugins: 1382
* Total vulnerable themes: 379
* Total wordpress vulnerabilities: 2617
* Total plugin vulnerabilities: 2190
* Total theme vulnerabilities: 452
## Version 2.9.1
Released: 2016-05-06
* Update to Ruby 2.3.1, drop older ruby support
* New data file location
* Added experimental Windows support
* Display WordPress metadata on the detected version
* Several small fixes
WPScan Database Statistics:
* Total vulnerable versions: 156
* Total vulnerable plugins: 1324
* Total vulnerable themes: 376
* Total version vulnerabilities: 1998
* Total plugin vulnerabilities: 2057
* Total theme vulnerabilities: 449
## Version 2.9
Released: 2015-10-15
New
* GZIP Encoding in updater
* Adds --throttle option to throttle requests
* Uses new API and local database file structure
* Adds last updated and latest version to plugins and themes
Removed
* ArchAssault from README
* APIv1 local databases
General core
* Update to Ruby 2.2.3
* Use yajl-ruby as JSON parser
* New dependancy for Ubuntu 14.04 (libgmp-dev)
* Use Travis container based infra and caching
Fixed issues
* Fix #835 - Readme requests to wp root dir
* Fix #836 - Critical icon output twice when the site is not running WP
* Fix #839 - Terminal-table dependency is broken
* Fix #841 - error: undefined method `cells' for #<Array:0x000000029cc2f8>
* Fix #852 - GZIP Encoding in updater
* Fix #853 - APIv2 integration
* Fix #858 - Detection FP
* Fix #873 - false positive "site has Must Use Plugins"
WPScan Database Statistics:
* Total vulnerable versions: 132
* Total vulnerable plugins: 1170
* Total vulnerable themes: 368
* Total version vulnerabilities: 1476
* Total plugin vulnerabilities: 1913
* Total theme vulnerabilities: 450
## Version 2.8
Released: 2015-06-22
New
* Warn the user to update his DB files
* Added last db update to --version option (see #815)
* Add db checksum to verbose logging during update
* Option to hide banner
* Continue if user chooses not to update + db exists
* Don't update if user chooses default + no DBs exist
* Updates request timeout values to realistic ones (and in seconds)
Removed
* Removed `Time.parse('2000-01-01')` expedient
* Removed unnecessary 'return' and '()'
* Removed debug output
* Removed wpstools
General core
* Update to Ruby 2.2.2
* Switch to mitre
* Install bundler gem README
* Switch from gnutls to openssl
Fixed issues
* Fix #789 - Add blackarch to readme
* Fix #790 - Consider the target down after 30 requests timed out requests instead of 10
* Fix #791 - Rogue character causing the scan of non-wordpress site to crash
* Fix #792 - Adds the HttpError exception
* Fix #795 - Remove GHOST warning
* Fix #796 - Do not swallow exit code
* Fix #797 - Increases the timeout values
* Fix #801 - Forces UTF-8 encoding when enumerating usernames
* Fix #803 - Increases default connect-timeout to 10s
* Fix #804 - Updates the Theme detection pattern
* Fix #816 - Ignores potential non version chars in theme version detection
* Fix #819 - Removes potential spaces in robots.txt entries
WPScan Database Statistics:
* Total vulnerable versions: 98
* Total vulnerable plugins: 1076
* Total vulnerable themes: 361
* Total version vulnerabilities: 1104
* Total plugin vulnerabilities: 1763
* Total theme vulnerabilities: 443
## Version 2.7
Released: 2015-03-16
New
* Detects version in release date format
* Copyrights updated
* WP version detection from stylesheets
* New license
* Global HTTP request counter
* Add security-protection plugin detection
* Add GHOST warning if XMLRPC enabled
* Update databases from wpvulndb.com
* Enumerate usernames from WP <= 3.0 (thanks berotti3)
Removed
* README.txt
General core
* Update to Ruby 2.2.1
* Update to Ruby 2.2.0
* Add addressable gem
* Update Typhoeus gem to 0.7.0
* IDN support: encode non-ascii domain names (thanks dctabuyz)
* Improve page hash calculation (thanks dctabuyz)
* Version detection regex improved
Fixed issues
* Fix #745 - Plugin version pattern in readme.txt file not detected
* Fix #746 - Add a global counter for all active requests to server.
* Fix #747 - Add 'security-protection' plugin to wp_login_protection module
* Fix #753 - undefined method `round' for "10":String for request or connect timeouts
* Fix #760 - typhoeus issue (infinite loop)
WPScan Database Statistics:
* Total vulnerable versions: 89
* Total vulnerable plugins: 953
* Total vulnerable themes: 329
* Total version vulnerabilities: 1070
* Total plugin vulnerabilities: 1451
* Total theme vulnerabilities: 378
## Version 2.6
Released: 2014-12-19
New
* Updates the readmes to reflect the new --usernames option
* Improves plugin/theme version detection by looking at the "Version:"
* Solution to avoid mandatory blank newline at the end of the wordlist
* Add check for valid credentials
* Add Sucuri sponsor to banner
* Add protocol to sucuri url in banner
* Add response code to proxy error output
* Add a statement about mandatory newlines at the end of list
* Give warning if default username 'admin' is still used
* License amendment to make it more clear about value added usage
Removed
* remove malwares
* remove malware folder
* Removes the theme version check from the readme, unrealistic scenario
General core
* Update to Ruby 2.1.5 and travis
* Prevent parent theme infinite loop
* Fixes the progressbar being overriden by next brute forcing attempts
Fixed issues
* Fix UTF-8 encode on security db file download
* Fix #703 - Disable logging by default. Implement log option.
* Fix #705 - Installation instructions for Ubuntu < 14.04 apparently incomplete
* Fix #717 - Expand on readme.html finding output
* Fix #716 - Adds the --version in the help
* Fix #715 - Add new updating info to docs
* Fix #727 - WpItems detection: Perform the passive check and filter only vulnerable results at the end if required
* Fix #737 - Adds some readme files to check for plugin versions
* Fix #739 - Adds the --usernames option
WPScan Database Statistics:
* Total vulnerable versions: 88
* Total vulnerable plugins: 901
* Total vulnerable themes: 313
* Total version vulnerabilities: 1050
* Total plugin vulnerabilities: 1355
* Total theme vulnerabilities: 349
## Version 2.5.1
Released: 2014-09-29
Fixes reference URL to WPVDB
## Version 2.5
Released: 2014-09-26 (@ BruCON 2014)
New
* Exit program after --update
* Detect directory listing in upload folder
* Be more verbose when no version can be detected
* Added detection for Yoast Wordpress SEO plugin
* Also ensure to not process empty Location headers
* Ensures a nil location is not processed when enumerating usernames
* Fix #626 - Detect 'Must_Use_Plugins'
* better username extraction
* Add a --cookie option. Ref #485
* Add a --no-color option
* Output: Give 'Fixed in' an informational tag
* Added ArchAssault distro - WPScan comes pre-installed with this distro
* Layout changes with new colors
Removed
* Removes the source code updaters
* Removes the ListGenerator plugin from WPStools
* Removes all files from data/
General core
* Update docs to reflect new updating logic
* Little output change and coloring
* Adds a missing verbose output
* Re-build redirection url if begin with slash '/'
* Fixes the remove_conditional_comments function
* Ensures to give a string to Typhoeus
* Fix wpstools check-vuln-ref-urls
* Fix rspecs for new json
* Only output if different from style_url
* Add exception so 'ruby wpscan.rb http://domain.com' is detected
* Added make to Debian installation, which is needed in minimal installation.
* Add build-essentials requirement to Ubuntu > 14.04
* Updated installation instr. for GNU/Linux Debian.
* Changes VersionCompare#is_newer_or_same? by lesser_or_equal?
* Fixes the location of the robots.txt check
* Updates the recommended ruby version
* Rspec 3.0 support
* Adds ruby 2.1.2 to Travis
* Updated ruby-progressbar to 1.5.0
WordPress Fingerprints
* Adds WP 4.0 fingerprints
* Adds WP 3.9.2, 3.8.4 & 3.7.4 fingerprints - Ref #652
* Adds 3.9.1 fingerprints
Fixed issues
* Fix #689 - Adds config file to check
* Fix #694 - Output Arrays
* Fix #693 - Adds pathname require statement
* Fix #657 - generate method
* Fix #685 - Potenial fix for 'marshal data too short' error
* Fix #686 - Adds specs for relative URI in Location headers
* Fix #435 - Update license
* Fix #674 - Improves the Plugins & Themes passive detection
* Fix #673 - Problem with the output
* Fix #661 - Don't hash directories named like a file
* Fix #653 - Fix for infinite loop in wpstools
* Fix #625 - Only parse styles when needed
* Fix #481 - Fix for Jetpack plugin false positive
* Fix #480 - Properly removes the colour sequence from log
* Fix #472 - WPScan stops after redirection if not WordPress website
* Fix #464 - Readmes updated to reflect recent changes about the config file & batch mode
Vulnerabilities
* geoplaces4 also uses name GeoPlaces4beta
* Added metasploit module's
* Added some timthumb detections
WPScan Database Statistics:
* Total vulnerable versions: 87
* Total vulnerable plugins: 854
* Total vulnerable themes: 303
* Total version vulnerabilities: 752
* Total plugin vulnerabilities: 1351
* Total theme vulnerabilities: 345
## Version 2.4
Released: 2014-04-17
New
* '--batch' switch option added - Fix #454
* Add random-agent
* Added more CLI options
* Switch over to nist - Fix #301
* New choice added when a redirection is detected - Fix #438
Removed
* Removed 'Total WordPress Sites in the World' counter from stats
* Old wpscan repo links removed - Fix #440
* Fingerprinting Dev script removed
* Useless code removed
General core
* Rspecs update
* Forcing Travis notify the team
* Ruby 2.1.1 added to Travis
* Equal output layout for interaction questions
* Only output error trace if verbose if enabled
* Memory improvements during wp-items enumerations
* Fixed broken link checker, fixed some broken links
* Couple more 404s fixed
* Themes & Plugins list updated
WordPress Fingerprints
* WP 3.8.2 & 3.7.2 Fingerprints added - Fix #448
* WP 3.8.3 & 3.7.3 fingerprints
* WP 3.9 fingerprints
Fixed issues
* Fix #380 - Redirects in WP 3.6-3.0
* Fix #413 - Check the version of the Timthumbs files found
* Fix #429 - Error WpScan Cache Browser
* Fix #431 - Version number comparison between '2.3.3' and '0.42b'
* Fix #439 - Detect if the target goes down during the scan
* Fix #451 - Do not rely only on files in wp-content for fingerprinting
* Fix #453 - Documentation or inplemention of option parameters
* Fix #455 - Fails with a message if the target returns a 403 during the wordpress check
Vulnerabilities
* Update WordPress Vulnerabilities
* Fixed some duplicate vulnerabilities
WPScan Database Statistics:
* Total vulnerable versions: 79; 1 is new
* Total vulnerable plugins: 748; 55 are new
* Total vulnerable themes: 292; 41 are new
* Total version vulnerabilities: 617; 326 are new
* Total plugin vulnerabilities: 1162; 146 are new
* Total theme vulnerabilities: 330; 47 are new
## Version 2.3
Released: 2014-02-11
New
* Brute forcing over https!
* Detect and output parent theme!
* Complete fingerprint script & hash search
* New spell checker!
* Added database modification dates in status report
* Added 'Total WordPress Sites in the World' statistics
* Added separator between Name and Version in Item
* Added a "Work in progress" URL in the CHANGELOG
Removed
* Removed "Exiting!" sentence
* Removed Backtrack Linux. Not maintained anymore.
General core
* Ruby 2.1.0 added to Travis
* Updated the version of WebMock required
* Better string concatenation in code (improves speed)
* Some modifications in the output of an item
* Output cosmetics
* rspec-mocks version constraint released
* Tabs replaced by spaces
* Rspecs update
* Indent code cleanup
* Themes & Plugins lists regenerated
Vulnerabilities
* Update WordPress Vulnerabilities
* Disabled some fake reported vulnerabilities
* Fixed some duplicate vulnerabilities
WPScan Database Statistics:
* Total vulnerable versions: 78; 2 are new
* Total vulnerable plugins: 693; 83 are new
* Total vulnerable themes: 251; 55 are new
* Total version vulnerabilities: 291 17 are new
* Total plugin vulnerabilities: 1016; 236 are new
* Total theme vulnerabilities: 283; 79 are new
WordPress Fingerprints
* Better fingerprints
* WP 3.8.1 Fingerprinting
* WP 3.8 Fingerprinting
Fixed issues
* Fix #404 - Brute forcing issue over https
* Fix #398 - Removed a fake vuln in WP Super Cache
* Fix #393 - sudo added to the bundle install cmd for Mac OSX
* Fix #228, #327 - Infinite loop when self-redirect
* Fix #201 - Incorrect Paramter Parsing when no url was supplied
## Version 2.2
Released: 2013-11-12
New
* Output the vulnerability fix if available
* Added 'WordPress Version Vulnerability' statistics
* Added Kali Linux on the list of pre-installed Linux distributions
* Added hosted wordpress detection. See issue #343.
* Add detection for all-in-one-seo-pack
* Use less memory when brute forcing with a large wordlist
* Memory Usage output
* Added cve tag to xml file
* Add documentation to readme
* Add --version switch
* Parse robots.txt
* Show twitter usernames
* Clean logfile on wpstools too
* Added pingback header
* Request_timeout and connect_timeout implemented
* Output interesting http-headers
* Kali Linux detection
* Ensure that brute forcing results are output even if an error occurs or the user exits
* Added debug output
* Fixed Version compare for issue #179
* Added ruby-progressbar version to Gemfile
* Use the redirect_to parameter on bruteforce
* Readded "junk removal" from usernames before output
* Add license file
* Output the timthumb version if found
* New enumeration system
* More error details for XSD checks
* Added default wp-content dir detection, see Issue #141.
* Added checks for well formed xml
Changed
* Trying a fix for Kali Linux
* Make a seperator between plugin name and vulnerability name
* It's WordPress, not Wordpress
* Changed wordpress.com scanning error to warning. See issue #343.
* Make output lines consistent
* Replace packetstormsecurity.org to packetstormsecurity.com
* Same URL syntax for all Packet Storm Security URL's
* Packet Storm Security URL's don't need the 'friendly part' of the URL. So it can be neglected.
* Use online documentation
* User prompt on same line
* Don't skip passwords that start with a hash. This is fairly common (see RockYou list for example).
* Updated Fedora install instructions as per Issue #92
* Slight update to security plugin warning. Issue #212.
* Ruby-progressbar Gemfile version bump
* Fix error with the -U option (undefined method 'merge' for #WpTarget:)
* Banner artwork
* Fix hacks.rb conflict
* Handle when there are 2 headers of the same name
* Releasing the Typhoeus version constraint
* Amended Arch Linux install instructions. See issue #183.
Updated
* Plugins & Themes updated
* Update README.md
* Updated documentation
Removed
* Removed 'smileys' in output messages
* Removed 'for WordPress' and 'plugin' in title strings.
* Removed reference
* Removed useless code
* Removed duplicate vulnerabilities
General core
* Code cleaning
* Fix typo's
* Clean up rspecs
* Themes & Plugins lists regenerated
* Rspecs update
* Code Factoring
* Added checks for old ruby. Otherwise there will be syntax errors
Vulnerabilities
* Update WordPress Vulnerabilities
* Update timthumb due to Secunia #54801
* Added WP vuln: 3.4 - 3.5.1 wp-admin/users.php FPD
WPScan Database Statistics:
* Total vulnerable versions: 76; 4 are new
* Total vulnerable plugins: 610; 201 are new
* Total vulnerable themes: 196; 47 are new
* Total version vulnerabilities: 274; 53 are new
* Total plugin vulnerabilities: 780; 286 are new
* Total theme vulnerabilities: 204; 52 are new
Add WP Fingerprints
* WP 3.7.1 Fingerprinting
* WP 3.7 Fingerprinting
* Ref #280 WP 3.6.1 fingerprint
* Added WP 3.6 advanced fingerprint hash. See Issue #255.
* Updated MD5 hash of WP 3.6 detection. See Issue #277.
* WP 3.5.2 Fingerprint
* Bug Fix : Wp 3.5 & 3.5.1 not detected from advanced fingerprinting.
Fixed issues
* Fix #249 - [ERROR] "\xF1" on US-ASCII
* Fix #275 - [ERROR] "\xC3" on US-ASCII
* Fix #271 - Further Instructions added to the Mac Install
* Fix #266 - passive detection regex
* Fix #265 - remove base64 images before passive detection
* Fix #262 - [ERROR] bad component(expected absolute path component)
* Fix #260 - Fixes Travis Fail, due to rspec-mock v2.14.3
* Fix #208 - Fixed vulnerable plugins still appear in the results
* Fix #245 - all theme enumeration error
* Fix #241 - Cant convert array to string
* Fix #232 - Crash while enumerating usernames
* Fix #223 - New wordpress urls for most popular plugins & themes
* Fix #177 - Passive Cache plugins detection (no spec)
* Fix #169 - False reports
* Fix #182 - Remove the progress-bar static length (120), and let it to automatic
* Fix #181 - Don't exit if no usernames found during a simple enumeration (but exit if a brute force is asked)
* Fix #200 - Log file not recording the list of username retireved
* Fix #164 - README.txt detection
* Fix #166 - ListGenerator using the old Browser#get method for full generation
* Fix #153 - Disable error trace when it's from the main script
* Fix #163 - in the proper way
* Fix #144 - Use cookie jar to prevent infinite redirections loop
* Fix #158 - Add the solution to 'no such file to load -- rubygems' in the README
* Fix #152 - invalid ssl_certificate - response code 0
* Fix #147 - can't modify frozen string
* Fix #140 - xml_rpc_url in the body
* Fix #153 - No error trace when 'No argument supplied'
## Version 2.1
Released 2013-3-4

View File

@@ -1,2 +0,0 @@
WPScan is not responsible for misuse or for any damage that you may cause!
You agree that you use this software at your own risk.

View File

@@ -1,37 +1,41 @@
FROM ruby:2.5-alpine
FROM ruby:2.6.3-alpine AS builder
LABEL maintainer="WPScan Team <team@wpscan.org>"
ARG BUNDLER_ARGS="--jobs=8 --without test"
ARG BUNDLER_ARGS="--jobs=8 --without test development"
# Add a new user
RUN adduser -h /wpscan -g WPScan -D wpscan
# Setup gems
RUN echo "gem: --no-ri --no-rdoc" > /etc/gemrc
COPY Gemfile /wpscan
COPY Gemfile.lock /wpscan
# Runtime dependencies
RUN apk add --no-cache libcurl procps && \
# build dependencies
apk add --no-cache --virtual build-deps alpine-sdk ruby-dev libffi-dev zlib-dev && \
bundle install --system --gemfile=/wpscan/Gemfile $BUNDLER_ARGS && \
apk del --no-cache build-deps
# Copy over data & set permissions
COPY . /wpscan
RUN apk add --no-cache git libcurl ruby-dev libffi-dev make gcc musl-dev zlib-dev procps sqlite-dev && \
bundle install --system --clean --no-cache --gemfile=/wpscan/Gemfile $BUNDLER_ARGS && \
# temp fix for https://github.com/bundler/bundler/issues/6680
rm -rf /usr/local/bundle/cache
WORKDIR /wpscan
RUN rake install --trace
# needed so non superusers can read gems
RUN chmod -R a+r /usr/local/bundle
FROM ruby:2.6.3-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
# Switch directory
# runtime dependencies
RUN apk add --no-cache libcurl procps sqlite-libs
WORKDIR /wpscan
# Switch users
USER wpscan
# Update WPScan
RUN /wpscan/wpscan.rb --update --verbose --no-color
RUN /usr/local/bundle/bin/wpscan --update --verbose
# Run WPScan
ENTRYPOINT ["/wpscan/wpscan.rb"]
ENTRYPOINT ["/usr/local/bundle/bin/wpscan"]
CMD ["--help"]

18
Gemfile
View File

@@ -1,16 +1,6 @@
# frozen_string_literal: true
source 'https://rubygems.org'
gemspec
gem 'addressable', '>=2.5.0'
gem 'nokogiri', '>=1.7.0.1'
gem 'ruby-progressbar', '>=1.8.1'
gem 'rubyzip', '>=1.2.1'
gem 'terminal-table', '>=1.6.0'
gem 'typhoeus', '>=1.1.2'
gem 'yajl-ruby', '>=1.3.0' # Better JSON parser regarding memory usage
group :test do
gem 'webmock', '>=2.3.2'
gem 'simplecov', '>=0.13.0'
gem 'rspec', '>=3.5.0'
gem 'rspec-its', '>=1.2.0'
end
# gem 'cms_scanner', branch: 'xxx', git: 'https://github.com/wpscanteam/CMSScanner.git'

View File

@@ -1,71 +0,0 @@
GEM
remote: https://rubygems.org/
specs:
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
crack (0.4.3)
safe_yaml (~> 1.0.0)
diff-lcs (1.3)
docile (1.3.1)
ethon (0.11.0)
ffi (>= 1.3.0)
ffi (1.9.25)
hashdiff (0.3.7)
json (2.1.0)
mini_portile2 (2.3.0)
nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
public_suffix (3.0.2)
rspec (3.7.0)
rspec-core (~> 3.7.0)
rspec-expectations (~> 3.7.0)
rspec-mocks (~> 3.7.0)
rspec-core (3.7.1)
rspec-support (~> 3.7.0)
rspec-expectations (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-its (1.2.0)
rspec-core (>= 3.0.0)
rspec-expectations (>= 3.0.0)
rspec-mocks (3.7.0)
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.7.0)
rspec-support (3.7.1)
ruby-progressbar (1.9.0)
rubyzip (1.2.1)
safe_yaml (1.0.4)
simplecov (0.16.1)
docile (~> 1.1)
json (>= 1.8, < 3)
simplecov-html (~> 0.10.0)
simplecov-html (0.10.2)
terminal-table (1.8.0)
unicode-display_width (~> 1.1, >= 1.1.1)
typhoeus (1.3.0)
ethon (>= 0.9.0)
unicode-display_width (1.4.0)
webmock (3.4.2)
addressable (>= 2.3.6)
crack (>= 0.3.2)
hashdiff
yajl-ruby (1.4.0)
PLATFORMS
ruby
DEPENDENCIES
addressable (>= 2.5.0)
nokogiri (>= 1.7.0.1)
rspec (>= 3.5.0)
rspec-its (>= 1.2.0)
ruby-progressbar (>= 1.8.1)
rubyzip (>= 1.2.1)
simplecov (>= 0.13.0)
terminal-table (>= 1.6.0)
typhoeus (>= 1.1.2)
webmock (>= 2.3.2)
yajl-ruby (>= 1.3.0)
BUNDLED WITH
1.16.3

10
LICENSE
View File

@@ -1,14 +1,14 @@
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.
1. Definitions
1.1 License means this document.
1.2 Contributor means each individual or legal entity that creates, contributes to the creation of, or owns WPScan.
1.3 WPScan Team means WPScans core developers.
1.1 "License" means this document.
1.2 "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns WPScan.
1.3 "WPScan Team" means WPScans core developers.
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
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

386
README.md
View File

@@ -1,17 +1,154 @@
![alt text](https://raw.githubusercontent.com/wpscanteam/wpscan/gh-pages/wpscan_logo_407x80.png "WPScan - WordPress Security Scanner")
<p align="center">
<a href="https://wpscan.org/">
<img src="https://raw.githubusercontent.com/wpscanteam/wpscan/gh-pages/images/wpscan_logo.png" alt="WPScan logo">
</a>
</p>
[![Build Status](https://travis-ci.org/wpscanteam/wpscan.svg?branch=master)](https://travis-ci.org/wpscanteam/wpscan)
[![Code Climate](https://img.shields.io/codeclimate/github/wpscanteam/wpscan.svg)](https://codeclimate.com/github/wpscanteam/wpscan)
[![Docker Pulls](https://img.shields.io/docker/pulls/wpscanteam/wpscan.svg)](https://hub.docker.com/r/wpscanteam/wpscan/)
[![Patreon Donate](https://img.shields.io/badge/patreon-donate-green.svg)](https://www.patreon.com/wpscan)
<h3 align="center">WPScan</h3>
![alt text](https://wpscan.org/images/tty.gif "WPScan Screen Recording")
<p align="center">
WordPress Vulnerability Scanner
<br>
<br>
<a href="https://wpscan.org/" title="homepage" target="_blank">Homepage</a> - <a href="https://wpscan.io/" title="wpscan.io" target="_blank">WPScan.io</a> - <a href="https://wpvulndb.com/" title="vulnerability database" target="_blank">Vulnerability Database</a> - <a href="https://wordpress.org/plugins/wpscan/" title="wordpress plugin" target="_blank">WordPress Plugin</a>
</p>
<p align="center">
<a href="https://badge.fury.io/rb/wpscan" target="_blank"><img src="https://badge.fury.io/rb/wpscan.svg"></a>
<a href="https://travis-ci.org/wpscanteam/wpscan" target="_blank"><img src="https://travis-ci.org/wpscanteam/wpscan.svg?branch=master"></a>
<a href="https://codeclimate.com/github/wpscanteam/wpscan" target="_blank"><img src="https://codeclimate.com/github/wpscanteam/wpscan/badges/gpa.svg"></a>
</p>
# INSTALL
## Prerequisites
- (Optional but highly recommended: [RVM](https://rvm.io/rvm/install))
- 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
- Nokogiri might require packages to be installed via your package manager depending on your OS, see https://nokogiri.org/tutorials/installing_nokogiri.html
### From RubyGems (Recommended)
```shell
gem install wpscan
```
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
```shell
git clone https://github.com/wpscanteam/wpscan
cd wpscan/
bundle install && rake install
```
# Updating
You can update the local database by using ```wpscan --update```
Updating WPScan itself is either done via ```gem update wpscan``` or the packages manager (this is quite important for distributions such as in Kali Linux: ```apt-get update && apt-get upgrade```) depending how WPScan was (pre)installed
# Docker
Pull the repo with ```docker pull wpscanteam/wpscan```
Enumerating usernames
```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
```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.
As a result, when using the ```--enumerate``` option, don't forget to set the ```--plugins-detection``` accordingly, as its default is 'passive'.
For more options, open a terminal and type ```wpscan --help``` (if you built wpscan from the source, you should type the command outside of the git repo)
The DB is located at ~/.wpscan/db
## Vulnerability Database
The WPScan CLI tool uses the [WPVulnDB API](https://wpvulndb.com/api) to retrieve WordPress vulnerability data in real time. For WPScan to retrieve the vulnerability data an API token must be supplied via the `--api-token` option, or via a configuration file, as discussed below. An API token can be obtained by registering an account on [WPVulnDB](https://wpvulndb.com/users/sign_up). Up to 50 API requests per day are given free of charge to registered users. Once the 50 API requests are exhausted, WPScan will continue to work as normal but without any vulnerability data. Users can upgrade to paid API usage to increase their API limits within their user profile on [WPVulnDB](https://wpvulndb.com/).
## Load CLI options from file/s
WPScan can load all options (including the --url) from configuration files, the following locations are checked (order: first to last):
- ~/.wpscan/scan.json
- ~/.wpscan/scan.yml
- pwd/.wpscan/scan.json
- pwd/.wpscan/scan.yml
If those files exist, options from the `cli_options` key will be loaded and overridden if found twice.
e.g:
~/.wpscan/scan.yml:
```yml
cli_options:
proxy: 'http://127.0.0.1:8080'
verbose: true
```
pwd/.wpscan/scan.yml:
```yml
cli_options:
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```
## Save API Token in a file
The feature mentioned above is useful to keep the API Token in a config file and not have to supply it via the CLI each time. To do so, create the ~/.wpscan/scan.yml file containing the below:
```yml
cli_options:
api_token: YOUR_API_TOKEN
```
## 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.
# 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.
@@ -21,7 +158,7 @@ Cases that include commercialization of WPScan require a commercial, non-free li
1.2 "Contributor" means each individual or legal entity that creates, contributes to the creation of, or owns WPScan.
1.3 "WPScan Team" means WPScans core developers, an updated list of whom can be found within the CREDITS file.
1.3 "WPScan Team" means WPScans core developers.
### 2. Commercialization
@@ -42,8 +179,6 @@ Example cases which do not require a commercial license, and thus fall under the
If you need to purchase a commercial license or are unsure whether you need to purchase a commercial license contact us - team@wpscan.org.
We may grant commercial licenses at no monetary cost at our own discretion if the commercial usage is deemed by the WPScan Team to significantly benefit WPScan.
Free-use Terms and Conditions;
### 3. Redistribution
@@ -85,234 +220,3 @@ Running WPScan against websites without prior mutual consent may be illegal in y
### 11. Trademark
The "wpscan" term is a registered trademark. This License does not grant the use of the "wpscan" trademark or the use of the WPScan logo.
# INSTALL
WPScan comes pre-installed on the following Linux distributions:
- [BackBox Linux](http://www.backbox.org/)
- [Kali Linux](http://www.kali.org/)
- [Pentoo](http://www.pentoo.ch/)
- [SamuraiWTF](http://samurai.inguardians.com/)
- [BlackArch](http://blackarch.org/)
On macOS WPScan is packaged by [Homebrew](https://brew.sh/) as [`wpscan`](http://braumeister.org/formula/wpscan).
Windows is not supported
We suggest you use our official Docker image from https://hub.docker.com/r/wpscanteam/wpscan/ to avoid installation problems.
# DOCKER
## Install Docker
[https://docs.docker.com/engine/installation/](https://docs.docker.com/engine/installation/)
## Get the image
Pull the repo with `docker pull wpscanteam/wpscan`
## Start WPScan
```
docker run -it --rm wpscanteam/wpscan -u https://yourblog.com [options]
```
For the available Options, please see https://github.com/wpscanteam/wpscan#wpscan-arguments
If you run the git version of wpscan we included some binstubs in ./bin for easier start of wpscan.
## Examples
Mount a local wordlist to the docker container and start a bruteforce attack for user admin
```
docker run -it --rm -v ~/wordlists:/wordlists wpscanteam/wpscan --url https://yourblog.com --wordlist /wordlists/crackstation.txt --username admin
```
(This mounts the host directory `~/wordlists` to the container in the path `/wordlists`)
Use logfile option
```
# the file must exist prior to starting the container, otherwise docker will create a directory with the filename
touch ~/FILENAME
docker run -it --rm -v ~/FILENAME:/wpscan/output.txt wpscanteam/wpscan --url https://yourblog.com --log /wpscan/output.txt
```
Published on https://hub.docker.com/r/wpscanteam/wpscan/
# Manual install
## Prerequisites
- Ruby >= 2.1.9 - Recommended: 2.5.1
- Curl >= 7.21 - Recommended: latest - FYI the 7.29 has a segfault
- RubyGems - Recommended: latest
- Git
### Installing dependencies on Ubuntu
sudo apt-get install libcurl4-openssl-dev libxml2 libxml2-dev libxslt1-dev ruby-dev build-essential libgmp-dev zlib1g-dev
### Installing dependencies on Debian
sudo apt-get install gcc git ruby ruby-dev libcurl4-openssl-dev make zlib1g-dev
### Installing dependencies on Fedora
sudo dnf install gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel libcurl-devel patch rpm-build
### Installing dependencies on Arch Linux
pacman -Syu ruby
pacman -Syu libyaml
### Installing dependencies on macOS
Apple Xcode, Command Line Tools and the libffi are needed (to be able to install the FFI gem), See [http://stackoverflow.com/questions/17775115/cant-setup-ruby-environment-installing-fii-gem-error](http://stackoverflow.com/questions/17775115/cant-setup-ruby-environment-installing-fii-gem-error)
## Installing with RVM (recommended when doing a manual install)
If you are using GNOME Terminal, there are some steps required before executing the commands. See here for more information:
https://rvm.io/integration/gnome-terminal#integrating-rvm-with-gnome-terminal
# Install all prerequisites for your OS (look above)
cd ~
curl -sSL https://rvm.io/mpapis.asc | gpg --import -
curl -sSL https://get.rvm.io | bash -s stable
source ~/.rvm/scripts/rvm
echo "source ~/.rvm/scripts/rvm" >> ~/.bashrc
rvm install 2.5.1
rvm use 2.5.1 --default
echo "gem: --no-ri --no-rdoc" > ~/.gemrc
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
gem install bundler
bundle install --without test
## Installing manually (not recommended)
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
sudo gem install bundler && bundle install --without test
# KNOWN ISSUES
- no such file to load -- rubygems
```update-alternatives --config ruby```
And select your ruby version
See [https://github.com/wpscanteam/wpscan/issues/148](https://github.com/wpscanteam/wpscan/issues/148)
# WPSCAN ARGUMENTS
--update Update the database to the latest version.
--url | -u <target url> The WordPress URL/domain to scan.
--force | -f Forces WPScan to not check if the remote site is running WordPress.
--enumerate | -e [option(s)] Enumeration.
option :
u usernames from id 1 to 10
u[10-20] usernames from id 10 to 20 (you must write [] chars)
p plugins
vp only vulnerable plugins
ap all plugins (can take a long time)
tt timthumbs
t themes
vt only vulnerable themes
at all themes (can take a long time)
Multiple values are allowed : "-e tt,p" will enumerate timthumbs and plugins
If no option is supplied, the default is "vt,tt,u,vp"
--exclude-content-based "<regexp or string>"
Used with the enumeration option, will exclude all occurrences based on the regexp or string supplied.
You do not need to provide the regexp delimiters, but you must write the quotes (simple or double).
--config-file | -c <config file> Use the specified config file, see the example.conf.json.
--user-agent | -a <User-Agent> Use the specified User-Agent.
--cookie <string> String to read cookies from.
--random-agent | -r Use a random User-Agent.
--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not
--batch Never ask for user input, use the default behaviour.
--no-color Do not use colors in the output.
--log [filename] Creates a log.txt file with WPScan's output if no filename is supplied. Otherwise the filename is used for logging.
--no-banner Prevents the WPScan banner from being displayed.
--disable-accept-header Prevents WPScan sending the Accept HTTP header.
--disable-referer Prevents setting the Referer header.
--disable-tls-checks Disables SSL/TLS certificate verification.
--wp-content-dir <wp content dir> WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specify it.
Subdirectories are allowed.
--wp-plugins-dir <wp plugins dir> Same thing than --wp-content-dir but for the plugins directory.
If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed
--proxy <[protocol://]host:port> Supply a proxy. HTTP, SOCKS4 SOCKS4A and SOCKS5 are supported.
If no protocol is given (format host:port), HTTP will be used.
--proxy-auth <username:password> Supply the proxy login credentials.
--basic-auth <username:password> Set the HTTP Basic authentication.
--wordlist | -w <wordlist> Supply a wordlist for the password brute forcer.
If the "-" option is supplied, the wordlist is expected via STDIN.
--username | -U <username> Only brute force the supplied username.
--usernames <path-to-file> Only brute force the usernames from the file.
--cache-dir <cache-directory> Set the cache directory.
--cache-ttl <cache-ttl> Typhoeus cache TTL.
--request-timeout <request-timeout> Request Timeout.
--connect-timeout <connect-timeout> Connect Timeout.
--threads | -t <number of threads> The number of threads to use when multi-threading requests.
--throttle <milliseconds> Milliseconds to wait before doing another web request. If used, the --threads should be set to 1.
--help | -h This help screen.
--verbose | -v Verbose output.
--version Output the current version and exit.
# WPSCAN EXAMPLES
Do 'non-intrusive' checks...
```ruby wpscan.rb --url www.example.com```
Do wordlist password brute force on enumerated users using 50 threads...
```ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --threads 50```
Do wordlist password brute force on enumerated users using STDIN as the wordlist...
```crunch 5 13 -f charset.lst mixalpha | ruby wpscan.rb --url www.example.com --wordlist -```
Do wordlist password brute force on the 'admin' username only...
```ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --username admin```
Enumerate installed plugins...
```ruby wpscan.rb --url www.example.com --enumerate p```
Run all enumeration tools...
```ruby wpscan.rb --url www.example.com --enumerate```
Use custom content directory...
```ruby wpscan.rb -u www.example.com --wp-content-dir custom-content```
Update WPScan's databases...
```ruby wpscan.rb --update```
Debug output...
```ruby wpscan.rb --url www.example.com --debug-output 2>debug.log```
# PROJECT HOME
[http://www.wpscan.org](http://www.wpscan.org)
# VULNERABILITY DATABASE
[https://wpvulndb.com](https://wpvulndb.com)
# GIT REPOSITORY
[https://github.com/wpscanteam/wpscan](https://github.com/wpscanteam/wpscan)
# ISSUES
[https://github.com/wpscanteam/wpscan/issues](https://github.com/wpscanteam/wpscan/issues)
# DEVELOPER DOCUMENTATION
[http://rdoc.info/github/wpscanteam/wpscan/frames](http://rdoc.info/github/wpscanteam/wpscan/frames)

24
Rakefile Normal file
View File

@@ -0,0 +1,24 @@
# rubocop:disable all
require 'bundler/gem_tasks'
exec = []
begin
require 'rubocop/rake_task'
RuboCop::RakeTask.new
exec << :rubocop
rescue LoadError
end
begin
require 'rspec/core/rake_task'
RSpec::Core::RakeTask.new(:spec)
exec << :spec
rescue LoadError
end
# Run rubocop & rspec before the build (only if installed)
task build: exec
# rubocop:enable all

5
app/app.rb Normal file
View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
require_relative 'models'
require_relative 'finders'
require_relative 'controllers'

10
app/controllers.rb Normal file
View File

@@ -0,0 +1,10 @@
# frozen_string_literal: true
require_relative 'controllers/core'
require_relative 'controllers/vuln_api'
require_relative 'controllers/custom_directories'
require_relative 'controllers/wp_version'
require_relative 'controllers/main_theme'
require_relative 'controllers/enumeration'
require_relative 'controllers/password_attack'
require_relative 'controllers/aliases'

View File

@@ -0,0 +1,15 @@
# frozen_string_literal: true
module WPScan
module Controller
# Controller to add the aliases in the CLI
class Aliases < CMSScanner::Controller::Base
def cli_options
[
OptAlias.new(['--stealthy'],
alias_for: '--random-user-agent --detection-mode passive --plugins-version-detection passive')
]
end
end
end
end

109
app/controllers/core.rb Normal file
View File

@@ -0,0 +1,109 @@
# frozen_string_literal: true
module WPScan
module Controller
# Specific Core controller to include WordPress checks
class Core < CMSScanner::Controller::Core
# @return [ Array<OptParseValidator::Opt> ]
def cli_options
[OptURL.new(['--url URL', 'The URL of the blog to scan'],
required_unless: %i[update help hh version], default_protocol: 'http')] +
super.drop(1) + # delete the --url from CMSScanner
[
OptChoice.new(['--server SERVER', 'Force the supplied server module to be loaded'],
choices: %w[apache iis nginx],
normalize: %i[downcase to_sym],
advanced: true),
OptBoolean.new(['--force', 'Do not check if the target is running WordPress']),
OptBoolean.new(['--[no-]update', 'Whether or not to update the Database'])
]
end
# @return [ DB::Updater ]
def local_db
@local_db ||= DB::Updater.new(DB_DIR)
end
# @return [ Boolean ]
def update_db_required?
if local_db.missing_files?
raise Error::MissingDatabaseFile if ParsedCli.update == false
return true
end
return ParsedCli.update unless ParsedCli.update.nil?
return false unless user_interaction? && local_db.outdated?
output('@notice', msg: 'It seems like you have not updated the database for some time.')
print '[?] Do you want to update now? [Y]es [N]o, default: [N]'
/^y/i.match?(Readline.readline) ? true : false
end
def update_db
output('db_update_started')
output('db_update_finished', updated: local_db.update, verbose: ParsedCli.verbose)
exit(0) unless ParsedCli.url
end
def before_scan
@last_update = local_db.last_update
maybe_output_banner_help_and_version # From CMSScanner
update_db if update_db_required?
setup_cache
check_target_availability
load_server_module
check_wordpress_state
rescue Error::NotWordPress => e
target.maybe_add_cookies
raise e unless target.wordpress?(ParsedCli.detection_mode)
end
# Raises errors if the target is hosted on wordpress.com or is not running WordPress
# Also check if the homepage_url is still the install url
def check_wordpress_state
raise Error::WordPressHosted if target.wordpress_hosted?
if %r{/wp-admin/install.php$}i.match?(Addressable::URI.parse(target.homepage_url).path)
output('not_fully_configured', url: target.homepage_url)
exit(WPScan::ExitCode::VULNERABLE)
end
raise Error::NotWordPress unless target.wordpress?(ParsedCli.detection_mode) || ParsedCli.force
end
# Loads the related server module in the target
# and includes it in the WpItem class which will be needed
# to check if directory listing is enabled etc
#
# @return [ Symbol ] The server module loaded
def load_server_module
server = target.server || :Apache # Tries to auto detect the server
# Force a specific server module to be loaded if supplied
case ParsedCli.server
when :apache
server = :Apache
when :iis
server = :IIS
when :nginx
server = :Nginx
end
mod = CMSScanner::Target::Server.const_get(server)
target.extend mod
Model::WpItem.include mod
server
end
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
module WPScan
module Controller
# Controller to ensure that the wp-content and wp-plugins
# directories are found
class CustomDirectories < CMSScanner::Controller::Base
def cli_options
[
OptString.new(['--wp-content-dir DIR',
'The wp-content directory if custom or not detected, such as "wp-content"']),
OptString.new(['--wp-plugins-dir DIR',
'The plugins directory if custom or not detected, such as "wp-content/plugins"'])
]
end
def before_scan
target.content_dir = ParsedCli.wp_content_dir if ParsedCli.wp_content_dir
target.plugins_dir = ParsedCli.wp_plugins_dir if ParsedCli.wp_plugins_dir
return if target.content_dir(ParsedCli.detection_mode)
raise Error::WpContentDirNotDetected
end
end
end
end

View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
require_relative 'enumeration/cli_options'
require_relative 'enumeration/enum_methods'
module WPScan
module Controller
# Enumeration Controller
class Enumeration < CMSScanner::Controller::Base
def run
enum = ParsedCli.enumerate || {}
enum_plugins if enum_plugins?(enum)
enum_themes if enum_themes?(enum)
%i[timthumbs config_backups db_exports medias].each do |key|
send("enum_#{key}".to_sym) if enum.key?(key)
end
enum_users if enum_users?(enum)
end
end
end
end

View File

@@ -0,0 +1,179 @@
# frozen_string_literal: true
module WPScan
module Controller
# Enumeration CLI Options
class Enumeration < CMSScanner::Controller::Base
def cli_options
cli_enum_choices + cli_plugins_opts + cli_themes_opts +
cli_timthumbs_opts + cli_config_backups_opts + cli_db_exports_opts +
cli_medias_opts + cli_users_opts
end
# @return [ Array<OptParseValidator::OptBase> ]
def cli_enum_choices
[
OptMultiChoices.new(
['-e', '--enumerate [OPTS]', 'Enumeration Process'],
choices: {
vp: OptBoolean.new(['--vulnerable-plugins']),
ap: OptBoolean.new(['--all-plugins']),
p: OptBoolean.new(['--popular-plugins']),
vt: OptBoolean.new(['--vulnerable-themes']),
at: OptBoolean.new(['--all-themes']),
t: OptBoolean.new(['--popular-themes']),
tt: OptBoolean.new(['--timthumbs']),
cb: OptBoolean.new(['--config-backups']),
dbe: OptBoolean.new(['--db-exports']),
u: OptIntegerRange.new(['--users', 'User IDs range. e.g: u1-5'], value_if_empty: '1-10'),
m: OptIntegerRange.new(['--medias',
'Media IDs range. e.g m1-15',
'Note: Permalink setting must be set to "Plain" for those to be detected'],
value_if_empty: '1-100')
},
value_if_empty: 'vp,vt,tt,cb,dbe,u,m',
incompatible: [%i[vp ap p], %i[vt at t]],
default: { all_plugins: true, config_backups: true }
),
OptRegexp.new(
[
'--exclude-content-based REGEXP_OR_STRING',
'Exclude all responses matching the Regexp (case insensitive) during parts of the enumeration.',
'Both the headers and body are checked. Regexp delimiters are not required.'
], options: Regexp::IGNORECASE
)
]
end
# @return [ Array<OptParseValidator::OptBase> ]
def cli_plugins_opts
[
OptSmartList.new(['--plugins-list LIST', 'List of plugins to enumerate'], advanced: true),
OptChoice.new(
['--plugins-detection MODE',
'Use the supplied mode to enumerate Plugins, instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, default: :passive
),
OptBoolean.new(
['--plugins-version-all',
'Check all the plugins version locations according to the choosen mode (--detection-mode, ' \
'--plugins-detection and --plugins-version-detection)'],
advanced: true
),
OptChoice.new(
['--plugins-version-detection MODE',
'Use the supplied mode to check plugins versions instead of the --detection-mode ' \
'or --plugins-detection modes.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, default: :mixed
),
OptInteger.new(
['--plugins-threshold THRESHOLD',
'Raise an error when the number of detected plugins via known locations reaches the threshold. ' \
'Set to 0 to ignore the threshold.'], default: 100
)
]
end
# @return [ Array<OptParseValidator::OptBase> ]
def cli_themes_opts
[
OptSmartList.new(['--themes-list LIST', 'List of themes to enumerate'], advanced: true),
OptChoice.new(
['--themes-detection MODE',
'Use the supplied mode to enumerate Themes, instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
),
OptBoolean.new(
['--themes-version-all',
'Check all the themes version locations according to the choosen mode (--detection-mode, ' \
'--themes-detection and --themes-version-detection)'],
advanced: true
),
OptChoice.new(
['--themes-version-detection MODE',
'Use the supplied mode to check themes versions instead of the --detection-mode ' \
'or --themes-detection modes.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
),
OptInteger.new(
['--themes-threshold THRESHOLD',
'Raise an error when the number of detected themes via known locations reaches the threshold. ' \
'Set to 0 to ignore the threshold.'], default: 20
)
]
end
# @return [ Array<OptParseValidator::OptBase> ]
def cli_timthumbs_opts
[
OptFilePath.new(
['--timthumbs-list FILE-PATH', 'List of timthumbs\' location to use'],
exists: true, default: DB_DIR.join('timthumbs-v3.txt').to_s, advanced: true
),
OptChoice.new(
['--timthumbs-detection MODE',
'Use the supplied mode to enumerate Timthumbs, instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
)
]
end
# @return [ Array<OptParseValidator::OptBase> ]
def cli_config_backups_opts
[
OptFilePath.new(
['--config-backups-list FILE-PATH', 'List of config backups\' filenames to use'],
exists: true, default: DB_DIR.join('config_backups.txt').to_s, advanced: true
),
OptChoice.new(
['--config-backups-detection MODE',
'Use the supplied mode to enumerate Config Backups, instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
)
]
end
# @return [ Array<OptParseValidator::OptBase> ]
def cli_db_exports_opts
[
OptFilePath.new(
['--db-exports-list FILE-PATH', 'List of DB exports\' paths to use'],
exists: true, default: DB_DIR.join('db_exports.txt').to_s, advanced: true
),
OptChoice.new(
['--db-exports-detection MODE',
'Use the supplied mode to enumerate DB Exports, instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
)
]
end
# @return [ Array<OptParseValidator::OptBase> ]
def cli_medias_opts
[
OptChoice.new(
['--medias-detection MODE',
'Use the supplied mode to enumerate Medias, instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
)
]
end
# @return [ Array<OptParseValidator::OptBase> ]
def cli_users_opts
[
OptSmartList.new(
['--users-list LIST',
'List of users to check during the users enumeration from the Login Error Messages'],
advanced: true
),
OptChoice.new(
['--users-detection MODE',
'Use the supplied mode to enumerate Users, instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
)
]
end
end
end
end

View File

@@ -0,0 +1,207 @@
# frozen_string_literal: true
module WPScan
module Controller
# Enumeration Methods
class Enumeration < CMSScanner::Controller::Base
# @param [ String ] type (plugins or themes)
# @param [ Symbol ] detection_mode
#
# @return [ String ] The related enumration message depending on the ParsedCli and type supplied
def enum_message(type, detection_mode)
return unless %w[plugins themes].include?(type)
details = if ParsedCli.enumerate[:"vulnerable_#{type}"]
'Vulnerable'
elsif ParsedCli.enumerate[:"all_#{type}"]
'All'
else
'Most Popular'
end
"Enumerating #{details} #{type.capitalize} #{enum_detection_message(detection_mode)}"
end
# @param [ Symbol ] detection_mode
#
# @return [ String ]
def enum_detection_message(detection_mode)
detection_method = if detection_mode == :mixed
'Passive and Aggressive'
else
detection_mode.to_s.capitalize
end
"(via #{detection_method} Methods)"
end
# @param [ String ] type (plugins, themes etc)
#
# @return [ Hash ]
def default_opts(type)
mode = ParsedCli.options[:"#{type}_detection"] || ParsedCli.detection_mode
{
mode: mode,
exclude_content: ParsedCli.exclude_content_based,
show_progression: user_interaction?,
version_detection: {
mode: ParsedCli.options[:"#{type}_version_detection"] || mode,
confidence_threshold: ParsedCli.options[:"#{type}_version_all"] ? 0 : 100
}
}
end
# @param [ Hash ] opts
#
# @return [ Boolean ] Wether or not to enumerate the plugins
def enum_plugins?(opts)
opts[:popular_plugins] || opts[:all_plugins] || opts[:vulnerable_plugins]
end
def enum_plugins
opts = default_opts('plugins').merge(
list: plugins_list_from_opts(ParsedCli.options),
threshold: ParsedCli.plugins_threshold,
sort: true
)
output('@info', msg: enum_message('plugins', opts[:mode])) if user_interaction?
# Enumerate the plugins & find their versions to avoid doing that when #version
# is called in the view
plugins = target.plugins(opts)
if user_interaction? && !plugins.empty?
output('@info',
msg: "Checking Plugin Versions #{enum_detection_message(opts[:version_detection][:mode])}")
end
plugins.each(&:version)
plugins.select!(&:vulnerable?) if ParsedCli.enumerate[:vulnerable_plugins]
output('plugins', plugins: plugins)
end
# @param [ Hash ] opts
#
# @return [ Array<String> ] The plugins list associated to the cli options
def plugins_list_from_opts(opts)
# List file provided by the user via the cli
return opts[:plugins_list] if opts[:plugins_list]
if opts[:enumerate][:all_plugins]
DB::Plugins.all_slugs
elsif opts[:enumerate][:popular_plugins]
DB::Plugins.popular_slugs
else
DB::Plugins.vulnerable_slugs
end
end
# @param [ Hash ] opts
#
# @return [ Boolean ] Wether or not to enumerate the themes
def enum_themes?(opts)
opts[:popular_themes] || opts[:all_themes] || opts[:vulnerable_themes]
end
def enum_themes
opts = default_opts('themes').merge(
list: themes_list_from_opts(ParsedCli.options),
threshold: ParsedCli.themes_threshold,
sort: true
)
output('@info', msg: enum_message('themes', opts[:mode])) if user_interaction?
# Enumerate the themes & find their versions to avoid doing that when #version
# is called in the view
themes = target.themes(opts)
if user_interaction? && !themes.empty?
output('@info',
msg: "Checking Theme Versions #{enum_detection_message(opts[:version_detection][:mode])}")
end
themes.each(&:version)
themes.select!(&:vulnerable?) if ParsedCli.enumerate[:vulnerable_themes]
output('themes', themes: themes)
end
# @param [ Hash ] opts
#
# @return [ Array<String> ] The themes list associated to the cli options
def themes_list_from_opts(opts)
# List file provided by the user via the cli
return opts[:themes_list] if opts[:themes_list]
if opts[:enumerate][:all_themes]
DB::Themes.all_slugs
elsif opts[:enumerate][:popular_themes]
DB::Themes.popular_slugs
else
DB::Themes.vulnerable_slugs
end
end
def enum_timthumbs
opts = default_opts('timthumbs').merge(list: ParsedCli.timthumbs_list)
output('@info', msg: "Enumerating Timthumbs #{enum_detection_message(opts[:mode])}") if user_interaction?
output('timthumbs', timthumbs: target.timthumbs(opts))
end
def enum_config_backups
opts = default_opts('config_backups').merge(list: ParsedCli.config_backups_list)
output('@info', msg: "Enumerating Config Backups #{enum_detection_message(opts[:mode])}") if user_interaction?
output('config_backups', config_backups: target.config_backups(opts))
end
def enum_db_exports
opts = default_opts('db_exports').merge(list: ParsedCli.db_exports_list)
output('@info', msg: "Enumerating DB Exports #{enum_detection_message(opts[:mode])}") if user_interaction?
output('db_exports', db_exports: target.db_exports(opts))
end
def enum_medias
opts = default_opts('medias').merge(range: ParsedCli.enumerate[:medias])
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))
end
# @param [ Hash ] opts
#
# @return [ Boolean ] Wether or not to enumerate the users
def enum_users?(opts)
opts[:users] || (ParsedCli.passwords && !ParsedCli.username && !ParsedCli.usernames)
end
def enum_users
opts = default_opts('users').merge(
range: enum_users_range,
list: ParsedCli.users_list
)
output('@info', msg: "Enumerating Users #{enum_detection_message(opts[:mode])}") if user_interaction?
output('users', users: target.users(opts))
end
# @return [ Range ] The user ids range to enumerate
# If the --enumerate is used, the default value is handled by the Option
# However, when using --passwords alone, the default has to be set by the code below
def enum_users_range
ParsedCli.enumerate[:users] || cli_enum_choices[0].choices[:u].validate(nil)
end
end
end
end

View File

@@ -0,0 +1,28 @@
# frozen_string_literal: true
module WPScan
module Controller
# Main Theme Controller
class MainTheme < CMSScanner::Controller::Base
def cli_options
[
OptChoice.new(
['--main-theme-detection MODE',
'Use the supplied mode for the Main theme detection, instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
)
]
end
def run
output(
'theme',
theme: target.main_theme(
mode: ParsedCli.main_theme_detection || ParsedCli.detection_mode
),
verbose: ParsedCli.verbose
)
end
end
end
end

View File

@@ -0,0 +1,127 @@
# frozen_string_literal: true
module WPScan
module Controller
# Password Attack Controller
class PasswordAttack < CMSScanner::Controller::Base
def cli_options
[
OptFilePath.new(
['--passwords FILE-PATH', '-P',
'List of passwords to use during the password attack.',
'If no --username/s option supplied, user enumeration will be run.'],
exists: true
),
OptSmartList.new(['--usernames LIST', '-U', 'List of usernames to use during the password attack.']),
OptInteger.new(['--multicall-max-passwords MAX_PWD',
'Maximum number of passwords to send by request with XMLRPC multicall'],
default: 500),
OptChoice.new(['--password-attack ATTACK',
'Force the supplied attack to be used rather than automatically determining one.'],
choices: %w[wp-login xmlrpc xmlrpc-multicall],
normalize: %i[downcase underscore to_sym])
]
end
def run
return unless ParsedCli.passwords
if user_interaction?
output('@info',
msg: "Performing password attack on #{attacker.titleize} against #{users.size} user/s")
end
attack_opts = {
show_progression: user_interaction?,
multicall_max_passwords: ParsedCli.multicall_max_passwords
}
begin
found = []
attacker.attack(users, passwords(ParsedCli.passwords), attack_opts) do |user|
found << user
attacker.progress_bar.log("[SUCCESS] - #{user.username} / #{user.password}")
end
ensure
output('users', users: found)
end
end
# @return [ CMSScanner::Finders::Finder ] The finder used to perform the attack
def attacker
@attacker ||= attacker_from_cli_options || attacker_from_automatic_detection
end
# @return [ Model::XMLRPC ]
def xmlrpc
@xmlrpc ||= target.xmlrpc
end
# @return [ CMSScanner::Finders::Finder ]
def attacker_from_cli_options
return unless ParsedCli.password_attack
case ParsedCli.password_attack
when :wp_login
Finders::Passwords::WpLogin.new(target)
when :xmlrpc
raise Error::XMLRPCNotDetected unless xmlrpc
Finders::Passwords::XMLRPC.new(xmlrpc)
when :xmlrpc_multicall
raise Error::XMLRPCNotDetected unless xmlrpc
Finders::Passwords::XMLRPCMulticall.new(xmlrpc)
end
end
# @return [ Boolean ]
def xmlrpc_get_users_blogs_enabled?
if xmlrpc&.enabled? &&
xmlrpc.available_methods.include?('wp.getUsersBlogs') &&
xmlrpc.method_call('wp.getUsersBlogs', [SecureRandom.hex[0, 6], SecureRandom.hex[0, 4]])
.run.body !~ /XML\-RPC services are disabled/
true
else
false
end
end
# @return [ CMSScanner::Finders::Finder ]
def attacker_from_automatic_detection
if xmlrpc_get_users_blogs_enabled?
wp_version = target.wp_version
if wp_version && wp_version < '4.4'
Finders::Passwords::XMLRPCMulticall.new(xmlrpc)
else
Finders::Passwords::XMLRPC.new(xmlrpc)
end
else
Finders::Passwords::WpLogin.new(target)
end
end
# @return [ Array<Users> ] The users to brute force
def users
return target.users unless ParsedCli.usernames
ParsedCli.usernames.reduce([]) do |acc, elem|
acc << Model::User.new(elem.chomp)
end
end
# @param [ String ] wordlist_path
#
# @return [ Array<String> ]
def passwords(wordlist_path)
@passwords ||= File.open(wordlist_path).reduce([]) do |acc, elem|
acc << elem.chomp
end
end
end
end
end

View File

@@ -0,0 +1,30 @@
# frozen_string_literal: true
module WPScan
module Controller
# Controller to handle the API token
class VulnApi < CMSScanner::Controller::Base
def cli_options
[
OptString.new(['--api-token TOKEN', 'The WPVulnDB API Token to display vulnerability data'])
]
end
def before_scan
return unless ParsedCli.api_token
DB::VulnApi.token = ParsedCli.api_token
api_status = DB::VulnApi.status
raise Error::InvalidApiToken if api_status['error']
raise Error::ApiLimitReached if api_status['requests_remaining'] == 0
raise api_status['http_error'] if api_status['http_error']
end
def after_scan
output('status', status: DB::VulnApi.status, api_requests: WPScan.api_requests)
end
end
end
end

View File

@@ -0,0 +1,35 @@
# frozen_string_literal: true
module WPScan
module Controller
# Wp Version Controller
class WpVersion < CMSScanner::Controller::Base
def cli_options
[
OptBoolean.new(['--wp-version-all', 'Check all the version locations'], advanced: true),
OptChoice.new(
['--wp-version-detection MODE',
'Use the supplied mode for the WordPress version detection, ' \
'instead of the global (--detection-mode) mode.'],
choices: %w[mixed passive aggressive], normalize: :to_sym, advanced: true
)
]
end
def before_scan
DB::DynamicFinders::Wordpress.create_versions_finders
end
def run
output(
'version',
version: target.wp_version(
mode: ParsedCli.wp_version_detection || ParsedCli.detection_mode,
confidence_threshold: ParsedCli.wp_version_all ? 0 : 100,
show_progression: user_interaction?
)
)
end
end
end
end

17
app/finders.rb Normal file
View File

@@ -0,0 +1,17 @@
# frozen_string_literal: true
require_relative 'finders/interesting_findings'
require_relative 'finders/wp_items'
require_relative 'finders/wp_version'
require_relative 'finders/main_theme'
require_relative 'finders/timthumb_version'
require_relative 'finders/timthumbs'
require_relative 'finders/config_backups'
require_relative 'finders/db_exports'
require_relative 'finders/medias'
require_relative 'finders/users'
require_relative 'finders/plugins'
require_relative 'finders/plugin_version'
require_relative 'finders/theme_version'
require_relative 'finders/themes'
require_relative 'finders/passwords'

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'config_backups/known_filenames'
module WPScan
module Finders
module ConfigBackups
# Config Backup Finder
class Base
include CMSScanner::Finders::SameTypeFinder
# @param [ WPScan::Target ] target
def initialize(target)
finders << ConfigBackups::KnownFilenames.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,47 @@
# frozen_string_literal: true
module WPScan
module Finders
module ConfigBackups
# Config Backup finder
class KnownFilenames < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::Enumerator
# @param [ Hash ] opts
# @option opts [ String ] :list
# @option opts [ Boolean ] :show_progression
#
# @return [ Array<ConfigBackup> ]
def aggressive(opts = {})
found = []
enumerate(potential_urls(opts), opts.merge(check_full_response: 200)) do |res|
next unless res.body =~ /define/i && res.body !~ /<\s?html/i
found << Model::ConfigBackup.new(res.request.url, found_by: DIRECT_ACCESS, confidence: 100)
end
found
end
# @param [ Hash ] opts
# @option opts [ String ] :list Mandatory
#
# @return [ Hash ]
def potential_urls(opts = {})
urls = {}
File.open(opts[:list]).each_with_index do |file, index|
urls[target.url(file.chomp)] = index
end
urls
end
def create_progress_bar(opts = {})
super(opts.merge(title: ' Checking Config Backups -'))
end
end
end
end
end

19
app/finders/db_exports.rb Normal file
View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'db_exports/known_locations'
module WPScan
module Finders
module DbExports
# DB Exports Finder
class Base
include CMSScanner::Finders::SameTypeFinder
# @param [ WPScan::Target ] target
def initialize(target)
finders << DbExports::KnownLocations.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,61 @@
# frozen_string_literal: true
module WPScan
module Finders
module DbExports
# DB Exports finder
# See https://github.com/wpscanteam/wpscan-v3/issues/62
class KnownLocations < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::Enumerator
SQL_PATTERN = /(?:DROP|(?:UN)?LOCK|CREATE) TABLE|INSERT INTO/.freeze
# @param [ Hash ] opts
# @option opts [ String ] :list
# @option opts [ Boolean ] :show_progression
#
# @return [ Array<DBExport> ]
def aggressive(opts = {})
found = []
enumerate(potential_urls(opts), opts.merge(check_full_response: 200)) do |res|
if res.effective_url.end_with?('.zip')
next unless %r{\Aapplication/zip}i.match?(res.headers['Content-Type'])
else
next unless SQL_PATTERN.match?(res.body)
end
found << Model::DbExport.new(res.request.url, found_by: DIRECT_ACCESS, confidence: 100)
end
found
end
def full_request_params
@full_request_params ||= { headers: { 'Range' => 'bytes=0-3000' } }
end
# @param [ Hash ] opts
# @option opts [ String ] :list Mandatory
#
# @return [ Hash ]
def potential_urls(opts = {})
urls = {}
domain_name = target.uri.host[/(^[\w|-]+)/, 1]
File.open(opts[:list]).each_with_index do |path, index|
path.gsub!('{domain_name}', domain_name)
urls[target.url(path.chomp)] = index
end
urls
end
def create_progress_bar(opts = {})
super(opts.merge(title: ' Checking DB Exports -'))
end
end
end
end
end

View File

@@ -0,0 +1,37 @@
# frozen_string_literal: true
require_relative 'interesting_findings/readme'
require_relative 'interesting_findings/wp_cron'
require_relative 'interesting_findings/multisite'
require_relative 'interesting_findings/debug_log'
require_relative 'interesting_findings/backup_db'
require_relative 'interesting_findings/mu_plugins'
require_relative 'interesting_findings/registration'
require_relative 'interesting_findings/tmm_db_migrate'
require_relative 'interesting_findings/upload_sql_dump'
require_relative 'interesting_findings/full_path_disclosure'
require_relative 'interesting_findings/duplicator_installer_log'
require_relative 'interesting_findings/upload_directory_listing'
require_relative 'interesting_findings/emergency_pwd_reset_script'
module WPScan
module Finders
module InterestingFindings
# Interesting Files Finder
class Base < CMSScanner::Finders::InterestingFindings::Base
# @param [ WPScan::Target ] target
def initialize(target)
super(target)
%w[
Readme DebugLog FullPathDisclosure BackupDB DuplicatorInstallerLog
Multisite MuPlugins Registration UploadDirectoryListing TmmDbMigrate
UploadSQLDump EmergencyPwdResetScript WPCron
].each do |f|
finders << InterestingFindings.const_get(f).new(target)
end
end
end
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# BackupDB finder
class BackupDB < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
path = 'wp-content/backup-db/'
res = target.head_and_get(path, [200, 403])
return unless [200, 403].include?(res.code) && !target.homepage_or_404?(res)
Model::BackupDB.new(
target.url(path),
confidence: 70,
found_by: DIRECT_ACCESS,
interesting_entries: target.directory_listing_entries(path),
references: { url: 'https://github.com/wpscanteam/wpscan/issues/422' }
)
end
end
end
end
end

View File

@@ -0,0 +1,23 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# debug.log finder
class DebugLog < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
path = 'wp-content/debug.log'
return unless target.debug_log?(path)
Model::DebugLog.new(
target.url(path),
confidence: 100, found_by: DIRECT_ACCESS,
references: { url: 'https://codex.wordpress.org/Debugging_in_WordPress' }
)
end
end
end
end
end

View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# DuplicatorInstallerLog finder
class DuplicatorInstallerLog < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
path = 'installer-log.txt'
return unless /DUPLICATOR INSTALL-LOG/.match?(target.head_and_get(path).body)
Model::DuplicatorInstallerLog.new(
target.url(path),
confidence: 100,
found_by: DIRECT_ACCESS,
references: { url: 'https://www.exploit-db.com/ghdb/3981/' }
)
end
end
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# Emergency Password Reset Script finder
class EmergencyPwdResetScript < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
path = 'emergency.php'
res = target.head_and_get(path)
return unless res.code == 200 && !target.homepage_or_404?(res)
Model::EmergencyPwdResetScript.new(
target.url(path),
confidence: /password/i.match?(res.body) ? 100 : 40,
found_by: DIRECT_ACCESS,
references: {
url: 'https://codex.wordpress.org/Resetting_Your_Password#Using_the_Emergency_Password_Reset_Script'
}
)
end
end
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# Full Path Disclosure finder
class FullPathDisclosure < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
path = 'wp-includes/rss-functions.php'
fpd_entries = target.full_path_disclosure_entries(path)
return if fpd_entries.empty?
Model::FullPathDisclosure.new(
target.url(path),
confidence: 100,
found_by: DIRECT_ACCESS,
interesting_entries: fpd_entries,
references: { url: 'https://www.owasp.org/index.php/Full_Path_Disclosure' }
)
end
end
end
end
end

View File

@@ -0,0 +1,51 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# Must Use Plugins Directory checker
class MuPlugins < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def passive(_opts = {})
pattern = %r{#{target.content_dir}/mu\-plugins/}i
target.in_scope_uris(target.homepage_res) do |uri|
next unless uri.path&.match?(pattern)
url = target.url('wp-content/mu-plugins/')
target.mu_plugins = true
return Model::MuPlugins.new(
url,
confidence: 70,
found_by: 'URLs In Homepage (Passive Detection)',
to_s: "This site has 'Must Use Plugins': #{url}",
references: { url: 'http://codex.wordpress.org/Must_Use_Plugins' }
)
end
nil
end
# @return [ InterestingFinding ]
def aggressive(_opts = {})
url = target.url('wp-content/mu-plugins/')
res = Browser.get_and_follow_location(url)
return unless [200, 401, 403].include?(res.code)
return if target.homepage_or_404?(res)
target.mu_plugins = true
Model::MuPlugins.new(
url,
confidence: 80,
found_by: DIRECT_ACCESS,
to_s: "This site has 'Must Use Plugins': #{url}",
references: { url: 'http://codex.wordpress.org/Must_Use_Plugins' }
)
end
end
end
end
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# Multisite checker
class Multisite < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
url = target.url('wp-signup.php')
res = Browser.get(url)
location = res.headers_hash['location']
return unless [200, 302].include?(res.code)
return if res.code == 302 && location =~ /wp-login\.php\?action=register/
return unless res.code == 200 || res.code == 302 && location =~ /wp-signup\.php/
target.multisite = true
Model::Multisite.new(
url,
confidence: 100,
found_by: DIRECT_ACCESS,
to_s: 'This site seems to be a multisite',
references: { url: 'http://codex.wordpress.org/Glossary#Multisite' }
)
end
end
end
end
end

View File

@@ -0,0 +1,28 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# Readme.html finder
class Readme < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
potential_files.each do |path|
res = target.head_and_get(path)
next unless res.code == 200 && res.body =~ /wordpress/i
return Model::Readme.new(target.url(path), confidence: 100, found_by: DIRECT_ACCESS)
end
nil
end
# @retun [ Array<String> ] The list of potential readme files
def potential_files
%w[readme.html olvasdel.html lisenssi.html liesmich.html]
end
end
end
end
end

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# Registration Enabled checker
class Registration < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def passive(_opts = {})
# Maybe check in the homepage if there is the registration url ?
end
# @return [ InterestingFinding ]
def aggressive(_opts = {})
res = Browser.get_and_follow_location(target.registration_url)
return unless res.code == 200
return if res.html.css('form#setupform').empty? &&
res.html.css('form#registerform').empty?
target.registration_enabled = true
Model::Registration.new(
res.effective_url,
confidence: 100,
found_by: DIRECT_ACCESS,
to_s: "Registration is enabled: #{res.effective_url}"
)
end
end
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# Tmm DB Migrate finder
class TmmDbMigrate < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
path = 'wp-content/uploads/tmm_db_migrate/tmm_db_migrate.zip'
url = target.url(path)
res = browser.forge_request(url, target.head_or_get_request_params).run
return unless res.code == 200 && res.headers['Content-Type'] =~ %r{\Aapplication/zip}i
Model::TmmDbMigrate.new(
url,
confidence: 100,
found_by: DIRECT_ACCESS,
references: { packetstorm: 131_957 }
)
end
end
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# UploadDirectoryListing finder
class UploadDirectoryListing < CMSScanner::Finders::Finder
# @return [ InterestingFinding ]
def aggressive(_opts = {})
path = 'wp-content/uploads/'
return unless target.directory_listing?(path)
url = target.url(path)
Model::UploadDirectoryListing.new(
url,
confidence: 100,
found_by: DIRECT_ACCESS,
to_s: "Upload directory has listing enabled: #{url}"
)
end
end
end
end
end

View File

@@ -0,0 +1,26 @@
# frozen_string_literal: true
module WPScan
module Finders
module InterestingFindings
# UploadSQLDump finder
class UploadSQLDump < CMSScanner::Finders::Finder
SQL_PATTERN = /(?:DROP|CREATE|(?:UN)?LOCK) TABLE|INSERT INTO/.freeze
# @return [ InterestingFinding ]
def aggressive(_opts = {})
path = 'wp-content/uploads/dump.sql'
res = target.head_and_get(path, [200], get: { headers: { 'Range' => 'bytes=0-3000' } })
return unless SQL_PATTERN.match?(res.body)
Model::UploadSQLDump.new(
target.url(path),
confidence: 100,
found_by: DIRECT_ACCESS
)
end
end
end
end
end

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
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
Model::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

24
app/finders/main_theme.rb Normal file
View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
require_relative 'main_theme/css_style'
require_relative 'main_theme/woo_framework_meta_generator'
require_relative 'main_theme/urls_in_homepage'
module WPScan
module Finders
module MainTheme
# Main Theme Finder
class Base
include CMSScanner::Finders::UniqueFinder
# @param [ WPScan::Target ] target
def initialize(target)
finders <<
MainTheme::CssStyle.new(target) <<
MainTheme::WooFrameworkMetaGenerator.new(target) <<
MainTheme::UrlsInHomepage.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,45 @@
# frozen_string_literal: true
module WPScan
module Finders
module MainTheme
# From the css style
class CssStyle < CMSScanner::Finders::Finder
include Finders::WpItems::URLsInHomepage
def create_theme(slug, style_url, opts)
Model::Theme.new(
slug,
target,
opts.merge(found_by: found_by, confidence: 70, style_url: style_url)
)
end
def passive(opts = {})
passive_from_css_href(target.homepage_res, opts) || passive_from_style_code(target.homepage_res, opts)
end
def passive_from_css_href(res, opts)
target.in_scope_uris(res, '//style/@src|//link/@href') do |uri|
next unless uri.path =~ %r{/themes/([^\/]+)/style.css\z}i
return create_theme(Regexp.last_match[1], uri.to_s, opts)
end
nil
end
def passive_from_style_code(res, opts)
res.html.css('style').each do |tag|
code = tag.text.to_s
next if code.empty?
next unless code =~ %r{#{item_code_pattern('themes')}\\?/style\.css[^"'\( ]*}i
return create_theme(Regexp.last_match[1], Regexp.last_match[0].strip, opts)
end
nil
end
end
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
module WPScan
module Finders
module MainTheme
# URLs In Homepage Finder
class UrlsInHomepage < CMSScanner::Finders::Finder
include WpItems::URLsInHomepage
# @param [ Hash ] opts
#
# @return [ Array<Theme> ]
def passive(opts = {})
found = []
slugs = items_from_links('themes', false) + items_from_codes('themes', false)
slugs.each_with_object(Hash.new(0)) { |slug, counts| counts[slug] += 1 }.each do |slug, occurences|
found << Model::Theme.new(slug, target, opts.merge(found_by: found_by, confidence: 2 * occurences))
end
found
end
end
end
end
end

View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
module WPScan
module Finders
module MainTheme
# From the WooFramework meta generators
class WooFrameworkMetaGenerator < CMSScanner::Finders::Finder
THEME_PATTERN = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?"\s+/?>}.freeze
FRAMEWORK_PATTERN = %r{<meta name="generator" content="WooFramework\s?([^"]+)?"\s+/?>}.freeze
PATTERN = /#{THEME_PATTERN}\s+#{FRAMEWORK_PATTERN}/i.freeze
def passive(opts = {})
return unless target.homepage_res.body =~ PATTERN
Model::Theme.new(
Regexp.last_match[1],
target,
opts.merge(found_by: found_by, confidence: 80)
)
end
end
end
end
end

19
app/finders/medias.rb Normal file
View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'medias/attachment_brute_forcing'
module WPScan
module Finders
module Medias
# Medias Finder
class Base
include CMSScanner::Finders::SameTypeFinder
# @param [ WPScan::Target ] target
def initialize(target)
finders << Medias::AttachmentBruteForcing.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,46 @@
# frozen_string_literal: true
module WPScan
module Finders
module Medias
# Medias Finder, see https://github.com/wpscanteam/wpscan/issues/172
class AttachmentBruteForcing < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::Enumerator
# @param [ Hash ] opts
# @option opts [ Range ] :range Mandatory
#
# @return [ Array<Media> ]
def aggressive(opts = {})
found = []
enumerate(target_urls(opts), opts) do |res|
next unless res.code == 200
found << Model::Media.new(res.effective_url, opts.merge(found_by: found_by, confidence: 100))
end
found
end
# @param [ Hash ] opts
# @option opts [ Range ] :range Mandatory
#
# @return [ Hash ]
def target_urls(opts = {})
urls = {}
opts[:range].each do |id|
urls[target.uri.join("?attachment_id=#{id}").to_s] = id
end
urls
end
def create_progress_bar(opts = {})
super(opts.merge(title: ' Brute Forcing Attachment IDs -'))
end
end
end
end
end

5
app/finders/passwords.rb Normal file
View File

@@ -0,0 +1,5 @@
# frozen_string_literal: true
require_relative 'passwords/wp_login'
require_relative 'passwords/xml_rpc'
require_relative 'passwords/xml_rpc_multicall'

View File

@@ -0,0 +1,25 @@
# frozen_string_literal: true
module WPScan
module Finders
module Passwords
# Password attack against the wp-login.php
class WpLogin < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::BreadthFirstDictionaryAttack
def login_request(username, password)
target.login_request(username, password)
end
def valid_credentials?(response)
response.code == 302 &&
[*response.headers['Set-Cookie']]&.any? { |cookie| cookie =~ /wordpress_logged_in_/i }
end
def errored_response?(response)
response.code != 200 && response.body !~ /login_error/i
end
end
end
end
end

View File

@@ -0,0 +1,24 @@
# frozen_string_literal: true
module WPScan
module Finders
module Passwords
# Password attack against the XMLRPC interface
class XMLRPC < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::BreadthFirstDictionaryAttack
def login_request(username, password)
target.method_call('wp.getUsersBlogs', [username, password], cache_ttl: 0)
end
def valid_credentials?(response)
response.code == 200 && response.body =~ /blogName/
end
def errored_response?(response)
response.code != 200 && response.body !~ /login_error/i
end
end
end
end
end

View File

@@ -0,0 +1,104 @@
# frozen_string_literal: true
module WPScan
module Finders
module Passwords
# Password attack against the XMLRPC interface with the multicall method
# WP < 4.4 is vulnerable to such attack
class XMLRPCMulticall < CMSScanner::Finders::Finder
# @param [ Array<User> ] users
# @param [ Array<String> ] passwords
#
# @return [ Typhoeus::Response ]
def do_multi_call(users, passwords)
methods = []
users.each do |user|
passwords.each do |password|
methods << ['wp.getUsersBlogs', user.username, password]
end
end
target.multi_call(methods, cache_ttl: 0).run
end
# @param [ Array<Model::User> ] users
# @param [ Array<String> ] passwords
# @param [ Hash ] opts
# @option opts [ Boolean ] :show_progression
# @option opts [ Integer ] :multicall_max_passwords
#
# @yield [ Model::User ] When a valid combination is found
#
# TODO: Make rubocop happy about metrics etc
#
# rubocop:disable all
def attack(users, passwords, opts = {})
wordlist_index = 0
max_passwords = opts[:multicall_max_passwords]
current_passwords_size = passwords_size(max_passwords, users.size)
create_progress_bar(total: (passwords.size / current_passwords_size.round(1)).ceil,
show_progression: opts[:show_progression])
loop do
current_users = users.select { |user| user.password.nil? }
current_passwords = passwords[wordlist_index, current_passwords_size]
wordlist_index += current_passwords_size
break if current_users.empty? || current_passwords.nil? || current_passwords.empty?
res = do_multi_call(current_users, current_passwords)
progress_bar.increment
check_and_output_errors(res)
# Avoid to parse the response and iterate over all the structs in the document
# if there isn't any tag matching a valid combination
next unless res.body =~ /isAdmin/ # maybe a better one ?
Nokogiri::XML(res.body).xpath('//struct').each_with_index do |struct, index|
next if struct.text =~ /faultCode/
user = current_users[index / current_passwords.size]
user.password = current_passwords[index % current_passwords.size]
yield user
# Updates the current_passwords_size and progress_bar#total
# given that less requests will be done due to a valid combination found.
current_passwords_size = passwords_size(max_passwords, current_users.size - 1)
if current_passwords_size == 0
progress_bar.log('All Found') # remove ?
progress_bar.stop
break
end
progress_bar.total = progress_bar.progress + ((passwords.size - wordlist_index) / current_passwords_size.round(1)).ceil
end
end
# Maybe a progress_bar.stop ?
end
# rubocop:disable all
def passwords_size(max_passwords, users_size)
return 1 if max_passwords < users_size
return 0 if users_size == 0
max_passwords / users_size
end
# @param [ Typhoeus::Response ] res
def check_and_output_errors(res)
progress_bar.log("Incorrect response: #{res.code} / #{res.return_message}") unless res.code == 200
progress_bar.log('Parsing error, might be caused by a too high --max-passwords value (such as >= 2k)') if res.body =~ /parse error. not well formed/i
progress_bar.log('The requested method is not supported') if res.body =~ /requested method [^ ]+ does not exist/i
end
end
end
end
end

View File

@@ -0,0 +1,30 @@
# frozen_string_literal: true
require_relative 'plugin_version/readme'
module WPScan
module Finders
module PluginVersion
# Plugin Version Finder
class Base
include CMSScanner::Finders::UniqueFinder
# @param [ Model::Plugin ] plugin
def initialize(plugin)
finders << PluginVersion::Readme.new(plugin)
create_and_load_dynamic_versions_finders(plugin)
end
# Create the dynamic version finders related to the plugin and register them
#
# @param [ Model::Plugin ] plugin
def create_and_load_dynamic_versions_finders(plugin)
DB::DynamicFinders::Plugin.create_versions_finders(plugin.slug).each do |finder|
finders << finder.new(plugin)
end
end
end
end
end
end

View File

@@ -0,0 +1,83 @@
# frozen_string_literal: true
module WPScan
module Finders
module PluginVersion
# Plugin Version Finder from the readme.txt file
class Readme < CMSScanner::Finders::Finder
# @return [ Version ]
def aggressive(_opts = {})
found_by_msg = 'Readme - %s (Aggressive Detection)'
# The target(plugin)#readme_url can't be used directly here
# as if the --detection-mode is passive, it will always return nil
target.potential_readme_filenames.each do |file|
res = target.head_and_get(file)
next unless res.code == 200 && !(numbers = version_numbers(res.body)).empty?
return numbers.reduce([]) do |a, e|
a << Model::Version.new(
e[0],
found_by: format(found_by_msg, e[1]),
confidence: e[2],
interesting_entries: [res.effective_url]
)
end
end
nil
end
# @return [ Array<String, String, Integer> ] number, found_by, confidence
def version_numbers(body)
numbers = []
if (number = from_stable_tag(body))
numbers << [number, 'Stable Tag', 80]
end
if (number = from_changelog_section(body))
numbers << [number, 'ChangeLog Section', 50]
end
numbers
end
# @param [ String ] body
#
# @return [ String, nil ] The version number detected from the stable tag
def from_stable_tag(body)
return unless body =~ /\b(?:stable tag|version):\s*(?!trunk)([0-9a-z\.-]+)/i
number = Regexp.last_match[1]
number if /[0-9]+/.match?(number)
end
# @param [ String ] body
#
# @return [ String, nil ] The best version number detected from the changelog section
def from_changelog_section(body)
extracted_versions = body.scan(%r{[=]+\s+(?:v(?:ersion)?\s*)?([0-9\.-]+)[ \ta-z0-9\(\)\.\-\/]*[=]+}i)
return if extracted_versions.nil? || extracted_versions.empty?
extracted_versions.flatten!
# must contain at least one number
extracted_versions = extracted_versions.select { |x| x =~ /[0-9]+/ }
sorted = extracted_versions.sort do |x, y|
begin
Gem::Version.new(x) <=> Gem::Version.new(y)
rescue StandardError
0
end
end
sorted.last
end
end
end
end
end

35
app/finders/plugins.rb Normal file
View File

@@ -0,0 +1,35 @@
# frozen_string_literal: true
require_relative 'plugins/urls_in_homepage'
require_relative 'plugins/known_locations'
# From the DynamicFinders
require_relative 'plugins/comment'
require_relative 'plugins/xpath'
require_relative 'plugins/header_pattern'
require_relative 'plugins/body_pattern'
require_relative 'plugins/javascript_var'
require_relative 'plugins/query_parameter'
require_relative 'plugins/config_parser' # Not loaded below as not implemented
module WPScan
module Finders
module Plugins
# Plugins Finder
class Base
include CMSScanner::Finders::SameTypeFinder
# @param [ WPScan::Target ] target
def initialize(target)
finders <<
Plugins::UrlsInHomepage.new(target) <<
Plugins::HeaderPattern.new(target) <<
Plugins::Comment.new(target) <<
Plugins::Xpath.new(target) <<
Plugins::BodyPattern.new(target) <<
Plugins::JavascriptVar.new(target) <<
Plugins::KnownLocations.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,29 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# Plugins finder from Dynamic Finder 'BodyPattern'
class BodyPattern < Finders::DynamicFinder::WpItems::Finder
DEFAULT_CONFIDENCE = 30
# @param [ Hash ] opts The options from the #passive, #aggressive methods
# @param [ Typhoeus::Response ] response
# @param [ String ] slug
# @param [ String ] klass
# @param [ Hash ] config The related dynamic finder config hash
#
# @return [ Plugin ] The detected plugin in the response, related to the config
def process_response(opts, response, slug, klass, config)
return unless response.body&.match?(config['pattern'])
Model::Plugin.new(
slug,
target,
opts.merge(found_by: found_by(klass), confidence: config['confidence'] || DEFAULT_CONFIDENCE)
)
end
end
end
end
end

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# Plugins finder from the Dynamic Finder 'Comment'
class Comment < Finders::DynamicFinder::WpItems::Finder
DEFAULT_CONFIDENCE = 30
# @param [ Hash ] opts The options from the #passive, #aggressive methods
# @param [ Typhoeus::Response ] response
# @param [ String ] slug
# @param [ String ] klass
# @param [ Hash ] config The related dynamic finder config hash
#
# @return [ Plugin ] The detected plugin in the response, related to the config
def process_response(opts, response, slug, klass, config)
response.html.xpath(config['xpath'] || '//comment()').each do |node|
comment = node.text.to_s.strip
next unless comment&.match?(config['pattern'])
return Model::Plugin.new(
slug,
target,
opts.merge(found_by: found_by(klass), confidence: config['confidence'] || DEFAULT_CONFIDENCE)
)
end
end
end
end
end
end

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# Plugins finder from Dynamic Finder 'ConfigParser'
class ConfigParser < Finders::DynamicFinder::WpItems::Finder
DEFAULT_CONFIDENCE = 40
# @param [ Hash ] opts The options from the #passive, #aggressive methods
# @param [ Typhoeus::Response ] response
# @param [ String ] slug
# @param [ String ] klass
# @param [ Hash ] config The related dynamic finder config hash
#
# @return [ Plugin ] The detected plugin in the response, related to the config
def _process_response(_opts, _response, slug, klass, config)
#
# TODO. Currently not implemented, and not even loaded by the Finders, as this
# finder only has an aggressive method, which has been disabled (globally)
# when checking for plugins
#
Model::Plugin.new(
slug,
target,
opts.merge(found_by: found_by(klass), confidence: config['confidence'] || DEFAULT_CONFIDENCE)
)
end
end
end
end
end

View File

@@ -0,0 +1,43 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# Plugins finder from Dynamic Finder 'HeaderPattern'
class HeaderPattern < Finders::DynamicFinder::WpItems::Finder
DEFAULT_CONFIDENCE = 30
# @param [ Hash ] opts
#
# @return [ Array<Plugin> ]
def passive(opts = {})
found = []
headers = target.homepage_res.headers
return found if headers.empty?
DB::DynamicFinders::Plugin.passive_header_pattern_finder_configs.each do |slug, configs|
configs.each do |klass, config|
next unless headers[config['header']] && headers[config['header']].to_s =~ config['pattern']
found << Model::Plugin.new(
slug,
target,
opts.merge(found_by: found_by(klass), confidence: config['confidence'] || DEFAULT_CONFIDENCE)
)
end
end
found
end
# @param [ Hash ] opts
#
# @return [ nil ]
def aggressive(_opts = {})
# None
end
end
end
end
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# Plugins finder from the Dynamic Finder 'JavascriptVar'
class JavascriptVar < Finders::DynamicFinder::WpItems::Finder
DEFAULT_CONFIDENCE = 60
# @param [ Hash ] opts The options from the #passive, #aggressive methods
# @param [ Typhoeus::Response ] response
# @param [ String ] slug
# @param [ String ] klass
# @param [ Hash ] config The related dynamic finder config hash
#
# @return [ Plugin ] The detected plugin in the response, related to the config
def process_response(opts, response, slug, klass, config)
response.html.xpath(config['xpath'] || '//script[not(@src)]').each do |node|
next if config['pattern'] && !node.text.match(config['pattern'])
return Model::Plugin.new(
slug,
target,
opts.merge(found_by: found_by(klass), confidence: config['confidence'] || DEFAULT_CONFIDENCE)
)
end
end
end
end
end
end

View File

@@ -0,0 +1,52 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# Known Locations Plugins Finder
class KnownLocations < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::Enumerator
# @return [ Array<Integer> ]
def valid_response_codes
@valid_response_codes ||= [200, 401, 403, 500].freeze
end
# @param [ Hash ] opts
# @option opts [ String ] :list
#
# @return [ Array<Plugin> ]
def aggressive(opts = {})
found = []
enumerate(target_urls(opts), opts.merge(check_full_response: true)) do |_res, slug|
found << Model::Plugin.new(slug, target, opts.merge(found_by: found_by, confidence: 80))
raise Error::PluginsThresholdReached if opts[:threshold].positive? && found.size >= opts[:threshold]
end
found
end
# @param [ Hash ] opts
# @option opts [ String ] :list
#
# @return [ Hash ]
def target_urls(opts = {})
slugs = opts[:list] || DB::Plugins.vulnerable_slugs
urls = {}
slugs.each do |slug|
urls[target.plugin_url(slug)] = slug
end
urls
end
def create_progress_bar(opts = {})
super(opts.merge(title: ' Checking Known Locations -'))
end
end
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# Plugins finder from Dynamic Finder 'QueryParameter'
class QueryParameter < Finders::DynamicFinder::WpItems::Finder
DEFAULT_CONFIDENCE = 10
def passive(_opts = {})
# Handled by UrlsInHomePage, so no need to check this twice
end
# @param [ Hash ] opts The options from the #passive, #aggressive methods
# @param [ Typhoeus::Response ] response
# @param [ String ] slug
# @param [ String ] klass
# @param [ Hash ] config The related dynamic finder config hash
#
# @return [ Plugin ] The detected plugin in the response, related to the config
def process_response(opts, response, slug, klass, config)
# TODO: when a real case will be found
end
end
end
end
end

View File

@@ -0,0 +1,27 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# URLs In Homepage Finder
# Typically, the items detected from URLs like
# /wp-content/plugins/<slug>/
class UrlsInHomepage < CMSScanner::Finders::Finder
include WpItems::URLsInHomepage
# @param [ Hash ] opts
#
# @return [ Array<Plugin> ]
def passive(opts = {})
found = []
(items_from_links('plugins') + items_from_codes('plugins')).uniq.sort.each do |slug|
found << Model::Plugin.new(slug, target, opts.merge(found_by: found_by, confidence: 80))
end
found
end
end
end
end
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
module WPScan
module Finders
module Plugins
# Plugins finder from the Dynamic Finder 'Xpath'
class Xpath < Finders::DynamicFinder::WpItems::Finder
DEFAULT_CONFIDENCE = 40
# @param [ Hash ] opts The options from the #passive, #aggressive methods
# @param [ Typhoeus::Response ] response
# @param [ String ] slug
# @param [ String ] klass
# @param [ Hash ] config The related dynamic finder config hash
#
# @return [ Plugin ] The detected plugin in the response, related to the config
def process_response(opts, response, slug, klass, config)
response.html.xpath(config['xpath']).each do |node|
next if config['pattern'] && !node.text.match(config['pattern'])
return Model::Plugin.new(
slug,
target,
opts.merge(found_by: found_by(klass), confidence: config['confidence'] || DEFAULT_CONFIDENCE)
)
end
end
end
end
end
end

View File

@@ -0,0 +1,33 @@
# frozen_string_literal: true
require_relative 'theme_version/style'
require_relative 'theme_version/woo_framework_meta_generator'
module WPScan
module Finders
module ThemeVersion
# Theme Version Finder
class Base
include CMSScanner::Finders::UniqueFinder
# @param [ Model::Theme ] theme
def initialize(theme)
finders <<
ThemeVersion::Style.new(theme) <<
ThemeVersion::WooFrameworkMetaGenerator.new(theme)
create_and_load_dynamic_versions_finders(theme)
end
# Create the dynamic version finders related to the theme and register them
#
# @param [ Model::Theme ] theme
def create_and_load_dynamic_versions_finders(theme)
DB::DynamicFinders::Theme.create_versions_finders(theme.slug).each do |finder|
finders << finder.new(theme)
end
end
end
end
end
end

View File

@@ -0,0 +1,45 @@
# frozen_string_literal: true
module WPScan
module Finders
module ThemeVersion
# Theme Version Finder from the style.css file
class Style < CMSScanner::Finders::Finder
# @param [ Hash ] opts
#
# @return [ Version ]
def passive(_opts = {})
return unless cached_style?
style_version
end
# @param [ Hash ] opts
#
# @return [ Version ]
def aggressive(_opts = {})
return if cached_style?
style_version
end
# @return [ Boolean ]
def cached_style?
Typhoeus::Config.cache.get(browser.forge_request(target.style_url)) ? true : false
end
# @return [ Version ]
def style_version
return unless Browser.get(target.style_url).body =~ /Version:[\t ]*(?!trunk)([0-9a-z\.-]+)/i
Model::Version.new(
Regexp.last_match[1],
found_by: found_by,
confidence: 80,
interesting_entries: ["#{target.style_url}, Match: '#{Regexp.last_match}'"]
)
end
end
end
end
end

View File

@@ -0,0 +1,21 @@
# frozen_string_literal: true
module WPScan
module Finders
module ThemeVersion
# Theme Version Finder from the WooFramework generators
class WooFrameworkMetaGenerator < CMSScanner::Finders::Finder
# @param [ Hash ] opts
#
# @return [ Version ]
def passive(_opts = {})
return unless target.blog.homepage_res.body =~ Finders::MainTheme::WooFrameworkMetaGenerator::PATTERN
return unless Regexp.last_match[1] == target.slug
Model::Version.new(Regexp.last_match[2], found_by: found_by, confidence: 80)
end
end
end
end
end

22
app/finders/themes.rb Normal file
View File

@@ -0,0 +1,22 @@
# frozen_string_literal: true
require_relative 'themes/urls_in_homepage'
require_relative 'themes/known_locations'
module WPScan
module Finders
module Themes
# themes Finder
class Base
include CMSScanner::Finders::SameTypeFinder
# @param [ WPScan::Target ] target
def initialize(target)
finders <<
Themes::UrlsInHomepage.new(target) <<
Themes::KnownLocations.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,52 @@
# frozen_string_literal: true
module WPScan
module Finders
module Themes
# Known Locations Themes Finder
class KnownLocations < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::Enumerator
# @return [ Array<Integer> ]
def valid_response_codes
@valid_response_codes ||= [200, 401, 403, 500].freeze
end
# @param [ Hash ] opts
# @option opts [ String ] :list
#
# @return [ Array<Theme> ]
def aggressive(opts = {})
found = []
enumerate(target_urls(opts), opts.merge(check_full_response: true)) do |_res, slug|
found << Model::Theme.new(slug, target, opts.merge(found_by: found_by, confidence: 80))
raise Error::ThemesThresholdReached if opts[:threshold].positive? && found.size >= opts[:threshold]
end
found
end
# @param [ Hash ] opts
# @option opts [ String ] :list
#
# @return [ Hash ]
def target_urls(opts = {})
slugs = opts[:list] || DB::Themes.vulnerable_slugs
urls = {}
slugs.each do |slug|
urls[target.theme_url(slug)] = slug
end
urls
end
def create_progress_bar(opts = {})
super(opts.merge(title: ' Checking Known Locations -'))
end
end
end
end
end

View File

@@ -0,0 +1,25 @@
# frozen_string_literal: true
module WPScan
module Finders
module Themes
# URLs In Homepage Finder
class UrlsInHomepage < CMSScanner::Finders::Finder
include WpItems::URLsInHomepage
# @param [ Hash ] opts
#
# @return [ Array<Theme> ]
def passive(opts = {})
found = []
(items_from_links('themes') + items_from_codes('themes')).uniq.sort.each do |slug|
found << Model::Theme.new(slug, target, opts.merge(found_by: found_by, confidence: 80))
end
found
end
end
end
end
end

View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'timthumb_version/bad_request'
module WPScan
module Finders
module TimthumbVersion
# Timthumb Version Finder
class Base
include CMSScanner::Finders::UniqueFinder
# @param [ Model::Timthumb ] target
def initialize(target)
finders << TimthumbVersion::BadRequest.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,23 @@
# frozen_string_literal: true
module WPScan
module Finders
module TimthumbVersion
# Timthumb Version Finder from the body of a bad request
# See https://code.google.com/p/timthumb/source/browse/trunk/timthumb.php#435
class BadRequest < CMSScanner::Finders::Finder
# @return [ Version ]
def aggressive(_opts = {})
return unless Browser.get(target.url).body =~ /(TimThumb version\s*: ([^<]+))/
Model::Version.new(
Regexp.last_match[2],
found_by: 'Bad Request (Aggressive Detection)',
confidence: 90,
interesting_entries: ["#{target.url}, Match: '#{Regexp.last_match[1]}'"]
)
end
end
end
end
end

19
app/finders/timthumbs.rb Normal file
View File

@@ -0,0 +1,19 @@
# frozen_string_literal: true
require_relative 'timthumbs/known_locations'
module WPScan
module Finders
module Timthumbs
# Timthumbs Finder
class Base
include CMSScanner::Finders::SameTypeFinder
# @param [ WPScan::Target ] target
def initialize(target)
finders << Timthumbs::KnownLocations.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,65 @@
# frozen_string_literal: true
module WPScan
module Finders
module Timthumbs
# Known Locations Timthumbs Finder
# Note: A vulnerable version, 2.8.13 can be found here:
# https://github.com/GabrielGil/TimThumb/blob/980c3d6a823477761570475e8b83d3e9fcd2d7ae/timthumb.php
class KnownLocations < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::Enumerator
# @return [ Array<Integer> ]
def valid_response_codes
@valid_response_codes ||= [400]
end
# @param [ Hash ] opts
# @option opts [ String ] :list Mandatory
#
# @return [ Array<Timthumb> ]
def aggressive(opts = {})
found = []
enumerate(target_urls(opts), opts.merge(check_full_response: 400)) do |res|
next unless /no image specified/i.match?(res.body)
found << Model::Timthumb.new(res.request.url, opts.merge(found_by: found_by, confidence: 100))
end
found
end
# @param [ Hash ] opts
# @option opts [ String ] :list Mandatory
#
# @return [ Hash ]
def target_urls(opts = {})
urls = {}
File.open(opts[:list]).each_with_index do |path, index|
urls[target.url(path.chomp)] = index
end
# Add potential timthumbs located in the main theme
if target.main_theme
main_theme_timthumbs_paths.each do |path|
urls[target.main_theme.url(path)] = 1 # index not important there
end
end
urls
end
def main_theme_timthumbs_paths
%w[timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php
scripts/timthumb.php tools/timthumb.php functions/timthumb.php]
end
def create_progress_bar(opts = {})
super(opts.merge(title: ' Checking Known Locations -'))
end
end
end
end
end

32
app/finders/users.rb Normal file
View File

@@ -0,0 +1,32 @@
# frozen_string_literal: true
require_relative 'users/author_posts'
require_relative 'users/wp_json_api'
require_relative 'users/oembed_api'
require_relative 'users/rss_generator'
require_relative 'users/author_id_brute_forcing'
require_relative 'users/login_error_messages'
require_relative 'users/yoast_seo_author_sitemap.rb'
module WPScan
module Finders
module Users
# Users Finder
class Base
include CMSScanner::Finders::SameTypeFinder
# @param [ WPScan::Target ] target
def initialize(target)
finders <<
Users::AuthorPosts.new(target) <<
Users::WpJsonApi.new(target) <<
Users::OembedApi.new(target) <<
Users::RSSGenerator.new(target) <<
Users::YoastSeoAuthorSitemap.new(target) <<
Users::AuthorIdBruteForcing.new(target) <<
Users::LoginErrorMessages.new(target)
end
end
end
end
end

View File

@@ -0,0 +1,118 @@
# frozen_string_literal: true
module WPScan
module Finders
module Users
# Author Id Brute Forcing
class AuthorIdBruteForcing < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::Enumerator
# @return [ Array<Integer> ]
def valid_response_codes
@valid_response_codes ||= [200, 301, 302]
end
# @param [ Hash ] opts
# @option opts [ Range ] :range Mandatory
#
# @return [ Array<User> ]
def aggressive(opts = {})
found = []
found_by_msg = 'Author Id Brute Forcing - %s (Aggressive Detection)'
enumerate(target_urls(opts), opts.merge(check_full_response: true)) do |res, id|
username, found_by, confidence = potential_username(res)
next unless username
found << Model::User.new(
username,
id: id,
found_by: format(found_by_msg, found_by),
confidence: confidence
)
end
found
end
# @param [ Hash ] opts
# @option opts [ Range ] :range
#
# @return [ Hash ]
def target_urls(opts = {})
urls = {}
opts[:range].each do |id|
urls[target.uri.join("?author=#{id}").to_s] = id
end
urls
end
def create_progress_bar(opts = {})
super(opts.merge(title: ' Brute Forcing Author IDs -'))
end
def full_request_params
{ followlocation: true }
end
# @param [ Typhoeus::Response ] res
#
# @return [ Array<String, String, Integer>, nil ] username, found_by, confidence
def potential_username(res)
username = username_from_author_url(res.effective_url) || username_from_response(res)
return username, 'Author Pattern', 100 if username
username = display_name_from_body(res.body)
return username, 'Display Name', 50 if username
end
# @param [ String ] url
#
# @return [ String, nil ]
def username_from_author_url(url)
url[%r{/author/([^/\b]+)/?}i, 1]
end
# @param [ Typhoeus::Response ] res
#
# @return [ String, nil ] The username found
def username_from_response(res)
# Permalink enabled
target.in_scope_uris(res, '//link/@href|//a/@href') do |uri|
username = username_from_author_url(uri.to_s)
return username if username
end
# No permalink
res.body[/<body class="archive author author-([^\s]+)[ "]/i, 1]
end
# @param [ String ] body
#
# @return [ String, nil ]
def display_name_from_body(body)
page = Nokogiri::HTML.parse(body)
# WP >= 3.0
page.css('h1.page-title span').each do |node|
return node.text.to_s
end
# WP < 3.0
page.xpath('//link[@rel="alternate" and @type="application/rss+xml"]').each do |node|
title = node['title']
next unless title =~ /Posts by (.*) Feed\z/i
return Regexp.last_match[1] unless Regexp.last_match[1].empty?
end
nil
end
end
end
end
end

View File

@@ -0,0 +1,61 @@
# frozen_string_literal: true
module WPScan
module Finders
module Users
# Author Posts
class AuthorPosts < CMSScanner::Finders::Finder
# @param [ Hash ] opts
#
# @return [ Array<User> ]
def passive(opts = {})
found_by_msg = 'Author Posts - %s (Passive Detection)'
usernames(opts).reduce([]) do |a, e|
a << Model::User.new(
e[0],
found_by: format(found_by_msg, e[1]),
confidence: e[2]
)
end
end
# @param [ Hash ] opts
#
# @return [ Array<Array>> ]
def usernames(_opts = {})
found = potential_usernames(target.homepage_res)
return found unless found.empty?
target.homepage_res.html.css('header.entry-header a').each do |post_url_node|
url = post_url_node['href']
next if url.nil? || url.empty?
found += potential_usernames(Browser.get(url))
end
found.compact.uniq
end
# @param [ Typhoeus::Response ] res
#
# @return [ Array<Array> ]
def potential_usernames(res)
usernames = []
target.in_scope_uris(res, '//a/@href') do |uri, node|
if uri.path =~ %r{/author/([^/\b]+)/?\z}i
usernames << [Regexp.last_match[1], 'Author Pattern', 100]
elsif /author=[0-9]+/.match?(uri.query)
usernames << [node.text.to_s.strip, 'Display Name', 30]
end
end
usernames.uniq
end
end
end
end
end

View File

@@ -0,0 +1,47 @@
# frozen_string_literal: true
module WPScan
module Finders
module Users
# Login Error Messages
#
# Existing username:
# WP < 3.1 - Incorrect password.
# WP >= 3.1 - The password you entered for the username admin is incorrect.
# Non existent username: Invalid username.
#
class LoginErrorMessages < CMSScanner::Finders::Finder
# @param [ Hash ] opts
# @option opts [ String ] :list
#
# @return [ Array<User> ]
def aggressive(opts = {})
found = []
usernames(opts).each do |username|
res = target.do_login(username, SecureRandom.hex[0, 8])
error = res.html.css('div#login_error').text.strip
return found if error.empty? # Protection plugin / error disabled
next unless /The password you entered for the username|Incorrect Password/i.match?(error)
found << Model::User.new(username, found_by: found_by, confidence: 100)
end
found
end
# @return [ Array<String> ] List of usernames to check
def usernames(opts = {})
# usernames from the potential Users found
unames = opts[:found].map(&:username)
[*opts[:list]].each { |uname| unames << uname.chomp }
unames.uniq
end
end
end
end
end

View File

@@ -0,0 +1,57 @@
# frozen_string_literal: true
module WPScan
module Finders
module Users
# Since WP 4.4, the oembed API can disclose a user
# https://github.com/wpscanteam/wpscan/issues/1049
class OembedApi < CMSScanner::Finders::Finder
# @param [ Hash ] opts
#
# @return [ Array<User> ]
def passive(_opts = {})
# TODO: get the api_url from the Homepage and query it if present,
# then discard the aggressive check if same/similar URL
end
# @param [ Hash ] opts
#
# @return [ Array<User> ]
def aggressive(_opts = {})
oembed_data = JSON.parse(Browser.get(api_url).body)
details = user_details_from_oembed_data(oembed_data)
return [] unless details
[Model::User.new(details[0],
found_by: format(found_by_msg, details[1]),
confidence: details[2],
interesting_entries: [api_url])]
rescue JSON::ParserError
[]
end
def user_details_from_oembed_data(oembed_data)
return unless oembed_data
if oembed_data['author_url'] =~ %r{/author/([^/]+)/?\z}
details = [Regexp.last_match[1], 'Author URL', 90]
elsif oembed_data['author_name'] && !oembed_data['author_name'].empty?
details = [oembed_data['author_name'], 'Author Name', 70]
end
details
end
def found_by_msg
'Oembed API - %s (Aggressive Detection)'
end
# @return [ String ] The URL of the API listing the Users
def api_url
@api_url ||= target.url("wp-json/oembed/1.0/embed?url=#{target.url}&format=json")
end
end
end
end
end

View File

@@ -0,0 +1,46 @@
# frozen_string_literal: true
module WPScan
module Finders
module Users
# Users disclosed from the dc:creator field in the RSS
# The names disclosed are display names, however depending on the configuration of the blog,
# they can be the same than usernames
class RSSGenerator < Finders::WpVersion::RSSGenerator
def process_urls(urls, _opts = {})
found = []
urls.each do |url|
res = Browser.get_and_follow_location(url)
next unless res.code == 200 && res.body =~ /<dc\:creator>/i
potential_usernames = []
begin
res.xml.xpath('//item/dc:creator').each do |node|
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 username.strip.empty? || username.length > 60 || username =~ /[^\x00-\x7F]/
potential_usernames << username
end
rescue Nokogiri::XML::XPath::SyntaxError
next
end
potential_usernames.uniq.each do |username|
found << Model::User.new(username, found_by: found_by, confidence: 50)
end
break
end
found
end
end
end
end
end

View File

@@ -0,0 +1,69 @@
# frozen_string_literal: true
module WPScan
module Finders
module Users
# WP JSON API
#
# Since 4.7 - Need more investigation as it seems WP 4.7.1 reduces the exposure, see https://github.com/wpscanteam/wpscan/issues/1038)
# For the pagination, see https://github.com/wpscanteam/wpscan/issues/1285
#
class WpJsonApi < CMSScanner::Finders::Finder
MAX_PER_PAGE = 100 # See https://developer.wordpress.org/rest-api/using-the-rest-api/pagination/
# @param [ Hash ] opts
#
# @return [ Array<User> ]
def aggressive(_opts = {})
found = []
current_page = 0
loop do
current_page += 1
res = Typhoeus.get(api_url, params: { per_page: MAX_PER_PAGE, page: current_page })
total_pages ||= res.headers['X-WP-TotalPages'].to_i
users_in_page = users_from_response(res)
found += users_in_page
break if current_page >= total_pages || users_in_page.empty?
end
found
rescue JSON::ParserError, TypeError
found
end
# @param [ Typhoeus::Response ] response
#
# @return [ Array<User> ] The users from the response
def users_from_response(response)
found = []
JSON.parse(response.body)&.each do |user|
found << Model::User.new(user['slug'],
id: user['id'],
found_by: found_by,
confidence: 100,
interesting_entries: [response.effective_url])
end
found
end
# @return [ String ] The URL of the API listing the Users
def api_url
return @api_url if @api_url
target.in_scope_uris(target.homepage_res, "//link[@rel='https://api.w.org/']/@href").each do |uri|
return @api_url = uri.join('wp/v2/users/').to_s if uri.path.include?('wp-json')
end
@api_url = target.url('wp-json/wp/v2/users/')
end
end
end
end
end

View File

@@ -0,0 +1,36 @@
# frozen_string_literal: true
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 << Model::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
app/finders/wp_items.rb Normal file
View File

@@ -0,0 +1,3 @@
# frozen_string_literal: true
require_relative 'wp_items/urls_in_homepage'

View File

@@ -0,0 +1,70 @@
# frozen_string_literal: true
module WPScan
module Finders
module WpItems
# URLs In Homepage Module to use in plugins & themes finders
module URLsInHomepage
# @param [ String ] type plugins / themes
# @param [ Boolean ] uniq Wether or not to apply the #uniq on the results
#
# @return [Array<String> ] The plugins/themes detected in the href, src attributes of the homepage
def items_from_links(type, uniq = true)
found = []
target.in_scope_uris(target.homepage_res) do |uri|
next unless uri.to_s =~ item_attribute_pattern(type)
found << Regexp.last_match[1]
end
uniq ? found.uniq.sort : found.sort
end
# @param [ String ] type plugins / themes
# @param [ Boolean ] uniq Wether or not to apply the #uniq on the results
#
# @return [Array<String> ] The plugins/themes detected in the javascript/style of the homepage
def items_from_codes(type, uniq = true)
found = []
target.homepage_res.html.css('script,style').each do |tag|
code = tag.text.to_s
next if code.empty?
code.scan(item_code_pattern(type)).flatten.uniq.each { |slug| found << slug }
end
uniq ? found.uniq.sort : found.sort
end
# @param [ String ] type
#
# @return [ Regexp ]
def item_attribute_pattern(type)
@item_attribute_pattern ||= %r{\A#{item_url_pattern(type)}([^/]+)/}i
end
# @param [ String ] type
#
# @return [ Regexp ]
def item_code_pattern(type)
@item_code_pattern ||= %r{["'\( ]#{item_url_pattern(type)}([^\\\/\)"']+)}i
end
# @param [ String ] type
#
# @return [ Regexp ]
def item_url_pattern(type)
item_dir = type == 'plugins' ? target.plugins_dir : target.content_dir
item_url = type == 'plugins' ? target.plugins_url : target.content_url
url = /#{item_url.gsub(/\A(?:http|https)/i, 'https?').gsub('/', '\\\\\?\/')}/i
item_dir = %r{(?:#{url}|\\?\/#{item_dir.gsub('/', '\\\\\?\/')}\\?/)}i
type == 'plugins' ? item_dir : %r{#{item_dir}#{type}\\?\/}i
end
end
end
end
end

44
app/finders/wp_version.rb Normal file
View File

@@ -0,0 +1,44 @@
# frozen_string_literal: true
require_relative 'wp_version/rss_generator'
require_relative 'wp_version/atom_generator'
require_relative 'wp_version/rdf_generator'
require_relative 'wp_version/readme'
require_relative 'wp_version/unique_fingerprinting'
module WPScan
module Finders
# Specific Finders container to filter the version detected
# and remove the one with low confidence to avoid false
# positive when there is not enought information to accurately
# determine it.
class WpVersionFinders < UniqueFinders
def filter_findings
best_finding = super
best_finding && best_finding.confidence >= 40 ? best_finding : false
end
end
module WpVersion
# Wp Version Finder
class Base
include CMSScanner::Finders::UniqueFinder
# @param [ WPScan::Target ] target
def initialize(target)
(%w[RSSGenerator AtomGenerator RDFGenerator] +
DB::DynamicFinders::Wordpress.versions_finders_configs.keys +
%w[Readme UniqueFingerprinting]
).each do |finder_name|
finders << WpVersion.const_get(finder_name.to_sym).new(target)
end
end
def finders
@finders ||= Finders::WpVersionFinders.new
end
end
end
end
end

View File

@@ -0,0 +1,42 @@
# frozen_string_literal: true
module WPScan
module Finders
module WpVersion
# Atom Generator Version Finder
class AtomGenerator < CMSScanner::Finders::Finder
include Finder::WpVersion::SmartURLChecker
def process_urls(urls, _opts = {})
found = Findings.new
urls.each do |url|
res = Browser.get_and_follow_location(url)
res.html.css('generator').each do |node|
next unless node.text.to_s.strip.casecmp('wordpress').zero?
found << create_version(
node['version'],
found_by: found_by,
entries: ["#{res.effective_url}, #{node.to_s.strip}"]
)
end
end
found
end
def passive_urls_xpath
'//link[@rel="alternate" and @type="application/atom+xml"]/@href'
end
def aggressive_urls(_opts = {})
%w[feed/atom/ ?feed=atom].reduce([]) do |a, uri|
a << target.url(uri)
end
end
end
end
end
end

View File

@@ -0,0 +1,40 @@
# frozen_string_literal: true
module WPScan
module Finders
module WpVersion
# RDF Generator Version Finder
class RDFGenerator < CMSScanner::Finders::Finder
include Finder::WpVersion::SmartURLChecker
def process_urls(urls, _opts = {})
found = Findings.new
urls.each do |url|
res = Browser.get_and_follow_location(url)
res.html.xpath('//generatoragent').each do |node|
next unless node['rdf:resource'] =~ %r{\Ahttps?://wordpress\.(?:[a-z.]+)/\?v=(.*)\z}i
found << create_version(
Regexp.last_match[1],
found_by: found_by,
entries: ["#{res.effective_url}, #{node.to_s.strip}"]
)
end
end
found
end
def passive_urls_xpath
'//a[contains(@href, "rdf")]/@href'
end
def aggressive_urls(_opts = {})
[target.url('feed/rdf/')]
end
end
end
end
end

View File

@@ -0,0 +1,31 @@
# frozen_string_literal: true
module WPScan
module Finders
module WpVersion
# Readme Version Finder
class Readme < CMSScanner::Finders::Finder
# @return [ WpVersion ]
def aggressive(_opts = {})
readme_url = target.url('readme.html') # Maybe move this into the Target ?
node = Browser.get(readme_url).html.css('h1#logo').last
return unless node&.text.to_s.strip =~ /\AVersion (.*)\z/i
number = Regexp.last_match(1)
return unless Model::WpVersion.valid?(number)
Model::WpVersion.new(
number,
found_by: 'Readme (Aggressive Detection)',
# Since WP 4.7, the Readme only contains the major version (ie 4.7, 4.8 etc)
confidence: number >= '4.7' ? 10 : 90,
interesting_entries: ["#{readme_url}, Match: '#{node.text.to_s.strip}'"]
)
end
end
end
end
end

View File

@@ -0,0 +1,45 @@
# frozen_string_literal: true
module WPScan
module Finders
module WpVersion
# RSS Generator Version Finder
class RSSGenerator < CMSScanner::Finders::Finder
include Finder::WpVersion::SmartURLChecker
def process_urls(urls, _opts = {})
found = Findings.new
urls.each do |url|
res = Browser.get_and_follow_location(url)
res.html.xpath('//comment()[contains(., "wordpress")] | //generator').each do |node|
node_text = node.text.to_s.strip
next unless node_text =~ %r{\Ahttps?://wordpress\.(?:[a-z]+)/\?v=(.*)\z}i ||
node_text =~ %r{\Agenerator="wordpress/([^"]+)"\z}i
found << create_version(
Regexp.last_match[1],
found_by: found_by,
entries: ["#{res.effective_url}, #{node.to_s.strip}"]
)
end
end
found
end
def passive_urls_xpath
'//link[@rel="alternate" and @type="application/rss+xml"]/@href'
end
def aggressive_urls(_opts = {})
%w[feed/ comments/feed/ feed/rss/ feed/rss2/].reduce([]) do |a, uri|
a << target.url(uri)
end
end
end
end
end
end

View File

@@ -0,0 +1,32 @@
# frozen_string_literal: true
module WPScan
module Finders
module WpVersion
# Unique Fingerprinting Version Finder
class UniqueFingerprinting < CMSScanner::Finders::Finder
include CMSScanner::Finders::Finder::Fingerprinter
# @return [ WpVersion ]
def aggressive(opts = {})
fingerprint(DB::Fingerprints.wp_unique_fingerprints, opts) do |version_number, url, md5sum|
hydra.abort
progress_bar.finish
return Model::WpVersion.new(
version_number,
found_by: 'Unique Fingerprinting (Aggressive Detection)',
confidence: 100,
interesting_entries: ["#{url} md5sum is #{md5sum}"]
)
end
nil
end
def create_progress_bar(opts = {})
super(opts.merge(title: 'Fingerprinting the version -'))
end
end
end
end
end

Some files were not shown because too many files have changed in this diff Show More