Latest TweetsNew version of Disable Gutenberg includes options to disable for specific theme templates and/or post/page IDs. wordpress.org/plugins/disable-…
Perishable Press

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:

[ Screenshot: WP Default Database Error Page ]
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:

[ Screenshot: WP 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:

[ Screenshot: WP Installation Success ]
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 install.php file:

# 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:

  1. Rename the original install.php to something like, “install_DISABLED.php” or whatever.
  2. 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("your@email.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:

[ Screenshot: WP Database Error ]
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:

WP - install.php replacement file – Version 1.0 (655 B zip)

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.

Update

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!

Jeff Starr
About the Author Jeff Starr = Web Developer. Book Author. Secretly Important.
Archives
86 responses
  1. Jeff Starr

    If deleting a file is too much work for you, you could always add a few lines of code to your HTAccess file. That shouldn’t be too difficult, and there really is no maintenance involved. A simple three-second operation performed one time would protect your site and prevent an attacker from exploiting a known security vulnerability.

    Honestly, think about what you’re advocating here: that users should NOT protect their sites against a potential attack. Come on, give it a rest. Five seconds of time to eliminate a possible catastrophe is a no-brainer. You have no idea what the actual odds are, but even a one in a trillion-billion-billion chance is not worth the risk. I’m sorry, but ignoring security vulnerabilities based on odds is just bad policy.

  2. Callum, I know you’re trying to play Devil’s Advocate here, but there’s really no advantage to NOT take action.

    Plus, who’s to say that a hacker cannot reproduce the exact circumstances here in order to exploit a site?

  3. @Jeff, Terry, & Matthew: I’m looking at this vulnerability from the perspective of a fix within WP core. I think if it’s a problem that deserves a fix, that fix should be in WP core. From that perspective, I’m not sure it’s a “vulnerability” that needs to be fixed.

    I do think adding the option to disable the installer in wp-config.php would be worthwhile given the limited cost of implementation.

    @Matthew: I don’t think an attacker could cause MySQL to “lose” the WP tables in order to be able to install a new blog on a server. If they could affect MySQL in that way, I think there would be bigger issues than re-installing WordPress.

    I’m following up here because I feel like the “vulnerability” is being exaggerated. I don’t think it represents a significant risk. Specifically, I think this paragraph in the original posts overstates the risk:

    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:

    In my opinion, this paragraph misrepresents the facts. The paragraph suggests that a mere database failure will open your blog up to the world. That’s simply not true. It is a very specific and very unlikely MySQL failure that causes this issue.

    When I first read this article I felt like I needed to take immediate action to secure my blogs. After investigation, I haven’t taken any action because in my opinion there is virtually no risk of this issue arising.

    This scenario arises where the option siteurl is not found in the wp_options table. If that value is accidentally deleted, then the site could be compromised. I would support improving the algorithm in is_blog_installed() to better check if WordPress has already been installed. However, I don’t think this represents a security risk worthy of immediate action. I think it falls under the “nice to have, enhancement” category.

  4. Jeff Starr

    @Callum:

    I’m looking at this vulnerability from the perspective of a fix within WP core.

    That explains our differing views on this issue. I am looking at this vulnerability from the user’s perspective. The average user could not care less what’s in the core or how much development costs are, blah blah blah. What is important to them is that their hard work is safe and secure online. When a security issue is discovered, they have a right to know how to fix it. Almost losing my site was enough to scare the pajamas off me, so I figured I would do my readers a favor by sharing the issue and providing a few temporary solutions. From what I can tell, 99% of my readers are grateful for the heads up.

    You, on the other hand, insist on downplaying the whole event as if it’s just no big deal — a “nice to have, enhancement” sort of thing. If that is your approach to this particular security issue, then knock yourself out. As someone who is serious about security, I do my best to eliminate every risk, regardless of its perceived improbability.

    I appreciate your remarkable efforts in trying to justify your unwillingness to apply a simple fix to a known security vulnerability, but I simply cannot advocate that users just sit idly by and do nothing to protect themselves against a potential attack, especially when the fix requires all of five seconds to implement.

    Despite what you may think, security is not a “nice to have, enhancement,” but rather it is absolutely imperative to running a consistent, reliable, and safe website. At least, that’s how I am looking at it.

  5. I don’t want to start a virtual catfight *meow*, but I wish to get things straight.

    I understand your view, Callum. According to your latest reply, you mentioned that the fix should be carried out by the developers of WP and the users of self-hosted WP should not be responsible of the vulnerability. While there is definitely some truth within your statement, there is nothing wrong if one user (like Jeff) wishes to improve upon the current WP installation. And again, we’re back to the same argument – just like you’re the master of your own fate, you’re also the one who’s responsible for the security of your WP blog. If you think that it’s susceptible to attacks, then why not try to fix the problem instead of sitting and wait for the WP team to fix it? Plus, the fix is optional. It’s not a directive (sorry for the typo error previously) and is not mandatory.

    A risk is definitely involved for not fixing it, but not fixing it doesn’t mean it’s the end of the world. In Jeff’s point of view, he wants to improve the security of his WP blog and me too, see no problem with that (and your argument too).

    A analogy will be discovering a small problem with your window lock that a thief can open from the outside. Of course, the risk of it being picked open by a thief is low (not as if they know which window has a problematic lock) and so you can sit aside and do nothing about it. For Jeff, he spots a problem with the lock and replaces it with a new one. Nobody knows about it either, but it makes his house a tad bit safer :)

    I hope this gets the point across. While you have the right to iterate (and reiterate) your point, don’t forget that this is Jeff’s blog, and he has all the right to write anything as long as it does not infringe the right of others (that means, he’s entitled to it because that’s how rights work). The rule is simple: take it, or leave it.

    Jeff has also cited anecdotal evidence that he was scared by attacks on his site, and if you do read his archives, he was the victim of multiple hacking attempts. Just like the homeowner whose house was broken into a few times previously, of course he will make a conscious, concerted effort to make his house (or WP installation) safer by switching the window lock (deleting, modifying install.php).

    Right? ;) Let’s not pick the old scab and move on. There’s no point arguing back and forth for a simple solution like this.

  6. mccormicky May 13, 2009 @ 12:22 am

    Is the question really about protecting/deleting/renaming install.php or is it about what is causing install.php to show up to the whole world looking at your website in the first place??

    This error, which is repeated many many times in the error log, User XXX has exceeded the ‘max_questions’ resource(etc),… causes the flip to install.
    The database constantly burns out and wp goes to install. I check the error logs and they are full of nasties (mainly to do with wp-ecommerce currency list table which is a beast).The next baddie is about utf 8.I read on another website that commenting out define(‘DB_CHARSET’, ‘utf 8’); was the way to go. But now the posts all have little black diamonds with question marks in them.Pretty. So define(‘DB_CHARSET’, ‘utf 8’); actually does something important. I uncomment it.

    I found that by creating a new db user and adding it to the config.php reinstates the normal site. Phew. Only not really because who can sit by their monitor all day making sure the site doesn’t revert to install mode?

    I renamed install.php and used your file -got rid of the potentiality of some horrible person wiping out the site. Coincidentally or not suddenly all the posts/pages/users/products/categories were gone from the dashboard. Haxorz! I yelled and scrambled for the backups. I was too late? Everything was gone? Did all my base belong to them? Was I going to have to redo everything from a backup? At 3 am with not enough sleep and very little to eat? I was freaked. Nope all of a sudden all the posts,etc came back.Then they went away again. Then they came back. I had 2 small heart attacks.

    The error log is full again. I have 300 emails from your replacement install file telling me the database is down.

    What to do?

  7. mccormicky May 13, 2009 @ 1:14 am

    This might have already been mentioned but I will type it again:

    “By simply entering an email address and specifying a blog title, an attacker would administratively re-install WordPress and receive the following message:”

    Maybe. But isn’t what actually happens is the potential take over-er gets a message that wp is already installed?

    Or are you saying there are other more terrifying ways this file could give someone access to your database. If WP is already installed are the Bad ones given an admin account?

    When this 1st happened to me I did go on with trying to re install because I did not know any better. I didn’t get a password sent to me and no new account was made. It does seem as though the real point is nobody but the 1st person to install WP should EVER see this install file. So if your server is crap delete install.php. Perhaps people should make an “out of order page” and name that install.php.
    Because in Firefox I do not see anything on your replacement file but a message that “the server is redirecting in a way that will never complete.Try again”

  8. Jeff Starr

    @mccormicky: Yikes! That sounds like some serious drama (I also experienced a small heart attack when this happened to my site).. not too sure if I know where to begin on this one. Are you still experiencing the same errors? Have you resolved the database issue(s)? I just checked your site and everything seems to be loading correctly. I couldn’t even find your install.php file. Hmmm..

  9. Jeff Starr

    @Terry: Well said. Thanks for keeping things in perspective! :)

  10. Appreciate the article and thanks for the heads up. Peace.

  11. @Terry: I agree, it’s Jeff’s blog and he may write as he likes.

    My aim is to play down the risk. I think it was dramatically overstated in Jeff’s post. I think if an average user stumbles across this post they might misleadingly think that their install.php file represents a serious security risk. In my opinion, it does not. I think there are many other things that deserve their security related attention first (security checking plugins for example).

    I say, don’t panic, WordPress is just as secure as last week, this is not an exploit that attackers can purposefully target.

    Jeff, I do think it’s worth bringing this up. I’d encourage you to submit a ticket to trac with a recommended fix. I think it would be great if WordPress became even a little more secure as a result of your work.

    I’ll leave it at that. :-)

  12. mccormicky May 13, 2009 @ 12:37 pm

    Hi Jeff,
    No, this is happening to a client site-I should have said that.

    I could be wrong, but it might be that on a healthy set up you can’t load install.php directly. My wp-admin is not in the root so maybe that’s why.Though of course you’d have seen that in my source.

    This happened the 1st time a week ago and has happened very regularly ever since. It’s a pretty well visited website and the chances that someone with bad intentions has seen install.php are very high.

    I found your post and followed your directions for the security risk. Right after that the next time the error log filled up- instead of serving up install.php, wordpress was acting like the database was cleaned out.
    At one point it looked like the situation had resolved itself.For an entire hour the error logs were empty even though I was using plugins, updating posts and the product list,etc.

    I experimented with using htaccess to redirect to a different file with a custom error message. But you couldn’t load that page either if mysql was functioning. The only good news out of this mess is that now I know that when it looks like the site is dying all I have to do is switch the db user and the site comes back up.

    But it is obviously not a fix because I cannot monitor this website 24 hours a day.

[ Comments are closed for this post ]