
ETHICAL HACKING FRIDAYS: HOW TO HACK (PART 5) Secure WordPress
If almost half of the web uses WordPress should we not make sure it is secure?
I downloaded WordPress and installed a fresh installation on my Kali Linux virtual machine. Nothing special in terms of infrastructure, just a Kali Linux VirtualBox virtual machine, an Apache 2 web server, and a fork of MySQL called MariaDB as the database. I’m not going to cover the basic installation of WordPress as it is well documented on their website.
I’m going to use a series of hacking tools to “pen test” a fresh install of WordPress. I will then go through the results and make recommendations how to secure WordPress.
kali@kali:~$ wpscan --version
_______________________________________________________________
__ _______ _____
/ / __ / ____|
/ / /| |__) | (___ ___ __ _ _ __ ®
/ / / | ___/ ___ / __|/ _` | '_
/ / | | ____) | (__| (_| | | | |
/ / |_| |_____/ ___|__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.7
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________Current Version: 3.8.7
Last DB Update: 2020-10-02
I will make sure “wpscan” is up to date.
kali@kali:~$ wpscan --update
_______________________________________________________________
__ _______ _____
/ / __ / ____|
/ / /| |__) | (___ ___ __ _ _ __ ®
/ / / | ___/ ___ / __|/ _` | '_
/ / | | ____) | (__| (_| | | | |
/ / |_| |_____/ ___|__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.7
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[i] Updating the Database ...
[i] Update completed.
The first step is to use “wpscan” included with Kali Linux.
kali@kali:~$ wpscan --url http://192.168.1.2 --enumerate u,vp,vt,dbe
_______________________________________________________________
__ _______ _____
/ / __ / ____|
/ / /| |__) | (___ ___ __ _ _ __ ®
/ / / | ___/ ___ / __|/ _` | '_
/ / | | ____) | (__| (_| | | | |
/ / |_| |_____/ ___|__,_|_| |_|
WordPress Security Scanner by the WPScan Team
Version 3.8.7
Sponsored by Automattic - https://automattic.com/
@_WPScan_, @ethicalhack3r, @erwan_lr, @firefart
_______________________________________________________________
[+] URL: http://192.168.1.2/ [192.168.1.2]
[+] Started: Sat Oct 3 19:32:00 2020
Interesting Finding(s):
[+] Headers
| Interesting Entry: Server: Apache/2.4.46 (Debian)
| Found By: Headers (Passive Detection)
| Confidence: 100%
[+] XML-RPC seems to be enabled: http://192.168.1.2/xmlrpc.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
| References:
| - http://codex.wordpress.org/XML-RPC_Pingback_API
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_ghost_scanner
| - https://www.rapid7.com/db/modules/auxiliary/dos/http/wordpress_xmlrpc_dos
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_xmlrpc_login
| - https://www.rapid7.com/db/modules/auxiliary/scanner/http/wordpress_pingback_access
[+] WordPress readme found: http://192.168.1.2/readme.html
| Found By: Direct Access (Aggressive Detection)
| Confidence: 100%
[+] The external WP-Cron seems to be enabled: http://192.168.1.2/wp-cron.php
| Found By: Direct Access (Aggressive Detection)
| Confidence: 60%
| References:
| - https://www.iplocation.net/defend-wordpress-from-ddos
| - https://github.com/wpscanteam/wpscan/issues/1299
[+] WordPress version 5.5.1 identified (Latest, released on 2020-09-01).
| Found By: Rss Generator (Passive Detection)
| - http://192.168.1.2/index.php/feed/, <generator>https://wordpress.org/?v=5.5.1</generator>
| - http://192.168.1.2/index.php/comments/feed/, <generator>https://wordpress.org/?v=5.5.1</generator>
[+] WordPress theme in use: twentytwenty
| Location: http://192.168.1.2/wp-content/themes/twentytwenty/
| Latest Version: 1.5 (up to date)
| Last Updated: 2020-08-11T00:00:00.000Z
| Readme: http://192.168.1.2/wp-content/themes/twentytwenty/readme.txt
| Style URL: http://192.168.1.2/wp-content/themes/twentytwenty/style.css?ver=1.5
| Style Name: Twenty Twenty
| Style URI: https://wordpress.org/themes/twentytwenty/
| Description: Our default theme for 2020 is designed to take full advantage of the flexibility of the block editor...
| Author: the WordPress team
| Author URI: https://wordpress.org/
|
| Found By: Css Style In Homepage (Passive Detection)
|
| Version: 1.5 (80% confidence)
| Found By: Style (Passive Detection)
| - http://192.168.1.2/wp-content/themes/twentytwenty/style.css?ver=1.5, Match: 'Version: 1.5'
[+] Enumerating Vulnerable Plugins (via Passive Methods)
[i] No plugins Found.
[+] Enumerating Vulnerable Themes (via Passive and Aggressive Methods)
Checking Known Locations - Time: 00:00:00 <======================================================================> (363 / 363) 100.00% Time: 00:00:00
[+] Checking Theme Versions (via Passive and Aggressive Methods)
[i] No themes Found.
[+] Enumerating DB Exports (via Passive and Aggressive Methods)
Checking DB Exports - Time: 00:00:00 <=============================================================================> (36 / 36) 100.00% Time: 00:00:00
[i] No DB Exports Found.
[+] Enumerating Users (via Passive and Aggressive Methods)
Brute Forcing Author IDs - Time: 00:00:00 <========================================================================> (10 / 10) 100.00% Time: 00:00:00
[i] User(s) Identified:
[+] m-whittle
| Found By: Author Posts - Author Pattern (Passive Detection)
| Confirmed By:
| Wp Json Api (Aggressive Detection)
| - http://192.168.1.2/index.php/wp-json/wp/v2/users/?per_page=100&page=1
| Author Id Brute Forcing - Author Pattern (Aggressive Detection)
[+] m.whittle
| Found By: Rss Generator (Passive Detection)
| Confirmed By: Login Error Messages (Aggressive Detection)
[!] No WPVulnDB API Token given, as a result vulnerability data has not been output.
[!] You can get a free API token with 50 daily requests by registering at https://wpvulndb.com/users/sign_up
[+] Finished: Sat Oct 3 19:32:02 2020
[+] Requests Done: 413
[+] Cached Requests: 46
[+] Data Sent: 96.65 KB
[+] Data Received: 72.608 KB
[+] Memory used: 218.762 MB
[+] Elapsed time: 00:00:02
There are some points of interest above.
The first issue which isn’t directly related to WordPress is that “wpscan” was able to determine the operating system and web server including version. Why is this a problem? Because a quick search on Exploit DB shows there are verified and open vulnerabilities in Apache 2.4.

The web server should really hide this information as it can be used to exploit. You can edit the “httpd.conf”, update the following configuration, and restart Apache to fix this.
ServerTokens Prod
ServerSignature Off
You should really do the same for PHP as well. Edit the “php.ini” and include this.
expose_php = Off
“XML-RPC” isn’t necessarily a problem if you have a genuine use case for it, like updating your WordPress site using remote technologies and mobile applications. The problem is that xmlrpc.php poses a security risk. It creates an additional access point to your site, which could leave it vulnerable to external attacks. Every time you authenticate XML-RPC, you need to supply your username and password. As you can imagine, this isn’t exactly ideal for security purposes. You are able to prevent bruce force attacks when logging into your WordPress site but the same controls don’t exist for XML-RPC. It is a little crazy that it is enabled by default but it is. If you aren’t using it I recommend disabling it with the plugin Disable XML-RPC.
I’m not sure why “wpscan” is flagging “WP-Cron”. I’m not aware of any vulnerabilities with it. It’s used to schedule tasks within WordPress like scheduled posts. I believe the only issue with it is on large busy sites it may cause a performance problem. If you don’t have a need for scheduled tasks it would be best to disable it.
Edit your “wp-config.php file” and add this line:
define('DISABLE_WP_CRON', true);
It is never good practice to leave sample code and installation instructions on a site. In this case “readme.html”. It should definitely be removed.
I found some interesting statistics provided by WP Security.
“According to statistics From 40,000+ WordPress Websites in Alexa Top 1 Million, more than 70% of WordPress installations are vulnerable to hacker attacks.”
“The WPScan Vulnerability Database is an online browsable version of WPScan’s data files which are used to detect known WordPress core, plugins and themes vulnerabilities. To date it contains 2407 vulnerabilities, 1570 of which are unique vulnerabilities.”
“WordPress plugins are the biggest source of vulnerabilities in WordPress. So far there are 1,305 WordPress plugins vulnerabilities in the WPScan Vulnerability database. That accounts to 54% of the global WordPress vulnerabilities count. Then there are 344 (14.3%) WordPress themes vulnerabilities and 758 (31.5%) WordPress core vulnerabilities.”
The interesting point I want to show you here is that WordPress plugins account for 54% of the vulnerabilities, 14.4% for themes, and the remaining 31.5% for WordPress core. Not sure about the remaining 1%?
So really you don’t want to go overboard installing the latest themes and plugins without doing your due diligence and checking the WPScan Vulnerability Database. It’s important to check regularly and make sure WordPress and plugins are always updated to the latest versions. It may even be a good idea to automate a “wpscan” regularly and flag any vulnerabilities as they occur. According to the statistics the majority of attacks on 70%+ of WordPress sites is due to not keeping software and plugins up to date.
I was able to identify my username using a “wpscan” “ — enumerate u”. In my case this was “m.whittle”. So why is this a problem? Because I know exactly which username to bruce force now! The big saving grace here is that WordPress generated a really strong password when creating a new user. The password they offered me would mean a bruce forcing tool would need to try over 8 billion combinations. You really should be using the strong password they provide and not using your own. Any known password combination could take a very short time to crack. There is a database with comes with Kali Linux which has 14344392 common password combinations.
kali@kali:~$ wc -l /usr/share/wordlists/rockyou.txt
14344392 /usr/share/wordlists/rockyou.txt
My previous ethical hacking article covers brute force and password hacking in detail, so please review it for more information: “Ethical Hacking (Part 4): Password & Hash Cracking”.
In my test WordPress, my account was created with the username “m.whittle” and a strong 18 character password with a mixture of character types. A brute forcing tool won’t be able to crack it. But assuming I got lazy and replaced it with “Password1!” this would take up to ~40 or so hours depending on where it is on the password list, the speed of the connection, and hardware.
kali@kali:~$ wpscan --url http://192.168.1.2 --usernames m.whittle,m-whittle --passwords /usr/share/wordlists/rockyou.txt
OR
kali@kali:~$ wpscan --url http://192.168.1.2 --usernames usernames.txt --passwords /usr/share/wordlists/rockyou.txt
You could also carry out the brute force using Hydra…
kali@kali:~$ hydra -V -L usernames.txt -P /usr/share/wordlists/rockyou.txt 192.168.1.2 http-post-form '/wp-login.php:log=^USER^&pwd=^PASS^&wp-submit=Log:F=Invalid username'
There isn’t really any point trying to proper brute force WordPress as the generated passwords are too strong and you won’t be able to get through enough passwords per second over a network connection to make a dent. You would have to try your luck that the user was irresponsible and used a common password combination or sequence. Even common “random” keyboard sequences are in that list.
Here are some pointers in making sure your WordPress site is as secure as possible:
- Make sure your site traffic is encrypted with a certificate (TLS 1.2) and HTTP connections are redirected/disabled.
- Purchase and install the Sucuri plugin. It does not cost a lot and provides essential security to your site. One of the key features is detecting, alarming and dealing with brute force attacks.
- Make sure you regularly check your WordPress, plugins, and themes for updates. Ideally you should automate running “wpscan” and “ — enumerate vp,vt”. This will show you if you have vulnerable plugins or themes.
- Make sure all administrative accounts use the strong passwords generated by WordPress. With the account details of an administrative account the attacker can carry out irreparable damage.
- Disable any services you aren’t using like “XML-RPC” and potentially “WP-Cron”.
- Remove any sample pages or installation instructions. An example is “readme.html”.
- Ensure your web server and PHP do not disclose their versions as discussed earlier.
- Do not expose your database to the outside world. The WordPress application should be able to connect to it but nothing else (aside from any essential management connectivity).
- Use a limited database user for WordPress. WordPress only requires read and write access to the database so the database user should only be given SELECT, INSERT, UPDATE and DELETE privileges.
- Your web server should be running as a dedicated user (not root!) in a dedicated group. For example “wwwrun” and “www”. The reason for this is if for any reason your web site is compromised the attacker will gain access to the user which is running your web service. You want to limit as much as possible what that user can do so that is why you should be reducing the scope of what it can do.
- Make sure debugging is disabled in PHP. If any failures happen you only want the user to be presented with a very generic error message. You won’t want to give anyway too much about what is happening behind the scenes.
- Make sure you take regular backups of your site and database and don’t store them locally! There are actually backup plugins that can help with this like iThemes, BackupBuddy, UpdraftPlus, BackUpWordPress, and VaultPress.
- Disable file editing — WordPress comes with a set of theme and plugin editors. You can find them under Appearance > Theme Editor and Plugins > Plugin Editor. These allow direct access to your site’s code. Alternatively you can disable them in one go by editing the “wp-config.php” and adding, “define(‘DISALLOW_FILE_EDIT’, true);”.
- Make sure the permissions in your WordPress web server root are correct. For example my WordPress is installed in, “/var/www/html”. So I would run this, “find /var/www/html/ -type d -exec chmod 755 {} ;” and “find /var/www/html/ -type f -exec chmod 644 {} ;”.
- It would be worth adding server side authentication to the “wp-admin/” directory and files. If you are using Apache maybe an “.htaccess” file with basic auth just for an additional layer of security. Use a separate username and password to WordPress.
- Make sure your “wp-config.php” file has permission 400 which is read-only for the web server. You could take this one setup further and move it one level up from the web server root but this is tricky to do without breaking something. You can also restrict access to this file from the web server using “httpd.conf” or “.htconfig”.
<files wp-config.php>
order allow,deny
deny from all
</files>
17. You can also restrict access to scripts that are not intended to be accessed by a user like this.
# Block the include-only files.
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^wp-admin/includes/ - [F,L]
RewriteRule !^wp-includes/ - [S=3]
RewriteRule ^wp-includes/[^/]+.php$ - [F,L]
RewriteRule ^wp-includes/js/tinymce/langs/.+.php - [F,L]
RewriteRule ^wp-includes/theme-compat/ - [F,L]
</IfModule>
# BEGIN WordPress
Notice the “# BEGIN WordPress”, this tells WordPress not to insert any configuration above that invalidating any security configuration.