How to setup an AWS EC2 instance to reduce WordPress hacker attacks

Hacker Terminal Window
WordPress hacker attacks have been on the rise this year and although I haven’t been hacked (touch wood) they have managed to overload my site on a number of occasions. I have been on a quest to stop them getting in and also to reduce the instances of their repeated entry attempts taking it down. This has been a pretty long journey and one that I thought other people might benefit from so I have decided to share it here.

Monitoring

The first step that I took was setting up alerts in the Amazon EC2 console to send me an email if my CPU stays at 100% for over five minutes. You can do this by clicking on your server in the console and then hitting the “Monitoring” tab and then “Create Alarm”. This seemed to be about the right amount of time to stop too many false positives and usually indicated that something was up with the server.

The second set of monitoring I setup was New Relic, we use them extensively at work to monitor our servers and their free version gives you a load of really useful information about how both the server and PHP are performing. Think of it as a version of Google Real Time that allows you to look at the processes and speed of everything going on inside your server and application. They also have a really useful availability monitoring service built in which you can setup to ping your site every few minutes to see if it is accessible and a great iPhone App that sends push notifications when something goes down.

Logs

The next thing you need to do is SSH into your server and check your httpd access_log to see what is trying to access your server.

sudo tail -f /etc/httpd/logs/access_log

This will bring up what is currently happening on your server and you can see all of the requests that are coming in. If your site does go down this is the place to check right afterwards to see what the requests were that overloaded it.

Mod Security

I decided to install Mod Security along with the OWASP ruleset to give myself an added extra layer of protection from any issues that might get introduced into WordPress before a patch comes out. I have to say that this involved quite a steep learning curve and due to the amount of technical information that I write in my blog so it took me a long time to modify all of the rules to allow saving of posts amongst other things.

As I am running on the AWS Centos image and it already had the EPEL repository setup so all I needed to do was:

sudo yum install mod_security mod_security_crs
sudo service httpd restart

Once this has installed you should definitely start clicking around your blog and see what is broken, quite likely that actions like saving a post, updating a comments status and updating plugins will now throw 403 errors. In order to allow your site to function need to create a file called whitelist.conf in the following location.

/etc/httpd/modsecurity.d/activated_rules

You then need to populate it with rules that allow you to bypass the specific rules that are triggered when using WordPress. Mod_security isn’t aware of your logged in status and assumes every call is external so this throws up quite a few issues. I have included a link to the ruleset that I have built up over the last few months below. There are probably more entries than most people will need but due to the geeky and code based nature of my posts a lot of stuff gets blocked, I have also enabled XMLRPC so apps work as well.

whitelist.conf

Adding your own rules to whitelist.conf

Should you get a 403 error when performing any action on your site you should SSH to your server and via the terminal type in the below.

sudo tail -f /etc/httpd/logs/modsec_audit.log

Then when you retry the action you should see another entry in the log and you need to pick out the data that looks like this.

[id "960035"]

You then just need to add the following line to your whitelist.conf

  SecRuleRemoveById 960035

Under the correct Location e.g.

<LocationMatch "/xmlrpc.php">
  SecRuleRemoveById 981173
</LocationMatch>

This can be quite a laborious process and possibly the whole lot is overkill but have to say I have learnt quite a bit in the process. I also added the following to the bottom of my http.conf which bans an IP from attempting to login for five minutes after three failed attempts.

# Stop Brute Force Attack by banning IP http://www.frameloss.org/2011/07/29/stopping-brute-force-logins-against-wordpress/

        # This has to be global, cannot exist within a directory or location clause . . .
        SecAction phase:1,nolog,pass,initcol:ip=%{REMOTE_ADDR},initcol:user=%{REMOTE_ADDR},id:2323

                # Setup brute force detection. 

                # React if block flag has been set.
                SecRule user:bf_block "@gt 0" "deny,status:401,log,msg:'ip address blocked for 5 minutes, more than 3 login attempts in 3 minutes.',id:2323"

                # Setup Tracking.  On a successful login, a 302 redirect is performed, a 200 indicates login failed.
                SecRule RESPONSE_STATUS "^302" "phase:5,t:none,nolog,pass,setvar:ip.bf_counter=0,id:2324"
                SecRule RESPONSE_STATUS "^200" "phase:5,chain,t:none,nolog,pass,setvar:ip.bf_counter=+1,deprecatevar:ip.bf_counter=1/180,id:2325"
                SecRule ip:bf_counter "@gt 3" "t:none,setvar:user.bf_block=1,expirevar:user.bf_block=300,setvar:ip.bf_counter=0"

htaccess

The final part of this is the .htaccess changes that I made to stop people being able to post without a referrer as a lot of bots use this method as they are computer programs rather than real people. I also had two specific User Agents that had targeted me which I block all access to my wp-login page.

# Stop protected folders from being narked. Also helps with spammers
ErrorDocument 401 /401.html

# Stop spam attack logins and comments
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{REQUEST_METHOD} POST
RewriteCond %{REQUEST_URI} .(wp-comments-post|wp-login)\.php*
RewriteCond %{HTTP_REFERER} !.*(blog.david-jensen.com|dev.mariamjensen.com|www.cafeontherye.co.uk).* [OR]
RewriteCond %{HTTP_USER_AGENT} ^Mozilla/5\.0\ \(Windows\ NT\ 6\.1;\ WOW64\;\ rv\:18\.0\)\ Gecko/20100101\ Firefox/18\.0 [OR]
RewriteCond %{HTTP_USER_AGENT} ^Mozilla/5\.0\ \(Parsley\ NT\ 1.0\;\ rv\:1.0\)\ Parsley/1.0.0.0 [OR]
RewriteCond %{HTTP_USER_AGENT} ^$
RewriteRule .* - [F]
</ifModule>

Here are a few sites that helped the creation of this post.

Definitely interested in hearing if anyone else has any other good ideas around how to approach this issue or has any tips from me as I am certainly no security expert. However after the uptime for my server has definitely improved over the last while with all of this helping to reduce WordPress hacker attacks on this blog.

Music to write this Code to

Andy C delivers some seriously high paced hacker music to help you get through this code in a jiffy.

Leave a Reply

%d bloggers like this: