The WPSetup Attack: New Campaign Targets Fresh WordPress Installs
At Wordfence, we track millions of attacks from a wide variety of sources every day. From this data we create a list of the worst-of-the-worst attackers and add those to our IP blacklist to protect our Premium customers. We also carefully monitor the activity that those known bad IP addresses engage in.
In May and June, we saw our worst-of-the-worst IPs start using a new kind of attack targeting fresh WordPress installations. We also had our first site cleaning customer that was hit by this attack.
Attackers scan for the following URL:
/wp-admin/setup-config.php
This is the setup URL that new installations of WordPress use. If the attacker finds that URL and it contains a setup page, it indicates that someone has recently installed WordPress on their server but has not yet configured it. At this point, it is very easy for an attacker to take over not just the new WordPress website, but the entire hosting account and all other websites on that hosting account.
The graph below shows the campaign we tracked and the number of scans per day for /wp-admin/setup-config.php that we saw from several known bad IPs:
How the WPSetup Attack Works
There are several ways you can install WordPress. You can simply unzip the ZIP archive into a directory on your hosting account, or many hosting providers provide a one-click install that does the same thing.
At this stage, even though you have the base WordPress files installed, there is no configuration file yet, so it needs to be created. You used to have to do this manually, but new versions of WordPress guide you through creating this file using a web interface.
If you unzip WordPress or use a one-click installer and don’t immediately complete the installation steps, an attacker who is scanning for fresh installs on your server can use your fresh install to take control of your website.
Let’s walk through the steps to understand how the attacker takes control of your site once they have located your fresh WordPress installation. The first step is to select your language:
Then you see an introductory message:
And finally, you let WordPress know your database name, username, password and which server it lives on.
If an attacker finds your fresh install, they can easily click through the first two steps and then enter their own database server information in this final step. Their database can be on their own server, and it doesn’t have to contain any data – it can simply be an empty database. They just need to get a working WordPress installation running on your site that they have admin access to.
Once this step is complete, WordPress confirms that it can communicate with the database – in this case, the attacker’s database:
Once the attacker clicks “Run the install,” they are prompted to enter information to create the first admin-level account.
They enter their own account information, click the Install button and receive a confirmation that WordPress has been installed and the admin account has been created.
The attacker then retypes the admin credentials they created in the setup process…
… and is signed into a fresh WordPress install on your server using their own database.
How the WPSetup Attack Gets Full Control of Your Hosting Account
Once an attacker has admin access to a WordPress website running on your hosting account, they can execute any PHP code they want in your hosting account. There are several ways they can do this.
Executing PHP Using the Theme or Plugin Editor
WordPress gives you the ability to edit the code of themes and plugins within the administrative interface. To execute their own code, an attacker simply launches the theme or plugin editor and inserts their own PHP code. The next time a page is refreshed, their code will execute.
Executing PHP Using a Custom Plugin
Once an attacker has admin access to a WordPress site, they can upload any plugin with any PHP code, including their own custom plugin. To execute their code, they spend a few minutes creating a basic WordPress plugin and then upload it to the site and activate it.
What an Attacker Does Once They Can Execute PHP Code
Once an attacker can execute code on your site, they can perform a variety of malicious actions. One of the most common actions they will take is to install a malicious shell in a directory in your hosting account. At that point they can access all files and websites on that account. They can also access any databases that any WordPress installation has access to, and may be able to access other application data.
How to Protect Yourself Against the WPSetup Attack
This attack is gaining popularity. To avoid falling victim, we have provided two procedures you can use below:
Procedure 1: The Safe Way to Install WordPress
Before you install a fresh WordPress installation, create a .htaccess file in the base of your web directory containing the following:
order deny,allow deny from all allow from <your ip>
Replace the ‘<your ip>’ with your own IP address. You can find this out by visiting a site like whatsmyip.org.
This rule ensures that only you can access your website while you are installing WordPress. This will prevent anyone else from racing in, completing your installation and taking control of your hosting account by uploading malicious code.
Once complete, you can remove the .htaccess rule and allow the rest of the world to access your website.
Procedure 2: The Risky Way to Install WordPress
This procedure is risky because, if an attacker is fast enough, they can still take control of your site. We don’t recommend this, but include it for completeness.
Instead of creating the .htaccess rule above, you can use the standard WordPress installation method. To reduce the risk of being attacked, you need to shorten the time between installing the WordPress files and completing installation as much as possible.
- Install your WordPress files by unzipping them or doing a one-click install.
- Access your site immediately and complete the installation steps as quickly (though accurately) as you can.
- Once your site is up and running, an attacker can no longer run the installation and your site is no longer vulnerable.
Recommendations for Server Administrators and Hosting Providers
If you operate a server or a network of servers that provides WordPress hosting to customers, we recommend the following to mitigate this attack:
Scan your hosting accounts for WordPress installations that do not have a wp-config.php. These may be fresh installations that have not yet completed setup. If navigating to the base URL of the site redirects you to /wp-admin/setup-config.php then you have confirmation that setup is incomplete. We suggest you alert your customer they should either complete setup or remove the files.
If you have an IDS (intrusion detection system), you should consider monitoring traffic from your web servers to the open Internet for any MySQL traffic. This may indicate an attacker has configured a WordPress site on your network using their own database on the Internet.
If you have any other mechanisms in place to monitor or prevent connections from your web servers to arbitrary databases on the open Internet, we recommend you use those to mitigate this attack.
Final Advice and Your Thoughts
I recommend that you take the additional step of auditing your own hosting account to make sure you have not accidentally left any unconfigured WordPress installations lying around. If you don’t want to do this yourself, consider our WordPress Site Audit service, which provides a comprehensive site security audit and will include a check for incomplete installations.
As always, I welcome your feedback in the comments below. If you have additional ideas to help mitigate this attack or to help WordPress improve the setup process to avoid this attack, I’d love to hear them.
~Mark Maunder – Wordfence Founder/CEO
PS: Please share this with the WordPress community to create awareness of the risks of unconfigured WordPress installations.
Comments
10:19 am
Great info, as usual. Thanks.
I wonder...Is there anything the folks at WordPress can do to eliminate this problem?
10:20 am
Hi,
What about transferring a wordpress site from one host to a new host?
Can the setup file be renamed after setup has taken place?
Thanks,
Peter
10:50 am
I'm not sure I understand the question. When you first install WordPress there is a sample setup file called wp-config-sample.php. Once you complete the wizard a file called wp-config.php is created and your site can no longer be attacked using the above method.
If you transfer your site to another host, you need to move over the wp-config.php file and may need to edit it to modify your database credentials. As long as that file exists and is correct, you should be immune from the above attack. The attack above only applies to fresh installs.
Mark.
10:29 am
Love the htaccess trick! Thanks for keeping us informed, and safe.
10:30 am
This window of opportunity has always worried me in Wordpress, though it's usually pretty short. My normal practice has been to put a basic auth password on a putative site (I'm generally doing a "hello world" web page as a test step before installing Wordpress anyway), as my IP often changes so restricting ip isn't practical. In any case, this usually leads to a test or staging site in the first instance, so the basic auth is useful to keep things private until we're ready to publish. And over https its secure enough for this purpose. Even if not, an attacker is unlikely also to be using MITM attack at the same time, unless they were targeting specifically.
11:45 am
This sounds like a good idea, how do you add a basic auth password to a plain index.html page?
12:01 pm
I actually like the basic auth idea more than the IP restriction I suggested in the post. The IP restriction some may argue, is more secure. Basic auth is, well, basic. But it will stop this attack in it's tracks and as long as you complete install in a few minutes/hours it won't give the attacker much time to try and brute force your basic auth. Purists may disagree with the approach, but from a practical standpoint, I like it. Just make darn sure you use a very strong and unique password for basic auth because AFAIK apache (and other servers) don't provide brute force protection of any kind by default.
10:31 am
Simple but clever! I always force SSL beforehand via .htaccess, but I never thought of locking down the IP during install. I can't think of time when I didn't complete the full install process all at one time, but I suppose there's still a small window in there. Can't hurt! Thanks for the useful post as always Mark.
10:32 am
Very clear explanation. Thanks for giving some real workarounds to avoid this. You guys are doing a great job - keep it up!
10:46 am
This happened to my websites a few years ago when an attacker used a fresh wp install that I was too lazy to complete. This is the reason I have two hosting accounts now so some of my websites are on one and some on another so if anything happens, it doesn't affect all my websites. And unless I'm ready to complete an installation right then and there, I don't install wp.
10:46 am
It seems that all the installs done by Softalicious leave the config file behind!
11:00 am
@Mark can you confirm this please?
12:18 pm
I use Softalicious for all my WP installs. I just checked several older sites and there is still a wp-config-sample.php. However I believe Softalicious forces you all the way through the install process in one shot. So even though there is the sample file, the config is setup at install time (rendering the sample useless?). Hoping I understand that correctly!
10:47 am
excellent! as always.
love you guys. it's great to know people with knowledge are using it to help others.
i'm in your debt.
10:56 am
Honestly, I'll never understand why anyone would do this, it's evil in view. I appreciate your work, WordFence!
10:59 am
Just an idea; Another way to minimize the attack window could be using WP-CLI (provided you have shell access and enough permissions to the server) and run the download and install commands in a shell script or as a combined command (download && install) so the install starts immediately after download.
11:00 am
I checked a few of the WordPress sites I manage and got the following message when trying to access the /wp-admin/setup-config.php file:
The file 'wp-config.php' already exists. If you need to reset any of the configuration items in this file, please delete it first. You may try installing now.
Where "installing now." is a link to /wp-admin/install.php.
Wouldn't a potential attacker still be able to re-install WordPress with his/her own database?
Wouldn't it be smart to rename, or even better, remove both the install.php and setup-config.php file or have that be a procedure of the the WordPress setup script, since most people don't bother to look at these files? (didn't think about that while installing myself either.)
11:30 am
No, you can't do an install over a WP installation. You get this message
Already Installed
You appear to have already installed WordPress. To reinstall please clear your old database tables first.
11:38 am
I'm curious about the answers to these questions as well.
11:10 am
I'm new at this, but after you install WP and WF, it seems a good idea to go into WF Options under "Immediately block IPs that access these URLs" and add /wp-admin/setup-config.php to the list. Even if the setup is complete and the hole is closed, someone scanning for that file is up to no good.
11:15 am
Following up from Glenn Lyver's comment, should we delete the setup-config.php file if our fully completed installations still contain this file? If I navigate on a web browser to wp-admin/setup-config.php it says "The file 'wp-config.php' already exists"... etc etc. Since the site is fully set up and wp-config.php exists, does this mean I am safe, or should I delete the setup-config.php file anyway? Are there any disadvantages in deleting the setup-config.php file?
11:57 am
I don't think there is any reason to delete that file after installation is complete.
11:31 am
@Jermain --- The Install.php file will give you this result if the database is already populated:
"Already Installed / You appear to have already installed WordPress. To reinstall please clear your old database tables first."
It won't allow for a reinstall, or second install. In the OP, the difference is that the offender can loop back through the configuration steps to manipulate the database that has already been installed.
Leaving the install.php file doesn't seem to be a concern.
11:41 am
The definitive way to avoid this issue is never to 'install' Wordpress on a live server. Rather you should develop and stage locally and push the complete code base to the server using git/pipelines/source tree/ansible/ or what ever your preferred toolset comprises.
12:21 pm
Shouldn't it be better to upload a manually filled-up 'wp-config.php' to the site before unzipping the WordPress install?
2:57 pm
Unfortunately not. Please see my reply to Bonnie. I tested this before replying by using a correctly configured wp-config.php with an empty database and the site goes straight into the setup and asks you to create an admin account.
12:32 pm
Isn't it just as easy (and safer) to install Wordpress the old way? That is, unzip locally and change wp-config.php accordingly before uploading all files to your site? That way all your database and password details are already configured. Or maybe I'm missing something.
2:57 pm
Hi Lawrence. Unfortunately not. Please see my reply to Bonnie.
12:55 am
Thanks Mark (and thanks for the great article). However, whenever I upload the WP files with preconfigured wp-config.php I always visit the URL straight away to select the language, etc so although I guess, theoretically, someone could jump in before me, I think it is probably unlikely.
12:57 pm
Our application installation script installs the wp-config as we create the database at the same time as unpacking the files. The user still needs to do the setup of the first admin user but the window of opportunity is effectively removed if the user does go get a coffee.
1:23 pm
Hi,
super post again.
I have always installed WP the manual way, but my first job before i do anything is to set up the database for the install.
Next I go my WP files on my PC and rename wp-config-sample.php to wp-config.php, then I edit this file with the database credentials and add the salts and change the WP database prefix, then I save this file.
Now I upload all the WP files to the server and once they are up there I just go to the url and away we go, so I never put up an install without a wp-config.php file.
Hope this helps
Cheers
Dave
No
1:24 pm
Would it be a good idea for the Wordpress installation procedure to automatically create such a .htaccess file during the initial phase and then delete it when completing the installation? All this means is that whoever is starting the install needs to know the static IP to the server on which their site is to be hosted, information that the host should provide when you sign with them.
2:56 pm
Interesting idea Mike. That would work, although no doubt some people would switch IPs and get locked out - but that may be an edge case. The harder problem I think is that you would have to actually hit the web interface with your browser at least once to have it log your browser IP. The trouble with that is in the scenario above in the post that I described, you don't hit the web interface at all. You just unzip the files and leave them. It's that gap between unzipping and hitting it with a browser that is the problem.
Mark.
1:45 pm
Thank you WF for the post. I personally install WordPress on my local server at home, install WordFence too, work on some pages and make a full backup of the site and then install it on the hosting server.
1:56 pm
Couldn't you just populate the Wordpress setup-config.php file offline and then upload the copy into the server via FTP at the time of install (you could even name it something else, push it up with all the other files and then rename it at the time of install) so that it was completed at the same time as the install?
2:54 pm
Hi Greg. I think you mean the wp-config.php account. If so, please see my reply to Bonnie. No, the site is still exploitable.
2:33 pm
I usually unzip the WP files locally, create a db, create wp-config.php locally and manually edit it with the db info (plus a bunch of other settings I like to use in wp-config) and then upload to the server, with the wp-config.php already populated, then do the rest of the set up.
Does that also avoid the problem or do you still recommend the htaccess protection?
2:54 pm
Hi Bonnie. Unfortunately it does not. If you configure the wp-config.php file and leave the site for a few hours, it is in the following state:
If the attacker hits the site, they see the "select language" dialogue. Once they select language, they are prompted to create an admin account with password. They can then create their own admin account, complete site configuration and once again they have remote code exec on your hosting account.
Mark.
3:21 pm
I don't really get this. My 2 hosting providers - one uses Quickinstall (HostGator) and the other uses Softilicious - both these quick installs ask for the admin user and database details at install. WP doesn't install until it has all these details to complete the installation.
So I'm bemused by the need for any of this if you are using one-click installers.
3:48 pm
Hi David,
It depends how the installer works. If you have the opportunity to enter your admin creds in a secure environment (logged in CPanel for example) then you're probably OK. If it's just a package install (which unzips the files and that's it) where you then have to visit a URL to complete the install using the above method, then you have this situation where you have a gap in time where an attacker can take control of the site.
Mark.
12:21 am
The Softaculous installer on my shared hosting usually runs from cPanel, so you're in a secure environment and the only way for you to run a new WP installation is to fill in all the required fields before hitting "install". These fields include administrator login and password, and you can also set the database prefix to your preference. The database is automatically created the moment you run the Softaculous installation, so the WP files are unpacked simultaneously with the database creation, and the config file and database tables seem to be pre-populated by the information you've already provided.
It takes about a minute for the installation to complete, in my experience, and I haven't been able to see the actual WP wizard when trying to access the installation directory before Softaculous has finished doing its thing.
3:59 pm
I've noticed that some of my sites that are upgraded through Softaculous ask me to go to update.php afterwards. Once I'm there, I get the standard WP setup page even though the site is already live and set up. Is this a vulnerability?
4:04 pm
I'm using Softalicious to install WordPress. As commented previously, does this dfy all-in-one method of configuring mean that a hacker cannot hijack my installation in the way that is being suggested?
Or should I not be using Softalicious anyway!?
Excellent article by the way.
4:09 pm
Looks like my question was answered 3:48 pm whilst I was actually typing .........
10:06 pm
Thanks for the great insight once more Marc.
But I think I am missing something here.
As a hosting company we provide hosting accounts to customers that wish to install their site.
What we provide is simple ftp access and a pair of username/password credentials to a MySql server.
Both the ftp access and the MySql credentials are contained to this installation, hence any php can run just on the customer's ftp space. The same is true for the WordPress credentials as they can only access a certain database.
As an end result each site has its own contained access to the server.
So even if the WP installation is not complete the only damage that can happen is like local to this account/customer but in such a case if the customer hasn't completed yet the installation nothing really bad has happened to his account.
This of course is not true if he has transfered data via ftp, then the attacker has access to personal files.
This can also be true if a new WP installation is about to take place on top of an old site. But the customer should have known about the security hazards of leaving an unfinished WP installation.
In essence what I am saying is that is really bad practise where hosting providers squeeze several sites under the same ftp space (user directory) on the server.
So, I believe this is foremostly a hosting mistake and not a user mistake!
10:10 am
Unless you have specific protections in place, if your customer installs a fresh WP installation via FTP and leaves it there, their account will eventually be exploited by an attacker configuring the site using their own database and gaining remote code exec.
11:07 pm
Thank you Mark,
my hoster uses a software installation tool that creates a wp-config, so the wordpress-setup is not needed at all. I think that closes the problem as long as customers use their tool.
10:08 am
If it also creates your first admin account then you're OK. If not, you may have the same issue.
11:15 pm
Very well explained. I made a mistake in past while leaving in-configured WordPress installation. After reading this update I will definitely avoid this in future. Thanks Mark for sharing this information.
1:39 am
Thanks for this from a new WF user, v. grateful for your plugin that saved me last week.
I've just scanned my files and found numerous copies of 'setup-config.php' should I delete them all?
Cheers!
6:23 am
I have a shell script that collects all my info and generates any necessary stuff (db, pw, etc), then does the install using wp-cli scripts in one go. Not only is it super simple, the install/setup gap is basically nonexistent.
I realize most people are probably not self-hosted and using an automated installer from their host. Just a suggestion for anyone who might be interested in another option that's a bit higher level.
9:57 pm
How do this affect reseller hosting where you have other WordPress sites with their own cPanels and domains?