Sebastian Neef (@gehaxelt) is a IT security freelancer and a top contributor from the Detectify Crowdsource community. In this guest blog, he looks at ways WordPress plugins leak sensitive data in the wild:
WordPress is probably one of the most used Content Management Systems out there. The vast amount of available WordPress plugins certainly plays a huge role, as it allows your WordPress blog to become a full-fledged online shop (i.e link: woocommerce). But relying on 3rd-party plugins to customize your blog or shop comes with certain security risks. There are no restrictions on who can publish a plugin on wordpress.org, so the code quality and therefore security can vary a lot.
I have analyzed how the most popular WordPress plugins leak information with remediation tips so you can continue using WordPress in a more secure way.
What plugins are affected?
This research was part of my attempt to get some more valid submissions to the Detectify Crowdsource platform, so my focus was only on the top-ranking WordPress plugins. To qualify as a valid submission for Detectify Crowdsource, the vulnerable plugin needs to have at least 300,000 active installations and the issue needs to be exploitable remotely without any form of authentication. At least for the information disclosure the criteria was met for the following plugins:
- 5m+ WooCommerce
- 2m+ All in One SEO Pack
- 2m+ UpdraftPlus WordPress Backup Plugin
- 2m+ All-in-One WP Migration
- 1m+ W3 Total Cache
- 1m+ Mailchimp for WordPress
- 900k+ iThemes Security
- 900k+ WP-Optimize
- 800k+ One Click Demo Import *
- 700k+ Broken Link Checker
- 700k+ EWWW Image Optimizer
- 600k+ BackWPup
- 400k+ WP Google Maps
- 400k+ Easy WP SMTP
- 300k+ MainWP Child
- 300k+ Newsletter
* A module for this plugin was not implemented due to an increased request complexity.
Taking all installation counts from the above list together and assuming that one installation equals one website, we end up with about 19 million websites that are potentially affected by an information leak issue.
What information is leaked?
Let’s first have a look on what kind of information is leaked by those plugins. I think there are three categories of leaked data, which also seem to match with certain CWE (Common Weakness Enumeration Database) categories:
From the attacker’s perspective, gaining access to credentials is the jackpot. It might allow them to obtain usernames, passwords or API keys that could be used to escalate their privileges. A WordPress administrator account is allowed to edit themes or plugins, thus gaining remote code execution is trivial. Leaked API keys are no better, because they might allow the attackers to abuse them, gain unauthorized access or just create huge financial damage.
Here’s a list of things that fall into this category and that I’ve seen leaked:
- Passwords to protected posts
- Backup files or zips
- SMTP credentials
Personal Identifiable Information (PII)
The next level in the hierarchy is, in my opinion at least, personal identifiable information. Especially in 2020 with the new digital information processing laws and GDPR, it might become a company’s nightmare if customers’ PII become public due to hefty fines. For that reason, I was even more surprised to find several plugins to leak the following customers’ or users’ data:
- Email addresses
The third category comes down to the remainder of information about the system running WordPress or its configuration. Most of the following types might not have direct, critical security implications, but could still give the attacker useful information for more sophisticated exploitation chains. Most of the WordPress plugins were leaking the following information:
- Internal host names
- Database tables, SQL queries
- Security logs
- Full path disclosures
- File names
- Software versions (OS, PHP, MySQL, WordPress)
- PHP Configuration (safe_mode, memory limits, execution limits, etc)
How is information leaked?
So far we have discussed what plugins leak information and what kind of information is leaked, but we haven’t looked at how this information is potentially exposed to the attackers.
At the core, the issue lies within WordPress’ file permission scheme which mentions that the
wp-content/ folder should be writable, because some plugins might need write permissions there. Depending on how secure you or your WordPress administrator is, the whole
wp-content/ might have full
rwx permissions, and therefore most plugins choose to create directories and files there.
This is not a problem by itself, but becomes one as soon as some plugins begin to create log files with the above discussed information that the web administrator does not know about. Plugin developers are not guaranteed a writable “data” folder outside the document root, where they could securely store such log files containing sensitive information in a non-volatile way. PHP’s sys_get_temp_dir could be an option, because it is system agnostic (not everyone runs Linux), but it might not offer persistence. The latter is pretty important for log files. Therefore, most plugin developers opt for a folder that they can assume to be writable on most WordPress installations as this stackoverflow thread suggests:
The former works in most cases, because files uploaded through WordPress’ media library end up there, so it is writable to not break core functionality. The latter includes all subfolders, such as
wp-content/themes, if the administrator wants to easily install new plugins or edit themes.
If you are a security-minded person and you are running a WordPress instance, now is the time to ask yourself if you have reviewed the source code of all active plugins, or did you simply install a plugin, because someone needed it to change the website’s functionality? You should review your plugins, but first continue reading to know what you should look for.
Different types of log files
I have noticed two different patterns that developers use to create log files, and only one of them has basic security principals in mind. However, both approaches become ineffective security-wise once the administrator forgets to properly configure the web server. Therefore, we cannot just put all blame onto the WordPress plugin developers for leaks, but we need to reinforce basic security principles at any time.
Static file paths
Developers are not naturally security experts, and often they focus on building solutions that work. There is nothing easier than using WordPress’ wp_upload_dir() or WP_CONTENT_DIR to obtain the path a writable folder and appending a plugin specific suffix.
Here is a list of example paths:
/wp-content/all-in-one-seo-pack.log /wp-content/uploads/mc4wp-debug.log /wp-content/uploads/wp-google-maps/error_log.txt /wp-content/plugins/ewww-image-optimizer/debug.log /wp-content/plugins/all-in-one-wp-migration/storage/error.log /wp-content/plugins/all-in-one-wp-migration/storage/import.log /wp-content/plugins/all-in-one-wp-migration/storage/export.log ….
Let’s recall that the
wp-content/ folder lives in the DocumentRoot is accessible from the internet, thus all the files within it are usually accessible, too. This makes it trivial for an attacker to access those log files and their content by navigating to the well-known paths.
Random file names
A good portion of the plugins implemented their logging functionality with more security in mind. By adding a random portion to the file name, it cannot be requested directly without knowing the random part.
- an incremented 6-digit number (not really random)
- a randomly generated string
- a cryptographic hash (MD5 or SHA)
/wp-content/cache/log/000000/dbcache.log /wp-content/logs/newsletter/antibot-2018-09-87agc333.txt /wp-content/uploads/wc-logs/geoip-2019-03-17-57e9aab19e941762b0e731c2f65dc325.log ….
To a developer, this approach might look pretty robust and secure, but it disregards the fact administrators also play a role. Given that WordPress is an entry-level CMS, it might be set up and operated by novice administrators, who just followed a tutorial “to make things work”.
The file name randomization is instantly defeated if the administrator (accidentally) forgets to turn off “directory listing” on their web server. In such a case, an attacker just needs to browse to the respective folders to get a list of the random file names.
While working on this topic, I have found several examples of such misconfigured web servers on the internet. It is not just a hypothetical scenario.
If you have made it this far, you might be asking yourself how I discovered all those log file disclosures. I will happily answer this question in this section, so that you can review your own plugins. There were basically three approaches to this topic:
- Find existing files
- Review the plugins’ source code
- Use a search engine
While the first method did not show anything interesting in particular, the second one was the most fruitful, but also the most time-intensive. There were over 115 plugins to review, so naturally I could not invest the time to do a thorough in-depth source code review, but rather took some shortcuts and educated guesses. Last but not least, I used search engines to discover files that I might not have seen with the two methods before.
Let’s have a look at them in detail.
Find-ing existing files
find is a small linux command line tool to quickly find files or directories in a file system hierarchy. After installing some plugins, I ran it on my test WordPress instances like this:
$> cd path-to-wordpress/wp-content/ $> find . -type f -name ‘*log*’ -ls $> find . -type f -name ‘*txt*’ -ls 987828 4 -rw-r--r-- 1 gehaxelt gehaxelt 229 Feb 9 2018 ./sc_cache.txt
This showed me a few files containing
txt, thus matching either of the two regular expressions. It is by far the most efficient method to check if such files exist on your web server. If you are administering any WordPress instances, take a note and check your web servers after you have finished reading.
Source Code Review
Most of the work done was source code review using a few lines of bash, grep and less.
As the first step, I downloaded all plugins with more than 300k installation from the wordpress.org website and extracted them into separate folders. A few lines of python helped with that task.
The next step was to look for and identify paths where log entries are written to. PHP offers a few methods such as file_put_contents or fopen to create files. By having access to the source code, using the command line text searching tool “grep” was a suitable choice. Keywords such as “file_put_contents”, “file_get_contents”, “fopen”, “log”, gave a good idea where to look for.
From there, it became going bottom-up through the code and deducing where the file would be written and if it is randomized or not.
(Ab-)using search engines and their specific search keywords for security purposes is often referred to as “dorking”. No sophisticated hacking tools are required for such an attack, just a web browser, a search engine such as google and a query like
inurl:"/wp-content/uploads/wp-google-maps/error_log.txt" would be enough to find a whole lot of affected websites.
I took the route of searching for a plugin’s directory name while adding keywords like
txt etc. It gave mediocre results, but that was better than nothing and also helped to verify the findings from the previous step.
Overall the results using this method are limited to web sites that usually have
DirectoryListing enabled and make their contents indexable by certain search engines.
How to make it safer
We all know that breaking things is much easier than fixing it. I tried to come up with ideas for how to prevent such information leaks to make the ecosystem more secure.
Rule #1: Use randomized file names
Static file paths make it insignificant for an attacker to check the existence of a file and download it. Using randomized file names might take a bit more time for a developer to implement, but boosts the security immensely. Especially since the majority of web servers should have directory listing disabled, so that an attacker cannot guess the correct file name.
Rule #2: Prevent directory listing
Even the scenario of a directory-listing enabled web server can be mitigated by the plugin developer: For every folder that is created and where plugin-specific log files are written, an empty
index.php file should be created. On literally every web server the
index.php file is configured as the
DirectoryIndex, meaning instead of showing all contents of a directory, this file will be executed. As an empty file has no content, the attacker won’t see a list of file names, but an empty page.
Rule #3: Workaround
If Rule #1 and Rule #2 are not followed by a plugin, then one could try to move the created folder outside the “DocumentRoot” (i.e. using a symlink). Alternatively, explicit rules must be created to prevent access to static or randomized log files. Depending on the used web server, simple “.htaccess” files could be used.
Rule #4: WordPress hardening
The WordPress developers have a lengthy article on WordPress security and hardening. At the time of writing it contained a neat statement which fits this topic perfectly:
If a plugin wants write access to your WordPress files and directories, please read the code to make sure it is legit or check with someone you trust.
It is always a good idea to go over this article and check if oneself has considered and implemented the given hardening tips.
To round this section up, I firmly believe that most plugins should be able to implement and follow Rule #1 and Rule #2. The other two rules, Rule #3 and #4, lean more towards the side of the system administrators, but we cannot take them out of the equation. If a WordPress instance is provided for you, don’t forget to ask the responsible administrator to go over the issues mentioned in this article.
Log transparency with Detectify
All of the initially listed WordPress plugins and their potentially leaked log files have been implemented into Detectify’s automated security and asset monitoring since September – November 2019. The security modules will give you insight into which log files on your web server are discoverable by an attacker. That means, the modules can:
- easily identify the “static file path” log files
- detect the “randomized file path” log files, too, as long as the randomization can be circumvented with the method discussed earlier
My research doesn’t stop here. I am continuously pursuing this topic in order to bring more log file disclosures to users to secure more websites through the Detectify and the Crowdsource platform.
IT Security Freelancer and Detectify Crowdsource hacker
Sebastian Neef (@gehaxelt) is a security researcher at heart and has been interested in IT security since the age of 15. He became an IT security freelancer and consultant during his A-Levels back in 2012 when bug bounty and responsible disclosure programs were just starting out. Sebastian enjoys sharing his knowledge on conferences or his blog 0day.work, breaking things, playing CTFs with ENOFLAG and helping companies to improve their security.
How can Detectify help?
Detectify works with highly skilled ethical hackers like Gehaxelt to crowdsource the most up-to-date security research. Check for the latest WordPress vulnerabilities and 1500+ other known vulnerabilities with a start of a Detectify scan. Begin your 14-day free trial today.