This site got hacked again yesterday, although don’t panic – as best as I could tell the exploit was not actively injecting content into the webpages, just creating a backdoor for a potential future exploit.
I monitor recently changed files on a daily basis so I get a heads up if anyone manages to get a script onto the any of the domains that I manage, whether that be a CGI exploit, Shell or FTP password compromise. Basically, if someone modifies a script on my system I’ll get to see it listed, unless they are clever enough to change the last modified date. In this case they seemed to do that for one of the file, but it was still listed as needing backup, presumably because the content didn’t match.
For the technically minded, here are the details of the exploit:-
### Modified Files
### Modified Database Tables
The MySQL database that hosts the WordPress content was also modified so that the *wp_options* table contained a new row with the *option_name* value set to *page_option*. The value of this option was a serialised PHP array.
### functions.php Code modifications
The code added to the end of the *functions.php* file was:
### page.php Code Modifications
I couldn’t detect what had changed in this file – there was nothing tacked onto the end, and the modification date of the file was consistent with when I last upgraded WordPress. I suspect if I’d done a Diff with the previous version it would have contained a patch that inserted the *page_option* value into the *wp_options* table.
**Update: 10/Apr/2012** As per a user comment, */wp-includes/page.php* is not part of a WordPress install. It appears to be a copy of post.php from an earlier version and is designed to obfuscate the existence of the hack. *You are safe to delete this file*. If you have code additions to other files, check whether the file is part of WordPress before deleting the file – removing the hack may be enough in some cases. The safest possible approach would be to delete your WordPress install and reinstall WordPress, plugins and themes from official sources, or restoring a known-good backup.
### page.php Backdoor
The following line from my Apache *access.log* shows then the back door contained in *page.php* was triggered. The last modification date on page.php was November 17 2011, so its possible that this hack started way back then. It may have been the same backdoor that triggered the January 2012 hack (I don’t have logs for that far back).
`220.127.116.11 – – [07/Apr/2012:05:17:55 -0700] “POST /wp-includes/page.php HTTP/1.1” 200 335 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Safari/535.1″`
The same IP address made the following requests:
`18.104.22.168 – – [07/Apr/2012:05:47:50 -0700] “GET / HTTP/1.1” 200 61268 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Safari/535.1”
22.214.171.124 – – [08/Apr/2012:10:12:30 -0700] “POST /wp-content/themes/premiumnews/cache/b9bfbbf72ca9ca8419327d58dfa276c4.php HTTP/1.1” 200 30002 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Safari/535.1”
126.96.36.199 – – [08/Apr/2012:10:12:31 -0700] “POST /wp-content/themes/premiumnews/cache/pi.php HTTP/1.1” 200 29942 “-” “Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_1) AppleWebKit/535.1 (KHTML, like Gecko) Safari/535.1” `
I’ve already removed the *premiumnews* theme along with all other unused themes, but it looks like it was looking for another back door – perhaps because the first one was not delivering a detectable payload.
The IP address appears to come from a Canadian ISP, although I doubt that’s much help in tracking the perpetrators – its probably just another hacked web server or PC being used to distribute and activate the hacks.
### How The Script Operates
The above code pulls the value stored in the *page_option* row of the *wp_options* table and converts the string representation back to a PHP array. The array contains conventional strings, some of which appear to be random garbage, as it plucks out and concatenates only selected ones that form a base64_decode on a longer encoded string. This is passed through *eval()* in order to produce the code that is then executed in the *$arg(”)* call. All of this is done at the top of the WordPress posts loop.
The executed code is an implementation of a *dsCrypt* function, and a call to a remote server (the URI of which is decoded using the *dsCrypt* function). It includes parameters made up from the IP address and User Agent of the person who requested the original page on this site and its referer URI. I guess this allows the rogue server to customise the payload for the users browser, locale etc. When requesting this with Safari on the Mac, no payload is delivered.
`http://kadaffizzet.com/kasiapa.cc.php?ip188.8.131.52&ref=&ua=Mozilla%2F5.0+%28 Macintosh%3B+Intel+Mac+OS+X+10_7_3%29+AppleWebKit%2F534.55.3+%28KHTML%2C+like+Ge cko%29+Version%2F5.1.5+Safari%2F534.55.3`
NB: I’ve anonymised my static IP address in the above call.
### The Payload
The malicious script takes the contents returned from this server request and inserts it into the requested page from the site. I suspect it would insert a script to attempt a phishing attack or attempt to install a virus.
Maybe because I’m on Safari on the Mac I’m getting no payload as they don’t have a workable exploit for that platform. Perhaps visitors on other less secure browsers would have received some sort of payload, although I’ve not been contacted by anyone so far.
### The Security Hole
I’m mystified about how this hack was executed. I can’t see anything in any of the logs that suggest that anyone has logged in via the Shell or FTP to my account to patch these files, nor any CGI calls in the logs for the last 48 hours that are consistent with some code injection tacked onto the end of a normal page request. That leaves the potential for someone accessing my account from another user account, but as I run this on a Virtual Private Server, there are no ‘untrusted’ users who have access – and looking at the log only those user names have logged in that would have been consistent with me making updates.
In effect, that only leaves people with admin privilege at the hosts [Dreamhost](http://www.dreamhost.com), or a potential back door within their systems. Which is slightly worrying any annoying at the same time.
I’ve contacted the hosts and will be interested to see their response.
### TimThumb Vulnerability and Easy Comment Uploads
Dreamhost provided me with a standard security analysis of the account – no specific help on this hack but their report gives useful recommendations on potential security weaknesses.
I’ve been working through the list of recommendations from Dreamhost. Here were their recommendations:
* Two instances of TimThumb v1.18 contained in inactive themes installed in the affected domain (davemeehan.com)
* TimThumb v2.8 as part of Easy Comment Uploads (now apparently removed from the WordPress.org Plugin Repository) which Dreamhost advised was up-to-date
* World-writable files and directories existing in cache stores on one domain
TimThumb seems to be a culprit, and is often used by other plugins and themes to provide thumbnail generation for image uploading facilities. The fact I had inactive themes installed that contained TimThumb I would think was benign, but I’ve decided to adopt a policy of removing all inactive themes from my WordPress installations. Saves on disk space, clutter in the admin UI, and eliminates a risk.
Easy Comment Uploads was enabled on this domain, and Dreamhost advised that the installed 2.8 version was up-to-date and safe, but I’ve subsequently found advice that
2.8.2 2.8.10 (see the comments for a link) is the latest and safest. However, I decided to re-evaluate why that plugin was installed, and came to the conclusion that it was not needed.
There is the [TimThumb Vulnerability Scanner](http://wordpress.org/extend/plugins/timthumb-vulnerability-scanner/) in the plug repository, which will scan your entire *wp-content* directory looking for TimThumb installs, even if they are obfuscated by plugin or theme developers. It won’t fix the offending install, although it appears it does offer to upgrade it to the latest version, although you should probably look for an update of the container plugin or theme for an official update, or it might break functionality or be undone by a future plugin/theme update.
The world-writable files is I think only a problem if someone gains shell or FTP access to the hosting account, or you are on a shared server. In my case one of my domains was running on some old self-written code that contains a page caching mechanism. This was creating files and directories with 777 permissions within its cache directory. No signs of a hack here, but it was a simple fix in the code to update this to use 755 permissions on the directories and 644 on the files.
I’ve also now implemented additional checks on my daily backup run. This now checks for:
* World-writable permissions on files
`find ~ -type d -perm -o=w`
* Files modified in the last 24 hours
`find ~ \( -type d -name cache -prune -o -name logs -prune -o -name mysql_backups -prune \) -o -mtime -1 -print`
* Potentially malicious code in scripts
`grep -r eval\( */*.php
grep -r create_function */*.php
grep -r –exclude wp-app.php base64_decode */*.php`
I’ll keep monitoring things and see what difference that makes. Although I was initially scathing about problems only starting after [Dreamhost forced password resets due to a user database compromise in January 2012](http://blog.dreamhost.com/2012/01/21/security-update/), it also more or less coincided with when I installed Easy Comment Uploads, and so I think this was likely to be the hole that was being exploited. Read more about [how the Easy Comment Upload vulnerability can be exploited](http://techfoxy.blogspot.co.uk/2011/12/hack-any-wordpress-site-with-easy.html).
### Fresh Install or Restore from Backup?
It’s becoming clear that some of these hack attempts often lie dormant for months. The initial hack is to put in a back door. It can sit unnoticed for long periods before the hackers return and decide to add a payload. You may spot the payload when it occurs (as your site appears obviously hacked) but you may fail to spot the placement of the back door hack in a complex WordPress/theme/plugin setup.
The best possible advice if hacked will be to disable the hack as quickly as possible (by identifying modified files and injected code). Then take time to ensure that you have backups of database, uploads and installed themes/plugins before wiping the WordPress install completely and reinstalling from official sources.
You may already have a strategy for backing up your WordPress install, but if you fail to notice the presence of a back door, restoring from that backup may not prevent future attempts to take advantage of your site.