Nearly 1% of websites built with a content management system (like WordPress or Joomla) are unknowingly exposing their database password to anyone who knows where to look.

TL;DR – Summary of the Problem

Using a text editor to modify content management system (CMS) configuration files (like wp-config.php) could expose your database password to the world. Several popular text editors like Vim and Emacs automatically create backup copies of the files you edit, giving them names like wp-config.php~ and #wp-config.php#. If the text editor crashes or the SSH connection drops during editing, then the temporary backup files may not be cleaned up correctly. This means that the CMS config file (which contains the database password) could accidentally be made public to anyone who knows where to look.

Most servers, including the ubiquitous Apache, will happily serve the plaintext of .php~ and .php# files without passing them through the PHP preprocessor first, since they don’t have the .php file extension. Thus, your sensitive database credentials are just one GET request away from being accessed by a malicious party.

I wrote an automatic program, which I call CMSploit, to test for the prevalence of this issue across the wider web. I tested the top 200,000 websites (as ranked by Quantcast) and found that 0.11% of websites are vulnerable. If we eliminate non-CMS sites, and just look at CMS-powered websites, then we find that 0.77% of websites running a CMS have publicly-visible config files.

Here is a presentation I gave to the Stanford ACM about CMSploit, including screenshots of sites whose passwords I obtained using my CMSploit tool. Or, if you want all the gory details, then keep reading.

CMS Configuration Files

Most content management systems (CMSs) store sensitive settings like the database hostname, database name, database username, and database password in a file that sits in the root of the web directory.

Here is what a typical config file looks like:

<?php

define('DB_NAME', 'my_secret_database'); /** Name of WordPress database */
define('DB_USER', 'secret_agent_1'); /** MySQL database username */
define('DB_PASSWORD', 'you_will_never_guess_this'); /** MySQL database password */
define('DB_HOST', 'localhost'); /** MySQL hostname */

?>

Here is a list of the various configuration files used by the most popular CMSs:

wp-config.php        # WordPress
config.php           # phpBB, ExpressionEngine
configuration.php    # Joomla
LocalSettings.php    # MediaWiki
mt-config.cgi        # Movable Type
settings.php         # Drupal

Despite the fact that these configuration files exist in a publicly accessible folder, the file contents are unviewable by a normal web user. Accessing the file directly does not work because the PHP interpreter handles all requests to .php files and wisely returns a blank page instead of the actual file contents. (Try accessing http://www.example.com/wp-config.php on your favorite WordPress blog to see what I mean. You should get a blank page back.)

As you can see, all the sensitive database information is located within <?php ?> tags. So, even if a malicious user were to access your config file directly, the PHP preprocessor would just run the PHP code, which defines some PHP global variables and then returns a blank page. Thus, no harm done, right?

Text Editors Make Temporary Files

Popular command line text editors like Vim, Emacs, Gedit, and Nano create several temporary backup files during the course of file editing. When you open a file for editing, a backup of the original file is saved. Depending on your text editor, in-progress file changes might also be saved to a swap file, so you can restore your unsaved changes in the event of a program crash, power outage, or connectivity issue.

If all goes well, when you’re done editing the file, the text editor deletes the temporary files so your filesystem doesn’t accumulate dozens of old temporary files. However, if your text editor crashes or you lose your connection, then the temporary files will still be on your filesystem.

Here are the temporary filenames used by the most popular text editors (assuming a file named wp-config.php):

wp-config.php~        # Vim, Gedit
#wp-config.php#       # Emacs
wp-config.php.save    # Nano
wp-config.php.swp     # Vim (swap file)
wp-config.php.swo     # Vim (swap file)

Putting Two and Two Together

If a CMS user edits a config file on their live site (as opposed to editing it offline and uploading it over FTP), then there may be temporary files which contain their database password floating around in publicly-accessible folders.

If someone requests one of these temp files, then most servers will return the plaintext, skipping the PHP parser completelyyikes! By default, Apache assumes that only files which have a .php file extension are PHP files. If the file extension is not .php, Apache happily serves up the plaintext of the file.

How prevalent is this problem?

After noticing this security issue on one of my websites, I became curious to find out how common it is across the wider web. So, I wrote a program to test the top websites and get a rough idea of the prevalence of this problem. I call it CMSploit. The program is pretty simple – it issues GET requests to a site to test for the presence of temporary backup files with common CMS config filenames.

Here were my results:

  • Tested the 216,391 most popular websites (according to Quantcast).
  • Found 230 config files visible in root of site.
  • Thus, 230 / 216391 = 0.11% of all websites are vulnerable.
  • Latest stats say that about 13.8% of the top 10,000 websites run CMSs. If we just focus on CMS-powered websites, then the percentage of vulnerable sites is much higher:
  • Thus, 230 / (216391 * 0.138) = 0.77% of websites running a CMS are vulnerable.

It’s shocking to think that 0.77% of websites (1 out of every 130) built with a CMS has its database password just sitting there in a public folder for all the world to see. Lots of these are popular, active websites. You would likely recognize many of them. Most of the sites were WordPress blogs, but there were a surprising number of e-commerce sites too, which is a little scary.

Responsible Disclosure

  1. I contacted several of the highest profile sites to notify them of this security issue on their site. Most of them fixed the problem within a few days. All who replied to me were extremely grateful for bringing the issue to their attention. One of the companies even offered me a free license to their software.

  2. I submitted a vulnerability report with US-CERT. Unfortunately, they replied with “This issue is not the type of vulnerability class we are inclined to coordinate or publish on.” I also plan to submit reports with Apache, PHP, WordPress, and Vim/Emacs.

  3. After running the script and collecting my research statistics (published above), I securely wiped all the config files from my hard disk. I did not attempt to login with any of the database credentials I discovered. Therefore, it was not possible to determine what percentage of the database credentials were valid or what percentage of database servers were open to remote connections.

Lessons Learned

  1. CMS users should never edit their config.php file (or other sensitive files) with a text editor that creates temporary backup files. The best policy is to avoid editing any sensitive files on a live website. Instead, copy the file locally, make your edits to it, and copy it back to the server.

  2. It’s trivially easy to write a script to search for vulnerable sites. Bad people have probably been doing it for several years. In fact, this issue has even been discussed in other forums before. You should check your sites for wp-config.php~ and related files. Make sure your sites are not vulnerable.

  3. Someone should fix this. It’s not completely clear where responsibility lies, though. Is it Apache’s fault? Or PHP? Or vim/emacs? Should WordPress and other CMSs do something about it? There are many ways to fix this problem. I don’t particularly care how it gets fixed, as long as the default configuration of Apache + PHP + vim/emacs + WordPress don’t have this problem, I’ll be satisfied. In the meantime, using this very common web stack we have a scenario where ~1% of sites expose their passwords. This is bad.

  4. You should configure MySQL to deny remote connections to your database and connect to localhost instead. If you absolutely need remote access, then explicitly whitelist certain IPs and deny the rest. This way, if someone gets your database credentials, they’ll be unable to actually log in.

  5. In the short term, you should proactively protect all your websites. If you run WordPress and Apache, you can block access to any file containing the string wp-config.php with a .htaccess rule like this:

<Files ~ "(^#.*#|~|\.sw[op])$">
Order allow,deny
Deny from all
</Files>

Modify the rule to suit your CMS and server environment.

Final Thoughts

Even though the discovery that 0.77% of CMS-powered websites have public database passwords is already shocking, I’m pretty confident that you could easily double or triple the number of vulnerable sites with a better, more thorough script, and lots more time.

The script I wrote only tests the root of each site for CMS config files. However, lots of sites run CMSs in subfolders and subdomains like /blog/, /wiki/, /forums/, blog.mydomain.com, etc. Testing these places would dramatically increase the number of vulnerable sites detected.

I will not publish the source code of this script, because of the potential for harm. However, if you are a security researcher and are interested in reviewing the source code, send me an email.

This DEFCON talk is relevant: Pillaging distributed version control system repos for fun and profit.

Discussion on reddit.

Update (Mar 8 2012)

There is now an Nmap script, inspired by CMSploit, that appears to do everything that my script does. (I’m not affiliated with Nmap or this particular script.)

Update (Aug 22 2012)

The code for CMSploit is now available on Github.

Thanks to John Hiesey for reading a draft of this.



You can discuss, upvote, or poke fun at this post over at Hacker News.

(If you liked this, you might like How To Set Up Your Linode For Maximum Awesomeness.)

Thanks for reading! RSS Feed Icon

Feross Aboukhadijeh

I'm Feross, an entrepreneur, programmer, open source author, and mad scientist.

I maintain 100+ packages on npm. All my code is freely accessible on GitHub and funded by my supporters. I now offer a support contract for companies and teams.

I build innovative projects like WebTorrent, a streaming torrent client for the web, WebTorrent Desktop, a slick torrent app for Mac/Windows/Linux, and StandardJS, a JavaScript style guide, linter, and automatic code fixer.

I also work on fun projects like BitMidi, a free MIDI file database, Play, a music video app, and Study Notes, a study tool with college essay examples.

If you enjoyed this post, you should follow me on Twitter.

Or, sign up to get an email whenever I write a post: