Compare commits

..

302 Commits
2.9 ... v2

Author SHA1 Message Date
Erwan
3a94b8362a Delete Gemfile.lock 2020-07-28 11:35:45 +02:00
Ryan Dewhurst
a25b493064 Merge pull request #1211 from sudoaza/master
Fixing error on missformated rss
2018-09-19 13:17:17 +02:00
aza
2acf88d83e fixing error on missformated rss 2018-09-17 01:44:36 +02:00
Ryan Dewhurst
baf3b4bc2b Add command line gif 2018-08-30 15:09:49 +02:00
Ryan Dewhurst
750411d9e1 Add Patreon shield/badge 2018-08-24 15:40:44 +02:00
Christian Mehlmauer
aa7b922d30 gem update 2018-07-17 17:59:01 +02:00
Christian Mehlmauer
fd660632e0 Update version for dev branch 2018-06-18 07:46:23 +02:00
Ryan Dewhurst
c7df7265ab Ready for 2.9.4 release #1187 2018-06-15 09:40:06 +02:00
Ryan Dewhurst
42685a45b3 Missing space 2018-06-08 09:58:07 +02:00
Ryan Dewhurst
ce5d26a220 Enhacements to sql export code. Thanks to javiercasares for list. 2018-06-08 09:56:28 +02:00
Ryan Dewhurst
0e73774bd9 Add check for .sql backup files 2018-06-07 17:17:39 +02:00
Christian Mehlmauer
85b491472a revert, just a test 2018-05-30 23:35:19 +02:00
Christian Mehlmauer
4b382acbad change twitter handle 2018-05-30 23:32:46 +02:00
Ryan Dewhurst
12d15bfc7e Update data.zip file 2018-05-30 14:39:58 +02:00
Ryan Dewhurst
ea1b6b9c17 Update version information 2018-05-30 14:39:31 +02:00
Ryan Dewhurst
5cb2d16601 Remove Gemnasium as deprecated 2018-05-30 12:56:25 +02:00
Christian Mehlmauer
913717bcf7 update gems 2018-05-30 12:51:50 +02:00
Ryan Dewhurst
99fe1855d9 Output is not plugin specific 2018-05-23 14:54:34 +02:00
Ryan Dewhurst
e2eb94be22 Grammar 2018-05-23 14:46:28 +02:00
Ryan Dewhurst
aca1b487ba Remove spacer in output 2018-05-23 14:44:53 +02:00
Ryan Dewhurst
5820c53d0f More informative output 2018-05-23 14:32:04 +02:00
Christian Mehlmauer
9298758acd Merge pull request #1182 from g0tmi1k/users
Multiple Features
2018-05-22 12:40:52 +02:00
g0tmi1k
a981c2b17b @FireFart's suggestions 2018-05-22 10:06:57 +01:00
g0tmi1k
a783b53107 Fix grammar
..and bots
2018-05-15 11:17:03 +01:00
g0tmi1k
cf2881fda6 Fix bots issues?
...Happy now? Please?
2018-05-15 10:47:55 +01:00
g0tmi1k
59368a72bd Don't fail silent. 2018-05-15 10:39:16 +01:00
g0tmi1k
439900a1ea Misc fixes 2018-05-15 09:05:58 +01:00
g0tmi1k
44557797b0 Update data.zip location to be $HOME 2018-05-15 08:19:44 +01:00
g0tmi1k
ba065d5974 ...Removed too much fat. 2018-05-15 08:09:24 +01:00
g0tmi1k
105e9cbcac Sorted out .*ignore & *files + removed some fat 2018-05-15 07:52:40 +01:00
g0tmi1k
fe277c1e89 Make travis happy 2018-05-15 07:12:02 +01:00
g0tmi1k
b5e3e6280e Trying to make code climate happier 2018-05-14 18:08:42 +01:00
g0tmi1k
f90a64ce81 Tried to make code climate happy 2018-05-14 17:56:49 +01:00
g0tmi1k
b9fa1e3587 Misc fixes and typos 2018-05-14 16:37:14 +01:00
g0tmi1k
4333ecb989 Check for sitemaps (using /robots.txt) 2018-05-14 16:36:52 +01:00
g0tmi1k
715d3d4ad6 Moved http response to a function 2018-05-14 16:35:41 +01:00
g0tmi1k
38f70a88ae Follow any redirections (e.g. http -> https) 2018-05-14 16:17:12 +01:00
g0tmi1k
4b4b968710 Check HTTP status of each value in /robots.txt 2018-05-14 15:57:33 +01:00
g0tmi1k
3b94fc49a7 Fix EOL issue when checking /robots.txt 2018-05-14 15:12:35 +01:00
g0tmi1k
e41aab3a80 Re-worked off-line update only as a fall back (when possible) 2018-05-14 15:12:20 +01:00
g0tmi1k
9450ba6cc5 Add RSS author information 2018-05-14 13:44:02 +01:00
g0tmi1k
ae3c164350 Improved API output results 2018-05-14 13:43:49 +01:00
g0tmi1k
24e6820a90 Clean up wording 2018-05-14 13:43:33 +01:00
g0tmi1k
0e05f77fb7 Made offline extraction more verbose 2018-05-14 13:37:34 +01:00
g0tmi1k
de960ff9db Fix offline extraction zip bug 2018-05-11 18:18:19 +01:00
g0tmi1k
1d0128af72 Move spacer to a function 2018-05-11 18:07:57 +01:00
g0tmi1k
285b1a1733 Cleaner output and fix a typo 2018-05-11 17:10:02 +01:00
g0tmi1k
ab67816dd9 Check for API access and /wp-json/'s users output 2018-05-11 17:01:06 +01:00
g0tmi1k
fea6665876 Re-order output around slightly 2018-05-11 16:59:25 +01:00
g0tmi1k
6cbc8c9924 Clean up some output confusion 2018-05-11 16:58:47 +01:00
g0tmi1k
f542a50213 Remove debug statement 2018-05-11 12:24:11 +01:00
g0tmi1k
fa430606ce Move the last item to ~/.wpscan/ 2018-05-11 11:25:18 +01:00
g0tmi1k
05d27c64be Check location before using them 2018-05-11 11:21:14 +01:00
g0tmi1k
0cd680bb29 Add dev information to file locations 2018-05-11 11:20:58 +01:00
g0tmi1k
ced94a7338 Fix up .gitignore 2018-05-11 11:20:20 +01:00
g0tmi1k
b65a4d0a60 Fix up gemfile 2018-05-11 11:20:03 +01:00
g0tmi1k
2b85b44bd1 Add offline database update support 2018-05-11 11:19:51 +01:00
g0tmi1k
991c87a89e Fix inconsistencies with line endings 2018-05-09 16:35:54 +01:00
g0tmi1k
37a72f0c72 Add /.well-known/security.txt check
See https://securitytxt.org/
2018-05-09 16:34:30 +01:00
g0tmi1k
6c0a21c80d Add /humans.txt check
See http://humanstxt.org/
2018-05-09 16:33:44 +01:00
g0tmi1k
dc48008d43 Bug with user-agent being shown 2018-05-09 16:16:18 +01:00
g0tmi1k
5720d29492 Fix inconsistencies with line endings 2018-05-09 16:11:09 +01:00
g0tmi1k
358f3d59d8 Say when to use --force 2018-05-09 16:04:01 +01:00
g0tmi1k
b6c6a46d25 Remove un-needed single quotes in output 2018-05-09 13:58:23 +01:00
g0tmi1k
25c393d557 gitignore cleanup 2018-05-09 13:58:04 +01:00
g0tmi1k
435fb34233 Check for user-agents.txt before using it 2018-05-09 13:15:12 +01:00
g0tmi1k
2c40913a64 Misc wording fixes 2018-05-09 13:14:41 +01:00
g0tmi1k
e437b952da Move timthumbs.txt to all the other data.zip files 2018-05-09 13:14:05 +01:00
g0tmi1k
282c595b38 Improve user prompt 2018-05-09 13:13:07 +01:00
g0tmi1k
c2c8d63e75 Show database date when updating 2018-05-09 13:12:27 +01:00
g0tmi1k
ad21d97d11 Grammar police! 2018-05-09 13:11:46 +01:00
g0tmi1k
5c27c78ed0 Add friendly reminder about using -u / --url 2018-05-09 13:10:34 +01:00
g0tmi1k
a53e9a5e12 Show the file being downloaded with verbose 2018-05-09 13:09:58 +01:00
g0tmi1k
c8036692ee Display user-agent with verbose mode (Handy with --random-agent) 2018-05-09 13:09:33 +01:00
Ryan Dewhurst
b9535a3648 Merge pull request #1180 from g0tmi1k/fixes
Stop trying to execute when it shouldn't
2018-05-09 10:05:14 +02:00
Ryan Dewhurst
651c364fa9 Merge pull request #1181 from g0tmi1k/users
Add a quick message about doing more wordpress users to usage
2018-05-09 10:03:49 +02:00
g0tmi1k
958410d4c9 Add a quick message about doing more wordpress users to usage 2018-05-08 17:19:33 +01:00
g0tmi1k
e9fba126d2 Stop trying to execute when it shouldn't 2018-05-08 17:14:48 +01:00
Christian Mehlmauer
95d39cce5a resolve 2018-05-08 07:53:45 +02:00
Christian Mehlmauer
32d9afdf9b update 2018-05-08 07:52:51 +02:00
Christian Mehlmauer
7e9a4168ff update 2018-05-08 07:50:32 +02:00
Christian Mehlmauer
9d6415a89b update gems 2018-03-28 00:25:48 +02:00
erwanlr
1499b07176 Fixes #1152 2018-01-30 19:59:41 +00:00
Christian Mehlmauer
9c7188a312 Merge branch 'master' of github.com:wpscanteam/wpscan 2018-01-11 07:25:05 +01:00
Christian Mehlmauer
b63e28c150 update readme 2018-01-11 07:24:51 +01:00
ethicalhack3r
50d48902cf Happy New Year! 2018-01-09 17:14:42 +01:00
Christian Mehlmauer
aa6899cbc5 ruby upgrade 2017-12-27 00:50:33 +01:00
Christian Mehlmauer
94e6b2eab6 upgrade ruby 2017-12-27 00:41:04 +01:00
erwanlr
54c0e79c58 Fixes #1154 2017-12-11 09:21:56 +00:00
erwanlr
859d7f1c60 Fixes spec, Ref #1147 2017-12-11 09:08:25 +00:00
Christian Mehlmauer
166112209e fix #1147 2017-12-06 19:18:15 +01:00
Christian Mehlmauer
952395d0c1 try to fix travis 2017-11-25 16:37:30 +01:00
Christian Mehlmauer
c7061f8a51 try to fix travis 2017-11-25 16:34:01 +01:00
Erwan
0c71bce221 Fix #1149 2017-11-24 08:43:20 +00:00
Christian Mehlmauer
b2b4eebd78 Merge branch 'master' of github.com:wpscanteam/wpscan 2017-11-14 19:41:24 +01:00
Christian Mehlmauer
5257a8b997 update 2017-11-14 19:41:15 +01:00
ethicalhack3r
9844f9d8ab Remove --max-threads option from output. Fix #1142 2017-11-08 10:59:33 +01:00
Christian Mehlmauer
000f275263 update bundler 2017-11-01 19:47:14 +01:00
Christian Mehlmauer
e5077c490a Merge branch 'master' of github.com:wpscanteam/wpscan 2017-10-22 00:36:25 +02:00
Christian Mehlmauer
d76968c15f update 2017-10-22 00:36:16 +02:00
Ryan Dewhurst
289ef5b0dd Remove some known issues. Fix #1141 2017-10-11 10:51:19 +02:00
Ryan Dewhurst
7ec227873c Update wording 2017-10-11 10:49:43 +02:00
Ryan Dewhurst
1deccfd477 Remove space 2017-10-11 10:40:10 +02:00
Ryan Dewhurst
286e6bd51a Update banner 2017-10-11 10:35:11 +02:00
Ryan Dewhurst
8167fa2e17 Remove CREDITS file 2017-10-11 10:34:17 +02:00
Ryan Dewhurst
c960df0bb1 Update copyright dates 2017-10-11 10:31:12 +02:00
Christian Mehlmauer
ebf8d31c6c specs 2017-10-09 12:59:43 +02:00
Christian Mehlmauer
082ae650fc specs 2017-10-09 12:53:18 +02:00
Christian Mehlmauer
2f5599c863 specs 2017-10-09 12:43:35 +02:00
Christian Mehlmauer
a764bdd993 update 2017-10-09 12:30:28 +02:00
Christian Mehlmauer
ef46d2c956 update readme and changelog files 2017-10-09 12:26:09 +02:00
Christian Mehlmauer
d2c2c1defb update 2017-09-18 20:40:51 +02:00
ethicalhack3r
dede023ec8 Update to Ruby 2.4.2 2017-09-14 19:50:31 +02:00
ethicalhack3r
d8a9b3aa77 Only show readme.html output when wp <= 4.8 #1127 2017-09-14 19:12:37 +02:00
Christian Mehlmauer
ad364e6a2e bundle update 2017-09-04 20:01:19 +02:00
Christian Mehlmauer
523954e507 bundle update 2017-08-11 10:08:25 +02:00
Christian Mehlmauer
872bbdb8e0 more output 2017-08-01 18:19:03 +02:00
Christian Mehlmauer
3ca8727b64 Merge branch 'master' of github.com:wpscanteam/wpscan 2017-08-01 18:15:50 +02:00
Christian Mehlmauer
1d3ca87772 better output 2017-08-01 18:15:37 +02:00
Christian Mehlmauer
90c42f42a1 Update README.md 2017-07-21 13:25:38 +02:00
Christian Mehlmauer
641108e7eb Stats 2017-07-19 15:24:32 +02:00
Christian Mehlmauer
0e87384b0a update data.zip 2017-07-19 15:05:41 +02:00
Christian Mehlmauer
5175170c4b prepare release 2017-07-19 14:59:33 +02:00
ethicalhack3r
79864cae7b Add emergency.php detection #1108 2017-07-17 20:56:38 +02:00
Christian Mehlmauer
ca5f92ca61 travis 2017-07-08 01:12:06 +02:00
Christian Mehlmauer
d29de83c41 prepare release, update gems 2017-07-08 01:10:00 +02:00
Christian Mehlmauer
1f42ce6e2f Merge pull request #1109 from zmwangx/readme-homebrew
Document Homebrew package in README
2017-07-07 09:39:30 +02:00
Zhiming Wang
0dc7128582 Document Homebrew package in README
Also, (Mac) OS X has been rebranded as macOS since June 2016, so rename that.
2017-07-06 20:13:57 -04:00
Christian Mehlmauer
21f4de2ec1 make logfile configurable 2017-05-31 23:16:07 +02:00
ethicalhack3r
d65567fc8f Remove previous version detection commit #1092 2017-05-02 16:13:54 +02:00
Christian Mehlmauer
20af778fa1 fix rspecs 2017-05-02 15:37:38 +02:00
ethicalhack3r
5f77832386 Improve version detection regex. Fix #1092 2017-05-02 12:30:16 +02:00
Christian Mehlmauer
6ccfe70775 install only supported gems 2017-04-21 20:07:02 +02:00
Christian Mehlmauer
6b0f687abb typo 2017-04-21 19:45:17 +02:00
Christian Mehlmauer
67ba526b5b use ruby alpine image from now on 2017-04-21 19:40:25 +02:00
ethicalhack3r
e186ec7534 Update install instruction for ruby 2.4.0 2017-04-20 16:35:11 +02:00
Christian Mehlmauer
23ef1e75b3 remove unneeded statement 2017-04-12 20:26:47 +02:00
Christian Mehlmauer
8170390f92 fix rspecs 2017-04-12 20:22:47 +02:00
Christian Mehlmauer
c148295f64 use Gemfile.lock from now on 2017-04-12 20:18:13 +02:00
Christian Mehlmauer
37b99f9baa Merge branch 'master' of github.com:wpscanteam/wpscan 2017-04-12 20:15:22 +02:00
Christian Mehlmauer
8e4643874d more docker work 2017-04-12 20:13:49 +02:00
Ryan Dewhurst
0522023fd4 Merge pull request #1081 from jamesalbert/master
--wordlist - reads stdin
2017-04-12 09:12:06 +02:00
jamesalbert
711ee730a0 updated readme 2017-04-11 09:58:43 -07:00
jamesalbert
f3bd995528 differentiate between stdin and file (estimating) 2017-04-11 03:20:11 -07:00
jamesalbert
beec0bd35a fixed progress_bar scope 2017-04-11 03:09:24 -07:00
jamesalbert
9d7f35f3b2 tightened up the threshold 2017-04-11 02:58:47 -07:00
jamesalbert
c7488e28f7 added estimation for stdin 2017-04-11 02:55:34 -07:00
jamesalbert
9150e0ca52 reads stdin line by line 2017-04-10 02:44:43 -07:00
jamesalbert
475288deeb --wordlist - reads stdin 2017-04-10 02:10:34 -07:00
erwanlr
82335d7399 Merge pull request #1075 from qutorial/master
Preciser reporting in bruteforcing password with bad response
2017-03-25 15:42:26 +00:00
Zaur
338eacd63b Preciser reporting in bruteforcing password with bad response
When bruteforcing for multiple logins and passwords the bad response code reported
might indicate a match! But the reporting for it is not clear enough.
For example "Unkown response for admin" might mean a user name admin and some password
or a password 'admin' for some user.

This commit makes in unambiguous reporting a bad response, and naming which login and
which password caused it.
2017-03-25 16:18:05 +01:00
Christian Mehlmauer
0b9b79f55f change tag 2017-03-24 18:55:49 +01:00
Christian Mehlmauer
5303b28957 add docker examples 2017-03-23 20:09:30 +01:00
Christian Mehlmauer
11c05a3590 some more help 2017-03-11 19:49:22 +01:00
Christian Mehlmauer
862c0a9014 binstub 2017-03-03 16:21:07 +01:00
Christian Mehlmauer
487a483aa6 gitignore 2017-01-31 22:03:43 +01:00
Christian Mehlmauer
030c20a11b travis 2017-01-31 22:02:53 +01:00
Christian Mehlmauer
ec831f7fed wtf? it was never required? 2017-01-31 22:02:20 +01:00
Christian Mehlmauer
50fa79b331 try to fix travis 2017-01-31 21:46:07 +01:00
Christian Mehlmauer
edab0e812a try to fix travis 2017-01-31 21:43:07 +01:00
Christian Mehlmauer
f0126ca860 try to fix travis 2017-01-31 21:36:00 +01:00
Christian Mehlmauer
01261d4d29 try to fix travis 2017-01-31 21:33:09 +01:00
Christian Mehlmauer
f97d3436a5 try to fix travis 2017-01-31 21:23:43 +01:00
Christian Mehlmauer
0bcb8b4b3b try to fix travis 2017-01-31 21:12:42 +01:00
Christian Mehlmauer
489545dd75 try to fix travis 2017-01-31 21:08:58 +01:00
Christian Mehlmauer
f6c152f58a update all gems to newest version 2017-01-31 20:36:32 +01:00
Christian Mehlmauer
16734418be Merge pull request #1053 from wpscanteam/revert-1052-master
Revert "Fix logic error in parsing command line args"
2017-01-29 23:16:42 +01:00
Christian Mehlmauer
b17ee20f58 Revert "Fix logic error in parsing command line args" 2017-01-29 23:16:01 +01:00
Ryan Dewhurst
aaee6f1e6d Merge pull request #1052 from petercunha/master
Fix logic error in parsing command line args
2017-01-29 21:26:58 +01:00
Peter Cunha
64d8240b8a Fix logic error in parsing command line args 2017-01-29 14:25:25 -05:00
Christian Mehlmauer
0a6d430c9f fix typo 2017-01-28 00:40:51 +01:00
Christian Mehlmauer
7bf0314561 try to fix travis 2017-01-17 20:47:01 +01:00
Christian Mehlmauer
409897fec4 fix travis and older ruby versions 2017-01-17 20:40:37 +01:00
Christian Mehlmauer
91b0d20665 forgot travis 2017-01-17 20:26:43 +01:00
Christian Mehlmauer
f6644eebf9 make wpscan ruby 2.4.0 compatible
fixes #1044
2017-01-17 20:24:32 +01:00
Ryan Dewhurst
88bddd4f87 Merge pull request #1046 from dctabuyz/fix__require_readline
'gem install readline' issues fix
2017-01-12 12:34:50 +01:00
dctabuyz
c61b023fb7 placing 'require readline' before require 'bundler/setup' fixes 'gem install readline' issues 2017-01-12 01:32:07 -05:00
Christian Mehlmauer
1b5df8751f Merge pull request #1045 from thijskh/patch-1
Add gcc to Debian prerequisites
2017-01-11 17:51:25 +01:00
Thijs Kinkhorst
314c98f101 Add gcc to Debian prerequisites
This is needed to install some gems and mirrors the fact that gcc is included in the command lines Fedora and Ubuntu (there contained in `build-essential`).
2017-01-11 17:19:27 +01:00
ethicalhack3r
8274e2efe9 Update to Ruby 2.3.3 2016-11-24 19:00:45 +01:00
ethicalhack3r
2bff063805 More changelog info 2016-11-15 20:51:38 +01:00
ethicalhack3r
53d9956829 Update data.zip 2016-11-15 20:37:54 +01:00
ethicalhack3r
6e98678c3c Bump wpscan version 2016-11-15 20:37:07 +01:00
ethicalhack3r
f0f21f5ac2 Add stats to changelog 2016-11-15 20:35:48 +01:00
ethicalhack3r
aa233b1c4d Add total vuln stats 2016-11-15 20:34:55 +01:00
ethicalhack3r
93f9123f45 Document missing options 2016-11-15 20:17:09 +01:00
ethicalhack3r
5c710d88e4 Update changelog 2016-11-15 20:00:54 +01:00
ethicalhack3r
ded70ff743 add R symbol 2016-11-08 14:03:33 +01:00
Christian Mehlmauer
9df7443aa4 color 2016-11-02 22:23:00 +01:00
Christian Mehlmauer
8362975691 apt tweak 2016-11-02 21:52:14 +01:00
Christian Mehlmauer
49771419ae Merge branch 'master' of github.com:wpscanteam/wpscan 2016-11-01 19:39:24 +01:00
Christian Mehlmauer
d344f84824 remove cloudflare error handling 2016-11-01 19:38:47 +01:00
Christian Mehlmauer
89c0b8d4d0 Merge pull request #1019 from wpscanteam/hash
remove scripts before calculating hashes
2016-10-26 11:48:13 +02:00
Christian Mehlmauer
3c74ee8d97 remove scripts before calculating hashes 2016-10-25 20:44:00 +02:00
ethicalhack3r
785c6efa5b Fix typo 2016-10-14 14:52:54 +02:00
ethicalhack3r
4e2bf5322e Markdown formating 2016-10-14 14:51:40 +02:00
ethicalhack3r
54ed148c87 Add passive detection of google-universal-analytics 2016-10-14 14:48:48 +02:00
Christian Mehlmauer
b08e298eba Merge branch 'master' of github.com:wpscanteam/wpscan 2016-10-06 20:35:44 +02:00
Christian Mehlmauer
89e2088357 fix #1008 2016-10-06 20:35:29 +02:00
ethicalhack3r
f3cc35bd74 trademark update 2016-09-08 09:39:52 +02:00
Christian Mehlmauer
a007d283e5 rspecs 2016-09-05 23:25:33 +02:00
Christian Mehlmauer
70902aa013 Merge branch 'master' of github.com:wpscanteam/wpscan 2016-09-05 22:59:14 +02:00
Christian Mehlmauer
91151fc53b check for ssl related errors. Fix #993 2016-09-05 22:58:56 +02:00
Christian Mehlmauer
d4ee82dac5 Update README.md 2016-08-17 18:31:35 +02:00
Christian Mehlmauer
88d3c26113 moar rspecs 2016-08-16 21:40:19 +02:00
Christian Mehlmauer
054a4ee6aa fix #984 2016-08-16 21:20:29 +02:00
ethicalhack3r
c291022753 Improve yoast seo pasive detection regex #984 2016-08-16 17:20:52 +02:00
Christian Mehlmauer
2fc488b602 rework readme 2016-08-15 00:25:46 +02:00
Christian Mehlmauer
009ddd690e verbose update 2016-08-13 12:52:33 +02:00
Christian Mehlmauer
88b5cd8751 readme 2016-08-13 10:30:06 +02:00
Christian Mehlmauer
cfd19d02b1 readme 2016-08-13 10:29:28 +02:00
Christian Mehlmauer
19ce30d862 trigger docker build 2016-08-13 10:27:52 +02:00
Christian Mehlmauer
c6df6e0e89 move docker stuff 2016-08-13 10:24:02 +02:00
Christian Mehlmauer
e942a5bcf6 Exit on exceptions 2016-08-12 23:56:36 +02:00
Christian Mehlmauer
c0f5163d07 handle null 2016-08-12 21:50:59 +02:00
Christian Mehlmauer
f5aa9f117f fix #968 2016-08-12 21:29:05 +02:00
Christian Mehlmauer
498d93377d rvm install instructions 2016-08-12 21:25:45 +02:00
Christian Mehlmauer
52242e706b Merge branch 'master' of github.com:wpscanteam/wpscan 2016-08-12 20:55:20 +02:00
Christian Mehlmauer
22d69a1bf9 more detailed update exception 2016-08-12 20:54:24 +02:00
Ryan Dewhurst
0b1fa13696 Merge pull request #973 from pierre-dargham/feature_option_cache
Enable --cache-dir option in command line parameters, which solves write permission issues when wpscan is installed in system or root-owned directories
2016-08-12 12:16:11 +02:00
Christian Mehlmauer
19b15b5327 travis 2016-08-08 22:35:20 +02:00
Christian Mehlmauer
e63e96f5ed travis 2016-08-08 22:04:42 +02:00
Christian Mehlmauer
e8ac8f26a7 travis 2016-08-08 22:00:52 +02:00
Christian Mehlmauer
13e4327de4 travis 2016-08-08 21:57:38 +02:00
Christian Mehlmauer
c22a1ed12a travis 2016-08-08 21:55:40 +02:00
Christian Mehlmauer
be5662b5f1 travis 2016-08-08 21:52:30 +02:00
Christian Mehlmauer
6e840ca920 fix #974 2016-08-08 21:40:36 +02:00
Pierre Dargham
8492190f4c Allow --cache-dir option in command line parameters 2016-08-05 10:56:40 +02:00
Christian Mehlmauer
93ab6ee2a0 fucking specs 2016-08-01 22:13:38 +02:00
Christian Mehlmauer
7075e01886 Merge branch 'master' of github.com:wpscanteam/wpscan 2016-08-01 22:07:47 +02:00
Christian Mehlmauer
436a83434c fix #972 2016-08-01 22:04:13 +02:00
pvdl
d270391b56 Fix for missing 'zlib.h' in Nokogiri 2016-07-26 19:43:45 +02:00
Christian Mehlmauer
7f2762eb6f new options 2016-07-21 21:27:21 +02:00
Christian Mehlmauer
2cc5bb0311 fix rspecs 2016-07-21 13:57:18 +02:00
Christian Mehlmauer
d697127261 set user agent globally 2016-07-21 13:21:07 +02:00
Christian Mehlmauer
825523a851 changelog 2016-06-27 16:07:40 +02:00
Christian Mehlmauer
0f3f9cac33 more info 2016-06-24 21:17:43 +02:00
ethicalhack3r
f9b545b100 Clearer instructions 2016-06-23 13:40:15 +02:00
Christian Mehlmauer
943bfc39b3 fix for #957 2016-06-14 03:30:17 +02:00
Ryan Dewhurst
b1a8f445c6 Merge pull request #950 from anthraxx/master
bump terminal-table to 1.6.0 and drop workaround
2016-06-07 09:54:42 +02:00
anthraxx
5435df4345 bump terminal-table to 1.6.0 and drop workaround 2016-06-06 19:28:40 +02:00
ethicalhack3r
8e9d29e94f Update dependencies #939 2016-06-02 11:21:07 +02:00
ethicalhack3r
1afa761f09 RandomStorm is no more 2016-06-02 11:09:10 +02:00
Ryan Dewhurst
d626913ce9 Merge pull request #949 from wpscanteam/finders
more advanced version detection
2016-06-02 11:04:38 +02:00
ethicalhack3r
9c52e4a5ee Update dependencies #939 2016-06-02 11:03:07 +02:00
Christian Mehlmauer
72c2c1992b rspec fixed 2016-05-31 15:23:34 +02:00
Christian Mehlmauer
e1b4b5e8e5 typo 2016-05-31 14:53:50 +02:00
Christian Mehlmauer
0243522854 more advanced version detection 2016-05-31 14:51:09 +02:00
Christian Mehlmauer
5118c68f45 fix #943 2016-05-13 21:23:22 +02:00
Christian Mehlmauer
442884b5c5 remove executable flags 2016-05-09 16:19:11 +02:00
Christian Mehlmauer
f832e27b49 correct stats an correct data files 2016-05-06 11:52:05 +02:00
ethicalhack3r
6ce29f73c5 Update with correct stat #935 2016-05-06 11:35:57 +02:00
ethicalhack3r
920338fb62 Prepare 2.9.1 release #935 2016-05-06 00:15:53 +02:00
Christian Mehlmauer
49d0a9e6d9 check directory listing in wp-includes 2016-05-05 00:01:52 +02:00
Christian Mehlmauer
fe401e622b add stats 2016-05-04 23:09:00 +02:00
Christian Mehlmauer
6e32cb0db2 changelog 2016-05-04 22:46:02 +02:00
Ryan Dewhurst
73171eb39d Merge pull request #929 from wpscanteam/wp_metadata
WP Metadata Integration
2016-04-28 14:35:43 +02:00
ethicalhack3r
2e05f4171e Update to Ruby 2.3.1 2016-04-28 14:04:54 +02:00
Christian Mehlmauer
75b8c303e2 more verbose error 2016-04-27 15:19:07 +02:00
Christian Mehlmauer
bd7a493f1c travis errors 2016-04-20 20:49:17 +02:00
Christian Mehlmauer
9dada7c8f4 travis errors 2016-04-20 20:41:46 +02:00
ethicalhack3r
fe7aede458 Better output 2016-04-20 13:39:05 +02:00
ethicalhack3r
cdf2b38780 Only show changelog if verbose 2016-04-20 13:09:02 +02:00
ethicalhack3r
a09dbab6a8 Use db_file 2016-04-20 12:43:56 +02:00
ethicalhack3r
49a6d275d2 Update comment 2016-04-20 12:37:46 +02:00
ethicalhack3r
8192a4a215 Fix typo 2016-04-20 12:27:09 +02:00
ethicalhack3r
1d6593fd4d Add WP metadata #704 2016-04-20 12:02:15 +02:00
Christian Mehlmauer
bf99e31e70 higher update timeout 2016-04-20 09:33:56 +02:00
Christian Mehlmauer
5386496bdc move wordpress check to the top 2016-04-06 14:13:56 +02:00
Christian Mehlmauer
6451510449 new ruby version with security bugfixes released 2016-04-03 00:34:52 +02:00
Christian Mehlmauer
cd68aa719c possible fix for timeouts 2016-04-01 11:52:13 +02:00
Christian Mehlmauer
b328dc4ff9 possible fix for #912 2016-03-11 09:28:42 +01:00
Christian Mehlmauer
1e1c79aa56 Merge pull request #909 from wpscanteam/ruby_version
drop ruby 1.9 and 2.0 support, whitespaces
2016-02-26 14:08:38 +01:00
Christian Mehlmauer
08650ce156 fix travis 2016-02-25 06:39:47 +01:00
Christian Mehlmauer
a1929719f3 version 2.1.8 minimum requirement 2016-02-24 23:48:50 +01:00
Christian Mehlmauer
d34da72cd3 ruby 2.0.0 is EOL 2016-02-24 23:41:32 +01:00
Christian Mehlmauer
816b18b604 drop ruby 1.9 support, whitespaces 2016-02-23 18:07:20 +01:00
Christian Mehlmauer
a78a13bf3f revert change 2016-02-18 00:02:55 +01:00
Christian Mehlmauer
33f8aaf1dc Merge branch 'master' of github.com:wpscanteam/wpscan 2016-02-17 23:30:45 +01:00
Christian Mehlmauer
26ab95d822 more actual gems 2016-02-17 23:30:28 +01:00
erwanlr
cea01d8aa0 Improves brute forcer output to avoid confustions 2016-02-13 16:44:29 +00:00
Ryan Dewhurst
0e61f1e284 Merge pull request #901 from wpscanteam/new_urls
add new urls
2016-02-06 22:26:25 +01:00
Christian Mehlmauer
ddef061b90 add new urls 2016-02-05 22:25:18 +01:00
erwanlr
addeab8947 Fixes #900 2016-02-04 20:37:13 +01:00
erwanlr
55dc665404 Better specs 2016-01-11 16:33:29 +00:00
erwanlr
8f8538e9e9 Changes the order of the WP version from stylesheets check - Fixes #865 2016-01-11 16:27:22 +00:00
Christian Mehlmauer
348ca55bee copyright 2016-01-08 23:54:04 +01:00
Christian Mehlmauer
1bb5bc7f33 fix rspec 2016-01-03 21:28:02 +01:00
ethicalhack3r
3be5e1fcf5 Add Windows OS detection 2016-01-03 20:15:11 +01:00
Christian Mehlmauer
9df8cc9243 Update README.md 2016-01-02 10:57:55 +01:00
Christian Mehlmauer
e28c84aa34 Update fedore install instructions
See #886
2016-01-02 10:52:23 +01:00
Christian Mehlmauer
7db6b54761 Merge pull request #894 from nonmadden/update-ruby
Update to Ruby 2.3.0
2015-12-31 10:22:47 +01:00
nonmadden
e3a06f5694 Update to Ruby 2.3.0 2015-12-31 10:41:04 +07:00
erwanlr
7c5d15e098 Updates Nokogiri dep 2015-12-18 18:59:32 +01:00
ethicalhack3r
d683c0f151 Update to Ruby 2.2.4 2015-12-18 11:13:41 +01:00
erwanlr
1e67fa26ff Fixes #890 2015-11-26 14:12:04 +00:00
erwanlr
0ae6ef59ec Fixes an issue with --cache-ttl being a Strig instead of an integer 2015-11-26 13:52:12 +00:00
erwanlr
e27ef40e0f Updates Nokogiri dep version 2015-11-26 11:53:13 +00:00
ethicalhack3r
380760d028 Onlt shoe theme description when there is one 2015-10-26 16:06:13 +01:00
ethicalhack3r
18cfdafc19 Fix typo in options 2015-10-15 16:28:42 +02:00
ethicalhack3r
0934a2e329 Recommend RVM in readme 2015-10-15 15:51:38 +02:00
ethicalhack3r
d1a320324e Update reame CLI options 2015-10-15 15:49:18 +02:00
131 changed files with 3008 additions and 1333 deletions

21
.dockerignore Normal file
View File

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

32
.gitignore vendored
View File

@@ -1,15 +1,21 @@
cache # WPScan (If not using ~/.wpscan/)
coverage 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
.bundle .bundle
.DS_Store .DS_Store
.DS_Store? .DS_Store?
*.sublime-*
.idea
.*.swp
Gemfile.lock
log.txt
.yardoc
debug.log
wordlist.txt
rspec_results.html
data/

View File

@@ -1 +1 @@
2.2.3 2.5.1

View File

@@ -2,28 +2,34 @@ language: ruby
sudo: false sudo: false
cache: bundler cache: bundler
rvm: rvm:
- 1.9.2 - 2.1.9
- 1.9.3
- 2.0.0
- 2.1.0
- 2.1.1
- 2.1.2
- 2.1.3
- 2.1.4
- 2.1.5
- 2.2.0 - 2.2.0
- 2.2.1 - 2.2.1
- 2.2.2 - 2.2.2
- 2.2.3 - 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.5.0
- 2.5.1
- ruby-head
before_install: before_install:
- "env"
- "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc" - "echo 'gem: --no-ri --no-rdoc' > ~/.gemrc"
script: bundle exec rspec - "gem install bundler"
- "gem regenerate_binstubs"
- "bundle --version"
before_script:
- "unzip -o $TRAVIS_BUILD_DIR/data.zip -d $HOME/.wpscan/"
script:
- "bundle exec rspec"
notifications: notifications:
email: email:
- team@wpscan.org - team@wpscan.org
matrix:
allow_failures:
- rvm: 1.9.2
# do not build gh-pages branch # do not build gh-pages branch
branches: branches:
except: except:

View File

@@ -1,6 +1,98 @@
# Changelog # Changelog
## Master ## Master
[Work in progress](https://github.com/wpscanteam/wpscan/compare/2.9...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 ## Version 2.9
Released: 2015-10-15 Released: 2015-10-15
@@ -137,7 +229,7 @@ New
* Add Sucuri sponsor to banner * Add Sucuri sponsor to banner
* Add protocol to sucuri url in banner * Add protocol to sucuri url in banner
* Add response code to proxy error output * Add response code to proxy error output
* Add a statement about mendatory newlines at the end of list * Add a statement about mandatory newlines at the end of list
* Give warning if default username 'admin' is still used * Give warning if default username 'admin' is still used
* License amendment to make it more clear about value added usage * License amendment to make it more clear about value added usage
@@ -493,4 +585,3 @@ Fixed issues
## Version 2.1 ## Version 2.1
Released 2013-3-4 Released 2013-3-4

21
CREDITS
View File

@@ -1,21 +0,0 @@
**CREDITS**
This file is used to state the individual WPScan Team members (core developers) and give credit to WPScan's other contributors. If you feel your name should be in here email team@wpscan.org.
*WPScan Team*
Erwan.LR - @erwan_lr - (Project Developer)
Christian Mehlmauer - @_FireFart_ - (Project Developer)
Peter van der Laan - pvdl - (Project Developer)
Ryan Dewhurst - @ethicalhack3r (Project Lead)
*Other Contributors*
Henri Salo AKA fgeek - Reported lots of vulnerabilities
Alip AKA Undead - alip.aswalid at gmail.com
michee08 - Reported and gave potential solutions to bugs
Callum Pember - Implemented proxy support - callumpember at gmail.com
g0tmi1k - Additional timthumb checks + bug reports
Melvin Lammerts - Reported a couple of fake vulnerabilities - melvin at 12k.nl
Paolo Perego - @thesp0nge - Basic authentication
Gianluca Brindisi - @gbrindisi - Ex Project Developer

37
Dockerfile Normal file
View File

@@ -0,0 +1,37 @@
FROM ruby:2.5-alpine
LABEL maintainer="WPScan Team <team@wpscan.org>"
ARG BUNDLER_ARGS="--jobs=8 --without test"
# 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 chown -R wpscan:wpscan /wpscan
# Switch directory
WORKDIR /wpscan
# Switch users
USER wpscan
# Update WPScan
RUN /wpscan/wpscan.rb --update --verbose --no-color
# Run WPScan
ENTRYPOINT ["/wpscan/wpscan.rb"]
CMD ["--help"]

23
Gemfile
View File

@@ -1,17 +1,16 @@
source 'https://rubygems.org' source 'https://rubygems.org'
gem 'typhoeus', '~>0.8.0' gem 'addressable', '>=2.5.0'
gem 'nokogiri' gem 'nokogiri', '>=1.7.0.1'
gem 'addressable' gem 'ruby-progressbar', '>=1.8.1'
gem 'yajl-ruby' # Better JSON parser regarding memory usage gem 'rubyzip', '>=1.2.1'
# TODO: update the below when terminal-table 1.5.3+ is released. gem 'terminal-table', '>=1.6.0'
# (and delete the Terminal module in lib/common/hacks.rb) gem 'typhoeus', '>=1.1.2'
gem 'terminal-table', '~>1.4.5' gem 'yajl-ruby', '>=1.3.0' # Better JSON parser regarding memory usage
gem 'ruby-progressbar', '>=1.6.0'
group :test do group :test do
gem 'webmock', '>=1.17.2' gem 'webmock', '>=2.3.2'
gem 'simplecov' gem 'simplecov', '>=0.13.0'
gem 'rspec', '>=3.3.0' gem 'rspec', '>=3.5.0'
gem 'rspec-its' gem 'rspec-its', '>=1.2.0'
end end

View File

@@ -1,6 +1,6 @@
WPScan Public Source License WPScan Public Source License
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2015 WPScan Team. The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2018 WPScan Team.
Cases that include commercialization of WPScan require a commercial, non-free license. Otherwise, WPScan can be used without charge under the terms set out below. Cases that include commercialization of WPScan require a commercial, non-free license. Otherwise, WPScan can be used without charge under the terms set out below.
@@ -8,7 +8,7 @@ Cases that include commercialization of WPScan require a commercial, non-free li
1.1 “License” means this document. 1.1 “License” means this document.
1.2 “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns WPScan. 1.2 “Contributor” means each individual or legal entity that creates, contributes to the creation of, or owns WPScan.
1.3 “WPScan Team” means 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 2. Commercialization
@@ -68,3 +68,7 @@ To the extent permitted under Law, WPScan is provided under an AS-IS basis. The
10. Disclaimer 10. Disclaimer
Running WPScan against websites without prior mutual consent may be illegal in your country. The WPScan Team accept no liability and are not responsible for any misuse or damage caused by WPScan. Running WPScan against websites without prior mutual consent may be illegal in your country. The WPScan Team accept no liability and are not responsible for any misuse or damage caused by WPScan.
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.

296
README.md
View File

@@ -1,19 +1,21 @@
![alt text](https://raw.githubusercontent.com/wpscanteam/wpscan/gh-pages/wpscan_logo_407x80.png "WPScan - WordPress Security Scanner") ![alt text](https://raw.githubusercontent.com/wpscanteam/wpscan/gh-pages/wpscan_logo_407x80.png "WPScan - WordPress Security Scanner")
[![Build Status](https://travis-ci.org/wpscanteam/wpscan.svg?branch=master)](https://travis-ci.org/wpscanteam/wpscan) [![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) [![Code Climate](https://img.shields.io/codeclimate/github/wpscanteam/wpscan.svg)](https://codeclimate.com/github/wpscanteam/wpscan)
[![Dependency Status](https://img.shields.io/gemnasium/wpscanteam/wpscan.svg)](https://gemnasium.com/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)
#### LICENSE ![alt text](https://wpscan.org/images/tty.gif "WPScan Screen Recording")
#### WPScan Public Source License # LICENSE
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2015 WPScan Team. ## WPScan Public Source License
The WPScan software (henceforth referred to simply as "WPScan") is dual-licensed - Copyright 2011-2018 WPScan Team.
Cases that include commercialization of WPScan require a commercial, non-free license. Otherwise, WPScan can be used without charge under the terms set out below. Cases that include commercialization of WPScan require a commercial, non-free license. Otherwise, WPScan can be used without charge under the terms set out below.
##### 1. Definitions ### 1. Definitions
1.1 "License" means this document. 1.1 "License" means this document.
@@ -21,7 +23,7 @@ Cases that include commercialization of WPScan require a commercial, non-free li
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, an updated list of whom can be found within the CREDITS file.
##### 2. Commercialization ### 2. Commercialization
A commercial use is one intended for commercial advantage or monetary compensation. A commercial use is one intended for commercial advantage or monetary compensation.
@@ -44,7 +46,7 @@ We may grant commercial licenses at no monetary cost at our own discretion if th
Free-use Terms and Conditions; Free-use Terms and Conditions;
##### 3. Redistribution ### 3. Redistribution
Redistribution is permitted under the following conditions: Redistribution is permitted under the following conditions:
@@ -52,35 +54,39 @@ Redistribution is permitted under the following conditions:
- Unmodified Copyright notices are provided with WPScan. - Unmodified Copyright notices are provided with WPScan.
- Does not conflict with the commercialization clause. - Does not conflict with the commercialization clause.
##### 4. Copying ### 4. Copying
Copying is permitted so long as it does not conflict with the Redistribution clause. Copying is permitted so long as it does not conflict with the Redistribution clause.
##### 5. Modification ### 5. Modification
Modification is permitted so long as it does not conflict with the Redistribution clause. Modification is permitted so long as it does not conflict with the Redistribution clause.
##### 6. Contributions ### 6. Contributions
Any Contributions assume the Contributor grants the WPScan Team the unlimited, non-exclusive right to reuse, modify and relicense the Contributor's content. Any Contributions assume the Contributor grants the WPScan Team the unlimited, non-exclusive right to reuse, modify and relicense the Contributor's content.
##### 7. Support ### 7. Support
WPScan is provided under an AS-IS basis and without any support, updates or maintenance. Support, updates and maintenance may be given according to the sole discretion of the WPScan Team. WPScan is provided under an AS-IS basis and without any support, updates or maintenance. Support, updates and maintenance may be given according to the sole discretion of the WPScan Team.
##### 8. Disclaimer of Warranty ### 8. Disclaimer of Warranty
WPScan is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the WPScan is free of defects, merchantable, fit for a particular purpose or non-infringing. WPScan is provided under this License on an “as is” basis, without warranty of any kind, either expressed, implied, or statutory, including, without limitation, warranties that the WPScan is free of defects, merchantable, fit for a particular purpose or non-infringing.
##### 9. Limitation of Liability ### 9. Limitation of Liability
To the extent permitted under Law, WPScan is provided under an AS-IS basis. The WPScan Team shall never, and without any limit, be liable for any damage, cost, expense or any other payment incurred as a result of WPScan's actions, failure, bugs and/or any other interaction between WPScan and end-equipment, computers, other software or any 3rd party, end-equipment, computer or services. To the extent permitted under Law, WPScan is provided under an AS-IS basis. The WPScan Team shall never, and without any limit, be liable for any damage, cost, expense or any other payment incurred as a result of WPScan's actions, failure, bugs and/or any other interaction between WPScan and end-equipment, computers, other software or any 3rd party, end-equipment, computer or services.
##### 10. Disclaimer ### 10. Disclaimer
Running WPScan against websites without prior mutual consent may be illegal in your country. The WPScan Team accept no liability and are not responsible for any misuse or damage caused by WPScan. Running WPScan against websites without prior mutual consent may be illegal in your country. The WPScan Team accept no liability and are not responsible for any misuse or damage caused by WPScan.
#### INSTALL ### 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: WPScan comes pre-installed on the following Linux distributions:
@@ -90,114 +96,104 @@ WPScan comes pre-installed on the following Linux distributions:
- [SamuraiWTF](http://samurai.inguardians.com/) - [SamuraiWTF](http://samurai.inguardians.com/)
- [BlackArch](http://blackarch.org/) - [BlackArch](http://blackarch.org/)
Prerequisites: On macOS WPScan is packaged by [Homebrew](https://brew.sh/) as [`wpscan`](http://braumeister.org/formula/wpscan).
- Ruby >= 1.9.2 - Recommended: 2.2.3 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 - Curl >= 7.21 - Recommended: latest - FYI the 7.29 has a segfault
- RubyGems - Recommended: latest - RubyGems - Recommended: latest
- Git - Git
Windows is not supported. ### Installing dependencies on Ubuntu
If installed from Github update the code base with ```git pull```. The databases are updated with ```wpscan.rb --update```.
####Installing on Ubuntu: sudo apt-get install libcurl4-openssl-dev libxml2 libxml2-dev libxslt1-dev ruby-dev build-essential libgmp-dev zlib1g-dev
Before Ubuntu 14.04: ### Installing dependencies on Debian
sudo apt-get install libcurl4-openssl-dev libopenssl-ruby libxml2 libxml2-dev libxslt1-dev ruby-dev sudo apt-get install gcc git ruby ruby-dev libcurl4-openssl-dev make zlib1g-dev
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
sudo gem install bundler && bundle install --without test
From Ubuntu 14.04: ### Installing dependencies on Fedora
sudo apt-get install libcurl4-openssl-dev libxml2 libxml2-dev libxslt1-dev ruby-dev build-essential libgmp-dev sudo dnf install gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel libcurl-devel patch rpm-build
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
sudo gem install bundler && bundle install --without test
####Installing on Debian: ### Installing dependencies on Arch Linux
sudo apt-get install git ruby ruby-dev libcurl4-openssl-dev make
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
sudo gem install bundler
bundle install --without test --path vendor/bundle
####Installing on Fedora:
sudo yum install gcc ruby-devel libxml2 libxml2-devel libxslt libxslt-devel libcurl-devel patch
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
sudo gem install bundler && bundle install --without test
####Installing on Archlinux:
pacman -Syu ruby pacman -Syu ruby
pacman -Syu libyaml pacman -Syu libyaml
git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
sudo gem install bundler && bundle install --without test
gem install typhoeus
gem install nokogiri
####Installing on Mac OSX: ### 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) 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)
git clone https://github.com/wpscanteam/wpscan.git ## Installing with RVM (recommended when doing a manual install)
cd wpscan
sudo gem install bundler && sudo bundle install --without test
####Installing with RVM: 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 ~ cd ~
curl -sSL https://rvm.io/mpapis.asc | gpg --import -
curl -sSL https://get.rvm.io | bash -s stable curl -sSL https://get.rvm.io | bash -s stable
source ~/.rvm/scripts/rvm source ~/.rvm/scripts/rvm
echo "source ~/.rvm/scripts/rvm" >> ~/.bashrc echo "source ~/.rvm/scripts/rvm" >> ~/.bashrc
rvm install 2.2.3 rvm install 2.5.1
rvm use 2.2.3 --default rvm use 2.5.1 --default
echo "gem: --no-ri --no-rdoc" > ~/.gemrc echo "gem: --no-ri --no-rdoc" > ~/.gemrc
gem install bundler
git clone https://github.com/wpscanteam/wpscan.git git clone https://github.com/wpscanteam/wpscan.git
cd wpscan cd wpscan
gem install bundler gem install bundler
bundle install --without test bundle install --without test
#### KNOWN ISSUES ## Installing manually (not recommended)
- Typhoeus segmentation fault git clone https://github.com/wpscanteam/wpscan.git
cd wpscan
sudo gem install bundler && bundle install --without test
Update cURL to version => 7.21 (may have to install from source) # KNOWN ISSUES
- Proxy not working
Update cURL to version => 7.21.7 (may have to install from source).
Installation from sources :
Grab the sources from http://curl.haxx.se/download.html
Decompress the archive
Open the folder with the extracted files
Run ./configure
Run make
Run sudo make install
Run sudo ldconfig
- cannot load such file -- readline:
sudo aptitude install libreadline5-dev libncurses5-dev
Then, open the directory of the readline gem (you have to locate it)
cd ~/.rvm/src/ruby-1.9.2-p180/ext/readline
ruby extconf.rb
make
make install
See [http://vvv.tobiassjosten.net/ruby-on-rails/fixing-readline-for-the-ruby-on-rails-console/](http://vvv.tobiassjosten.net/ruby-on-rails/fixing-readline-for-the-ruby-on-rails-console/) for more details
- no such file to load -- rubygems - no such file to load -- rubygems
@@ -207,15 +203,12 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install
See [https://github.com/wpscanteam/wpscan/issues/148](https://github.com/wpscanteam/wpscan/issues/148) See [https://github.com/wpscanteam/wpscan/issues/148](https://github.com/wpscanteam/wpscan/issues/148)
#### WPSCAN ARGUMENTS # WPSCAN ARGUMENTS
--update Update the databases. --update Update the database to the latest version.
--url | -u <target url> The WordPress URL/domain to scan.
--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.
--force | -f Forces WPScan to not check if the remote site is running WordPress.
--enumerate | -e [option(s)] Enumeration.
option : option :
u usernames from id 1 to 10 u usernames from id 1 to 10
u[10-20] usernames from id 10 to 20 (you must write [] chars) u[10-20] usernames from id 10 to 20 (you must write [] chars)
@@ -229,55 +222,44 @@ Apple Xcode, Command Line Tools and the libffi are needed (to be able to install
Multiple values are allowed : "-e tt,p" will enumerate timthumbs and plugins Multiple values are allowed : "-e tt,p" will enumerate timthumbs and plugins
If no option is supplied, the default is "vt,tt,u,vp" 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 --exclude-content-based "<regexp or string>"
You do not need to provide the regexp delimiters, but you must write the quotes (simple or double) 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.
--config-file | -c <config file> Use the specified config file, see the example.conf.json # WPSCAN EXAMPLES
--user-agent | -a <User-Agent> Use the specified User-Agent
--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
--wp-content-dir <wp content dir> WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified 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 (will override the one from conf/browser.conf.json).
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.
--threads | -t <number of threads> The number of threads to use when multi-threading requests.
--username | -U <username> Only brute force the supplied username.
--usernames <path-to-file> Only brute force the usernames from the file.
--cache-ttl <cache-ttl> Typhoeus cache TTL.
--request-timeout <request-timeout> Request Timeout.
--connect-timeout <connect-timeout> Connect Timeout.
--max-threads <max-threads> Maximum Threads.
--help | -h This help screen.
--verbose | -v Verbose output.
--batch Never ask for user input, use the default behavior.
--no-color Do not use colors in the output.
--log Save STDOUT to log.txt
#### WPSCAN EXAMPLES
Do 'non-intrusive' checks... Do 'non-intrusive' checks...
@@ -287,6 +269,10 @@ Do wordlist password brute force on enumerated users using 50 threads...
```ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --threads 50``` ```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... Do wordlist password brute force on the 'admin' username only...
```ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --username admin``` ```ruby wpscan.rb --url www.example.com --wordlist darkc0de.lst --username admin```
@@ -311,26 +297,22 @@ Debug output...
```ruby wpscan.rb --url www.example.com --debug-output 2>debug.log``` ```ruby wpscan.rb --url www.example.com --debug-output 2>debug.log```
#### PROJECT HOME # PROJECT HOME
[http://www.wpscan.org](http://www.wpscan.org) [http://www.wpscan.org](http://www.wpscan.org)
#### VULNERABILITY DATABASE # VULNERABILITY DATABASE
[https://wpvulndb.com](https://wpvulndb.com) [https://wpvulndb.com](https://wpvulndb.com)
#### GIT REPOSITORY # GIT REPOSITORY
[https://github.com/wpscanteam/wpscan](https://github.com/wpscanteam/wpscan) [https://github.com/wpscanteam/wpscan](https://github.com/wpscanteam/wpscan)
#### ISSUES # ISSUES
[https://github.com/wpscanteam/wpscan/issues](https://github.com/wpscanteam/wpscan/issues) [https://github.com/wpscanteam/wpscan/issues](https://github.com/wpscanteam/wpscan/issues)
#### DEVELOPER DOCUMENTATION # DEVELOPER DOCUMENTATION
[http://rdoc.info/github/wpscanteam/wpscan/frames](http://rdoc.info/github/wpscanteam/wpscan/frames) [http://rdoc.info/github/wpscanteam/wpscan/frames](http://rdoc.info/github/wpscanteam/wpscan/frames)
#### SPECIAL THANKS
[RandomStorm](https://www.randomstorm.com)

21
bin/rspec Executable file
View File

@@ -0,0 +1,21 @@
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
cd $DIR/../
# always rebuild and include all GEMs
docker build --build-arg "BUNDLER_ARGS=--jobs=8" -t wpscan:rspec .
# update all gems (this updates Gemfile.lock on the host)
# this also needs some build dependencies
docker run --rm -u root -v $DIR/../Gemfile.lock:/wpscan/Gemfile.lock --entrypoint "" wpscan:rspec sh -c 'apk add --no-cache alpine-sdk ruby-dev libffi-dev zlib-dev && bundle update'
# rebuild image with latest GEMs
docker build --build-arg "BUNDLER_ARGS=--jobs=8" -t wpscan:rspec .
# run spec
docker run --rm -v $DIR/../:/wpscan --entrypoint "" wpscan:rspec rspec

12
bin/update_gems Executable file
View File

@@ -0,0 +1,12 @@
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
cd $DIR/../
docker run --rm -v "$DIR/../":/usr/src/app -w /usr/src/app ruby:2.5-alpine /bin/sh -c "gem install bundler; bundle lock --update"

14
bin/wpscan Executable file
View File

@@ -0,0 +1,14 @@
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
cd $DIR/../
docker build -q -t wpscan:git .
docker run -it --rm wpscan:git "$@"

16
bin/wpscan-dev Executable file
View File

@@ -0,0 +1,16 @@
#!/bin/bash
SOURCE="${BASH_SOURCE[0]}"
while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
SOURCE="$(readlink "$SOURCE")"
[[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located
done
DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )"
cd $DIR/../
if [[ -n "$WPSCAN_BUILD" ]]; then
docker build -q -t wpscan:git .
fi
docker run -it --rm -v $DIR/../:/wpscan wpscan:git "$@"

BIN
data.zip

Binary file not shown.

2
data/.gitignore vendored
View File

@@ -1,2 +0,0 @@
*
!.gitignore

19
dev/stats.rb Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env ruby
# encoding: UTF-8
require File.expand_path(File.join(__dir__, '..', 'lib', 'wpscan', 'wpscan_helper'))
wordpress_json = json(WORDPRESSES_FILE)
plugins_json = json(PLUGINS_FILE)
themes_json = json(THEMES_FILE)
puts 'WPScan Database Statistics:'
puts "* Total tracked wordpresses: #{wordpress_json.count}"
puts "* Total tracked plugins: #{plugins_json.count}"
puts "* Total tracked themes: #{themes_json.count}"
puts "* Total vulnerable wordpresses: #{wordpress_json.select { |item| !wordpress_json[item]['vulnerabilities'].empty? }.count}"
puts "* Total vulnerable plugins: #{plugins_json.select { |item| !plugins_json[item]['vulnerabilities'].empty? }.count}"
puts "* Total vulnerable themes: #{themes_json.select { |item| !themes_json[item]['vulnerabilities'].empty? }.count}"
puts "* Total wordpress vulnerabilities: #{wordpress_json.map {|k,v| v['vulnerabilities'].count}.inject(:+)}"
puts "* Total plugin vulnerabilities: #{plugins_json.map {|k,v| v['vulnerabilities'].count}.inject(:+)}"
puts "* Total theme vulnerabilities: #{themes_json.map {|k,v| v['vulnerabilities'].count}.inject(:+)}"

View File

@@ -2,8 +2,8 @@
"user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0", "user_agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10.6; rv:9.0) Gecko/20100101 Firefox/9.0",
/* Uncomment the "proxy" line to use the proxy /* Uncomment the "proxy" line to use the proxy
SOCKS proxies (4, 4A, 5) are supported, ie : "proxy": "socks5://127.0.0.1:9000" SOCKS proxies (4, 4A, 5) are supported, ie : "proxy": "socks5://127.0.0.1:9000"
If you do not specify the protocol, http will be used If you do not specify the protocol, http will be used
*/ */
//"proxy": "127.0.0.1:3128", //"proxy": "127.0.0.1:3128",
//"proxy_auth": "username:password", //"proxy_auth": "username:password",

View File

@@ -18,7 +18,10 @@ class Browser
:request_timeout, :request_timeout,
:connect_timeout, :connect_timeout,
:cookie, :cookie,
:throttle :throttle,
:disable_accept_header,
:disable_referer,
:disable_tls_checks
] ]
@@instance = nil @@instance = nil
@@ -67,17 +70,23 @@ class Browser
@@instance = nil @@instance = nil
end end
# Override for setting the User-Agent
# @param [ String ] user_agent
def user_agent=(user_agent)
Typhoeus::Config.user_agent = user_agent
end
# #
# sets browser default values # sets browser default values
# #
def browser_defaults def browser_defaults
Typhoeus::Config.user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)"
@max_threads = 20 @max_threads = 20
# 10 minutes, at this time the cache is cleaned before each scan. # 10 minutes, at this time the cache is cleaned before each scan.
# If this value is set to 0, the cache will be disabled # If this value is set to 0, the cache will be disabled
@cache_ttl = 600 @cache_ttl = 600
@request_timeout = 60 # 60s @request_timeout = 60 # 60s
@connect_timeout = 10 # 10s @connect_timeout = 10 # 10s
@user_agent = "WPScan v#{WPSCAN_VERSION} (http://wpscan.org)"
@throttle = 0 @throttle = 0
end end
@@ -115,15 +124,9 @@ class Browser
# #
# @return [ Hash ] # @return [ Hash ]
def merge_request_params(params = {}) def merge_request_params(params = {})
params = Browser.append_params_header_field(
params,
'User-Agent',
@user_agent
)
if @proxy if @proxy
params.merge!(proxy: @proxy) params.merge!(proxy: @proxy)
params.merge!(proxyauth: @proxy_auth) if @proxy_auth params.merge!(proxyuserpwd: @proxy_auth) if @proxy_auth
end end
if @basic_auth if @basic_auth
@@ -143,8 +146,8 @@ class Browser
end end
params.merge!(referer: referer) params.merge!(referer: referer)
params.merge!(timeout: @request_timeout) if @request_timeout params.merge!(timeout: @request_timeout) if @request_timeout && !params.key?(:timeout)
params.merge!(connecttimeout: @connect_timeout) if @connect_timeout params.merge!(connecttimeout: @connect_timeout) if @connect_timeout && !params.key?(:connecttimeout)
# Used to enable the cache system if :cache_ttl > 0 # Used to enable the cache system if :cache_ttl > 0
params.merge!(cache_ttl: @cache_ttl) unless params.key?(:cache_ttl) params.merge!(cache_ttl: @cache_ttl) unless params.key?(:cache_ttl)
@@ -153,12 +156,18 @@ class Browser
params.merge!(maxredirs: 3) unless params.key?(:maxredirs) params.merge!(maxredirs: 3) unless params.key?(:maxredirs)
# Disable SSL-Certificate checks # Disable SSL-Certificate checks
params.merge!(ssl_verifypeer: false) if @disable_tls_checks
params.merge!(ssl_verifyhost: 0) # Cert validity check
params.merge!(ssl_verifypeer: 0) unless params.key?(:ssl_verifypeer)
# Cert hostname check
params.merge!(ssl_verifyhost: 0) unless params.key?(:ssl_verifyhost)
end
params.merge!(cookiejar: @cache_dir + '/cookie-jar') params.merge!(cookiejar: @cache_dir + '/cookie-jar')
params.merge!(cookiefile: @cache_dir + '/cookie-jar') params.merge!(cookiefile: @cache_dir + '/cookie-jar')
params.merge!(cookie: @cookie) if @cookie params.merge!(cookie: @cookie) if @cookie
params = Browser.remove_params_header_field(params, 'Accept') if @disable_accept_header
params = Browser.remove_params_header_field(params, 'Referer') if @disable_referer
params params
end end
@@ -178,4 +187,18 @@ class Browser
end end
params params
end end
# @param [ Hash ] params
# @param [ String ] field
# @param [ Mixed ] field_value
#
# @return [ Array ]
def self.remove_params_header_field(params = {}, field)
if !params.has_key?(:headers)
params = params.merge(:headers => { field => nil })
elsif !params[:headers].has_key?(field)
params[:headers][field] = nil
end
params
end
end end

View File

@@ -3,9 +3,8 @@
class Browser class Browser
module Options module Options
attr_accessor :cache_ttl, :request_timeout, :connect_timeout attr_accessor :request_timeout, :connect_timeout, :user_agent, :disable_accept_header, :disable_referer, :disable_tls_checks
attr_reader :basic_auth, :proxy, :proxy_auth, :throttle attr_reader :basic_auth, :cache_ttl, :proxy, :proxy_auth, :throttle
attr_writer :user_agent
# Sets the Basic Authentification credentials # Sets the Basic Authentification credentials
# Accepted format: # Accepted format:
@@ -21,10 +20,14 @@ class Browser
elsif auth =~ /\ABasic [a-zA-Z0-9=]+\z/ elsif auth =~ /\ABasic [a-zA-Z0-9=]+\z/
@basic_auth = auth @basic_auth = auth
else else
raise 'Invalid basic authentication format, "login:password" or "Basic base_64_encoded" expected' raise "Invalid basic authentication format, \"login:password\" or \"Basic base_64_encoded\" expected. Your input: #{auth}"
end end
end end
def cache_ttl=(ttl)
@cache_ttl = ttl.to_i
end
# @return [ Integer ] # @return [ Integer ]
def max_threads def max_threads
@max_threads || 1 @max_threads || 1

View File

@@ -23,11 +23,13 @@ class CacheFileStore
@storage_path = File.expand_path(File.join(storage_path, storage_dir)) @storage_path = File.expand_path(File.join(storage_path, storage_dir))
@serializer = serializer @serializer = serializer
# File.directory? for ruby <= 1.9 otherwise, unless Dir.exist?(@storage_path)
# it makes more sense to do Dir.exist? :/
unless File.directory?(@storage_path)
FileUtils.mkdir_p(@storage_path) FileUtils.mkdir_p(@storage_path)
end end
unless Pathname.new(@storage_path).writable?
fail "#{@storage_path} is not writable"
end
end end
def clean def clean
@@ -51,7 +53,7 @@ class CacheFileStore
end end
def write_entry(key, data_to_store, cache_ttl) def write_entry(key, data_to_store, cache_ttl)
if cache_ttl > 0 if cache_ttl && cache_ttl > 0
File.open(get_entry_file_path(key), 'w') do |f| File.open(get_entry_file_path(key), 'w') do |f|
begin begin
f.write(@serializer.dump(data_to_store)) f.write(@serializer.dump(data_to_store))

2
lib/common/collections/wp_items.rb Executable file → Normal file
View File

@@ -67,7 +67,7 @@ class WpItems < Array
end end
protected protected
# @return [ Class ] # @return [ Class ]
def item_class def item_class
Object.const_get(self.class.to_s.gsub(/.$/, '')) Object.const_get(self.class.to_s.gsub(/.$/, ''))

6
lib/common/collections/wp_items/detectable.rb Executable file → Normal file
View File

@@ -95,6 +95,10 @@ class WpItems < Array
code = tag.text.to_s code = tag.text.to_s
next if code.empty? next if code.empty?
if !code.valid_encoding?
code = code.encode('UTF-16be', :invalid => :replace, :replace => '?').encode('UTF-8')
end
code.scan(code_pattern(wp_target)).flatten.uniq.each do |item_name| code.scan(code_pattern(wp_target)).flatten.uniq.each do |item_name|
names << item_name names << item_name
end end
@@ -116,7 +120,7 @@ class WpItems < Array
wp_content_dir = wp_target.wp_content_dir wp_content_dir = wp_target.wp_content_dir
wp_content_url = wp_target.uri.merge(wp_content_dir).to_s wp_content_url = wp_target.uri.merge(wp_content_dir).to_s
url = /#{wp_content_url.gsub(%r{\A(?:http|https)}, 'https?').gsub('/', '\\\\\?\/')}/i url = wp_content_url.gsub(%r{\A(?:http|https)://}, '(?:https?:)?//').gsub('/', '\\\\\?\/')
content_dir = %r{(?:#{url}|\\?\/\\?\/?#{wp_content_dir})}i content_dir = %r{(?:#{url}|\\?\/\\?\/?#{wp_content_dir})}i
%r{#{content_dir}\\?/#{type}\\?/} %r{#{content_dir}\\?/#{type}\\?/}

16
lib/common/collections/wp_plugins.rb Executable file → Normal file
View File

@@ -1,8 +1,8 @@
# encoding: UTF-8 # encoding: UTF-8
require 'common/collections/wp_plugins/detectable' require 'common/collections/wp_plugins/detectable'
class WpPlugins < WpItems class WpPlugins < WpItems
extend WpPlugins::Detectable extend WpPlugins::Detectable
end end

View File

@@ -62,10 +62,14 @@ class WpPlugins < WpItems
wp_plugins.add('all-in-one-seo-pack', version: $1) wp_plugins.add('all-in-one-seo-pack', version: $1)
end end
if body =~ /<!-- This site is optimized with the Yoast WordPress SEO plugin v([^\s]+) -/i if body =~ /<!-- This site is optimized with the Yoast (?:WordPress )?SEO plugin v([^\s]+) -/i
wp_plugins.add('wordpress-seo', version: $1) wp_plugins.add('wordpress-seo', version: $1)
end end
if body =~ /<!-- Google Universal Analytics for WordPress v([^\s]+) -/i
wp_plugins.add('google-universal-analytics', version: $1)
end
wp_plugins wp_plugins
end end

16
lib/common/collections/wp_themes.rb Executable file → Normal file
View File

@@ -1,8 +1,8 @@
# encoding: UTF-8 # encoding: UTF-8
require 'common/collections/wp_themes/detectable' require 'common/collections/wp_themes/detectable'
class WpThemes < WpItems class WpThemes < WpItems
extend WpThemes::Detectable extend WpThemes::Detectable
end end

16
lib/common/collections/wp_timthumbs.rb Executable file → Normal file
View File

@@ -1,8 +1,8 @@
# encoding: UTF-8 # encoding: UTF-8
require 'common/collections/wp_timthumbs/detectable' require 'common/collections/wp_timthumbs/detectable'
class WpTimthumbs < WpItems class WpTimthumbs < WpItems
extend WpTimthumbs::Detectable extend WpTimthumbs::Detectable
end end

View File

@@ -41,7 +41,7 @@ class WpTimthumbs < WpItems
%w{ %w{
timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php
scripts/timthumb.php tools/timthumb.php functions/timthumb.php scripts/timthumb.php tools/timthumb.php functions/timthumb.php thumb.php
}.each do |path| }.each do |path|
wp_timthumb.path = "$wp-content$/themes/#{theme_name}/#{path}" wp_timthumb.path = "$wp-content$/themes/#{theme_name}/#{path}"

22
lib/common/collections/wp_users.rb Executable file → Normal file
View File

@@ -1,11 +1,11 @@
# encoding: UTF-8 # encoding: UTF-8
require 'common/collections/wp_users/detectable' require 'common/collections/wp_users/detectable'
require 'common/collections/wp_users/output' require 'common/collections/wp_users/output'
require 'common/collections/wp_users/brute_forcable' require 'common/collections/wp_users/brute_forcable'
class WpUsers < WpItems class WpUsers < WpItems
extend WpUsers::Detectable extend WpUsers::Detectable
include WpUsers::Output include WpUsers::Output
include WpUsers::BruteForcable include WpUsers::BruteForcable
end end

68
lib/common/collections/wp_users/detectable.rb Executable file → Normal file
View File

@@ -1,34 +1,34 @@
# encoding: UTF-8 # encoding: UTF-8
class WpUsers < WpItems class WpUsers < WpItems
module Detectable module Detectable
# @return [ Hash ] # @return [ Hash ]
def request_params; {} end def request_params; {} end
# No passive detection # No passive detection
# #
# @return [ WpUsers ] # @return [ WpUsers ]
def passive_detection(wp_target, options = {}) def passive_detection(wp_target, options = {})
new new
end end
protected protected
# @param [ WpTarget ] wp_target # @param [ WpTarget ] wp_target
# @param [ Hash ] options # @param [ Hash ] options
# @option options [ Range ] :range ((1..10)) # @option options [ Range ] :range ((1..10))
# #
# @return [ Array<WpUser> ] # @return [ Array<WpUser> ]
def targets_items(wp_target, options = {}) def targets_items(wp_target, options = {})
range = options[:range] || (1..10) range = options[:range] || (1..10)
targets = [] targets = []
range.each do |user_id| range.each do |user_id|
targets << WpUser.new(wp_target.uri, id: user_id) targets << WpUser.new(wp_target.uri, id: user_id)
end end
targets targets
end end
end end
end end

View File

@@ -9,7 +9,7 @@ class WpUsers < WpItems
# @return [ void ] # @return [ void ]
def output(options = {}) def output(options = {})
rows = [] rows = []
headings = ['Id', 'Login', 'Name'] headings = ['ID', 'Login', 'Name']
headings << 'Password' if options[:show_password] headings << 'Password' if options[:show_password]
remove_junk_from_display_names remove_junk_from_display_names

View File

@@ -1,34 +1,34 @@
# encoding: UTF-8 # encoding: UTF-8
LIB_DIR = File.expand_path(File.join(File.dirname(__FILE__), '..')) # Location directories
ROOT_DIR = File.expand_path(File.join(LIB_DIR, '..')) # expand_path is used to get "wpscan/" instead of "wpscan/lib/../" LIB_DIR = File.expand_path(File.join(__dir__, '..')) # wpscan/lib/
DATA_DIR = File.join(ROOT_DIR, 'data') ROOT_DIR = File.expand_path(File.join(LIB_DIR, '..')) # wpscan/ - expand_path is used to get "wpscan/" instead of "wpscan/lib/../"
CONF_DIR = File.join(ROOT_DIR, 'conf') USER_DIR = File.expand_path(Dir.home) # ~/
CACHE_DIR = File.join(ROOT_DIR, 'cache')
WPSCAN_LIB_DIR = File.join(LIB_DIR, 'wpscan')
UPDATER_LIB_DIR = File.join(LIB_DIR, 'updater')
COMMON_LIB_DIR = File.join(LIB_DIR, 'common')
MODELS_LIB_DIR = File.join(COMMON_LIB_DIR, 'models')
COLLECTIONS_LIB_DIR = File.join(COMMON_LIB_DIR, 'collections')
LOG_FILE = File.join(ROOT_DIR, 'log.txt') # Core WPScan directories
CACHE_DIR = File.join(USER_DIR, '.wpscan/cache') # ~/.wpscan/cache/
DATA_DIR = File.join(USER_DIR, '.wpscan/data') # ~/.wpscan/data/
CONF_DIR = File.join(USER_DIR, '.wpscan/conf') # ~/.wpscan/conf/ - Not used ATM (only ref via ./spec/ for travis)
COMMON_LIB_DIR = File.join(LIB_DIR, 'common') # wpscan/lib/common/
WPSCAN_LIB_DIR = File.join(LIB_DIR, 'wpscan') # wpscan/lib/wpscan/
MODELS_LIB_DIR = File.join(COMMON_LIB_DIR, 'models') # wpscan/lib/common/models/
# Plugins directories # Core WPScan files
COMMON_PLUGINS_DIR = File.join(COMMON_LIB_DIR, 'plugins') DEFAULT_LOG_FILE = File.join(USER_DIR, '.wpscan/log.txt') # ~/.wpscan/log.txt
WPSCAN_PLUGINS_DIR = File.join(WPSCAN_LIB_DIR, 'plugins') # Not used ATM DATA_FILE = File.join(ROOT_DIR, 'data.zip') # wpscan/data.zip
# Data files # WPScan Data files (data.zip)
WORDPRESSES_FILE = File.join(DATA_DIR, 'wordpresses.json') LAST_UPDATE_FILE = File.join(DATA_DIR, '.last_update') # ~/.wpscan/data/.last_update
PLUGINS_FILE = File.join(DATA_DIR, 'plugins.json') PLUGINS_FILE = File.join(DATA_DIR, 'plugins.json') # ~/.wpscan/data/plugins.json
THEMES_FILE = File.join(DATA_DIR, 'themes.json') THEMES_FILE = File.join(DATA_DIR, 'themes.json') # ~/.wpscan/data/themes.json
WP_VERSIONS_FILE = File.join(DATA_DIR, 'wp_versions.xml') TIMTHUMBS_FILE = File.join(DATA_DIR, 'timthumbs.txt') # ~/.wpscan/data/timthumbs.txt
LOCAL_FILES_FILE = File.join(DATA_DIR, 'local_vulnerable_files.xml') USER_AGENTS_FILE = File.join(DATA_DIR, 'user-agents.txt') # ~/.wpscan/data/user-agents.txt
WP_VERSIONS_XSD = File.join(DATA_DIR, 'wp_versions.xsd') WORDPRESSES_FILE = File.join(DATA_DIR, 'wordpresses.json') # ~/.wpscan/data/wordpresses.json
LOCAL_FILES_XSD = File.join(DATA_DIR, 'local_vulnerable_files.xsd') WP_VERSIONS_FILE = File.join(DATA_DIR, 'wp_versions.xml') # ~/.wpscan/data/wp_versions.xml
USER_AGENTS_FILE = File.join(DATA_DIR, 'user-agents.txt')
LAST_UPDATE_FILE = File.join(DATA_DIR, '.last_update')
WPSCAN_VERSION = '2.9' MIN_RUBY_VERSION = '2.1.9'
WPSCAN_VERSION = '2.9.5-dev'
$LOAD_PATH.unshift(LIB_DIR) $LOAD_PATH.unshift(LIB_DIR)
$LOAD_PATH.unshift(WPSCAN_LIB_DIR) $LOAD_PATH.unshift(WPSCAN_LIB_DIR)
@@ -42,7 +42,13 @@ def kali_linux?
end end
end end
# Determins if installed on Windows OS
def windows?
Gem.win_platform?
end
require 'environment' require 'environment'
require 'zip'
def escape_glob(s) def escape_glob(s)
s.gsub(/[\\\{\}\[\]\*\?]/) { |x| '\\' + x } s.gsub(/[\\\{\}\[\]\*\?]/) { |x| '\\' + x }
@@ -71,13 +77,39 @@ def add_trailing_slash(url)
url =~ /\/$/ ? url : "#{url}/" url =~ /\/$/ ? url : "#{url}/"
end end
def missing_db_file? def missing_db_files?
DbUpdater::FILES.each do |db_file| DbUpdater::FILES.each do |db_file|
return true unless File.exist?(File.join(DATA_DIR, db_file)) return true unless File.exist?(File.join(DATA_DIR, db_file))
end end
false false
end end
# Find data.zip?
def has_db_zip?
return File.exist?(DATA_FILE)
end
# Extract data.zip
def extract_db_zip
# Create data folder
FileUtils.mkdir_p(DATA_DIR)
Zip::File.open(DATA_FILE) do |zip_file|
zip_file.each do |f|
# Feedback to the user
#puts "[+] Extracting: #{File.basename(f.name)}"
f_path = File.join(DATA_DIR, File.basename(f.name))
# Delete if already there
#puts "[+] Deleting: #{File.basename(f.name)}" if File.exist?(f_path)
FileUtils.rm(f_path) if File.exist?(f_path)
# Extract
zip_file.extract(f, f_path)
end
end
end
def last_update def last_update
date = nil date = nil
if File.exists?(LAST_UPDATE_FILE) if File.exists?(LAST_UPDATE_FILE)
@@ -87,9 +119,12 @@ def last_update
date date
end end
# Was it 5 days ago?
def update_required? def update_required?
date = last_update date = last_update
(true if date.nil?) or (date < 5.days.ago) day_seconds = 24 * 60 * 60
five_days_ago = Time.now - (5 * day_seconds)
(true if date.nil?) or (date < five_days_ago)
end end
# Define colors # Define colors
@@ -144,7 +179,7 @@ def banner
puts '_______________________________________________________________' puts '_______________________________________________________________'
puts ' __ _______ _____ ' puts ' __ _______ _____ '
puts ' \\ \\ / / __ \\ / ____| ' puts ' \\ \\ / / __ \\ / ____| '
puts ' \\ \\ /\\ / /| |__) | (___ ___ __ _ _ __ ' puts ' \\ \\ /\\ / /| |__) | (___ ___ __ _ _ __ ®'
puts ' \\ \\/ \\/ / | ___/ \\___ \\ / __|/ _` | \'_ \\ ' puts ' \\ \\/ \\/ / | ___/ \\___ \\ / __|/ _` | \'_ \\ '
puts ' \\ /\\ / | | ____) | (__| (_| | | | |' puts ' \\ /\\ / | | ____) | (__| (_| | | | |'
puts ' \\/ \\/ |_| |_____/ \\___|\\__,_|_| |_|' puts ' \\/ \\/ |_| |_____/ \\___|\\__,_|_| |_|'
@@ -152,7 +187,7 @@ def banner
puts ' WordPress Security Scanner by the WPScan Team ' puts ' WordPress Security Scanner by the WPScan Team '
puts " Version #{WPSCAN_VERSION}" puts " Version #{WPSCAN_VERSION}"
puts ' Sponsored by Sucuri - https://sucuri.net' puts ' Sponsored by Sucuri - https://sucuri.net'
puts ' @_WPScan_, @ethicalhack3r, @erwan_lr, pvdl, @_FireFart_' puts ' @_WPScan_, @ethicalhack3r, @erwan_lr, @_FireFart_'
puts '_______________________________________________________________' puts '_______________________________________________________________'
puts puts
end end
@@ -223,7 +258,11 @@ end
# #
# @return [ Integer ] The number of lines in the given file # @return [ Integer ] The number of lines in the given file
def count_file_lines(file) def count_file_lines(file)
`wc -l #{file.shellescape}`.split[0].to_i if windows?
`findstr /R /N "^" #{file.shellescape} | find /C ":"`.split[0].to_i
else
`wc -l #{file.shellescape}`.split[0].to_i
end
end end
# Truncates a string to a specific length and adds ... at the end # Truncates a string to a specific length and adds ... at the end
@@ -240,14 +279,26 @@ end
# @return [ String ] A random user-agent from data/user-agents.txt # @return [ String ] A random user-agent from data/user-agents.txt
def get_random_user_agent def get_random_user_agent
user_agents = [] user_agents = []
# If we can't access the file, die
raise('[ERROR] Missing user-agent data. Please re-run with just --update.') unless File.exist?(USER_AGENTS_FILE)
# Read in file
f = File.open(USER_AGENTS_FILE, 'r') f = File.open(USER_AGENTS_FILE, 'r')
# Read every line in the file
f.each_line do |line| f.each_line do |line|
# ignore comments # Remove any End of Line issues, and leading/trailing spaces
line = line.strip.chomp
# Ignore empty files and comments
next if line.empty? or line =~ /^\s*(#|\/\/)/ next if line.empty? or line =~ /^\s*(#|\/\/)/
# Add to array
user_agents << line.strip user_agents << line.strip
end end
# Close file handler
f.close f.close
# return ransom user-agent
# Return random user-agent
user_agents.sample user_agents.sample
end end
@@ -257,3 +308,25 @@ end
def directory_listing_enabled?(url) def directory_listing_enabled?(url)
Browser.get(url.to_s).body[%r{<title>Index of}] ? true : false Browser.get(url.to_s).body[%r{<title>Index of}] ? true : false
end end
def url_encode(str)
CGI.escape(str).gsub("+", "%20")
end
# Check valid JSON?
def valid_json?(json)
JSON.parse(json)
return true
rescue JSON::ParserError => e
return false
end
# Get the HTTP response code
def get_http_status(url)
Browser.get(url.to_s).code
end
# Check to see if we need a "s"
def grammar_s(size)
size.to_i >= 2 ? "s" : ""
end

View File

@@ -13,8 +13,13 @@ class DbUpdater
def initialize(repo_directory) def initialize(repo_directory)
@repo_directory = repo_directory @repo_directory = repo_directory
fail "#{repo_directory} is not writable" unless \ unless Dir.exist?(@repo_directory)
Pathname.new(repo_directory).writable? FileUtils.mkdir_p(@repo_directory)
end
unless Pathname.new(@repo_directory).writable?
fail "#{@repo_directory} is not writable"
end
end end
# @return [ Hash ] The params for Typhoeus::Request # @return [ Hash ] The params for Typhoeus::Request
@@ -22,13 +27,15 @@ class DbUpdater
{ {
ssl_verifyhost: 2, ssl_verifyhost: 2,
ssl_verifypeer: true, ssl_verifypeer: true,
accept_encoding: 'gzip, deflate' accept_encoding: 'gzip, deflate',
timeout: 300,
connecttimeout: 20
} }
end end
# @return [ String ] The raw file URL associated with the given filename # @return [ String ] The raw file URL associated with the given filename
def remote_file_url(filename) def remote_file_url(filename)
"https://wpvulndb.com/data/#{filename}" "https://data.wpscan.org/#{filename}"
end end
# @return [ String ] The checksum of the associated remote filename # @return [ String ] The checksum of the associated remote filename
@@ -81,7 +88,7 @@ class DbUpdater
def update(verbose = false) def update(verbose = false)
FILES.each do |filename| FILES.each do |filename|
begin begin
puts "[+] Checking #{filename}" if verbose puts "[+] Checking: #{filename}" if verbose
db_checksum = remote_file_checksum(filename) db_checksum = remote_file_checksum(filename)
# Checking if the file needs to be updated # Checking if the file needs to be updated
@@ -93,13 +100,13 @@ class DbUpdater
puts ' [i] Needs to be updated' if verbose puts ' [i] Needs to be updated' if verbose
create_backup(filename) create_backup(filename)
puts ' [i] Backup Created' if verbose puts ' [i] Backup Created' if verbose
puts ' [i] Downloading new file' if verbose puts " [i] Downloading new file: #{remote_file_url(filename)}" if verbose
dl_checksum = download(filename) dl_checksum = download(filename)
puts " [i] Downloaded File Checksum: #{dl_checksum}" if verbose puts " [i] Downloaded File Checksum: #{dl_checksum}" if verbose
puts " [i] Database File Checksum : #{db_checksum}" if verbose puts " [i] Database File Checksum : #{db_checksum}" if verbose
unless dl_checksum == db_checksum unless dl_checksum == db_checksum
fail "#{filename}: checksums do not match" raise ChecksumError.new(File.read(local_file_path(filename))), "#{filename}: checksums do not match (local: #{dl_checksum} remote: #{db_checksum})"
end end
rescue => e rescue => e
puts ' [i] Restoring Backup due to error' if verbose puts ' [i] Restoring Backup due to error' if verbose

View File

@@ -31,3 +31,11 @@ class DownloadError < HttpError
"Unable to get #{failure_details}" "Unable to get #{failure_details}"
end end
end end
class ChecksumError < StandardError
attr_reader :file
def initialize(file)
@file = file
end
end

View File

@@ -1,35 +1,5 @@
# encoding: UTF-8 # encoding: UTF-8
# Since ruby 1.9.2, URI::escape is obsolete
# See http://rosettacode.org/wiki/URL_encoding#Ruby and http://www.ruby-forum.com/topic/207489
if RUBY_VERSION >= '1.9.2'
module URI
extend self
def escape(str)
URI::Parser.new.escape(str)
end
alias :encode :escape
end
end
if RUBY_VERSION < '1.9'
class Array
# Fix for grep with symbols in ruby <= 1.8.7
def _grep_(regexp)
matches = []
self.each do |value|
value = value.to_s
matches << value if value.match(regexp)
end
matches
end
alias_method :grep, :_grep_
end
end
# This is used in WpItem::Existable # This is used in WpItem::Existable
module Typhoeus module Typhoeus
class Response class Response
@@ -51,71 +21,17 @@ end
def puts(o = '') def puts(o = '')
if $log && o.respond_to?(:gsub) if $log && o.respond_to?(:gsub)
temp = o.gsub(/\e\[\d+m/, '') # remove color for logging temp = o.gsub(/\e\[\d+m/, '') # remove color for logging
File.open(LOG_FILE, 'a+') { |f| f.puts(temp) } File.open($log, 'a+') { |f| f.puts(temp) }
end end
super(o) super(o)
end end
module Terminal
class Table
def render
separator = Separator.new(self)
buffer = [separator]
unless @title.nil?
buffer << Row.new(self, [title_cell_options])
buffer << separator
end
unless @headings.cells.empty?
buffer << @headings
buffer << separator
end
buffer += @rows
buffer << separator
buffer.map { |r| style.margin_left + r.render }.join("\n")
end
alias :to_s :render
class Style
@@defaults = {
:border_x => '-', :border_y => '|', :border_i => '+',
:padding_left => 1, :padding_right => 1,
:margin_left => '',
:width => nil, :alignment => nil
}
attr_accessor :margin_left
attr_accessor :border_x
attr_accessor :border_y
attr_accessor :border_i
attr_accessor :padding_left
attr_accessor :padding_right
attr_accessor :width
attr_accessor :alignment
end
end
end
class Numeric class Numeric
def bytes_to_human def bytes_to_human
units = %w{B KB MB GB TB} units = %w{B KB MB GB TB}
e = (Math.log(self)/Math.log(1024)).floor e = (Math.log(abs)/Math.log(1024)).floor
s = '%.3f' % (to_f / 1024**e) s = '%.3f' % (abs.to_f / 1024**e)
s.sub(/\.?0*$/, ' ' + units[e]) s.sub(/\.?0*$/, ' ' + units[e])
end end
end end
# time calculations
class Fixnum
SECONDS_IN_DAY = 24 * 60 * 60
def days
self * SECONDS_IN_DAY
end
def ago
Time.now - self
end
end

124
lib/common/models/vulnerability.rb Executable file → Normal file
View File

@@ -1,62 +1,62 @@
# encoding: UTF-8 # encoding: UTF-8
require 'vulnerability/output' require 'vulnerability/output'
require 'vulnerability/urls' require 'vulnerability/urls'
class Vulnerability class Vulnerability
include Vulnerability::Output include Vulnerability::Output
include Vulnerability::Urls include Vulnerability::Urls
attr_accessor :title, :references, :type, :fixed_in attr_accessor :title, :references, :type, :fixed_in
# #
# @param [ String ] title The title of the vulnerability # @param [ String ] title The title of the vulnerability
# @param [ String ] type The type of the vulnerability # @param [ String ] type The type of the vulnerability
# @param [ Hash ] references References # @param [ Hash ] references References
# @param [ String ] fixed_in Vuln fixed in Version X # @param [ String ] fixed_in Vuln fixed in Version X
# #
# @return [ Vulnerability ] # @return [ Vulnerability ]
def initialize(title, type, references = {}, fixed_in = '') def initialize(title, type, references = {}, fixed_in = '')
@title = title @title = title
@type = type @type = type
@references = references @references = references
@fixed_in = fixed_in @fixed_in = fixed_in
end end
# @param [ Vulnerability ] other # @param [ Vulnerability ] other
# #
# @return [ Boolean ] # @return [ Boolean ]
# :nocov: # :nocov:
def ==(other) def ==(other)
title == other.title && title == other.title &&
type == other.type && type == other.type &&
references == other.references && references == other.references &&
fixed_in == other.fixed_in fixed_in == other.fixed_in
end end
# :nocov: # :nocov:
# Create the Vulnerability from the json_item # Create the Vulnerability from the json_item
# #
# @param [ Hash ] json_item # @param [ Hash ] json_item
# #
# @return [ Vulnerability ] # @return [ Vulnerability ]
def self.load_from_json_item(json_item) def self.load_from_json_item(json_item)
references = {} references = {}
references['id'] = [json_item['id']] references['id'] = [json_item['id']]
%w(url cve secunia osvdb metasploit exploitdb).each do |key| %w(url cve secunia osvdb metasploit exploitdb).each do |key|
if json_item['references'][key] if json_item['references'][key]
json_item['references'][key] = [json_item['references'][key]] if json_item['references'][key].class != Array json_item['references'][key] = [json_item['references'][key]] if json_item['references'][key].class != Array
references[key] = json_item['references'][key] references[key] = json_item['references'][key]
end end
end end
new( new(
json_item['title'], json_item['title'],
json_item['type'], json_item['type'],
references, references,
json_item['fixed_in'] json_item['fixed_in']
) )
end end
end end

244
lib/common/models/wp_item.rb Executable file → Normal file
View File

@@ -1,123 +1,121 @@
# encoding: UTF-8 # encoding: UTF-8
require 'wp_item/findable' require 'wp_item/findable'
require 'wp_item/versionable' require 'wp_item/versionable'
require 'wp_item/vulnerable' require 'wp_item/vulnerable'
require 'wp_item/existable' require 'wp_item/existable'
require 'wp_item/infos' require 'wp_item/infos'
require 'wp_item/output' require 'wp_item/output'
class WpItem class WpItem
extend WpItem::Findable extend WpItem::Findable
include WpItem::Versionable include WpItem::Versionable
include WpItem::Vulnerable include WpItem::Vulnerable
include WpItem::Existable include WpItem::Existable
include WpItem::Infos include WpItem::Infos
include WpItem::Output include WpItem::Output
attr_reader :path attr_reader :path
attr_accessor :name, :wp_content_dir, :wp_plugins_dir attr_accessor :name, :wp_content_dir, :wp_plugins_dir
# @return [ Array ] # @return [ Array ]
# Make it private ? # Make it private ?
def allowed_options def allowed_options
[:name, :wp_content_dir, :wp_plugins_dir, :path, :version, :db_file] [:name, :wp_content_dir, :wp_plugins_dir, :path, :version, :db_file]
end end
# @param [ URI ] target_base_uri # @param [ URI ] target_base_uri
# @param [ Hash ] options See allowed_option # @param [ Hash ] options See allowed_option
# #
# @return [ WpItem ] # @return [ WpItem ]
def initialize(target_base_uri, options = {}) def initialize(target_base_uri, options = {})
options[:wp_content_dir] ||= 'wp-content' options[:wp_content_dir] ||= 'wp-content'
options[:wp_plugins_dir] ||= options[:wp_content_dir] + '/plugins' options[:wp_plugins_dir] ||= options[:wp_content_dir] + '/plugins'
set_options(options) set_options(options)
forge_uri(target_base_uri) forge_uri(target_base_uri)
end end
def identifier def identifier
@identifier ||= name @identifier ||= name
end end
# @return [ Hash ] # @return [ Hash ]
def db_data def db_data
@db_data ||= json(db_file)[identifier] || {} @db_data ||= json(db_file)[identifier] || {}
end end
def latest_version def latest_version
db_data['latest_version'] db_data['latest_version']
end end
def last_updated def last_updated
db_data['last_ipdated'] db_data['last_updated']
end end
def popular? def popular?
db_data['popular'] db_data['popular']
end end
# @param [ Hash ] options # @param [ Hash ] options
# #
# @return [ void ] # @return [ void ]
def set_options(options) def set_options(options)
allowed_options.each do |allowed_option| allowed_options.each do |allowed_option|
if options.has_key?(allowed_option) if options.has_key?(allowed_option)
method = :"#{allowed_option}=" method = :"#{allowed_option}="
if self.respond_to?(method) if self.respond_to?(method)
self.send(method, options[allowed_option]) self.send(method, options[allowed_option])
else else
raise "#{self.class} does not respond to #{method}" raise "#{self.class} does not respond to #{method}"
end end
end end
end end
end end
private :set_options private :set_options
# @param [ URI ] target_base_uri # @param [ URI ] target_base_uri
# #
# @return [ void ] # @return [ void ]
def forge_uri(target_base_uri) def forge_uri(target_base_uri)
@uri = target_base_uri @uri = target_base_uri
end end
# @return [ URI ] The uri to the WpItem, with the path if present # @return [ URI ] The uri to the WpItem, with the path if present
def uri def uri
path ? @uri.merge(path) : @uri path ? @uri.merge(path) : @uri
end end
# @return [ String ] The url to the WpItem # @return [ String ] The url to the WpItem
def url; uri.to_s end def url; uri.to_s end
# Sets the path # Sets the path
# #
# Variable, such as $wp-plugins$ and $wp-content$ can be used # Variable, such as $wp-plugins$ and $wp-content$ can be used
# and will be replace by their value # and will be replace by their value
# #
# @param [ String ] path # @param [ String ] path
# #
# @return [ void ] # @return [ void ]
def path=(path) def path=(path)
@path = URI.encode( @path = path.gsub(/\$wp-plugins\$/i, wp_plugins_dir).gsub(/\$wp-content\$/i, wp_content_dir)
path.gsub(/\$wp-plugins\$/i, wp_plugins_dir).gsub(/\$wp-content\$/i, wp_content_dir) end
)
end # @param [ WpItem ] other
def <=>(other)
# @param [ WpItem ] other name <=> other.name
def <=>(other) end
name <=> other.name
end # @param [ WpItem ] other
def ==(other)
# @param [ WpItem ] other name === other.name
def ==(other) end
name === other.name
end # @param [ WpItem ] other
def ===(other)
# @param [ WpItem ] other self == other && version === other.version
def ===(other) end
self == other && version === other.version
end end
end

100
lib/common/models/wp_item/existable.rb Executable file → Normal file
View File

@@ -1,50 +1,50 @@
# encoding: UTF-8 # encoding: UTF-8
class WpItem class WpItem
module Existable module Existable
# Check the existence of the WpItem # Check the existence of the WpItem
# If the response is supplied, it's used for the verification # If the response is supplied, it's used for the verification
# Otherwise a new request is done # Otherwise a new request is done
# #
# @param [ Hash ] options See exists_from_response? # @param [ Hash ] options See exists_from_response?
# @param [ Typhoeus::Response ] response # @param [ Typhoeus::Response ] response
# #
# @return [ Boolean ] # @return [ Boolean ]
def exists?(options = {}, response = nil) def exists?(options = {}, response = nil)
unless response unless response
response = Browser.get(url) response = Browser.get(url)
end end
exists_from_response?(response, options) exists_from_response?(response, options)
end end
protected protected
# @param [ Typhoeus::Response ] response # @param [ Typhoeus::Response ] response
# @param [ options ] options # @param [ options ] options
# #
# @option options [ Hash ] :error_404_hash The hash of the error 404 page # @option options [ Hash ] :error_404_hash The hash of the error 404 page
# @option options [ Hash ] :homepage_hash The hash of the homepage # @option options [ Hash ] :homepage_hash The hash of the homepage
# @option options [ Hash ] :exclude_content A regexp with the pattern to exclude from the body of the response # @option options [ Hash ] :exclude_content A regexp with the pattern to exclude from the body of the response
# #
# @return [ Boolean ] # @return [ Boolean ]
def exists_from_response?(response, options = {}) def exists_from_response?(response, options = {})
# 301 included as some items do a self-redirect # 301 included as some items do a self-redirect
# Redirects to the 404 and homepage should be ignored (unless dynamic content is used) # Redirects to the 404 and homepage should be ignored (unless dynamic content is used)
# by the page hashes (error_404_hash & homepage_hash) # by the page hashes (error_404_hash & homepage_hash)
if [200, 401, 403, 301].include?(response.code) if [200, 401, 403, 301].include?(response.code)
if response.has_valid_hash?(options[:error_404_hash], options[:homepage_hash]) if response.has_valid_hash?(options[:error_404_hash], options[:homepage_hash])
if options[:exclude_content] if options[:exclude_content]
unless response.body.match(options[:exclude_content]) unless response.body.match(options[:exclude_content])
return true return true
end end
else else
return true return true
end end
end end
end end
false false
end end
end end
end end

37
lib/common/models/wp_item/findable.rb Executable file → Normal file
View File

@@ -1,19 +1,18 @@
# encoding: UTF-8 # encoding: UTF-8
class WpItem class WpItem
attr_reader :found_from attr_reader :found_from
# Sets the found_from attribute # Sets the found_from attribute
# #
# @param [ String ] method The method which found the WpItem # @param [ String ] method The method which found the WpItem
# #
# @return [ void ] # @return [ void ]
def found_from=(method) def found_from=(method)
found = method[%r{find_from_(.*)}, 1] @found_from = method.to_s.gsub(/find_from_/, '').gsub(/_/, ' ')
@found_from = found.gsub('_', ' ') if found end
end
module Findable
module Findable
end
end end
end

View File

@@ -5,27 +5,6 @@ class WpItem
# @uri is used instead of #uri to avoid the presence of the :path into it # @uri is used instead of #uri to avoid the presence of the :path into it
module Infos module Infos
# @return [ Boolean ]
def has_readme?
!readme_url.nil?
end
# @return [ String,nil ] The url to the readme file, nil if not found
def readme_url
# See https://github.com/wpscanteam/wpscan/pull/737#issuecomment-66375445
# for any question about the order
%w{readme.txt README.txt Readme.txt ReadMe.txt README.TXT readme.TXT}.each do |readme|
url = @uri.merge(readme).to_s
return url if url_is_200?(url)
end
nil
end
# @return [ Boolean ]
def has_changelog?
url_is_200?(changelog_url)
end
# Checks if the url status code is 200 # Checks if the url status code is 200
# #
# @param [ String ] url # @param [ String ] url
@@ -35,9 +14,34 @@ class WpItem
Browser.get(url).code == 200 Browser.get(url).code == 200
end end
# @return [ Boolean ]
def has_readme?
!readme_url.nil?
end
# @return [ String,nil ] The url to the readme file, nil if not found
def readme_url
# See https://github.com/wpscanteam/wpscan/pull/737#issuecomment-66375445
# for any question about the order
%w{readme.txt README.txt README.md readme.md Readme.txt}.each do |readme|
url = @uri.merge(readme).to_s
return url if url_is_200?(url)
end
nil
end
# @return [ Boolean ]
def has_changelog?
!changelog_url.nil?
end
# @return [ String ] The url to the changelog file # @return [ String ] The url to the changelog file
def changelog_url def changelog_url
@uri.merge('changelog.txt').to_s %w{changelog.txt CHANGELOG.md changelog.md}.each do |changelog|
url = @uri.merge(changelog).to_s
return url if url_is_200?(url)
end
nil
end end
# @return [ Boolean ] # @return [ Boolean ]

View File

@@ -23,7 +23,7 @@ class WpItem
if version.nil? && vulnerabilities.length > 0 if version.nil? && vulnerabilities.length > 0
puts puts
puts warning('We could not determine a version so all vulnerabilities are printed out') puts warning('We could not determine the version installed. All of the past known vulnerabilities will be output to allow you to do your own manual investigation.')
end end
vulnerabilities.output vulnerabilities.output

0
lib/common/models/wp_item/versionable.rb Executable file → Normal file
View File

88
lib/common/models/wp_item/vulnerable.rb Executable file → Normal file
View File

@@ -1,44 +1,44 @@
# encoding: UTF-8 # encoding: UTF-8
class WpItem class WpItem
module Vulnerable module Vulnerable
attr_accessor :db_file, :identifier attr_accessor :db_file, :identifier
# Get the vulnerabilities associated to the WpItem # Get the vulnerabilities associated to the WpItem
# Filters out already fixed vulnerabilities # Filters out already fixed vulnerabilities
# #
# @return [ Vulnerabilities ] # @return [ Vulnerabilities ]
def vulnerabilities def vulnerabilities
return @vulnerabilities if @vulnerabilities return @vulnerabilities if @vulnerabilities
@vulnerabilities = Vulnerabilities.new @vulnerabilities = Vulnerabilities.new
[*db_data['vulnerabilities']].each do |vulnerability| [*db_data['vulnerabilities']].each do |vulnerability|
vulnerability = Vulnerability.load_from_json_item(vulnerability) vulnerability = Vulnerability.load_from_json_item(vulnerability)
@vulnerabilities << vulnerability if vulnerable_to?(vulnerability) @vulnerabilities << vulnerability if vulnerable_to?(vulnerability)
end end
@vulnerabilities @vulnerabilities
end end
def vulnerable? def vulnerable?
vulnerabilities.empty? ? false : true vulnerabilities.empty? ? false : true
end end
# Checks if a item is vulnerable to a specific vulnerability # Checks if a item is vulnerable to a specific vulnerability
# #
# @param [ Vulnerability ] vuln Vulnerability to check the item against # @param [ Vulnerability ] vuln Vulnerability to check the item against
# #
# @return [ Boolean ] # @return [ Boolean ]
def vulnerable_to?(vuln) def vulnerable_to?(vuln)
if version && vuln && vuln.fixed_in && !vuln.fixed_in.empty? if version && vuln && vuln.fixed_in && !vuln.fixed_in.empty?
unless VersionCompare::lesser_or_equal?(vuln.fixed_in, version) unless VersionCompare::lesser_or_equal?(vuln.fixed_in, version)
return true return true
end end
else else
return true return true
end end
return false return false
end end
end end
end end

32
lib/common/models/wp_plugin.rb Executable file → Normal file
View File

@@ -1,16 +1,16 @@
# encoding: UTF-8 # encoding: UTF-8
class WpPlugin < WpItem class WpPlugin < WpItem
# Sets the @uri # Sets the @uri
# #
# @param [ URI ] target_base_uri The URI of the wordpress blog # @param [ URI ] target_base_uri The URI of the wordpress blog
# #
# @return [ void ] # @return [ void ]
def forge_uri(target_base_uri) def forge_uri(target_base_uri)
@uri = target_base_uri.merge(URI.encode(wp_plugins_dir + '/' + name + '/')) @uri = target_base_uri.merge("#{wp_plugins_dir}/#{url_encode(name)}/")
end end
def db_file def db_file
@db_file ||= PLUGINS_FILE @db_file ||= PLUGINS_FILE
end end
end end

74
lib/common/models/wp_theme.rb Executable file → Normal file
View File

@@ -1,37 +1,37 @@
# encoding: UTF-8 # encoding: UTF-8
require 'wp_theme/findable' require 'wp_theme/findable'
require 'wp_theme/versionable' require 'wp_theme/versionable'
require 'wp_theme/info' require 'wp_theme/info'
require 'wp_theme/output' require 'wp_theme/output'
require 'wp_theme/childtheme' require 'wp_theme/childtheme'
class WpTheme < WpItem class WpTheme < WpItem
extend WpTheme::Findable extend WpTheme::Findable
include WpTheme::Versionable include WpTheme::Versionable
include WpTheme::Info include WpTheme::Info
include WpTheme::Output include WpTheme::Output
include WpTheme::Childtheme include WpTheme::Childtheme
attr_accessor :referenced_url attr_accessor :referenced_url
def allowed_options; super << :referenced_url end def allowed_options; super << :referenced_url end
# Sets the @uri # Sets the @uri
# #
# @param [ URI ] target_base_uri The URI of the wordpress blog # @param [ URI ] target_base_uri The URI of the wordpress blog
# #
# @return [ void ] # @return [ void ]
def forge_uri(target_base_uri) def forge_uri(target_base_uri)
@uri = target_base_uri.merge(URI.encode(wp_content_dir + '/themes/' + name + '/')) @uri = target_base_uri.merge("#{wp_content_dir}/themes/#{url_encode(name)}/")
end end
# @return [ String ] The url to the theme stylesheet # @return [ String ] The url to the theme stylesheet
def style_url def style_url
@uri.merge('style.css').to_s @uri.merge('style.css').to_s
end end
def db_file def db_file
@db_file ||= THEMES_FILE @db_file ||= THEMES_FILE
end end
end end

128
lib/common/models/wp_theme/findable.rb Executable file → Normal file
View File

@@ -1,64 +1,64 @@
# encoding: UTF-8 # encoding: UTF-8
class WpTheme < WpItem class WpTheme < WpItem
module Findable module Findable
# Find the main theme of the blog # Find the main theme of the blog
# #
# @param [ URI ] target_uri # @param [ URI ] target_uri
# #
# @return [ WpTheme ] # @return [ WpTheme ]
def find(target_uri) def find(target_uri)
methods.grep(/^find_from_/).each do |method| methods.grep(/^find_from_/).each do |method|
if wp_theme = self.send(method, target_uri) if wp_theme = self.send(method, target_uri)
wp_theme.found_from = method wp_theme.found_from = method.to_s
return wp_theme return wp_theme
end end
end end
nil nil
end end
protected protected
# Discover the wordpress theme by parsing the css link rel # Discover the wordpress theme by parsing the css link rel
# #
# @param [ URI ] target_uri # @param [ URI ] target_uri
# #
# @return [ WpTheme ] # @return [ WpTheme ]
def find_from_css_link(target_uri) def find_from_css_link(target_uri)
response = Browser.get_and_follow_location(target_uri.to_s) response = Browser.get_and_follow_location(target_uri.to_s)
# https + domain is optional because of relative links # https + domain is optional because of relative links
return unless response.body =~ %r{(?:https?://[^"']+/)?([^/\s]+)/themes/([^"'/]+)[^"']*/style.css}i return unless response.body =~ %r{(?:https?://[^"']+/)?([^"'/\s]+)/themes/([^"'/]+)[^"']*/style\.css}i
new( new(
target_uri, target_uri,
name: Regexp.last_match[2], name: Regexp.last_match[2],
referenced_url: Regexp.last_match[0], referenced_url: Regexp.last_match[0],
wp_content_dir: Regexp.last_match[1] wp_content_dir: Regexp.last_match[1]
) )
end end
# @param [ URI ] target_uri # @param [ URI ] target_uri
# #
# @return [ WpTheme ] # @return [ WpTheme ]
def find_from_wooframework(target_uri) def find_from_wooframework(target_uri)
body = Browser.get(target_uri.to_s).body body = Browser.get(target_uri.to_s).body
regexp = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?" />\s+<meta name="generator" content="WooFramework\s?([^"]+)?" />} regexp = %r{<meta name="generator" content="([^\s"]+)\s?([^"]+)?" />\s+<meta name="generator" content="WooFramework\s?([^"]+)?" />}
if matches = regexp.match(body) if matches = regexp.match(body)
woo_theme_name = matches[1] woo_theme_name = matches[1]
woo_theme_version = matches[2] woo_theme_version = matches[2]
#woo_framework_version = matches[3] # Not used at this time #woo_framework_version = matches[3] # Not used at this time
return new( return new(
target_uri, target_uri,
name: woo_theme_name, name: woo_theme_name,
version: woo_theme_version version: woo_theme_version
) )
end end
end end
end end
end end

View File

@@ -6,13 +6,13 @@ class WpTheme
# @return [ Void ] # @return [ Void ]
def additional_output(verbose = false) def additional_output(verbose = false)
parse_style parse_style
theme_desc = verbose ? @theme_description : truncate(@theme_description, 100) theme_desc = verbose ? @theme_description : truncate(@theme_description, 100)
puts " | Style URL: #{style_url}" puts " | Style URL: #{style_url}"
puts " | Referenced style.css: #{referenced_url}" if referenced_url && referenced_url != style_url puts " | Referenced style.css: #{referenced_url}" if referenced_url && referenced_url != style_url
puts " | Theme Name: #{@theme_name}" if @theme_name puts " | Theme Name: #{@theme_name}" if @theme_name
puts " | Theme URI: #{@theme_uri}" if @theme_uri puts " | Theme URI: #{@theme_uri}" if @theme_uri
puts " | Description: #{theme_desc}" puts " | Description: #{theme_desc}" if theme_desc
puts " | Author: #{@theme_author}" if @theme_author puts " | Author: #{@theme_author}" if @theme_author
puts " | Author URI: #{@theme_author_uri}" if @theme_author_uri puts " | Author URI: #{@theme_author_uri}" if @theme_author_uri
puts " | Template: #{@theme_template}" if @theme_template and verbose puts " | Template: #{@theme_template}" if @theme_template and verbose

18
lib/common/models/wp_theme/versionable.rb Executable file → Normal file
View File

@@ -1,9 +1,9 @@
# encoding: UTF-8 # encoding: UTF-8
class WpTheme < WpItem class WpTheme < WpItem
module Versionable module Versionable
def version def version
@version ||= Browser.get(style_url).body[%r{Version:\s*(?!trunk)([0-9a-z\.-]+)}i, 1] @version ||= Browser.get(style_url).body[%r{Version:\s*(?!trunk)([0-9a-z\.-]+)}i, 1]
end end
end end
end end

40
lib/common/models/wp_timthumb.rb Executable file → Normal file
View File

@@ -1,20 +1,20 @@
# encoding: UTF-8 # encoding: UTF-8
require 'wp_timthumb/versionable' require 'wp_timthumb/versionable'
require 'wp_timthumb/existable' require 'wp_timthumb/existable'
require 'wp_timthumb/output' require 'wp_timthumb/output'
require 'wp_timthumb/vulnerable' require 'wp_timthumb/vulnerable'
class WpTimthumb < WpItem class WpTimthumb < WpItem
include WpTimthumb::Versionable include WpTimthumb::Versionable
include WpTimthumb::Existable include WpTimthumb::Existable
include WpTimthumb::Output include WpTimthumb::Output
include WpTimthumb::Vulnerable include WpTimthumb::Vulnerable
# @param [ WpTimthumb ] other # @param [ WpTimthumb ] other
# #
# @return [ Boolean ] # @return [ Boolean ]
def ==(other) def ==(other)
url == other.url url == other.url
end end
end end

48
lib/common/models/wp_timthumb/versionable.rb Executable file → Normal file
View File

@@ -1,24 +1,24 @@
# encoding: UTF-8 # encoding: UTF-8
class WpTimthumb < WpItem class WpTimthumb < WpItem
module Versionable module Versionable
# Get the version from the body of an invalid request # Get the version from the body of an invalid request
# See https://code.google.com/p/timthumb/source/browse/trunk/timthumb.php#426 # See https://code.google.com/p/timthumb/source/browse/trunk/timthumb.php#426
# #
# @return [ String ] The version # @return [ String ] The version
def version def version
unless @version unless @version
response = Browser.get(url) response = Browser.get(url)
@version = response.body[%r{TimThumb version\s*: ([^<]+)} , 1] @version = response.body[%r{TimThumb version\s*: ([^<]+)} , 1]
end end
@version @version
end end
# @return [ String ] # @return [ String ]
def to_s def to_s
"#{url}#{ ' v' + version if version}" "#{url}#{ ' v' + version if version}"
end end
end end
end end

0
lib/common/models/wp_user.rb Executable file → Normal file
View File

View File

@@ -3,6 +3,8 @@
class WpUser < WpItem class WpUser < WpItem
module BruteForcable module BruteForcable
attr_reader :progress_bar
# Brute force the user with the wordlist supplied # Brute force the user with the wordlist supplied
# #
# It can take a long time to queue 2 million requests, # It can take a long time to queue 2 million requests,
@@ -25,9 +27,19 @@ class WpUser < WpItem
hydra = browser.hydra hydra = browser.hydra
queue_count = 0 queue_count = 0
found = false found = false
progress_bar = self.progress_bar(count_file_lines(wordlist)+1, options)
File.open(wordlist).each do |password| if wordlist == '-'
words = ARGF
passwords_size = 10
options[:starting_at] = 0
else
words = File.open(wordlist)
passwords_size = count_file_lines(wordlist)+1
end
create_progress_bar(passwords_size, options)
words.each do |password|
password.chomp! password.chomp!
# A successfull login will redirect us to the redirect_to parameter # A successfull login will redirect us to the redirect_to parameter
@@ -40,9 +52,15 @@ class WpUser < WpItem
request = login_request(password, redirect_url) request = login_request(password, redirect_url)
request.on_complete do |response| request.on_complete do |response|
progress_bar.progress += 1 if options[:show_progression] && !found if options[:show_progression] && !found
progress_bar.progress += 1
percentage = progress_bar.progress.fdiv(progress_bar.total)
if options[:starting_at] && percentage >= 0.8
progress_bar.total *= 2
end
end
puts "\n Trying Username : #{login} Password : #{password}" if options[:verbose] progress_bar.log(" Trying Username: #{login} Password: #{password}") if options[:verbose]
if valid_password?(response, password, redirect_url, options) if valid_password?(response, password, redirect_url, options)
found = true found = true
@@ -57,7 +75,7 @@ class WpUser < WpItem
if queue_count >= browser.max_threads if queue_count >= browser.max_threads
hydra.run hydra.run
queue_count = 0 queue_count = 0
puts "Sent #{browser.max_threads} requests ..." if options[:verbose] progress_bar.log(" Sent #{browser.max_threads} request/s ...") if options[:verbose]
end end
end end
@@ -71,12 +89,13 @@ class WpUser < WpItem
# #
# @return [ ProgressBar ] # @return [ ProgressBar ]
# :nocov: # :nocov:
def progress_bar(passwords_size, options) def create_progress_bar(passwords_size, options)
if options[:show_progression] if options[:show_progression]
ProgressBar.create( @progress_bar = ProgressBar.create(
format: '%t %a <%B> (%c / %C) %P%% %e', format: '%t %a <%B> (%c / %C) %P%% %e',
title: " Brute Forcing '#{login}'", title: " Brute Forcing '#{login}'",
total: passwords_size total: passwords_size,
starting_at: options[:starting_at]
) )
end end
end end
@@ -107,20 +126,20 @@ class WpUser < WpItem
progression = "#{info('[SUCCESS]')} Login : #{login} Password : #{password}\n\n" progression = "#{info('[SUCCESS]')} Login : #{login} Password : #{password}\n\n"
valid = true valid = true
elsif response.body =~ /login_error/i elsif response.body =~ /login_error/i
verbose = "\n Incorrect login and/or password." verbose = "Incorrect login and/or password."
elsif response.timed_out? elsif response.timed_out?
progression = critical('ERROR: Request timed out.') progression = critical('ERROR: Request timed out.')
elsif response.code == 0 elsif response.code == 0
progression = critical("ERROR: No response from remote server. WAF/IPS? (#{response.return_message})") progression = critical("ERROR: No response from remote server. WAF/IPS? (#{response.return_message})")
elsif response.code.to_s =~ /^50/ elsif response.code.to_s =~ /^50/
progression = critical('ERROR: Server error, try reducing the number of threads.') progression = critical('ERROR: Server error, try reducing the number of threads or use the --throttle option.')
else else
progression = critical("ERROR: We received an unknown response for #{password}...") progression = critical("ERROR: We received an unknown response for login: #{login} and password: #{password}")
verbose = critical(" Code: #{response.code}\n Body: #{response.body}\n") verbose = critical(" Code: #{response.code}\n Body: #{response.body}\n")
end end
puts "\n " + progression if progression && options[:show_progression] progress_bar.log(" #{progression}") if progression && options[:show_progression]
puts verbose if verbose && options[:verbose] progress_bar.log(" #{verbose}") if verbose && options[:verbose]
valid || false valid || false
end end

172
lib/common/models/wp_user/existable.rb Executable file → Normal file
View File

@@ -1,86 +1,86 @@
# encoding: UTF-8 # encoding: UTF-8
class WpUser < WpItem class WpUser < WpItem
module Existable module Existable
# @param [ Typhoeus::Response ] response # @param [ Typhoeus::Response ] response
# @param [ Hash ] options # @param [ Hash ] options
# #
# @return [ Boolean ] # @return [ Boolean ]
def exists_from_response?(response, options = {}) def exists_from_response?(response, options = {})
load_from_response(response) load_from_response(response)
@login ? true : false @login ? true : false
end end
# Load the login and display_name from the response # Load the login and display_name from the response
# #
# @param [ Typhoeus::Response ] response # @param [ Typhoeus::Response ] response
# #
# @return [ void ] # @return [ void ]
def load_from_response(response) def load_from_response(response)
if response.code == 301 # login in location? if response.code == 301 # login in location?
location = response.headers_hash['Location'] location = response.headers_hash['Location']
return if location.nil? || location.empty? return if location.nil? || location.empty?
@login = Existable.login_from_author_pattern(location) @login = Existable.login_from_author_pattern(location)
@display_name = Existable.display_name_from_body( @display_name = Existable.display_name_from_body(
Browser.get(location).body Browser.get(location).body
) )
elsif response.code == 200 # login in body? elsif response.code == 200 # login in body?
@login = Existable.login_from_body(response.body) @login = Existable.login_from_body(response.body)
@display_name = Existable.display_name_from_body(response.body) @display_name = Existable.display_name_from_body(response.body)
end end
end end
private :load_from_response private :load_from_response
# @param [ String ] text # @param [ String ] text
# #
# @return [ String ] The login # @return [ String ] The login
def self.login_from_author_pattern(text) def self.login_from_author_pattern(text)
return unless text =~ %r{/author/([^/\b"']+)/?}i return unless text =~ %r{/author/([^/\b"']+)/?}i
Regexp.last_match[1].force_encoding('UTF-8') Regexp.last_match[1].force_encoding('UTF-8')
end end
# @param [ String ] body # @param [ String ] body
# #
# @return [ String ] The login # @return [ String ] The login
def self.login_from_body(body) def self.login_from_body(body)
# Feed URL with Permalinks # Feed URL with Permalinks
login = WpUser::Existable.login_from_author_pattern(body) login = WpUser::Existable.login_from_author_pattern(body)
unless login unless login
# No Permalinks # No Permalinks
login = body[%r{<body class="archive author author-([^\s]+)[ "]}i, 1] login = body[%r{<body class="archive author author-([^\s]+)[ "]}i, 1]
login ? login.force_encoding('UTF-8') : nil login ? login.force_encoding('UTF-8') : nil
end end
login login
end end
# @note Some bodies are encoded in ASCII-8BIT, and Nokogiri doesn't support it # @note Some bodies are encoded in ASCII-8BIT, and Nokogiri doesn't support it
# So it's forced to UTF-8 when this encoding is detected # So it's forced to UTF-8 when this encoding is detected
# #
# @param [ String ] body # @param [ String ] body
# #
# @return [ String ] The display_name # @return [ String ] The display_name
def self.display_name_from_body(body) def self.display_name_from_body(body)
if title_tag = body[%r{<title>([^<]+)</title>}i, 1] if title_tag = body[%r{<title>([^<]+)</title>}i, 1]
title_tag.force_encoding('UTF-8') if title_tag.encoding == Encoding::ASCII_8BIT title_tag.force_encoding('UTF-8') if title_tag.encoding == Encoding::ASCII_8BIT
title_tag = Nokogiri::HTML::DocumentFragment.parse(title_tag).to_s title_tag = Nokogiri::HTML::DocumentFragment.parse(title_tag).to_s
# &amp; are not decoded with Nokogiri # &amp; are not decoded with Nokogiri
title_tag.gsub!('&amp;', '&') title_tag.gsub!('&amp;', '&')
# replace UTF chars like &#187; with dummy character # replace UTF chars like &#187; with dummy character
title_tag.gsub!(/&#(\d+);/, '|') title_tag.gsub!(/&#(\d+);/, '|')
name = title_tag[%r{([^|«»]+) }, 1] name = title_tag[%r{([^|«»]+) }, 1]
return name.strip if name return name.strip if name
end end
end end
end end
end end

89
lib/common/models/wp_version.rb Executable file → Normal file
View File

@@ -1,38 +1,51 @@
# encoding: UTF-8 # encoding: UTF-8
require 'wp_version/findable' require 'wp_version/findable'
require 'wp_version/output' require 'wp_version/output'
class WpVersion < WpItem class WpVersion < WpItem
extend WpVersion::Findable extend WpVersion::Findable
include WpVersion::Output include WpVersion::Output
# The version number # The version number
attr_accessor :number attr_accessor :number, :metadata
alias_method :version, :number # Needed to have the right behaviour in Vulnerable#vulnerable_to? alias_method :version, :number # Needed to have the right behaviour in Vulnerable#vulnerable_to?
# @return [ Array ] # @return [ Array ]
def allowed_options; super << :number << :found_from end def allowed_options; super << :number << :found_from end
def identifier def identifier
@identifier ||= number @identifier ||= number
end end
def db_file def db_file
@db_file ||= WORDPRESSES_FILE @db_file ||= WORDPRESSES_FILE
end end
# @param [ WpVersion ] other # @param [ WpVersion ] other
# #
# @return [ Boolean ] # @return [ Boolean ]
def ==(other) def ==(other)
number == other.number number == other.number
end end
# @return [ Array<String> ] All the stable versions from version_file # @return [ Array<String> ] All the stable versions from version_file
def self.all(versions_file = WP_VERSIONS_FILE) def self.all(versions_file = WP_VERSIONS_FILE)
Nokogiri.XML(File.open(versions_file)).css('version').reduce([]) do |a, node| Nokogiri.XML(File.open(versions_file)).css('version').reduce([]) do |a, node|
a << node.text.to_s a << node.text.to_s
end end
end end
end
# @return [ Hash ] Metadata for specific WP version from WORDPRESSES_FILE
def metadata(version)
json = json(db_file)
metadata = {}
temp = json[version]
if !temp.nil?
metadata[:release_date] = temp['release_date']
metadata[:changelog_url] = temp['changelog_url']
end
metadata
end
end

82
lib/common/models/wp_version/findable.rb Executable file → Normal file
View File

@@ -12,6 +12,7 @@ class WpVersion < WpItem
# #
# @return [ WpVersion ] # @return [ WpVersion ]
def find(target_uri, wp_content_dir, wp_plugins_dir, versions_xml) def find(target_uri, wp_content_dir, wp_plugins_dir, versions_xml)
versions = {}
methods.grep(/^find_from_/).each do |method| methods.grep(/^find_from_/).each do |method|
if method === :find_from_advanced_fingerprinting if method === :find_from_advanced_fingerprinting
@@ -21,9 +22,21 @@ class WpVersion < WpItem
end end
if version if version
return new(target_uri, number: version, found_from: method) if versions.key?(version)
versions[version] << method.to_s
else
versions[version] = [ method.to_s ]
end
end end
end end
if versions.length > 0
determined_version = versions.max_by { |k, v| v.length }
if determined_version
return new(target_uri, number: determined_version[0], found_from: determined_version[1].join(', '))
end
end
nil nil
end end
@@ -114,34 +127,6 @@ class WpVersion < WpItem
) )
end end
def find_from_stylesheets_numbers(target_uri)
wp_versions = WpVersion.all
found = {}
pattern = /\bver=([0-9\.]+)/i
Nokogiri::HTML(Browser.get(target_uri.to_s).body).css('link,script').each do |tag|
%w(href src).each do |attribute|
attr_value = tag.attribute(attribute).to_s
next if attr_value.nil? || attr_value.empty?
uri = Addressable::URI.parse(attr_value)
next unless uri.query && uri.query.match(pattern)
version = Regexp.last_match[1].to_s
found[version] ||= 0
found[version] += 1
end
end
found.delete_if { |v, _| !wp_versions.include?(v) }
best_guess = found.sort_by(&:last).last
# best_guess[0]: version number, [1] numbers of occurences
best_guess && best_guess[1] > 1 ? best_guess[0] : nil
end
# Uses data/wp_versions.xml to try to identify a # Uses data/wp_versions.xml to try to identify a
# wordpress version. # wordpress version.
# #
@@ -158,8 +143,6 @@ class WpVersion < WpItem
def find_from_advanced_fingerprinting(target_uri, wp_content_dir, wp_plugins_dir, versions_xml) def find_from_advanced_fingerprinting(target_uri, wp_content_dir, wp_plugins_dir, versions_xml)
xml = xml(versions_xml) xml = xml(versions_xml)
# This wp_item will take care of encoding the path
# and replace variables like $wp-content$ & $wp-plugins$
wp_item = WpItem.new(target_uri, wp_item = WpItem.new(target_uri,
wp_content_dir: wp_content_dir, wp_content_dir: wp_content_dir,
wp_plugins_dir: wp_plugins_dir) wp_plugins_dir: wp_plugins_dir)
@@ -185,11 +168,14 @@ class WpVersion < WpItem
# #
# @return [ String ] The version number # @return [ String ] The version number
def find_from_readme(target_uri) def find_from_readme(target_uri)
scan_url( version = scan_url(
target_uri, target_uri,
%r{<br />\sversion #{version_pattern}}i, %r{<br />\sversion #{version_pattern}}i,
'readme.html' 'readme.html'
) )
# Since WP >= 4.7, the Readme only contains the major version
VersionCompare.lesser?(version, '4.7') ? version : nil
end end
# Attempts to find the WordPress version from the sitemap.xml file. # Attempts to find the WordPress version from the sitemap.xml file.
@@ -218,5 +204,37 @@ class WpVersion < WpItem
) )
end end
def find_from_stylesheets_numbers(target_uri)
wp_versions = WpVersion.all
found = {}
pattern = /\bver=([0-9\.]+)/i
Nokogiri::HTML(Browser.get(target_uri.to_s).body).css('link,script').each do |tag|
%w(href src).each do |attribute|
attr_value = tag.attribute(attribute).to_s
next if attr_value.nil? || attr_value.empty?
begin
uri = Addressable::URI.parse(attr_value)
rescue Addressable::URI::InvalidURIError
next
end
next unless uri.query && uri.query.match(pattern)
version = Regexp.last_match[1].to_s
found[version] ||= 0
found[version] += 1
end
end
found.delete_if { |v, _| !wp_versions.include?(v) }
best_guess = found.sort_by(&:last).last
# best_guess[0]: version number, [1] numbers of occurences
best_guess && best_guess[1] > 1 ? best_guess[0] : nil
end
end end
end end

View File

@@ -4,8 +4,16 @@ class WpVersion < WpItem
module Output module Output
def output(verbose = false) def output(verbose = false)
metadata = self.metadata(self.number)
puts puts
puts info("WordPress version #{self.number} identified from #{self.found_from}") if verbose
puts info("WordPress version #{self.number} identified from #{self.found_from}")
puts " | Released: #{metadata[:release_date]}"
puts " | Changelog: #{metadata[:changelog_url]}"
else
puts info("WordPress version #{self.number} #{"(Released on #{metadata[:release_date]}) identified from #{self.found_from}" if metadata[:release_date]}")
end
vulnerabilities = self.vulnerabilities vulnerabilities = self.vulnerabilities

View File

@@ -3,8 +3,9 @@
require 'rubygems' require 'rubygems'
version = RUBY_VERSION.dup version = RUBY_VERSION.dup
if Gem::Version.create(version) < Gem::Version.create(1.9)
puts "Ruby >= 1.9 required to run wpscan (You have #{version})" if Gem::Version.create(version) < Gem::Version.create(MIN_RUBY_VERSION)
puts "Ruby >= #{MIN_RUBY_VERSION} required to run wpscan (You have #{version})"
exit(1) exit(1)
end end
@@ -13,22 +14,22 @@ Encoding.default_external = Encoding::UTF_8
begin begin
# Standard libs # Standard libs
require 'readline'
require 'bundler/setup' unless kali_linux? require 'bundler/setup' unless kali_linux?
require 'getoptlong' require 'getoptlong'
require 'optparse' # Will replace getoptlong require 'optparse' # Will replace getoptlong
require 'uri' require 'uri'
require 'time' require 'time'
require 'resolv' require 'resolv'
require 'xmlrpc/client'
require 'digest/md5' require 'digest/md5'
require 'digest/sha1' require 'digest/sha1'
require 'readline'
require 'base64' require 'base64'
require 'rbconfig' require 'rbconfig'
require 'pp' require 'pp'
require 'shellwords' require 'shellwords'
require 'fileutils' require 'fileutils'
require 'pathname' require 'pathname'
require 'cgi'
# Third party libs # Third party libs
require 'typhoeus' require 'typhoeus'
require 'yajl/json_gem' require 'yajl/json_gem'

View File

@@ -1,11 +1,19 @@
# encoding: UTF-8 # encoding: UTF-8
require 'web_site/robots_txt' require 'web_site/humans_txt'
require 'web_site/interesting_headers' require 'web_site/interesting_headers'
require 'web_site/robots_txt'
require 'web_site/security_txt'
require 'web_site/sitemap'
require 'web_site/sql_file_export'
class WebSite class WebSite
include WebSite::RobotsTxt include WebSite::HumansTxt
include WebSite::InterestingHeaders include WebSite::InterestingHeaders
include WebSite::RobotsTxt
include WebSite::SecurityTxt
include WebSite::Sitemap
include WebSite::SqlFileExport
attr_reader :uri attr_reader :uri
@@ -21,6 +29,29 @@ class WebSite
@uri.to_s @uri.to_s
end end
# Checks if the remote website has ssl errors
def ssl_error?
return false unless @uri.scheme == 'https'
c = get_root_path_return_code
# http://www.rubydoc.info/github/typhoeus/ethon/Ethon/Easy:return_code
return (
c == :ssl_connect_error ||
c == :peer_failed_verification ||
c == :ssl_certproblem ||
c == :ssl_cipher ||
c == :ssl_cacert ||
c == :ssl_cacert_badfile ||
c == :ssl_issuer_error ||
c == :ssl_crl_badfile ||
c == :ssl_engine_setfailed ||
c == :ssl_engine_notfound
)
end
def get_root_path_return_code
Browser.get(@uri.to_s).return_code
end
# Checks if the remote website is up. # Checks if the remote website is up.
def online? def online?
Browser.get(@uri.to_s).code != 0 Browser.get(@uri.to_s).code != 0
@@ -68,15 +99,18 @@ class WebSite
end end
# Compute the MD5 of the page # Compute the MD5 of the page
# Comments are deleted from the page to avoid cache generation details # Comments and scripts are deleted from the page to avoid cache generation details
# #
# @param [ String, Typhoeus::Response ] page The url of the response of the page # @param [ String, Typhoeus::Response ] page The url of the response of the page
# #
# @return [ String ] The MD5 hash of the page # @return [ String ] The MD5 hash of the page
def self.page_hash(page) def self.page_hash(page)
page = Browser.get(page, { followlocation: true, cache_ttl: 0 }) unless page.is_a?(Typhoeus::Response) page = Browser.get(page, { followlocation: true, cache_ttl: 0 }) unless page.is_a?(Typhoeus::Response)
# remove comments
Digest::MD5.hexdigest(page.body.gsub(/<!--.*?-->/m, '')) page = page.body.gsub(/<!--.*?-->/m, '')
# remove javascript stuff
page = page.gsub(/<script\b[^<]*(?:(?!<\/script>)<[^<]*)*<\/script>/m, '')
Digest::MD5.hexdigest(page)
end end
def homepage_hash def homepage_hash
@@ -95,13 +129,6 @@ class WebSite
@error_404_hash @error_404_hash
end end
# Will try to find the rss url in the homepage
# Only the first one found is returned
def rss_url
homepage_body = Browser.get(@uri.to_s).body
homepage_body[%r{<link .* type="application/rss\+xml" .* href="([^"]+)" />}, 1]
end
# Only the first 700 bytes are checked to avoid the download # Only the first 700 bytes are checked to avoid the download
# of the whole file which can be very huge (like 2 Go) # of the whole file which can be very huge (like 2 Go)
# #

View File

@@ -0,0 +1,13 @@
# encoding: UTF-8
class WebSite
module HumansTxt
# Gets the humans.txt URL
# @return [ String ]
def humans_url
@uri.clone.merge('humans.txt').to_s
end
end
end

View File

@@ -18,49 +18,53 @@ class WebSite
# Parse robots.txt # Parse robots.txt
# @return [ Array ] URLs generated from robots.txt # @return [ Array ] URLs generated from robots.txt
def parse_robots_txt def parse_robots_txt
return unless has_robots?
return_object = [] return_object = []
# Make request
response = Browser.get(robots_url.to_s) response = Browser.get(robots_url.to_s)
body = response.body body = response.body
# Get all allow and disallow urls # Get all allow and disallow urls
entries = body.scan(/^(?:dis)?allow:\s*(.*)$/i) entries = body.scan(/^(?:dis)?allow:\s*(.*)$/i)
# Did we get something?
if entries if entries
entries.flatten! # Remove any rubbish
entries.compact.sort! entries = clean_uri(entries)
entries.uniq!
# Sort
entries.sort!
# Wordpress URL
wordpress_path = @uri.path wordpress_path = @uri.path
# Each "boring" value as defined below, remove
RobotsTxt.known_dirs.each do |d| RobotsTxt.known_dirs.each do |d|
entries.delete(d) entries.delete(d)
# also delete when wordpress is installed in subdir # Also delete when wordpress is installed in subdir
dir_with_subdir = "#{wordpress_path}/#{d}".gsub(/\/+/, '/') dir_with_subdir = "#{wordpress_path}/#{d}".gsub(/\/+/, '/')
entries.delete(dir_with_subdir) entries.delete(dir_with_subdir)
end end
entries.each do |d| # Convert to full URIs
begin return_object = full_uri(entries)
temp = @uri.clone
temp.path = d.strip
rescue URI::Error
temp = d.strip
end
return_object << temp.to_s
end
end end
return_object return return_object
end end
protected protected
# Useful ~ "function do_robots()" -> https://github.com/WordPress/WordPress/blob/master/wp-includes/functions.php
#
# @return [ Array ] # @return [ Array ]
def self.known_dirs def self.known_dirs
%w{ %w{
/ /
/wp-admin/ /wp-admin/
/wp-admin/admin-ajax.php
/wp-includes/ /wp-includes/
/wp-content/ /wp-content/
} }
end end
end end
end end

View File

@@ -0,0 +1,13 @@
# encoding: UTF-8
class WebSite
module SecurityTxt
# Gets the security.txt URL
# @return [ String ]
def security_url
@uri.clone.merge('.well-known/security.txt').to_s
end
end
end

View File

@@ -0,0 +1,53 @@
# encoding: UTF-8
class WebSite
module Sitemap
# Checks if a sitemap.txt file exists
# @return [ Boolean ]
def has_sitemap?
# Make the request
response = Browser.get(sitemap_url)
# Make sure its HTTP 200
return false unless response.code == 200
# Is there a sitemap value?
result = response.body.scan(/^sitemap\s*:\s*(.*)$/i)
return true if result[0]
return false
end
# Get the robots.txt URL
# @return [ String ]
def sitemap_url
@uri.clone.merge('robots.txt').to_s
end
# Parse robots.txt
# @return [ Array ] URLs generated from robots.txt
def parse_sitemap
return_object = []
# Make request
response = Browser.get(sitemap_url.to_s)
# Get all allow and disallow urls
entries = response.body.scan(/^sitemap\s*:\s*(.*)$/i)
# Did we get something?
if entries
# Remove any rubbish
entries = clean_uri(entries)
# Sort
entries.sort!
# Convert to full URIs
return_object = full_uri(entries)
end
return return_object
end
end
end

View File

@@ -0,0 +1,35 @@
# encoding: UTF-8
class WebSite
module SqlFileExport
# Checks if a .sql file exists
# @return [ Array ]
def sql_file_export
export_files = []
self.sql_file_export_urls.each do |url|
response = Browser.get(url)
export_files << url if response.code == 200 && response.body =~ /INSERT INTO/
end
export_files
end
# Gets a .sql export file URL
# @return [ Array ]
def sql_file_export_urls
urls = []
host = @uri.host[/(^[\w|-]+)/,1]
files = ["#{host}.sql", "#{host}.sql.gz", "#{host}.zip", 'db.sql', 'site.sql', 'database.sql',
'data.sql', 'backup.sql', 'dump.sql', 'db_backup.sql', 'dbdump.sql', 'wordpress.sql', 'mysql.sql']
files.each do |file|
urls << @uri.clone.merge(file).to_s
end
urls
end
end
end

View File

@@ -1,22 +1,26 @@
# encoding: UTF-8 # encoding: UTF-8
require 'web_site' require 'web_site'
require 'wp_target/wp_readme' require 'wp_target/wp_api'
require 'wp_target/wp_registrable'
require 'wp_target/wp_config_backup' require 'wp_target/wp_config_backup'
require 'wp_target/wp_must_use_plugins'
require 'wp_target/wp_login_protection'
require 'wp_target/wp_custom_directories' require 'wp_target/wp_custom_directories'
require 'wp_target/wp_full_path_disclosure' require 'wp_target/wp_full_path_disclosure'
require 'wp_target/wp_login_protection'
require 'wp_target/wp_must_use_plugins'
require 'wp_target/wp_readme'
require 'wp_target/wp_registrable'
require 'wp_target/wp_rss'
class WpTarget < WebSite class WpTarget < WebSite
include WpTarget::WpReadme include WpTarget::WpAPI
include WpTarget::WpRegistrable
include WpTarget::WpConfigBackup include WpTarget::WpConfigBackup
include WpTarget::WpMustUsePlugins
include WpTarget::WpLoginProtection
include WpTarget::WpCustomDirectories include WpTarget::WpCustomDirectories
include WpTarget::WpFullPathDisclosure include WpTarget::WpFullPathDisclosure
include WpTarget::WpLoginProtection
include WpTarget::WpMustUsePlugins
include WpTarget::WpReadme
include WpTarget::WpRegistrable
include WpTarget::WpRSS
attr_reader :verbose attr_reader :verbose
@@ -135,6 +139,11 @@ class WpTarget < WebSite
@uri.merge("#{wp_content_dir}/uploads/").to_s @uri.merge("#{wp_content_dir}/uploads/").to_s
end end
# @return [ String ]
def includes_dir_url
@uri.merge("wp-includes/").to_s
end
# Script for replacing strings in wordpress databases # Script for replacing strings in wordpress databases
# reveals database credentials after hitting submit # reveals database credentials after hitting submit
# http://interconnectit.com/124/search-and-replace-for-wordpress-databases/ # http://interconnectit.com/124/search-and-replace-for-wordpress-databases/
@@ -150,7 +159,26 @@ class WpTarget < WebSite
resp.code == 200 && resp.body[%r{by interconnect}i] resp.code == 200 && resp.body[%r{by interconnect}i]
end end
# Script used to recover locked out admin users
# http://yoast.com/emergency-wordpress-access/
# https://codex.wordpress.org/User:MichaelH/Orphaned_Plugins_needing_Adoption/Emergency
#
# @return [ String ]
def emergency_url
@uri.merge('emergency.php').to_s
end
# @return [ Boolean ]
def emergency_exists?
resp = Browser.get(emergency_url)
resp.code == 200 && resp.body[%r{password}i]
end
def upload_directory_listing_enabled? def upload_directory_listing_enabled?
directory_listing_enabled?(upload_dir_url) directory_listing_enabled?(upload_dir_url)
end end
def include_directory_listing_enabled?
directory_listing_enabled?(includes_dir_url)
end
end end

View File

@@ -0,0 +1,86 @@
# encoding: UTF-8
class WpTarget < WebSite
module WpAPI
# Checks to see if the REST API is enabled
#
# This by default in a WordPress installation since 4.5+
# @return [ Boolean ]
def has_api?(url)
# Make the request
response = Browser.get(url)
# Able to view the output?
if valid_json?(response.body) && response.body != ''
# Read in JSON
data = JSON.parse(response.body)
# If there is nothing there, return false
if data.empty?
return false
# WAF/API disabled response
elsif data.include?('message') and data['message'] =~ /Only authenticated users can access the REST API/
return false
# Success!
elsif response.code == 200
return true
end
end
# Something went wrong
return false
end
# @return [ String ] The API/JSON URL
def json_url
@uri.merge('/wp-json/').to_s
end
# @return [ String ] The API/JSON URL to show users
def json_users_url
@uri.merge('/wp-json/wp/v2/users').to_s
end
# @return [ String ] The API/JSON URL to show users
def json_get_users(url)
# Variables
users = []
# Make the request
response = Browser.get(url)
# If not HTTP 200, return false
return false unless response.code == 200
# Able to view the output?
return false unless valid_json?(response.body)
# Read in JSON
data = JSON.parse(response.body)
# If there is nothing there, return false
return false if data.empty?
# Add to array
data.each do |child|
row = [ child['id'], child['name'], child['link'] ]
users << row
end
# Sort and uniq
users = users.sort.uniq
if users and users.size >= 1
# Feedback
grammar = grammar_s(users.size)
puts warning("#{users.size} user#{grammar} exposed via API: #{json_users_url}")
# Print results
table = Terminal::Table.new(headings: ['ID', 'Name', 'URL'],
rows: users)
puts table
end
end
end
end

View File

@@ -14,7 +14,7 @@ class WpTarget < WebSite
queue_count = 0 queue_count = 0
backups.each do |file| backups.each do |file|
file_url = @uri.merge(URI.escape(file)).to_s file_url = @uri.merge(url_encode(file)).to_s
request = browser.forge_request(file_url) request = browser.forge_request(file_url)
request.on_complete do |response| request.on_complete do |response|

View File

@@ -0,0 +1,73 @@
# encoding: UTF-8
class WpTarget < WebSite
module WpRSS
# Checks to see if there is an rss feed
# Will try to find the rss url in the homepage
# Only the first one found is returned
#
# This file comes by default in a WordPress installation
#
# @return [ Boolean ]
def rss_url
homepage_body = Browser.get(@uri.to_s).body
# Format: <link rel="alternate" type="application/rss+xml" title=".*" href=".*" />
homepage_body[%r{<link\s*.*\s*type=['|"]application\/rss\+xml['|"]\s*.*\stitle=".*" href=['|"]([^"]+)['|"]\s*\/?>}i, 1]
end
# Gets all the authors from the RSS feed
#
# @return [ string ]
def rss_authors(url)
# Variables
users = []
# Make the request
response = Browser.get(url, followlocation: true)
# Valid repose to view? HTTP 200?
return false unless response.code == 200
# Get output
data = response.body
# If there is nothing there, return false
return false if data.empty?
begin
# Read in RSS/XML
xml = Nokogiri::XML(data)
rescue
puts critical("Missformed XML")
return false
end
begin
# Look for <dc:creator> item
xml.xpath('//item/dc:creator').each do |node|
#Format: <dc:creator><![CDATA[.*]]></dc:creator>
users << [%r{.*}i.match(node).to_s]
end
rescue
puts critical("Missing Author field. Maybe non-standard WordPress RSS feed?")
return false
end
# Sort and uniq
users = users.sort_by { |user| user.to_s.downcase }.uniq
if users and users.size >= 1
# Feedback
grammar = grammar_s(users.size)
puts warning("Detected #{users.size} user#{grammar} from RSS feed:")
# Print results
table = Terminal::Table.new(headings: ['Name'],
rows: users)
puts table
end
end
end
end

View File

@@ -1,6 +1,6 @@
# encoding: UTF-8 # encoding: UTF-8
require File.expand_path(File.dirname(__FILE__) + '/../common/common_helper') require File.expand_path(File.join(__dir__, '..', 'common', 'common_helper'))
require_files_from_directory(WPSCAN_LIB_DIR, '**/*.rb') require_files_from_directory(WPSCAN_LIB_DIR, '**/*.rb')
@@ -28,9 +28,12 @@ def usage
puts '-Enumerate installed themes ...' puts '-Enumerate installed themes ...'
puts "ruby #{script_name} --url www.example.com --enumerate t" puts "ruby #{script_name} --url www.example.com --enumerate t"
puts puts
puts '-Enumerate users ...' puts '-Enumerate users (from 1 - 10)...'
puts "ruby #{script_name} --url www.example.com --enumerate u" puts "ruby #{script_name} --url www.example.com --enumerate u"
puts puts
puts '-Enumerate users (from 1 - 20)...'
puts "ruby #{script_name} --url www.example.com --enumerate u[1-20]"
puts
puts '-Enumerate installed timthumbs ...' puts '-Enumerate installed timthumbs ...'
puts "ruby #{script_name} --url www.example.com --enumerate tt" puts "ruby #{script_name} --url www.example.com --enumerate tt"
puts puts
@@ -46,7 +49,7 @@ def usage
puts '-Use custom plugins directory ...' puts '-Use custom plugins directory ...'
puts "ruby #{script_name} -u www.example.com --wp-plugins-dir wp-content/custom-plugins" puts "ruby #{script_name} -u www.example.com --wp-plugins-dir wp-content/custom-plugins"
puts puts
puts '-Update the DB ...' puts '-Update the Database ...'
puts "ruby #{script_name} --update" puts "ruby #{script_name} --update"
puts puts
puts '-Debug output ...' puts '-Debug output ...'
@@ -62,7 +65,7 @@ def help
puts puts
puts 'Some values are settable in a config file, see the example.conf.json' puts 'Some values are settable in a config file, see the example.conf.json'
puts puts
puts '--update Update to the database to the latest version.' puts '--update Update the database to the latest version.'
puts '--url | -u <target url> The WordPress URL/domain to scan.' puts '--url | -u <target url> The WordPress URL/domain to scan.'
puts '--force | -f Forces WPScan to not check if the remote site is running WordPress.' puts '--force | -f Forces WPScan to not check if the remote site is running WordPress.'
puts '--enumerate | -e [option(s)] Enumeration.' puts '--enumerate | -e [option(s)] Enumeration.'
@@ -84,12 +87,17 @@ def help
puts ' You do not need to provide the regexp delimiters, but you must write the quotes (simple or double).' puts ' You do not need to provide the regexp delimiters, but you must write the quotes (simple or double).'
puts '--config-file | -c <config file> Use the specified config file, see the example.conf.json.' puts '--config-file | -c <config file> Use the specified config file, see the example.conf.json.'
puts '--user-agent | -a <User-Agent> Use the specified User-Agent.' puts '--user-agent | -a <User-Agent> Use the specified User-Agent.'
puts '--cookie <String> String to read cookies from.' puts '--cookie <string> String to read cookies from.'
puts '--random-agent | -r Use a random User-Agent.' puts '--random-agent | -r Use a random User-Agent.'
puts '--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not' puts '--follow-redirection If the target url has a redirection, it will be followed without asking if you wanted to do so or not'
puts '--batch Never ask for user input, use the default behaviour.' puts '--batch Never ask for user input, use the default behaviour.'
puts '--no-color Do not use colors in the output.' puts '--no-color Do not use colors in the output.'
puts '--wp-content-dir <wp content dir> WPScan try to find the content directory (ie wp-content) by scanning the index page, however you can specified it.' puts '--log [filename] Creates a log.txt file with WPScan\'s output if no filename is supplied. Otherwise the filename is used for logging.'
puts '--no-banner Prevents the WPScan banner from being displayed.'
puts '--disable-accept-header Prevents WPScan sending the Accept HTTP header.'
puts '--disable-referer Prevents setting the Referer header.'
puts '--disable-tls-checks Disables SSL/TLS certificate verification.'
puts '--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.'
puts ' Subdirectories are allowed.' puts ' Subdirectories are allowed.'
puts '--wp-plugins-dir <wp plugins dir> Same thing than --wp-content-dir but for the plugins directory.' puts '--wp-plugins-dir <wp plugins dir> Same thing than --wp-content-dir but for the plugins directory.'
puts ' If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed' puts ' If not supplied, WPScan will use wp-content-dir/plugins. Subdirectories are allowed'
@@ -100,11 +108,11 @@ def help
puts '--wordlist | -w <wordlist> Supply a wordlist for the password brute forcer.' puts '--wordlist | -w <wordlist> Supply a wordlist for the password brute forcer.'
puts '--username | -U <username> Only brute force the supplied username.' puts '--username | -U <username> Only brute force the supplied username.'
puts '--usernames <path-to-file> Only brute force the usernames from the file.' puts '--usernames <path-to-file> Only brute force the usernames from the file.'
puts '--threads | -t <number of threads> The number of threads to use when multi-threading requests.' puts '--cache-dir <cache-directory> Set the cache directory.'
puts '--cache-ttl <cache-ttl> Typhoeus cache TTL.' puts '--cache-ttl <cache-ttl> Typhoeus cache TTL.'
puts '--request-timeout <request-timeout> Request Timeout.' puts '--request-timeout <request-timeout> Request Timeout.'
puts '--connect-timeout <connect-timeout> Connect Timeout.' puts '--connect-timeout <connect-timeout> Connect Timeout.'
puts '--max-threads <max-threads> Maximum Threads.' puts '--threads | -t <number of threads> The number of threads to use when multi-threading requests.'
puts '--throttle <milliseconds> Milliseconds to wait before doing another web request. If used, the --threads should be set to 1.' puts '--throttle <milliseconds> Milliseconds to wait before doing another web request. If used, the --threads should be set to 1.'
puts '--help | -h This help screen.' puts '--help | -h This help screen.'
puts '--verbose | -v Verbose output.' puts '--verbose | -v Verbose output.'
@@ -112,6 +120,58 @@ def help
puts puts
end end
def clean_uri(entries)
# Extract elements
entries.flatten!
# Remove any leading/trailing spaces
entries.collect{|x| x.strip || x }
# End Of Line issues
entries.collect{|x| x.chomp! || x }
# Remove nil's
entries.compact
# Unique values only
entries.uniq!
return entries
end
# Return the full URL
def full_uri(entries)
return_object = []
# Each value now, try and make it a full URL
entries.each do |d|
begin
temp = @uri.clone
temp.path = d.strip
rescue URI::Error
temp = d.strip
end
return_object << temp.to_s
end
return return_object
end
# Parse humans.txt
# @return [ Array ] URLs generated from humans.txt
def parse_txt(url)
return_object = []
response = Browser.get(url.to_s)
body = response.body
# Get all non-comments
entries = body.split(/\n/)
# Did we get something?
if entries
# Remove any rubbish
entries = clean_uri(entries)
end
return return_object
end
# Hook to check if the target if down during the scan # Hook to check if the target if down during the scan
# And have the number of requests performed to display at the end of the scan # And have the number of requests performed to display at the end of the scan
# The target is considered down after 30 requests with status = 0 # The target is considered down after 30 requests with status = 0
@@ -130,3 +190,4 @@ Typhoeus.on_complete do |response|
sleep(Browser.instance.throttle) sleep(Browser.instance.throttle)
end end

View File

@@ -43,7 +43,11 @@ class WpscanOptions
:connect_timeout, :connect_timeout,
:max_threads, :max_threads,
:no_banner, :no_banner,
:throttle :throttle,
:disable_accept_header,
:disable_referer,
:cache_dir,
:disable_tls_checks
] ]
attr_accessor *ACCESSOR_OPTIONS attr_accessor *ACCESSOR_OPTIONS
@@ -71,7 +75,7 @@ class WpscanOptions
end end
def wordlist=(wordlist) def wordlist=(wordlist)
if File.exists?(wordlist) if File.exists?(wordlist) || wordlist == '-'
@wordlist = wordlist @wordlist = wordlist
else else
raise "The file #{wordlist} does not exist" raise "The file #{wordlist} does not exist"
@@ -148,11 +152,6 @@ class WpscanOptions
end end
end end
def basic_auth=(basic_auth)
raise 'Invalid basic authentication format, login:password expected' if basic_auth.index(':').nil?
@basic_auth = "Basic #{Base64.encode64(basic_auth).chomp}"
end
def debug_output=(debug_output) def debug_output=(debug_output)
Typhoeus::Config.verbose = debug_output Typhoeus::Config.verbose = debug_output
end end
@@ -208,7 +207,9 @@ class WpscanOptions
enumerate_options_from_string(cli_value) enumerate_options_from_string(cli_value)
else else
raise "Unknow option : #{cli_option} with value #{cli_value}" text = "Unknown option : #{cli_option}"
text << " with value #{cli_value}" if (cli_value && !cli_value.empty?)
raise text
end end
end end
@@ -276,13 +277,16 @@ class WpscanOptions
['--cache-ttl', GetoptLong::REQUIRED_ARGUMENT], ['--cache-ttl', GetoptLong::REQUIRED_ARGUMENT],
['--request-timeout', GetoptLong::REQUIRED_ARGUMENT], ['--request-timeout', GetoptLong::REQUIRED_ARGUMENT],
['--connect-timeout', GetoptLong::REQUIRED_ARGUMENT], ['--connect-timeout', GetoptLong::REQUIRED_ARGUMENT],
['--max-threads', GetoptLong::REQUIRED_ARGUMENT],
['--batch', GetoptLong::NO_ARGUMENT], ['--batch', GetoptLong::NO_ARGUMENT],
['--no-color', GetoptLong::NO_ARGUMENT], ['--no-color', GetoptLong::NO_ARGUMENT],
['--cookie', GetoptLong::REQUIRED_ARGUMENT], ['--cookie', GetoptLong::REQUIRED_ARGUMENT],
['--log', GetoptLong::NO_ARGUMENT], ['--log', GetoptLong::OPTIONAL_ARGUMENT],
['--no-banner', GetoptLong::NO_ARGUMENT], ['--no-banner', GetoptLong::NO_ARGUMENT],
['--throttle', GetoptLong::REQUIRED_ARGUMENT] ['--throttle', GetoptLong::REQUIRED_ARGUMENT],
['--disable-accept-header', GetoptLong::NO_ARGUMENT],
['--disable-referer', GetoptLong::NO_ARGUMENT],
['--cache-dir', GetoptLong::REQUIRED_ARGUMENT],
['--disable-tls-checks', GetoptLong::NO_ARGUMENT],
) )
end end

View File

@@ -124,11 +124,10 @@ describe Browser do
describe '#merge_request_params' do describe '#merge_request_params' do
let(:params) { {} } let(:params) { {} }
let(:cookie_jar) { CACHE_DIR + '/browser/cookie-jar' } let(:cookie_jar) { CACHE_DIR + '/browser/cookie-jar' }
let(:user_agent) { 'SomeUA' }
let(:default_expectation) { let(:default_expectation) {
{ {
cache_ttl: 250, cache_ttl: 250,
headers: { 'User-Agent' => 'SomeUA' },
ssl_verifypeer: false, ssl_verifyhost: 0,
cookiejar: cookie_jar, cookiefile: cookie_jar, cookiejar: cookie_jar, cookiefile: cookie_jar,
timeout: 60, connecttimeout: 10, timeout: 60, connecttimeout: 10,
maxredirs: 3, maxredirs: 3,
@@ -137,16 +136,25 @@ describe Browser do
} }
after :each do after :each do
browser.user_agent = 'SomeUA' browser.user_agent = user_agent
browser.cache_ttl = 250 browser.cache_ttl = 250
expect(browser.merge_request_params(params)).to eq @expected expect(browser.merge_request_params(params)).to eq @expected
expect(Typhoeus::Config.user_agent).to eq user_agent
end end
it 'sets the User-Agent header field and cache_ttl' do it 'sets the User-Agent header field and cache_ttl' do
@expected = default_expectation @expected = default_expectation
end end
context 'when @user_agent' do
let(:user_agent) { 'test' }
it 'sets the User-Agent' do
@expected = default_expectation
end
end
context 'when @proxy' do context 'when @proxy' do
let(:proxy) { '127.0.0.1:9050' } let(:proxy) { '127.0.0.1:9050' }
let(:proxy_expectation) { default_expectation.merge(proxy: proxy) } let(:proxy_expectation) { default_expectation.merge(proxy: proxy) }
@@ -160,7 +168,7 @@ describe Browser do
it 'sets the proxy_auth' do it 'sets the proxy_auth' do
browser.proxy = proxy browser.proxy = proxy
browser.proxy_auth = 'user:pass' browser.proxy_auth = 'user:pass'
@expected = proxy_expectation.merge(proxyauth: 'user:pass') @expected = proxy_expectation.merge(proxyuserpwd: 'user:pass')
end end
end end
end end
@@ -177,7 +185,7 @@ describe Browser do
it 'appends the basic_auth' do it 'appends the basic_auth' do
browser.basic_auth = 'user:pass' browser.basic_auth = 'user:pass'
@expected = default_expectation.merge( @expected = default_expectation.merge(
headers: default_expectation[:headers].merge('Authorization' => 'Basic ' + Base64.encode64('user:pass').chomp) headers: { 'Authorization' => 'Basic ' + Base64.encode64('user:pass').chomp }
) )
end end
end end
@@ -206,6 +214,13 @@ describe Browser do
@expected = default_expectation.merge(cookie: cookie) @expected = default_expectation.merge(cookie: cookie)
end end
end end
context 'when @disable_tls_checks' do
it 'disables tls checks' do
browser.disable_tls_checks = true
@expected = default_expectation.merge(ssl_verifypeer: 0, ssl_verifyhost: 0)
end
end
end end
describe '#forge_request' do describe '#forge_request' do

View File

@@ -18,7 +18,7 @@ describe WpItems do
vulnerable_targets_items: [ WpItem.new(uri, name: 'mr-smith'), vulnerable_targets_items: [ WpItem.new(uri, name: 'mr-smith'),
WpItem.new(uri, name: 'neo')], WpItem.new(uri, name: 'neo')],
passive_detection: (1..13).reduce(WpItems.new) { |o, i| o << WpItem.new(uri, name: "detect-me-#{i}") } passive_detection: (1..15).reduce(WpItems.new) { |o, i| o << WpItem.new(uri, name: "detect-me-#{i}") }
} }
end end
end end

View File

@@ -100,6 +100,13 @@ describe 'WpPlugins::Detectable' do
expected.add('all-in-one-seo-pack', version: '2.0.3.1') expected.add('all-in-one-seo-pack', version: '2.0.3.1')
end end
end end
context 'when google-universal-analytics detected' do
it 'returns google-universal-analytics' do
@body = '<!-- Google Universal Analytics for WordPress v2.4.2 -->'
expected.add('google-universal-analytics', version: '2.4.2')
end
end
end end
end end

View File

@@ -26,10 +26,10 @@ describe 'WpTimthumbs::Detectable' do
def expected_targets_from_theme(theme_name) def expected_targets_from_theme(theme_name)
expected = [] expected = []
%w{ %w(
timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php timthumb.php lib/timthumb.php inc/timthumb.php includes/timthumb.php
scripts/timthumb.php tools/timthumb.php functions/timthumb.php scripts/timthumb.php tools/timthumb.php functions/timthumb.php thumb.php
}.each do |file| ).each do |file|
path = "$wp-content$/themes/#{theme_name}/#{file}" path = "$wp-content$/themes/#{theme_name}/#{file}"
expected << WpTimthumb.new(uri, path: path) expected << WpTimthumb.new(uri, path: path)
end end
@@ -46,7 +46,7 @@ describe 'WpTimthumbs::Detectable' do
after do after do
targets = subject.send(:targets_items_from_file, file, wp_target) targets = subject.send(:targets_items_from_file, file, wp_target)
expect(targets.map { |t| t.url }).to eq @expected.map { |t| t.url } expect(targets.map(&:url)).to eq @expected.map(&:url)
end end
context 'when an empty file' do context 'when an empty file' do
@@ -71,7 +71,7 @@ describe 'WpTimthumbs::Detectable' do
theme = 'hello-world' theme = 'hello-world'
targets = subject.send(:theme_timthumbs, theme, wp_target) targets = subject.send(:theme_timthumbs, theme, wp_target)
expect(targets.map { |t| t.url }).to eq expected_targets_from_theme(theme).map { |t| t.url } expect(targets.map(&:url)).to eq expected_targets_from_theme(theme).map(&:url)
end end
end end
@@ -81,7 +81,7 @@ describe 'WpTimthumbs::Detectable' do
after do after do
targets = subject.send(:targets_items, wp_target, options) targets = subject.send(:targets_items, wp_target, options)
expect(targets.map { |t| t.url }).to eq @expected.sort.map { |t| t.url } expect(targets.map(&:url)).to match_array(@expected.map(&:url))
end end
context 'when no :theme_name' do context 'when no :theme_name' do
@@ -101,7 +101,7 @@ describe 'WpTimthumbs::Detectable' do
end end
context 'when :theme_name' do context 'when :theme_name' do
let(:theme) { 'theme-name'} let(:theme) { 'theme-name' }
context 'when no :file' do context 'when no :file' do
let(:options) { { theme_name: theme } } let(:options) { { theme_name: theme } }

View File

@@ -105,11 +105,6 @@ describe WpItem do
@expected = 'plugins/readme.txt' @expected = 'plugins/readme.txt'
end end
end end
it 'also encodes chars' do
@path = 'some dir with spaces'
@expected = 'some%20dir%20with%20spaces'
end
end end
describe '#uri' do describe '#uri' do

View File

@@ -45,9 +45,18 @@ describe 'WpTheme::Findable' do
# FIXME: the style_url should be checked in WpTheme for absolute / relative # FIXME: the style_url should be checked in WpTheme for absolute / relative
context 'when relative url is used' do context 'when relative url is used' do
it 'returns the WpTheme' do context 'when leading slash' do
@file = 'relative_urls.html' it 'returns the WpTheme' do
@expected = WpTheme.new(uri, name: 'theme_name') @file = 'relative_urls.html'
@expected = WpTheme.new(uri, name: 'theme_name')
end
end
context 'when no leading slash' do
it 'returns the WpTheme' do
@file = 'relative_urls_missing_slash.html'
@expected = WpTheme.new(uri, name: 'theme_name')
end
end end
end end

View File

@@ -134,6 +134,13 @@ describe 'WpVersion::Findable' do
@fixture = '/3.3.2.html' @fixture = '/3.3.2.html'
@expected = '3.3.2' @expected = '3.3.2'
end end
context 'when version >= 4.7' do
it 'returns nil' do
@fixture = '/4.7.2.html'
@expected = nil
end
end
end end
describe '::find_from_links_opml' do describe '::find_from_links_opml' do
@@ -159,6 +166,22 @@ describe 'WpVersion::Findable' do
end end
end end
describe '::find_from_stylesheets_numbers' do
after do
fixture = fixtures_dir + 'stylesheet_numbers' + @fixture
stub_request_to_fixture(url: uri, fixture: fixture)
expect(WpVersion.send(:find_from_stylesheets_numbers, uri)).to eq @expected
end
context 'invalid url' do
it 'returns nil' do
@fixture = '/invalid_url.html'
@expected = nil
end
end
end
describe '::find' do describe '::find' do
# Stub all WpVersion::find_from_* to return nil # Stub all WpVersion::find_from_* to return nil
def stub_all_to_nil def stub_all_to_nil

View File

@@ -160,6 +160,11 @@ describe 'VersionCompare' do
@version1 = '.47' @version1 = '.47'
@version2 = '.50.3' @version2 = '.50.3'
end end
it 'returns true' do
@version1 = '2.5.9'
@version2 = '2.5.10'
end
end end
context 'version checked is older' do context 'version checked is older' do

View File

@@ -176,6 +176,17 @@ describe 'WebSite' do
@expected = "yolo\n\n\nworld!" @expected = "yolo\n\n\nworld!"
end end
end end
context 'when there are scripts' do
let(:page) {
body = "yolo\n\n<script type=\"text/javascript\">alert('Hi');</script>\nworld!"
Typhoeus::Response.new(body: body)
}
it 'removes them' do
@expected = "yolo\n\n\nworld!"
end
end
end end
describe '#homepage_hash' do describe '#homepage_hash' do
@@ -196,18 +207,6 @@ describe 'WebSite' do
end end
end end
describe '#rss_url' do
it 'returns nil if the url is not found' do
stub_request(:get, web_site.url).to_return(body: 'No RSS link in this body !')
expect(web_site.rss_url).to be_nil
end
it "returns 'http://lamp-wp/wordpress-3.5/?feed=rss2'" do
stub_request_to_fixture(url: web_site.url, fixture: fixtures_dir + '/rss_url/wordpress-3.5.htm')
expect(web_site.rss_url).to be === 'http://lamp-wp/wordpress-3.5/?feed=rss2'
end
end
describe '::has_log?' do describe '::has_log?' do
let(:log_url) { web_site.uri.merge('log.txt').to_s } let(:log_url) { web_site.uri.merge('log.txt').to_s }
let(:pattern) { %r{PHP Fatal error} } let(:pattern) { %r{PHP Fatal error} }

View File

@@ -1,6 +1,6 @@
# encoding: UTF-8 # encoding: UTF-8
require File.expand_path(File.dirname(__FILE__) + '/wpscan_helper') require File.expand_path(File.join(__dir__, 'wpscan_helper'))
describe WpTarget do describe WpTarget do
subject(:wp_target) { WpTarget.new(target_url, options) } subject(:wp_target) { WpTarget.new(target_url, options) }
@@ -192,4 +192,27 @@ describe WpTarget do
end end
end end
describe '#emergency_url' do
it 'returns the correct url' do
expect(wp_target.emergency_url).to eq 'http://example.localhost/emergency.php'
end
end
describe '#emergency_exists?' do
it 'returns true' do
stub_request(:any, wp_target.emergency_url).to_return(status: 200, body: 'enter your password here')
expect(wp_target.emergency_exists?).to be_truthy
end
it 'returns false' do
stub_request(:any, wp_target.emergency_url).to_return(status: 500)
expect(wp_target.emergency_exists?).to be_falsey
end
it 'returns false' do
stub_request(:any, wp_target.emergency_url).to_return(status: 500, body: 'enter your password here')
expect(wp_target.emergency_exists?).to be_falsey
end
end
end end

View File

@@ -1,6 +1,6 @@
# encoding: UTF-8 # encoding: UTF-8
require File.expand_path(File.dirname(__FILE__) + '/wpscan_helper') require File.expand_path(File.join(__dir__, 'wpscan_helper'))
describe 'WpscanOptions' do describe 'WpscanOptions' do
@@ -186,23 +186,6 @@ describe 'WpscanOptions' do
end end
end end
describe '#basic_auth=' do
context 'invalid format' do
it 'should raise an error if the : is missing' do
expect { @wpscan_options.basic_auth = 'helloworld' }.to raise_error(
RuntimeError, 'Invalid basic authentication format, login:password expected'
)
end
end
context 'valid format' do
it "should add the 'Basic' word and do the encode64. See RFC 2617" do
@wpscan_options.basic_auth = 'Aladdin:open sesame'
expect(@wpscan_options.basic_auth).to eq 'Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ=='
end
end
end
describe '#has_options?' do describe '#has_options?' do
it 'should return false' do it 'should return false' do
expect(@wpscan_options.has_options?).to be_falsey expect(@wpscan_options.has_options?).to be_falsey

View File

@@ -19,6 +19,8 @@
<script type='text/javascript' src='//wp-content/items/detect-me-5/main.js'></script> <script type='text/javascript' src='//wp-content/items/detect-me-5/main.js'></script>
<link rel='stylesheet' id='ai1ec_style-css' href='//example.com/wp-content/items/detect-me-15/test.css' type='text/css' media='all' />
<style type="text/css"> <style type="text/css">
#fancybox-loading.fancybox-ie div { #fancybox-loading.fancybox-ie div {
background: transparent; background: transparent;
@@ -32,6 +34,7 @@
@import url('/wp-content/items/detect-me-8/css/datatables.css?ver=1.9.4'); @import url('/wp-content/items/detect-me-8/css/datatables.css?ver=1.9.4');
@import url(/wp-content/items/detect-me-9/css/datatables.css?ver=1.9.4); @import url(/wp-content/items/detect-me-9/css/datatables.css?ver=1.9.4);
@import url(//wp-content/items/detect-me-10/css/datatables.css?ver=1.9.4); @import url(//wp-content/items/detect-me-10/css/datatables.css?ver=1.9.4);
@import url(//example.com/wp-content/items/detect-me-14/css/datatables.css?ver=1.9.4);
/* ]]> */ /* ]]> */
</style> </style>

0
spec/samples/common/models/wp_item/error_log Executable file → Normal file
View File

View File

View File

@@ -0,0 +1,413 @@
=== WP Maintenance Mode ===
Contributors: Designmodo, GeorgeJipa
Plugin Name: WP Maintenance Mode
Plugin URI: http://designmodo.com/
Author: Designmodo
Author URI: http://designmodo.com/
Tags: maintenance mode, admin, administration, unavailable, coming soon, multisite, landing page, under construction, contact form, subscribe, countdown
Requires at least: 3.5
Tested up to: 4.7
License: GPL-2.0+
Adds a splash page to your site that lets visitors know your site is down for maintenance. It's perfect for a coming soon page.
== Description ==
Add a maintenance page to your blog that lets visitors know your blog is down for maintenance, or add a coming soon page for a new website. User with admin rights gets full access to the blog including the front end.
Activate the plugin and your blog is in maintenance-mode, works and only registered users with enough rights can see the front end. You can use a date with a countdown timer for visitor information or set a value and unit for information.
Also works with WordPress Multisite installs (each blog from the network has it's own maintenance settings).
= Features =
* Fully customizable (change colors, texts and backgrounds);
* Subscription form (export emails to .csv file);
* Countdown timer (remaining time);
* Contact form (receive emails from visitors);
* Coming soon page;
* Landing page templates;
* WordPress multisite;
* Responsive design;
* Social media icons;
* Works with any WordPress theme;
* SEO options;
* Exclude URLs from maintenance.
= Bugs, technical hints or contribute =
Please give us feedback, contribute and file technical bugs on [GitHub Repo](https://github.com/Designmodocom/WP-Maintenance-Mode).
= Credits =
Developed by [Designmodo](http://designmodo.com) & [StrictThemes – WordPress Themes](http://strictthemes.com/)
== Installation ==
1. Unpack the download package
2. Upload all files to the `/wp-content/plugins/` directory, include folders
3. Activate the plugin through the 'Plugins' menu in WordPress
4. Go to `Settings` page, where you can change what settings you need (pay attention to **Exclude** option!)
== Screenshots ==
1. Maintenance Mode example
2. Maintenance Mode example #2
3. Contact form
4. Dashboard General settings
5. Dashboard Design settings
6. Dashboard Modules settings
== Frequently Asked Questions ==
= How to use plugin filters =
See [GitHub Repo] (https://github.com/Designmodocom/WP-Maintenance-Mode) FAQ.
= Cache Plugin Support =
WP Maintenance Mode can be unstable due the cache plugins, we recommend to deactivate any cache plugin when maintenance mode is active.
= Exclude list =
If you change your login url, please add the new slug (url: http://domain.com/newlogin, then you should add: newlogin) to Exclude list from plugin settings -> General Tab.
== Changelog ==
= 2.0.9 (29/11/2016) =
* new hook (`wpmm_after_body`) in maintenance mode template (thanks @ [Karolína Vyskočilová](https://github.com/vyskoczilova))
* pt_PT (portuguese) language update (thanks @ [Pedro Mendonça](https://github.com/pedro-mendonca))
* maintenance mode template can also be loaded from theme/child-theme folder (thanks @ [Florian Tiar](https://github.com/Mahjouba91) and [Lachlan Heywood](https://github.com/lachieh))
* new hooks for contact form (if you want to add new fields): `wpmm_contact_form_start`, `wpmm_contact_form_before_message`, `wpmm_contact_form_after_message`, `wpmm_contact_form_end`
* new hook for contact form validation (if you want to validate new fields): `wpmm_contact_validation`
* new hooks for contact form template (if you want to display new fields): `wpmm_contact_template_start`, `wpmm_contact_template_before_message`, `wpmm_contact_template_after_message`, `wpmm_contact_template_end`
* some javascript improvements
* small css fix for contact form (thanks @ [frontenddev](https://wordpress.org/support/topic/please-fix-modal-window-of-contact-form/))
= 2.0.8 (09/09/2016) =
* add wp_scripts() function (in helpers.php) to maintain backward compatibility (for those with WP < 4.2.0)
* css fix for subscribe button on maintenance page
* fix multisite administrator access issue
* pt_PT (portuguese) language update (thanks @ Pedro Mendonça)
* new hooks for Contact module: `wpmm_contact_template`, `wpmm_contact_subject`, `wpmm_contact_headers`
* jQuery (google cdn) path fix when SCRIPT_DEBUG is true
= 2.0.7 (06/07/2016) =
* reset_settings _wpnonce check (thanks # Wordfence)
* modules > google analytics code sanitization (thanks @ Wordfence)
* move sidebar banners from our servers to plugin folder... as WordPress staff requested
* Subscribe button error on Mobile version (thanks @ Hostílio Thumbo)
* replace $wp_scripts global with wp_scripts() function
* de_DE language file update (thanks @ tt22tt)
= 2.0.6 (20/06/2016) =
* notifications update
* languages update
= 2.0.5 (17/06/2016) =
* roles (array) fix
= 2.0.4 (17/06/2016) =
* fixed issue: responsive subscribe form
* fixed issue: jQuery was loaded from a different folder on some WP installations
* fixed issue: errors after update (strstr on empty strings because of saving empty lines on exclude list)
* fixed issue: if "Redirection" from "General" tab is active, also redirects ajax calls
* fixed issue: settings page title was wrong placed
* "contact" feature update - nice email template + reply-to email header
* refactoring for some methods
* all assets are now minified
* rewrite count db records function (used on subscribers count)
* compatible with https://github.com/afragen/github-updater
* compatible with wp-cli http://wp-cli.org/
* improved responsivity
* improved roles access; now you can set multiple roles (editor, author, subscriber, contributor) and administrator will always have access to backend and frontend
* it_IT translation by benedettogit (https://github.com/benedettogit)
* updated all language files (need help for 100% translation)
= 2.0.3 (07/10/2014) =
* WP_Super_Cache issue was fixed
* fixed "Subscribe" button issue on Safari mobile
* fixed color of subscribe-success message (same color as subscribe_text)
* "Social networks" module edits: settings for links target + a new social network: linkedin
* new module "Google Analytics"
* loginform shortcode reintroduced
* dashboard link on maintenance page reintroduced
* the content editor accepts new css inline properties: min-height, max-height, min-width, max-width. Use them wisely! :)
* Settings & sidebar view + old translation files edited
* Update from old version 1.x to 2.x issue was fixed
* Translate on activation issue was fixed
* de_DE translation by Frank Bültge (http://bueltge.github.io/)
* pt_PT translation (100% translated) by Pedro Mendonça (http://www.pedromendonca.pt)
* ru_RU translation (100% translated) by affectiosus (https://github.com/affectiosus)
* nl_NL translation by dhunink (https://github.com/dhunink)
* es_ES translation (100% translated) by Erick Ruiz de Chavez (http://erickruizdechavez.com/)
* fr_FR translation by Florian TIAR (https://github.com/Mahjouba91)
* pt_BR translation by Jonatas Araújo (http://www.designworld.com.br/)
* sv_SE translation by Andréas Lundgren (http://adevade.com/)
= 2.0.2 (04/09/2014) =
* Removed "Author Link" option from General
* Countdown - save details fix
= 2.0.1 (02/09/2014) =
* Reintroduced some deprecated actions from old version (but still available in next 4 releases, after that will be removed) and replaced with new ones:
- `wm_head` -> `wpmm_head`
- `wm_footer` -> `wpmm_footer`
* Multisite settings link fix
* WP_Maintenance_Mode: init (array checking for custom_css arrays, move delete cache part into a helper, etc.), add_subscriber, send_contact, redirect fixes & optimizations
* WP_Maintenance_Mode_Admin: save_plugin_settings fixes, delete_cache (new method)
* Settings & Maintenance views fixes
* Readme.txt changes
= 2.0.0 (01/09/2014) =
* Changed design and functionality, new features
* Changed multisite behaviour: now you can activate maintenance individually (each blog from the network has it's own maintenance settings)
* Removed actions: `wm_header`, `wm_footer`, `wm_content`
* Removed filters: `wm_header`
* Removed [loginform] shortcode
* Some filters are deprecated (but still available in next 4 releases, after that will be removed) and replaced with new ones:
- `wm_heading` -> `wpmm_heading`,
- `wp_maintenance_mode_status_code` -> `wpmm_status_code`
- `wm_title` -> `wpmm_meta_title`
- `wm_meta_author` -> `wpmm_meta_author`
- `wm_meta_description` -> `wpmm_meta_description`
- `wm_meta_keywords` -> `wpmm_meta_keywords`
* Added new filters:
- `wpmm_backtime` - can be used to change the backtime from page header
- `wpmm_meta_robots` - can be used to change `Robots Meta Tag` option (from General)
- `wpmm_text` - can be used to change `Text` option (from Design > Content)
- `wpmm_scripts` - can be used to embed new javascripts files
- `wpmm_styles` - can be used to embed new css files
- `wpmm_search_bots` - if you have `Bypass for Search Bots` option (from General) activated, it can be used to add new bots (useragents)
* Removed themes and now we have a "Design" & "Modules" tabs, where the look and functionality of the maintenance page can be changed as you need
= 07/07/2014 =
* Switch to new owner, contributor
= 1.8.11 (07/25/2013) =
* Fixes for php notices in scrict mode
* Alternative for check url, if curl is not installed
= 1.8.10 (07/18/2013) =
* Add check for urls, Performance topics
* Change default setting of 'Support Link' to false
* Fix network settings php notices
= 1.8.9 (06/20/2013) =
* Allow empty header, title, heading string
* Small code changes
* Add Support function
* Remove preview, will include later in a new release with extra settings page
= 1.8.8 (06/05/2013) =
* Fix path to localized flash content
* Fix preview function
* Add ukrainian translation
* Add czech translation
* Fix exclude function for IP
* Security fix for save status via Ajax
= 1.8.7 (04/07/2013) =
* Add RTL support for splash page
* Add Filter Hook `wp_maintenance_mode_status_code` Status Code; default is 503
* Add support for custom splash page; leave a file with this name `wp-maintenance-mode.php` in the wp-content; the plugin use this file
The plugin checks in `WP_CONTENT_DIR . '/wp-maintenance-mode.php'`
* Small minor changes
* Add filter for more date on splash page
= 1.8.6 (02/22/2013) =
* Remove log inside console for JS
* Add support for time inside the countdown
* Add filter hook `wm_meta_author`for the meta data author
* Add filter hook `wm_meta_description` for custom description
* Add filter hook `wm_meta_keywords`for custom meta keys
= 1.8.5 (01/24/2013) =
* Added new settings for hide, view notices about the active maintenance mode
* Changes on source, codex
* Fix PHP Notices [Support Thread](http://wordpress.org/support/topic/error-message-in-settings-1)
* Change default settings, added ajax
* Fix Preview function
* Fix uninstall in WPMU
* Small updates on styles for login form
= 1.8.4 (12/06/2012) =
* Fix for include JS in frontend to use countdown
* Small mini fix for a php notice
* Add charset on spalsh page for strange databases
* Enhanced default exclude adresses
* Add shortcode `[loginform]` for easy use a login form in splash page
* Test with WordPress 3.5
= 1.8.3 =
* Fix for the forgotten update of JS-files; slow SVN :(
* Minor Fixes
= 1.8.2 =
* Add different access for Frontend and Backend
* Add Rewrite after Login for Frontend Access
* Different small changes
* Test for WP 3.5
= 1.8.1 =
* Add option for value of robots meta tag
* Add option for optional admin login
= 1.8.0 =
* Include all scripts in backend via function
* Update datepicker and countdown js
* Supportet IP as exclude for see the frontend
* Add support for flish cache od WP Super Cache and W3 Total Cache plugins
* Fix for changes in WP 3.3 Multisite
= 1.7.1 (12/05/2011) =
* fix for WP smaller 3.2* on Network
= 1.7.0 (12/02/2011) =
* add functionalities to use in WP Multisite
* remove message in header, current is not fixed the ticked in core and the message on Admin Bar an Notice is enough
* check on WP 3.3RC1
= 1.6.10 (08/30/2011) =
* add hint in Admin Bar, if active
* small changes for WP Codex
= 1.6.9 (06/13/2011) =
* Small fix for empty string on custom design
= 1.6.8 (04/05/2011) =
* Small changes on check for datepicker
* Fix for Design monster
= 1.6.7 (01/05/2011) =
* Bugfix: new check for files for different themes; hope this fix the server errors
* Bugfix: fix add default settings
* Maintenance: different changes on the syntax
* Feature: add check for Super Admin on WP Multisite; has allways the rights for access
* Feature: now it is possible to exclude feed from maintenance mode
* Maintenance: check with 3.0.4 and 3.1-RC2
* Maintenance: update language file: .pot, de_DE
* Bugfix: JavaScript error on Bulk Actions on plugins fixed
* Maintenance: fix all notice, if set no values
= 1.6.6. (10/09/2010) =
* Maintenance: many changes on the code; $locale and hook in side frontend
* Maintenance: change attribute_escaped to esc_attr with custom method for WP smaller 2.8
* Maintenance: Update german language files
* Feature: Shortcodes is now possible in the "Text" option
* Feature: no cache header rewrite
= 1.6.5 (09/16/2010) =
* add new design "Chemistry" by [elmastudio.de](http://www.elmastudio.de/ "elmastudio.de")
* changes for include methods od class for preview
* changes the possibility for include of language specific flash files
= 1.6.4 (09/13/2010) =
* add preview functions
* bugfix for list in wp-admin/plugins.php
* remove datepicker.regional - dont work fine
* different small changes
* new language file .pot
* add flash file and change on plugin for style "Animate" for spanish language
= 1.6.3 (07/27/2010) =
* bugfix to include stylesheet on maintenance mode message
= 1.6.2 (07/08/2010) =
* add functions for hint in the new UI of WP 3.0
* add more WP Codex standard source
* fix strings in the language and languages files
* add datetimepicker-de
= 1.6.1 (06/18/2010) =
* fix a problem with https://; see [Ticket #13941](http://core.trac.wordpress.org/ticket/13941)
= 1.6 (05/17/2010) =
* bugfix for exclude sites
= 1.5.9 (05/07/2010) =
* change different points
* add possibility to wotk with MySQLDumper
= 1.5.8 (21/03/2010)=
* fix exclude error
* add textareas for heading and header fields
= 1.5.7 (03/18/2010) =
* block admin-area via role
* add message for registered users with not enough rights
* add message on login-page
* different changes
= 1.5.6 (02/25/2010) =
* changes on css, site.php and different syntax on the plugin
= 1.5.5 (02/23/2010) =
* SORRY, small bug for the url to jQuery
= 1.5.4 (02/23/2010) =
* add time for countdown
* changes for WP 3.0
* changees on rights to see frontend
= 1.5.3 (01/05/2010) =
* Fix for JavaScript with WordPress 2.9
* Add new custom fields for fronted: title, header, heading
* Fix for setting userrole to see frontend
* Change laguage files
= 1.5.2 (01/04/2010) =
* add user-role setting
* correctly the de_DE language file
= 1.5.1 (10/04/2009) =
* add small fix
* add language files (en_ES, ro_RO)
= 1.5.0 (09/28/2009) =
* add countdown
* change options
* change default options
* add field for own adress to excerpt of the maintenance mode
* etc.
= 1.4.9 (07/09/2009) =
* also ready for WordPress 2.6
* add romanian language files
* add italian language file by [Gianni Diurno](http://gidibao.net/ "Gianni Diurno")
= 1.4.8 (03/09/2009) =
* add design "Damask" by [Fabian Letscher](http://fabianletscher.de/ "Fabian Letscher")
* add design "Lego" by [Alex Frison](http://www.afrison.com/ "Alex Frison")
= 1.4.7 (26/08/2009) =
* change doc-type to utf-8 without BOM
= v1.4.6 (24/08/2009) =
* add design "Animate (Flash)" by [Sebastian Schmiedel](http://www.cayou-media.de/ "Sebastian Schmiedel")
* add new hook for add content `wm_content` to include flash on content
* add frensh language files
= v1.4.5 (19/08/2009) =
* fix html string in text on frontend
* add design "Paint" by [Marvin Labod](http://bugeyes.de/ "Marvin Labod")
* add turkey language files
= v1.4.4 (18/08/2009) =
* add design "Chastely" by [Florian Andreas Vogelmaier](http://fv-web.de/ "Florian Andreas Vogelmaier")
* add design "Only Typo" by [Robert Pfotenhauer](http://krautsuppe.de/ "Robert Pfotenhauer")
= v1.4.3 (13/08/2009) =
* add option for the Text
* add option for active maintenance mode
* add design "The FF Error" by [Thomas Meschke](http://www.lokalnetz.com/ "Thomas Meschke")
* add design "Monster" by [Sebastian Sebald](http://www.backseatsurfer.de "Sebastian Sebald")
= v1.4.2 (10/08/2009) =
* add design "The Sun" by [Nicki Steiger](http://mynicki.net/ "Nicki Steiger")
* now it is possible to add own css and add in settings the url to the css-file
= v1.4.1 (07/08/2009) =
* small html-fix
= v1.4 (06/08/2009) =
* complety new code
* options menu
* new designs by [David Hellmann](http://www.davidhellmann.com/ "David Hellmann")

View File

@@ -1 +1 @@
<html><head><title>Test</title><link rel="stylesheet" type="text/css" href="/wp-content/themes/theme_name/style.css" /></head><body></body></html> <html><head><title>Test</title><link rel="stylesheet" type="text/css" href="/wp-content/themes/theme_name/style.css" /></head><body></body></html>

View File

@@ -0,0 +1 @@
<html><head><title>Test</title><link rel="stylesheet" type="text/css" href="wp-content/themes/theme_name/style.css" /></head><body></body></html>

View File

View File

View File

View File

@@ -0,0 +1,99 @@
<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>WordPress &#8250; ReadMe</title>
<link rel="stylesheet" href="wp-admin/css/install.css?ver=20100228" type="text/css" />
</head>
<body>
<h1 id="logo">
<a href="https://wordpress.org/"><img alt="WordPress" src="wp-admin/images/wordpress-logo.png" /></a>
<br /> Version 4.7
</h1>
<p style="text-align: center">Semantic Personal Publishing Platform</p>
<h2>First Things First</h2>
<p>Welcome. WordPress is a very special project to me. Every developer and contributor adds something unique to the mix, and together we create something beautiful that I&#8217;m proud to be a part of. Thousands of hours have gone into WordPress, and we&#8217;re dedicated to making it better every day. Thank you for making it part of your world.</p>
<p style="text-align: right">&#8212; Matt Mullenweg</p>
<h2>Installation: Famous 5-minute install</h2>
<ol>
<li>Unzip the package in an empty directory and upload everything.</li>
<li>Open <span class="file"><a href="wp-admin/install.php">wp-admin/install.php</a></span> in your browser. It will take you through the process to set up a <code>wp-config.php</code> file with your database connection details.
<ol>
<li>If for some reason this doesn&#8217;t work, don&#8217;t worry. It doesn&#8217;t work on all web hosts. Open up <code>wp-config-sample.php</code> with a text editor like WordPad or similar and fill in your database connection details.</li>
<li>Save the file as <code>wp-config.php</code> and upload it.</li>
<li>Open <span class="file"><a href="wp-admin/install.php">wp-admin/install.php</a></span> in your browser.</li>
</ol>
</li>
<li>Once the configuration file is set up, the installer will set up the tables needed for your blog. If there is an error, double check your <code>wp-config.php</code> file, and try again. If it fails again, please go to the <a href="https://wordpress.org/support/" title="WordPress support">support forums</a> with as much data as you can gather.</li>
<li><strong>If you did not enter a password, note the password given to you.</strong> If you did not provide a username, it will be <code>admin</code>.</li>
<li>The installer should then send you to the <a href="wp-login.php">login page</a>. Sign in with the username and password you chose during the installation. If a password was generated for you, you can then click on &#8220;Profile&#8221; to change the password.</li>
</ol>
<h2>Updating</h2>
<h3>Using the Automatic Updater</h3>
<p>If you are updating from version 2.7 or higher, you can use the automatic updater:</p>
<ol>
<li>Open <span class="file"><a href="wp-admin/update-core.php">wp-admin/update-core.php</a></span> in your browser and follow the instructions.</li>
<li>You wanted more, perhaps? That&#8217;s it!</li>
</ol>
<h3>Updating Manually</h3>
<ol>
<li>Before you update anything, make sure you have backup copies of any files you may have modified such as <code>index.php</code>.</li>
<li>Delete your old WordPress files, saving ones you&#8217;ve modified.</li>
<li>Upload the new files.</li>
<li>Point your browser to <span class="file"><a href="wp-admin/upgrade.php">/wp-admin/upgrade.php</a>.</span></li>
</ol>
<h2>Migrating from other systems</h2>
<p>WordPress can <a href="https://codex.wordpress.org/Importing_Content">import from a number of systems</a>. First you need to get WordPress installed and working as described above, before using <a href="wp-admin/import.php" title="Import to WordPress">our import tools</a>.</p>
<h2>System Requirements</h2>
<ul>
<li><a href="https://secure.php.net/">PHP</a> version <strong>5.2.4</strong> or higher.</li>
<li><a href="https://www.mysql.com/">MySQL</a> version <strong>5.0</strong> or higher.</li>
</ul>
<h3>Recommendations</h3>
<ul>
<li><a href="https://secure.php.net/">PHP</a> version <strong>7</strong> or higher.</li>
<li><a href="https://www.mysql.com/">MySQL</a> version <strong>5.6</strong> or higher.</li>
<li>The <a href="https://httpd.apache.org/docs/2.2/mod/mod_rewrite.html">mod_rewrite</a> Apache module.</li>
<li><a href="https://wordpress.org/news/2016/12/moving-toward-ssl/">HTTPS</a> support.</li>
<li>A link to <a href="https://wordpress.org/">wordpress.org</a> on your site.</li>
</ul>
<h2>Online Resources</h2>
<p>If you have any questions that aren&#8217;t addressed in this document, please take advantage of WordPress&#8217; numerous online resources:</p>
<dl>
<dt><a href="https://codex.wordpress.org/">The WordPress Codex</a></dt>
<dd>The Codex is the encyclopedia of all things WordPress. It is the most comprehensive source of information for WordPress available.</dd>
<dt><a href="https://wordpress.org/news/">The WordPress Blog</a></dt>
<dd>This is where you&#8217;ll find the latest updates and news related to WordPress. Recent WordPress news appears in your administrative dashboard by default.</dd>
<dt><a href="https://planet.wordpress.org/">WordPress Planet</a></dt>
<dd>The WordPress Planet is a news aggregator that brings together posts from WordPress blogs around the web.</dd>
<dt><a href="https://wordpress.org/support/">WordPress Support Forums</a></dt>
<dd>If you&#8217;ve looked everywhere and still can&#8217;t find an answer, the support forums are very active and have a large community ready to help. To help them help you be sure to use a descriptive thread title and describe your question in as much detail as possible.</dd>
<dt><a href="https://codex.wordpress.org/IRC">WordPress <abbr title="Internet Relay Chat">IRC</abbr> Channel</a></dt>
<dd>There is an online chat channel that is used for discussion among people who use WordPress and occasionally support topics. The above wiki page should point you in the right direction. (<a href="irc://irc.freenode.net/wordpress">irc.freenode.net #wordpress</a>)</dd>
</dl>
<h2>Final Notes</h2>
<ul>
<li>If you have any suggestions, ideas, or comments, or if you (gasp!) found a bug, join us in the <a href="https://wordpress.org/support/">Support Forums</a>.</li>
<li>WordPress has a robust plugin <abbr title="application programming interface">API</abbr> that makes extending the code easy. If you are a developer interested in utilizing this, see the <a href="https://developer.wordpress.org/plugins/">Plugin Developer Handbook</a>. You shouldn&#8217;t modify any of the core code.</li>
</ul>
<h2>Share the Love</h2>
<p>WordPress has no multi-million dollar marketing campaign or celebrity sponsors, but we do have something even better&#8212;you. If you enjoy WordPress please consider telling a friend, setting it up for someone less knowledgable than yourself, or writing the author of a media article that overlooks us.</p>
<p>WordPress is the official continuation of <a href="http://cafelog.com/">b2/caf&#233;log</a>, which came from Michel V. The work has been continued by the <a href="https://wordpress.org/about/">WordPress developers</a>. If you would like to support WordPress, please consider <a href="https://wordpress.org/donate/" title="Donate to WordPress">donating</a>.</p>
<h2>License</h2>
<p>WordPress is free software, and is released under the terms of the <abbr title="GNU General Public License">GPL</abbr> version 2 or (at your option) any later version. See <a href="license.txt">license.txt</a>.</p>
</body>
</html>

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