Important Security Fix for WordPress
The other day, my server crashed and Perishable Press was unable to connect to the MySQL database. Normally, when WordPress encounters a database error, it delivers a specific error message similar to the following:
Default database-error message
This customizable database error message explains the situation to visitors and circumvents any malicious activity involving exposed scripts, PHP errors, and other issues related to unexpected database issues.
That sounds nice, but there is a problem
The problem that I painfully discovered when my server crashed is that WordPress does not always display the default page for all database-related issues. Apparently, if the database is missing entirely, WordPress assumes that it has not yet been installed and loads the Installation Page:
WordPress Installation Page
Yikes! This is exactly what happened when my server crashed, MySQL was unavailable, and the WordPress Installation Page was displayed to over 100 visitors while I scrambled to resolve the issue.
During the event, there were several attempts to assume control of my site through the Installation Page. Fortunately, I was working on the site (via FTP, cPanel, phpMyAdmin, and so on) during the attacks, and was able to terminate an inevitable hostile takeover.
“john@greatCampingTrips.com”, I’m staring at you here.
It happened to me, and it could happen to you
To me, this scenario represents an enormous security risk for all currently available versions of WordPress (up to 2.8 at the time of this writing). If WordPress serves up the Installation Page the next time your database goes down, anyone could easily gain full control of your entire server. By simply entering an email address and specifying a blog title, an attacker would administratively re-install WordPress and receive the following message:
WordPress installation-success message
Ouch! This is no good. I was fortunate enough to have been there during the incident, however it could have happened while I was away from the computer. What if I had been asleep, at work, or on vacation? Trust me, it doesn’t take long for a savvy attacker to annihilate an entire server, and the damage may be irreversible.
A temporary solution, until WordPress does it better
After restoring full functionality to my site, deleting multiple “Hello world!” posts and “About” pages, and removing the newly added Administrator, it was time to prevent this situation from happening again. The easiest way to do this involves deleting, blocking, or modifying the
wp-admin/install.php file, which contains the script that generates the Installation Page.
Until WordPress incorporates a better solution, I recommend one of the following three fixes:
Fix #1: Just nuke it
Simply delete the
wp-admin/install.php file entirely. It is not needed after installation.
Fix #2: HTAccess to the rescue
Place the following slice of HTAccess into your site’s web-accessible root directory to prevent access to your
# PROTECT install.php <Files install.php> Order Allow,Deny Deny from all Satisfy all </Files>
Fix #3: Replace it with something safe and useful
Replace the insecure version of the file with something secure and informative by following these quick steps:
- Rename the original
install.phpto something like, “install_DISABLED.php” or whatever.
- Create a new file named “
install.php” and add the following code:
<?php // install.php replacement page: https://perishablepress.com/press/2009/05/05/important-security-fix-for-wordpress/ ?> <?php header("HTTP/1.1 503 Service Temporarily Unavailable"); ?> <?php header("Status 503 Service Temporarily Unavailable"); ?> <?php header("Retry-After 3600"); // 60 minutes ?> <?php mail("email@example.com", "Database Error", "There is a problem with teh database!"); ?> <!DOCTYPE HTML PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> <html xml:lang="en" xmlns="http://www.w3.org/1999/xhtml" lang="en"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>Error Establishing Database Connection</title> </head> <body> <img src="images/wordpress-logo.png" /> <h1>Error Establishing Database Connection</h1> <p>We are currently experiencing database issues. Please check back shortly. Thank you.</p> </body> </html>
Once uploaded to your server, this new
install.php file will prevent any malicious behavior by serving up a static web page. Now, instead of showing the Installation Page when your database is unavailable, WordPress will display the following message:
WordPress installation replacement page
In addition to displaying this information to your visitors, the Installation Replacement Page also performs the following actions:
- Communicates a
503 (Service Temporarily Unavailable)status code to clients and search engines
- Instructs clients and search engines to return after 60 minutes (configurable)
- Sends an email informing you of the situation so that you may take action
To use the Replacement Page, don’t forget to specify an email address in the fourth line. You may also change other variables, such as the time duration, email subject, or email message. If you need any help with these variables, please leave a comment. I have also made the Installation Replacement Page available for easy download:
Live long and prosper
Until the developers at WordPress implement a cleaner, more permanent solution for this issue, I highly recommend applying one of the solutions provided in this article. There is no reason to keep the original
install.php file after you have installed WordPress, so feel free to delete, modify, or block it. Trust me, dealing with the trauma of watching your site get hijacked by some unscrupulous cracker whore just ain’t worth the pain.
MustLive provides more insight into the install.php vulnerability via this comment and this article: Attack on Abuse of Functionality in WordPress. Many thanks to MustLive for his work on this security issue!
Htaccess protect all of wp-admin and you’re all set. This is exactly the reason that software like vBulletin requires that you delete the install file before you use it.
This is a long known and ignored issue…
Well hopefully this will help alert a few more users to the severity of the issue.
Be careful protecting the entire WordPress
/wp-admin/directory, however, there are files that are designed to be accessed via HTTP in order to function as intended. There are also scripts and plugins that require access to various files in the
/wp-admin/directory. Without proper permissions/access, many such scripts simply stop working.
So yes, HTAccess is a great way to protect your files if used mindfully, according to the needs of your particular configuration.
Yikes! That’s a really bad hole.
So you don’t recommend password protection of the entire Admin directory? Do you know of a commonly used plugin that accesses it?
Lazy me thinks it’s easiest to just delete the install file…
I just decided to nuke the file altogether.
There are a lot of articles out there on how to protect your site and I don’t think I’ve ever seen this one, so thanks for pointing this out.
Yes it is, and I could have lost my entire site because of it.
If you know for certain that no plugins are accessing the files in your admin directory, then you may want to simply block the entire thing, but I really don’t recommend it. I have seen way too many “silent” errors involving all sorts of files and scripts while working with blocking rules to feel comfortable with it.
If you decide to block the admin folder, make sure that you aren’t inadvertently preventing server access to the admin files.
My pleasure, Matthew. I likewise wasn’t aware that something like this could happen. Hopefully it will help others as well.
Something like this happened to me while creating a new site, however the place was new and luckily had no visitors.
Until now I hadn’t found a reasonable solution but I really like your custom install.php
Thanks for the various solutions. ;)
Thank you, thank you, thank you, Jeff, for sharing this experience. A killer tip.
Uh, whole wp-admin htaccess – I have 15 sites running in that config with no problem. Turn off XML-RPC, and lock down wp-admin. It’s the only way to be sure…
@Mark Cahill: If you allow people to register at your site and block the entire admin directory, they will not be able to login to the admin area. If it’s just you and nobody else on those fifteen sites, then cool, block the whole thing, but I respectfully disagree that your strategy is anywhere near a “one size fits all” solution.
It only serves that up if your database is UP but there is no WordPress install on the database and table specified in
This could happen if you deleted your blog tables, deleted your
optionstable, or if MySQL thought that you did. If your MySQL server is unavailable, you will NOT get this screen.
As you had to delete the new admin account, I guess I’m missing something… but the first thing that came to mind was, if MySQL’s unavailable, how does WP get re-installed? Did your crash involve MySQL going down, then coming back minus your WP database?