Looking for WordPress vulnerabilities with WPScan

Word Alert

© Lead Image © pnphoto, 123RF.com

© Lead Image © pnphoto, 123RF.com

Author(s):

The number of potential WordPress vulnerabilities is stunning. WPScan scans your site to find the problems that could lead to compromise.

When software becomes uber-popular, attackers spend much more time trying to find security holes. WordPress [1], an extremely popular content management system (CMS), is built on the PHP [2] language. WordPress also hooks into a relatively small database back end, such as MariaDB. I always advise very large commercial organizations to avoid using WordPress due to the constant battle of patching and checking for security issues, even when using some of the excellent automation which is now provided. Smaller businesses might be tempted to use WordPress because of its simplicity, but they need to be vigilant about staying up to date.

In a previous article [3], I introduced WPScan [4] and described how an attacker can use the powerful service to look for vulnerabilities in a WordPress website. The good news is that WordPress webmasters can also use WPScan to close any gaps before an intruder finds them.

Start at the Beginning

Security professionals have spent a long time trying to make life easier for those running WordPress sites. WPScan, in particular, has excelled and created a genuinely invaluable tool to check your site's security. WPScan helps users find every possible (currently) known issue present on a WordPress site in a fully automated fashion.

The open source WPScan has an impressive arsenal and boasts an ever-growing database that contains an eye-watering number of vulnerabilities to reference. Its own website states: "The WPScan CLI tool is a free, for non-commercial use, black box WordPress security scanner written for security professionals and blog maintainers to test the security of their sites. The WPScan CLI tool uses our database of 38,997 WordPress vulnerabilities" [4].

If you want to use the tool for commercial sites, there's a link that takes you to a WordPress plugin called Jetpack Protect [5], which WPscan works in partnership with. The premise is that your administrator's WordPress dashboard will light up like a Christmas tree if Jetpack Protect finds malware or security threats within your WordPress plugins, themes, or WordPress core system files. There's a pricing page [6] with packages that seem very reasonably priced, considering the potential loss of revenue and damage to a business's reputation.

Without further ado, I will show you what the venerable WPScan finds on the latest version of WordPress, which I have running on an AWS instance for testing. If you have never installed WordPress, the Ubuntu Linux site [7] provides useful configuration and installation instructions. Because my AWS instance is running Debian Linux 11 ("bullseye"), I'll use that guide [8]. The installation process essentially involves installing the Apache web server, the PHP language, and then the MariaDB database server. Finally, before some configuration, the last task is downloading WordPress [9].

Contain Your Stuff

I'll use the Docker container route to get WPScan up and running. (Make sure that you have permission to scan the sites where you are running WPScan. It is extremely thorough and other users and admins may notice the scans.) There's also a simple Ruby gem installation route [10].

To get the WordPress scanner running as a container, you need to use the following Docker Engine command:

$ docker run -it --rm wpscanteam/wpscan--url http://XXX.XXX.XXX.XXX/--enumerate ap,at,cb

(If your Ubuntu Linux or other Debian Linux derivative doesn't have Docker Engine installed, you need to use the apt install docker.io command.)

The XXXs in the example are the AWS instance's IP address. Later on, having used Let's Encrypt [11] to generate a TLS certificate, the eagle-eyed among you will notice that I replace the IP address and http with https://hostname.tld. (If you want to do this, the instructions are in the WordPress on Debian installation instructions [8]).

Hopefully, the rest of the Docker Engine command is self-explanatory. However, note the importance of the enumerate flag (abbreviated to -e if you like). Table 1 shows the enumerate options.

Table 1

WPScan enumerate Options

Option

Effect

vp

Check for vulnerable plugins

ap

Look at all plugins

p

Investigate popular plugins

vt

Check for vulnerable themes

at

Look at all themes

t

Investigate popular themes

tt

TimThumb [12]

cb

Check for WordPress configuration backups

dbe

Look at database exports

u

Investigate user IDs with u1-5

m

Check media IDs with m1-15

If you want to save the scan output, then you need to create a volume for the container (called a bind mount); otherwise, the output file gets written inside the scanner container, which then gets destroyed after running the scan. I start with creating a local filesystem directory (on my laptop in this case), followed by a long and somewhat unwieldy Docker Engine command shown in Listing 1 (admittedly I haven't tested this, so refer to the docs if you need help):

Listing 1

Saving the WPScan Output

$ mkdir ~/docker-bind
$ docker run --rm --mount type=bind,source=$HOME/docker-bind,target=/output wpscanteam/wpscan:latest -o /output/wpscan-output.txt --url 'http://XXX.XXX.XXX.XXX'

One final switch to mention: If you're faced with Web Application Firewalls (WAFs) that do clever, sophisticated sifting of incoming traffic, you need to address this before putting WPScan to work. To help mitigate WAF responses, you can add this option:

--random-user-agent

which alters how the scans are perceived from a WAF's point of view.

Where's It Gone?

It's not uncommon to struggle a little to find where WordPress is hiding on a web server, even though it's dynamically generating website content. In other words, if an admin has done the right thing by obfuscating the location of the admin dashboard login page, you may need to add options like --wp-content-dir or --wp-plugins-dir to point WPScan in the right direction.

To get WPScan working on steroids (to get full-fat information about discovered vulnerabilities in the output), the WPScan team asks you to create an API token. You can do this without logging in, by selecting For developers | API details. At the bottom of the page [13], under For Developers, you click on a link to register as a user, which asks for your name, email, a password, and optional billing information.

On this page, you'll also find vulnerability statistics. For instance, in the first half of October 2023, a staggering 117 new WordPress vulnerabilities were discovered (Figure 1) and presumably then added directly to the WPScan database. If you run a WordPress website and you don't think you need to worry about your site's security, Figure 1 may change your mind.

Figure 1: In October 2023, 117 new WordPress security issues were identified (Source: https://wpscan.com/api).

The API details page also provides an insightful yearly graph of WordPress security threats. A whopping 1,974 issues were discovered in 2022 alone. More worryingly, the year-on-year increases are steady with the last two years showing the largest yearly rises.

In order to gauge the quality and professionalism of the WPScan service, I would highly recommend reading the API details page [13], as well as the rest of WPScan website. The site explains that WPScan is a CVE Numbering Authority [14], which permits WPScan to directly register discovered Common Vulnerabilities and Exposures (CVEs), and this results in a security expert manually updating WPScan's vulnerabilities database (to ensure its integrity). (Each vulnerability considered to be of consequence is allocated a unique CVE number.)

There are also important API terms to abide by – such as only having one API token per organization and the prohibition against permanent storage of vulnerability data, among a number of other criteria – before using the API token. For WPScan's API reference, see the official Swagger page [15]. Once you register and log in, you will be able to regenerate your API token (or just make a copy of it initially). You will also be informed of the 75-per-day API call limit with the free subscription.

Beating the Bad Guys

I am running WordPress v6.2 on my AWS instance (the latest version at the time of writing). I can see the administrator dashboard login on the following URL (which I'm confident WPScan will find immediately, so I don't need to add any other options):

https://hostname.tld/wp-login.php

I use the Docker Engine command in Listing 2 to launch a scan. Note that I'm not using the API token in Listing 2.

Listing 2

Launching a Scan

$ docker run -it --rm wpscanteam/wpscan --url https://hostname.tld --enumerate ap,at,cb
Unable to find image 'wpscanteam/wpscan:latest' locally
latest: Pulling from wpscanteam/wpscan
97518928ae5f: Pull complete
d879f3f43643: Pull complete
[...snip?]

Figure 2 shows the beginning of the resulting lengthy output. The well-formatted information shown here helps point you to the salient security threat findings.

Figure 2: And so it begins. The initial output from the start of a scan.

For the enumerate option, I've included all plugins, all themes, and configuration backups. If you find the output from the scan is too verbose, I recommend reducing output to just vp for vulnerable plugins to get the most valuable information and then follow up with another vt scan for vulnerable themes.

The, frankly, unbelievable levels of detail that the WPScan tool produces is far too plentiful to show here (and I don't want to breach any of their terms by showing vulnerability data). I can however walk through some of the findings in even the most basic scan. By basic, I mean that I purposely have not enabled any plugins (and only enabled one theme) on my WordPress installation. I also haven't added the API token option to the scan to give detailed vulnerability information.

The scan queried a number of useful external WordPress settings (that attackers would be able to see without any credentials). Firstly, the results reported that XML-RPC appeared to be enabled. According to a blog post on the topic [16], XML-RPC can be vulnerable to brute-force login attempts. It should go without saying that the findings may not actually indicate a security issue, but the findings should certainly be investigated by a human to ensure the WordPress build isn't vulnerable. WPScan offers confidence levels (XML-RPC hit 100 percent), as well as multiple URL references accompanying the findings, which is helpful.

Another finding showed that the WordPress upload directory had directory listing enabled. If you are penetration testing or attacking a site, then enumerating useful assets on a web server is your first port of call (e.g., probably the best case for an attacker would be finding a password list). As a result, having the directory listing option enabled can be dangerous if lots of users are uploading documents and other data to a website.

WPScan promptly identified the version of WordPress correctly. It also mentioned that WP-Cron was enabled, which may be prone to Denial-of-Service (DoS) attacks. This seems a little contentious (having read the reference URLs), but it's certainly educational to learn more about potential threats like this.

The scan also correctly revealed I had activated the Twenty Twenty-Two WordPress theme, and it appeared to be using Cascading Style Sheets (CSS) content and other publicly available information to find additional issues with varying degrees of confidence.

Needless to say, even the very latest version of WordPress (with no active plugins) offered some food for thought that would be useful if I were attacking the web server.

Full Fat

Now I'll run the scan with the API token included (redacted because my API token should only be used by me). This time, I will enable two plugins within WordPress to offer a greater attack surface for WPScan to enumerate.

I've added the Duplicate Page plugin (chosen arbitrarily because it was updated three months prior and not as recently as others). This plugin lets you easily duplicate posts, pages, and custom posts with a single click.

I also enabled the WordPress gallery plugin, NextGEN Gallery (again because it hadn't been updated for three months). NextGEN Gallery claims to be the most popular gallery plugin with over 31 million downloads. That's a lot of downloads!

Two plugins, Akismet Anti-Spam (a blogging spam blocker) and Hello Dolly (which amusingly lets admins see random lyrics from Louis Armstrong's "Hello, Dolly" displayed in the upper right corner of the admin screen) were preloaded but not activated in the WordPress installation, so I activated them. While I did click activate, I didn't configure the plugins, which may skew the scans a little. For example, the Akismet plugin needed me to register with a spam service for it to fully work. Figure 3 shows the enabled plugins, four in total.

Figure 3: I added two plugins to WordPress, as well as activating two that were already there.

I'll use the same Docker Engine options as before for WPScan but add --api-token XXXXXXXX as an option (where the Xs are my API key from the WPScan website; note the actual token is much longer than the redacted version).

Having run the scan, the good news is that the scan didn't find anything relating to CVEs or flagged threats in these plugins.

Without betraying the confidences of WPScan's findings, a Proof of Concept (PoC) exploit was identified, and WPScan lit up with alarming red text for that section. It seems there isn't a vendor fix available for the issue yet, but from the levels of detail written about it expertly online, this seems like a threat that shouldn't be dismissed easily. Possibly, it can be mitigated.

When enumerating the themes, WPScan really went to town and spent over 12 minutes enumerating all plugins (using passive and aggressive scanning methods). It crawled the WordPress URLs for tens of thousands of locations to look for known themes (which are ostensibly obfuscated but still publicly reachable when installed, even though they are deactivated).

As a result of this scan, I would recommend registering for an API token to get the most out of WPScan.

Getting Wordy

If you install WPScan from the Ruby gem, then your command lines will look like Listing 3 (a little simpler, without the Docker Engine commands prepended). During Capture The Flag (CTF) exercises in the past, I've used WPScan to attempt to brute-force logins in WordPress.

Listing 3

WPScan with a Ruby Gem

$ wpscan --url https://hostname.tld/wp-login.php --enumerate u -U names.txt --passwords /directory-name/wordlists/1000-common-passwds.txt

Looking at Listing 3, I'll briefly dissect the new information. The -U option showing names.txt is for a text file that contains usernames that I discovered during the enumeration of various assets on a WordPress site. It may only contain a handful of usernames (possibly partly discovered from users who submitted posts on the blog sites) plus obvious users like admin, wp-admin, and wpadmin.

The --enumerate u option only looks for users (not plugins, etc.), so the scan is very focused.

The --passwords option is pointing at a downloaded file, which is one of a number of word lists that you can find online. As the name suggests, this list is only a thousand entries long, so it will iterate relatively quickly to see if any of the usernames match the passwords supplied. Brute-forcing WordPress like this can be done relatively quickly if there's no rate-limiting on the WordPress web server, if there are no hardware constraints (e.g., a busy website already consuming a portion of the server's resources), and the connectivity is adequate. The vast majority of cloud servers complete a scan within a few minutes for a handful of usernames checked against a thousand passwords.

Conclusion

After reading this article, I trust any WordPress website owners will immediately confirm that they have Jetpack Protect (or an alternative) installed and activated on their websites.

It's not an exaggeration to say that the sands are continually shifting in this area. If it hasn't already occurred to you, attackers may use the same tools that you use to defend your websites to cause damage.

If you are anything like me, you will find WPScan's findings fascinating. Hopefully, you will pay closer attention to security alerts when they are announced in the future and log into the WordPress dashboard more frequently to check for timely advisories from clever automated security plugins like Jetpack Protect.

Infos

  1. WordPress: https://wordpress.com
  2. PHP: https://www.php.net
  3. "How Attackers Slip Inside WordPress" by Chris Binnie, Linux Magazine, issue 275, October 2023, pp. 34-39
  4. WPScan: https://wpscan.com/wordpress-security-scanner
  5. Jetpack Protect: https://jetpack.com/protect
  6. Jetpack pricing: https://cloud.jetpack.com/pricing
  7. Ubuntu installation instructions: https://ubuntu.com/tutorials/install-and-configure-wordpress#1-overview
  8. Debian "bullseye" instructions: https://cloudinfrastructureservices.co.uk/install-wordpress-on-debian-10-11/
  9. Downloading WordPress: https://wordpress.org/latest.zip
  10. Installing with a Ruby gem: https://github.com/wpscanteam/wpscan/wiki/WPScan-User-Documentation
  11. Let's Encrypt: https://letsencrypt.org
  12. TimThumb: https://blog.sucuri.net/2019/08/timthumb-attacks-the-scale-of-legacy-malware-infections.html
  13. API Details: https://wpscan.com/api
  14. CVE Numbering Authority: https://www.cve.org/ProgramOrganization/CNAs
  15. Swagger: https://wpscan.com/docs/api/v3/
  16. "A Complete Guide on xmlrpc.php in WordPress" by Rachel McCollin, June 30, 2023: https://kinsta.com/blog/xmlrpc-php

The Author

Chris Binnie is a Cloud Native Security consultant and co-author of the book Cloud Native Security: https://www.amazon.com/Cloud-Native-Security-Chris-Binnie/dp/1119782236.