// you’re reading...

Apoplecticus

Hacked! Seven tips for fighting back!

hacked
In this post, I share what I’ve learned in battling back from hacking and spamming attacks to regain control of my website and make it secure. This brings to mind the wider issue of the internet’s vulnerability, which I will address in a follow-up post.

During the last six months, intruders repeatedly broke into my WordPress blog and ran amok. Don’t be concerned. It’s safe to visit truthalyzer.com now, but for awhile there . . . . After each incident, I cleaned up the mess, restored my site, and bolstered security. I felt like one of those crime scene cleaners who mop up after murders. But the experience made me both efficient at cleaning up and knowledgable about the styles and methods of the perpetrators.

That naturally led me to the investigative aspect of the hacking crime scene. It makes me feel a little better, after having been so often victimized, to be a website CSI, using “forensic science” tools like WordPress Firewall and phpMyAdmin (both described below) to track down cyber perps. Of course, my truthalyzer.com police force would not be complete without a crime prevention unit. I’m that, too, having installed security plugins and strengthened passwords, files, and permissions (also described below). Things have been quiet lately, but my annual performance review will be sub-par. Too much crime earlier in the year. Still, I’m getting better at all of these roles, and I’m ready to share with you what I’ve learned.

I suggest you first review the disclaimers on my “Boring legalisms” page and then have a look at the following seven tips for fighting back against hackers and spammers:

1. Detection

If you are already infected, it’s a waste of time to implement security measures. I speak from experience, having discovered an INVISIBLE ADMINISTRATOR of my website, someone who came and went as he pleased, hacking my site and then re-hacking it after I restored it and increased security. I finally noticed something that must have been in plain sight before me for months: “Administrator (3)” was displayed at the top of my WordPress “Users” page, but there were only two users listed with administrator privileges. It was as if my wife and I had noticed the shoes of a third person hiding behind our bedroom curtains.

I logged into my control panel on the host site and used phpMyAdmin to unmask the phantom administrator. “Google” is the username he chose. That’s probably a clue about what he was up to, somehow referring my visitors to his site to boost his Google rating and his advertising revenue. I deleted him and began the task of carefully examining my directories and files to find modifications he may have made. That investigation is still underway, and unfortunately in restoring backed up files I may have erased the evidence. For now, let me emphasize again that the first step in securing your website should be to determine whether security has already been breached and root out the intruders before you fortify the site.

You know you’ve been hacked when:

  • Ads and flashing banners of unknown origin suddenly appear on your website
  • Your comments are overflowing with spam, full of distasteful content and links to creeps and hucksters
  • New posts show up as blank pages
  • You cannot login to your dashboard
  • Your host informs you that your website has been taken down and quarantined

I’ve taken a few of those bullets, so I knew I was under attack. But sometimes it’s not so obvious. Keep an eye out for these clues:

  • Invisible or phantom administrators
  • Warnings from web browsers that your website is unsafe
  • File or directory permissions have mysteriously changed (see item #7 below)
  • Your pages are loading ever more slowly
  • Your browser status bar shows visits to exotic domains (e.g., .ru extensions)
  • Cached pages of your website on Google show embedded spam links when you click the “text-only version”

You know your website better than anyone else. If something just doesn’t look or feel right, then you should suspect that it has been hacked.

Of course, detection is more than just awareness that something’s wrong. It also involves determining exactly what the problem is, so that appropriate corrective action can be undertaken, including calling the undertaker to haul away the bodies. I did that once. I gave up and started all over with a fresh installation. But now I’ve decided to fight back, to go over suspected files and directories with a fine-toothed comb and disinfect them and to publish IP addresses of perpetrators.

2. Backup

Simply put, there is no excuse for not backing up your website regularly. Just do it. A plugin, WordPress Database Backup , which can be downloaded here, puts a “Backup” option on the Dashboard menu and also allows you to schedule automatic backups at given intervals. The rule of thumb is to backup often enough that you won’t be missing anything crucial when you restore a backup. I’ve set the plugin to automatically backup weekly and email the file to me, but I also take advantage of the plugin’s one-click option to manually download a backup to my computer after I publish a major post or update. It only takes a couple of minutes to backup, and it could save countless hours in the event of an attack.

After being hacked a few times, it became routine for me to simply login to my host and use phpMyAdmin to “import” the most recent backup, restoring my website to what it looked like at the time it was backed up. As mentioned above, that might erase the evidence, so it’s a good idea to rename suspected files so they won’t be overwritten and can be examined later. You should also be aware that the files you restore from your backup may have already been infected, even though you may not have seen any clues at the time. In that case hopefully you will have retained several earlier backups so that you can go through them to find one with clean files. And of course it’s not just files that you have to be concerned about. If you restore a perfectly healthy backup with an invisible administrator lurking about your website, as I did, your files will be reinfected no matter how many of the security measures below are implemented.

3. Passwords and usernames

Passwords can have numbers, upper and lower case letters, and special characters. You need to come up with a password that cannot easily be guessed and that resists a brute force attack (i.e., an attack in which a computer patiently inputs combinations of characters until it finds one that works). So words, such as “mypassword,” or dates, such as “12091986,” are weak, but something like “M!P$Wd19&6″ is strong, yet has embedded meaning to help you remember it. I am less concerned about brute force attacks now that I have installed and activated LoginLockdown, the first of the security-oriented plugins described below (item #4).

Oh, and don’t forget to change your passwords from time to time. It should be obvious that new passwords are in order after you’ve been hacked, since they might have been compromised by the hackers.

Usernames are no longer case-sensitive in WordPress, so it’s more of a challenge to create a secure name. Although you could strengthen a name like “natalie” by substituting numbers for some letters, such as “n4t4l1e,” it’s better to avoid actual names, nicknames, and email names altogether and use something less likely to be guessed, like “w12rd0v02″ (which you could remember as “wizard of oz”), or an acronym such as “1wb0tn50c” (which only you would know meant “I was born on the north side of Chicago”). Be sure to replace the default “admin” username with a name that hackers won’t be expecting to find. Just create an administrator with another name, login under that name, and delete admin. WordPress will offer you the opportunity to attribute the authorship of any posts or pages from the old user to the new one.

4. Plugins that increase security

Plugins are a mixed blessing. On the one hand, they provide increased functionality to your website. On the other hand, some have faults that could allow hackers to gain control over your website. As far as I am able to determine, all the plugins I am recommending are safe to install. Still, it’s a good idea to at least place an empty index.html file in your plugin directory, because that keeps outsiders from listing the contents of that directory and getting a head start in exploiting any plugin weaknesses of which they may be aware. There’s also a line in the sample .htaccess file (item #5 below) that prevents directory listing.

In addition to WordPress Database Backup, described and linked above, I recommend the following five plugins to harden WordPress against would-be intruders:

  • LoginLockdown blocks login attempts from an IP address after the number of unsuccessful tries within the time period and for the length of time thereafter that you have previously specified.
  • (download here)

  • WordPress Firewall intercepts many hack attempts and sends you an email identifying the form of attack, the IP address of the perpetrator, and a link to a map that shows where in the world the attack originated.
  • (download here)

  • WP Security Scan identifies your website’s “security vulnerabilities and suggests corrective actions,” such as hiding the WordPress version in meta tags and renaming default wp_ file prefixes to something hackers don’t expect, both of which the plugin can handle for you.
  • (download here)

  • WP-SpamFree protects against comment spam from mindless web bot intruders by utilizing JavaScript and cookies, which the bots cannot process.
  • (download here)

  • Akismet is included with WordPress, and I recommend that you activate it. It functions like a moderator, reviewing comments for spam and placing suspects in a queue. If you agree they’re spam, you delete them.

Akismet may seem superfluous with WP-SpamFree activated, because spam should not make it far enough to be moderated by Akismet. But I still occasionally find a spam comment in the queue, where it is easily deleted. Reoccurences from that source can be prevented by blacklisting its IP address in .htaccess (item #5 below).

In looking for security-related plugins, I came across a couple of useful lists with descriptions and links, one at WPWebHost and the other at SpeckyBoy.

By the way, all the plugins mentioned in this post are FREE.

UPDATE: I have tried plugins that pose a challenge question before accepting comments–annoying to my website visitors but effective in blocking web bot spams. reCAPTCHA presented distorted images of words, but I replaced that with Block-Spam-by-Math, which presented a simple math problem, because web bots are increasingly breaking CAPTCHAs, and visually impaired readers are stopped cold by CAPTCHAs but they can handle math plugins. Now I’m using WP-SpamFree, which screens comments unobtrusively in the background. It appears that spam-blocking plugins with challenge questions are outdated by this new approach. We’ll see.

UPDATE: I recently evaluated one additional plugin, WordPress File Monitor, which detects additions, deletions, or changes to files and sends an email alert to the address you specify. Given its frequent false alarms, and since I’ve already installed the above five plugins and modified .htaccess and other files as suggested below, I think this plugin is more trouble than it’s worth.

5. .htaccess and other files

This tip involves using your host’s file manager and text editor to muck around in a file named .htaccess (actually, it has no name, just an eight letter extension), which is usually found in the root directory of your website server. One thing this file is useful for is blacklisting IP addresses of hackers and spammers. Even if you are not willing or able to edit this file, some hosts allow you to blacklist from the control panel using an “IP Deny Manager.” You just enter the addresses and the program writes them into your .htaccess file. Offending IP addresses are obtained from the WordPress comment queue, or plugins, such as WordPress Firewall, or lists published on the internet (see below). But there’s a lot more that can be accomplished with .htaccess than just blacklisting IP addresses.

Several hacking strategies can be prevented by adding code to the .htaccess file. Without going into detail at this time, I am providing a sample of .htaccess file contents. This code is from MileHighTechGuy, Perishable Press, and other reputable sources. I must warn you, however, that it is quite possible that one or more lines of this code may conflict with functions of your website, even if you use WordPress, for which the code is optimized, because of differences between versions, themes, plugins, hosts, etc. If you are not using WordPress, you should search Google for .htaccess code that is optimized for your blogging software.

After adding the code, if you experience problems, you can isolate offending lines by simply removing portions of the code (or placing # at the beginning of lines) until your website is functioning properly again. Of course, you can also edit the other way around, adding code a block at a time until you encounter a problem with your website or you’re done. Either approach works. You will see that I found one line below that had to be deactivated with a # (RedirectMatch 403 \/\/), because it conflicted with a plugin (Post Thumb Revisited). Everything else has been working without a problem on my website. Oh, one other thing. The code should be placed before or after the “# BEGIN WordPress” and “# END WordPress” block, because lines in between those sometimes get overwritten by other processes. Here’s the sample code:

# PROTECT HTACCESS FILE
<Files .htaccess>
order allow,deny
deny from all
</Files>

# PROTECT WPCONFIG.PHP
<files wp-config.php>
order allow,deny
deny from all
</files>

# PREVENT DIRECTORY LISTING
Options All -Indexes
<Files 403.shtml>
order allow,deny
allow from all
</Files>

# BLACKLIST IP ADDRESSES
# Add to this list as you discover more offending addresses
# Easier to keep track of addresses if they are sorted
<Files *>
order allow,deny
deny from 24.19.202.10
deny from 24.238.170.10
deny from 58.125.181.214
deny from 61.67.196.240
deny from 64.13.192.17
deny from 64.15.69.17
deny from 66.36.243.91
deny from 66.63.167.50
deny from 66.74.199.125
deny from 67.69.254.245
deny from 67.215.238.186
deny from 72.46.136.130
# Next two are examples of blocking IP address range using CIDR
deny from 72.232.0.0/16
deny from 72.233.0.0/17
deny from 74.50.5.250
deny from 75.126.85.215
deny from 75.126.201.2
deny from 77.78.239.49
deny from 77.103.132.126
deny from 77.127.142.160
deny from 77.229.156.72
deny from 80.13.62.213
deny from 80.206.129.3
deny from 80.240.215.147
deny from 81.222.236.66
deny from 84.122.143.99
deny from 87.106.82.74
deny from 87.118.96.0/19
deny from 87.248.163.54
deny from 88.170.42.61
deny from 89.122.29.127
deny from 89.248.168.41
deny from 91.121.164.23
deny from 91.148.84.119
deny from 91.195.185.71
deny from 91.212.41.249
deny from 92.53.105.120
deny from 93.72.232.96
deny from 94.76.226.70
deny from 94.142.128.140
deny from 95.215.76.0/22
deny from 97.65.164.215
deny from 99.230.227.51
deny from 114.127.246.36
deny from 118.129.166.213
deny from 121.9.221.187
deny from 122.138.14.150
deny from 122.233.72.249
deny from 128.111.48.138
deny from 168.10.168.61
deny from 174.142.104.57
deny from 188.72.213.44
deny from 193.226.51.2
deny from 193.231.72.188
deny from 194.8.74.0/23
# Next is example of blocking range using truncated IP address
deny from 195.225
deny from 200.106.145.82
deny from 202
deny from 203
deny from 207.99.23.198
deny from 209.25.133.137
deny from 210
deny from 211.233.7.64
deny from 212.115.201.232
deny from 213.155.12.176
deny from 218
deny from 219
deny from 220
deny from 221
deny from 222
allow from all
</Files>

# QUERY STRING EXPLOITS
<IfModule mod_rewrite.c>
RewriteCond %{QUERY_STRING} \.\.\/    [NC,OR]
RewriteCond %{QUERY_STRING} boot\.ini [NC,OR]
RewriteCond %{QUERY_STRING} tag\=     [NC,OR]
RewriteCond %{QUERY_STRING} ftp\:     [NC,OR]
RewriteCond %{QUERY_STRING} http\:    [NC,OR]
RewriteCond %{QUERY_STRING} https\:   [NC,OR]
RewriteCond %{QUERY_STRING} mosConfig [NC,OR]
RewriteCond %{QUERY_STRING} ^.*(\[|\]|\(|\)|<|>|’|”|;|\?|\*).* [NC,OR]
RewriteCond %{QUERY_STRING} ^.*(%22|%27|%3C|%3E|%5C|%7B|%7C).* [NC,OR]
RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F|127\.0).* [NC,OR]
RewriteCond %{QUERY_STRING} ^.*(globals|encode|config|localhost|loopback).* [NC,OR]
RewriteCond %{QUERY_STRING} ^.*(request|select|insert|union|declare|drop).* [NC]
RewriteRule ^(.*)$ – [F,L]
</IfModule>

# CHARACTER STRINGS
<IfModule mod_alias.c>
# BASIC CHARACTERS
RedirectMatch 403 \,
RedirectMatch 403 \:
RedirectMatch 403 \;
RedirectMatch 403 \=
RedirectMatch 403 \@
RedirectMatch 403 \[
RedirectMatch 403 \]
RedirectMatch 403 \^
RedirectMatch 403 \`
RedirectMatch 403 \{
RedirectMatch 403 \}
RedirectMatch 403 \~
RedirectMatch 403 \”
RedirectMatch 403 \$
RedirectMatch 403 \<
RedirectMatch 403 \>
RedirectMatch 403 \|
RedirectMatch 403 \.\.
# RedirectMatch 403 \/\/
RedirectMatch 403 \%0
RedirectMatch 403 \%A
RedirectMatch 403 \%B
RedirectMatch 403 \%C
RedirectMatch 403 \%D
RedirectMatch 403 \%E
RedirectMatch 403 \%F
RedirectMatch 403 \%22
RedirectMatch 403 \%27
RedirectMatch 403 \%28
RedirectMatch 403 \%29
RedirectMatch 403 \%3C
RedirectMatch 403 \%3E
RedirectMatch 403 \%3F
RedirectMatch 403 \%5B
RedirectMatch 403 \%5C
RedirectMatch 403 \%5D
RedirectMatch 403 \%7B
RedirectMatch 403 \%7C
RedirectMatch 403 \%7D
# COMMON PATTERNS
Redirectmatch 403 \_vpi
RedirectMatch 403 \.inc
Redirectmatch 403 xAou6
Redirectmatch 403 db\_name
Redirectmatch 403 select\(
Redirectmatch 403 convert\(
Redirectmatch 403 \/query\/
RedirectMatch 403 ImpEvData
Redirectmatch 403 \.XMLHTTP
Redirectmatch 403 proxydeny
RedirectMatch 403 function\.
Redirectmatch 403 remoteFile
Redirectmatch 403 servername
Redirectmatch 403 \&rptmode\=
Redirectmatch 403 sys\_cpanel
RedirectMatch 403 db\_connect
RedirectMatch 403 doeditconfig
RedirectMatch 403 check\_proxy
Redirectmatch 403 system\_user
Redirectmatch 403 \/\(null\)\/
Redirectmatch 403 clientrequest
Redirectmatch 403 option\_value
RedirectMatch 403 ref\.outcontrol
# SPECIFIC EXPLOITS
RedirectMatch 403 errors\.
RedirectMatch 403 config\.
RedirectMatch 403 include\.
RedirectMatch 403 display\.
RedirectMatch 403 register\.
Redirectmatch 403 password\.
RedirectMatch 403 maincore\.
RedirectMatch 403 authorize\.
Redirectmatch 403 macromates\.
RedirectMatch 403 head\_auth\.
RedirectMatch 403 submit\_links\.
RedirectMatch 403 change\_action\.
Redirectmatch 403 com\_facileforms\/
RedirectMatch 403 admin\_db\_utilities\.
RedirectMatch 403 admin\.webring\.docs\.
Redirectmatch 403 Table\/Latest\/index\.
</IfModule>

# USER AGENTS
SetEnvIfNoCase User-Agent “libwww” keep_out
SetEnvIfNoCase User-Agent “DotBot” keep_out
SetEnvIfNoCase User-Agent “Nutch”  keep_out
SetEnvIfNoCase User-Agent “cr4nk”  keep_out
<Limit GET POST PUT>
Order Allow,Deny
Allow from all
Deny from env=keep_out
</Limit>

[UPDATED: At least one additional offending address added each month, from July, 2009 through August, 2010.]

That’s it for .htaccess, but here’s another file to check, php.ini. Make sure these lines are in it:

register_globals = Off
error_display (display_errors = Off)

The first line makes it harder for hackers to input malicious code, and the second line keeps hackers from discovering paths into your website from error information.

And in wp-config.php, replace the four default “secret keys” with your own. WordPress says the keys “make your site harder to hack and access harder to crack by adding random elements to the password.” You’ll never be asked for the keys. They function automatically to encrypt information. So make them as long and obscure as you want:

define(‘AUTH_KEY’, ‘YourSecretAuthKeyGoesHere’);
define(‘SECURE_AUTH_KEY’, ‘YourSecretSecureAuthKeyGoesHere’);
define(‘LOGGED_IN_KEY’, ‘YourSecretLoggedInKeyGoesHere’);
define(‘NONCE_KEY’, ‘YourSecretNonceKeyGoesHere’);

You can either make up keys, or click here for wordpress.org to generate random keys, which can be copied and pasted into wp-config.php.

Finally, add this line of code to your theme’s functions.php:

add_filter(‘login_errors’,create_function(‘$a’, “return null;”));

This will suppress login error messages, which would otherwise let hackers know that they were half-way into your website. For example, the error message “Incorrect password” means the username is correct and the password is incorrect. Why give out that information?

6. Permissions

Most web servers run UNIX or Linux software that designates file and directory permission levels, i.e., three digit numbers indicating limits to those allowed to read, write, and execute. If permissions are not set appropriately they can allow hackers to do mischief to your website. On my server, 755 is standard for directories, 644 for plugins and WordPress php files, and 666 for theme files. If you find permission 777, which allows anyone in the world to do anything, you will probably want to change it to a more restrictive number. I found an inappropriate 777 and was able to change it myself, using my host’s file manager. I just clicked on the directory, and then on the “change permissions” icon, and then I entered a new number. It’s a good idea to check with your host’s tech support as to what permissions they recommend and how best to change them if need be.

7. Upgrade

Finally, I encourage you to take seriously notices about the availability of updates for your blogging software, plugins, or theme. It’s tempting to ignore such notices, if your website has been running smoothly and you are not aware of any recent hack or spam attacks. But you know that there’s an endless cat and mouse game underway between hackers and bloggers. When security flaws are discovered in software we use, it’s prudent to install updates that patch those flaws before they can be exploited on our websites.

On the other hand, updates can themselves be the cause of problems. It’s wise to wait at least a few days after updates are released before installing them, to give you time to search the internet for reports of problems and give the software developers time to correct such problems. And there is one further caution for bloggers who have customized their files. Updating may cause custom code to be overwritten. If code was well documented, it should not be too difficult to add it back, unless the updates are substantially different than the original software. I have found that some of the functions from custom code are now standard in upgraded software, but more often than not I have to weigh the value of upgrading against the difficulty of restoring custom code. My need for security enhancements in the upgraded software is often the deciding factor.

The actual process of upgrading has been streamlined in recent WordPress releases. Blogging software, plugins, and themes can now be upgraded with a click of the mouse from within WordPress, making it unnecessary to download to your computer from developers’ websites, unzip files, upload them to the host, and manually install, as used to be the case.

[NOTE: This is a work-in-progress. As you see above, I have made several updates since the original post. At some point, I will make this a permanent page, accessible from the Main Menu to the right.]

Discussion

6 comments for “Hacked! Seven tips for fighting back!”

  1. Gib:

    Nice post. Thanks for the link back.

    For denying IP’s within a range you can replace the following lines:
    deny from 194.8.74.220
    deny from 194.8.75.149
    deny from 194.8.75.163

    With this single line:
    deny from 194.8 “# deny IP range”

    Another thing you can do is block by domain:
    #MileHighTechGuy blacklist by domain
    #deny from .*domain\.com.*
    deny from .*zctk\.ru.*

    Keep up the good fight!
    Cheers

    ~MileHighTechGuy

    Posted by MileHighTechGuy | June 15, 2009, 9:59 am
  2. Good tip, Jeff. I’ve revised the blacklist in this post and my actual .htaccess file accordingly. The latter is running on three websites now without a hitch (fingers crossed). No spam or reports of hackers attempting mischief (yet).

    Gib

    Posted by Gib | June 15, 2009, 4:11 pm
  3. I think we have a pretty good solution now since my site hasn’t been hacked in several weeks :)

    I trust yours hasn’t either.

    Now if I can just get all of my plugins to play nice with each other…

    Posted by MileHighTechGuy | June 29, 2009, 11:01 am
  4. As of this date, no hacks to report here or on our other two websites, either. A few spam comments have made it into the Akismet queue, where I can delete them before they’re published. I’m assuming that they must have been hand-entered, since reCAPTCHA should stop the bots. Anyway, I’m cautiously optimistic that the above security measures are working well.

    Posted by Gib | June 30, 2009, 3:11 pm
  5. FYI, I’ve been corresponding offline with MileHighTechGuy about the syntax for blocking a range of IP addresses. He previously suggested truncation (e.g., three addresses I was blocking with separate deny from lines, 194.8.74.220, 194.8.75.149, and 194.8.75.163, could all be blocked with 194.8). In researching blocking syntax, I came across examples that used asterisks as wildcards in truncated addresses (e.g., 194.8.*.*), but apparently the asterisks aren’t necessary.

    I also came across the use of classless inter-domain routing (CIDR) to block address ranges (e.g., 194.8.74.0/23), and I added a couple of examples of those to the above .htaccess file. You can Google CIDR to learn more about it.

    MileHighTechGuy also suggested blocking by domain (e.g., .*zctk\.ru.* for a particular Russian domain), and I found elsewhere that all addresses from entire countries (e.g., .ru for Russia and .cn for China) can be blocked. I’ll try the method for particular domains but not the one for entire countries. Apparently it slows the website down to block requests from a country, since the server does a DNS lookup of all the addresses from that country, so even though lots of spam and hacking originates in Russia and China, I have not blocked them. Yet.

    Oh, one other detail. I came across a tip that <Files *> is the preferred container to use for the blacklist, since it blocks the most requests (e.g., PUT, DELETE, CONNECT, OPTIONS, PATCH, PROPFIND, PROPPATCH, MKCOL, COPY, MOVE, LOCK, and UNLOCK), so that’s what the above example uses.

    Posted by Gib | July 24, 2009, 2:19 pm
  6. Won’t all this info help the Hackers?

    Posted by Marc | September 17, 2009, 4:49 pm

Leave a comment

Anti-Spam Protection by WP-SpamFree

Archives



Categories