PHP Developers Network

A community of PHP developers offering assistance, advice, discussion, and friendship.
 
Loading
It is currently Thu Jun 21, 2018 10:30 pm

All times are UTC - 5 hours




Post new topic Reply to topic  [ 10 posts ] 
Author Message
 Post subject: PHP Backdoor Example
PostPosted: Thu Dec 05, 2013 6:43 pm 
Offline
DevNet Resident

Joined: Sun Jun 14, 2009 3:13 pm
Posts: 1146
A family member said his wordpress site was hacked so I dug around and found a backdoor.

I thought I'd post the backdoor here for people to take a look at. It's malicious code if installed and ran so I wanted to check with the site's policy on this board on these things. Obviously it's out in the wild. It looks like it has been in his site since Feb. 2012...so it's nothing too new.

If it's ok to post it, let me know.


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Thu Dec 05, 2013 6:57 pm 
Offline
Spammer :|
User avatar

Joined: Wed Oct 15, 2008 2:35 am
Posts: 6617
Location: WA, USA
Should be fine if there are some parts of particular note that you want to post, but the whole thing... I don't know, I'd defer to someone else.


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Thu Dec 05, 2013 7:53 pm 
Offline
DevNet Resident

Joined: Sun Jun 14, 2009 3:13 pm
Posts: 1146
It was interesting for me to see how this thing works, but I suppose people in the know aren't interested and there are others might get the wrong ideas.


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Thu Dec 05, 2013 9:06 pm 
Offline
Spammer :|
User avatar

Joined: Wed Oct 15, 2008 2:35 am
Posts: 6617
Location: WA, USA
Certainly wouldn't want to hand it to them on silver platter, but on the other hand showing how some of it works helps keep people in the loop regarding the latest exploits.


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Thu Dec 05, 2013 11:08 pm 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13564
Location: New York, NY, US
It might be helpful to explain how it was added into the code, how the backdoor code works, how you detected it, and how to prevent it.

_________________
(#10850)


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Fri Dec 06, 2013 1:57 pm 
Offline
DevNet Resident

Joined: Sun Jun 14, 2009 3:13 pm
Posts: 1146
That sounds like work. :) I was just going to through it all up here for the world, but I immediately had second thoughts. I haven't really looked at backdoor in detail. It has a mix of things going on and I'll need to run it safely to see what it is doing. Perhaps tonight I'll go through it and sanitize it for posting.


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Sat Dec 07, 2013 1:24 am 
Offline
DevNet Resident

Joined: Sun Jun 14, 2009 3:13 pm
Posts: 1146
This backdoor was installed through a zero-day exploit of timthumb.php a common tool used by many Word Press templates. It was patched a long time ago but there are older versions out there and people are still hunting for them. This site owner didn't bother updating anything because "it might break". Ok, fair enough.

I found one instance of weird stuff in the logs going to this file. How the injection worked is the default configuration of timthumb.php which many themes use allow files to be remotely loaded and resized from the following domains (from the old insecure version of timthumb.php:

Syntax: [ Download ] [ Hide ]
$ allowedSites = array (
                'flickr.com',
                'staticflickr.com',
                'picasa.com',
                'img.youtube.com',
                'upload.wikimedia.org',
                'photobucket.com',
                'imgur.com',
                'imageshack.us',
                'tinypic.com',
        );
 

Where:
Syntax: [ Download ] [ Hide ]
foreach ($allowedSites as $site) {
   if(strpos (strtolower ($url_info['host']), $site) !== false) {
       $isAllowedSite = true;
   }
}


The $url_info['host] is pulled from $_SERVER['HTTP_HOST']. This is the one parameter that can be spoofed by injecting interesting things in the host request header and even though that spoofed string doesn't match an actual host on the server, chances are the server will serve up pages for the default host or first virtual host and pass that bogus host header to anything running on that site.

This makes $url_info['host'] suspect. The problem is the way the developer checks which domain he’s fetching from. He uses the PHP
Syntax: [ Download ] [ Hide ]
strpos
function and if the domain string appears anywhere in the hostname, the program will allow that file to be fetched. So easy to make it think you're a trusted allowed site and then upload your shell script. In general HTTP_HOST is not secure from tampering and in this case, the site was compromised by it.

Lesson here: don't trust external data! Note the patched version among other things looks like now:
Syntax: [ Download ] [ Hide ]
if ((strtolower(substr($this->url['host'],-strlen($site)-1)) === strtolower(".$site")) || (strtolower($this->url['host'])===strtolower($site)))

The attacker faked a HTTP_HOST header and got the template to to include a remote PHP file instead of an image and save it on the server.

Boom! They're in. So all they have to do is put in yoursite.com/path/to/shell/attack.php and you're p0wnd.

How was it found? Well fortunately there are sites that check other sites for malicious code. So when the back door was installed, it wasn't enough just to own the site (because they probably found nothing interesting to steal), they started sticking malicious javascripts and pharmaceutical spam (hard to believe the drug companies still think this is a good thing to be paying for spam hackers these days).

The site was flagged by browsers as malware so someone asked for help. So I got SSH access and looked around at the tampered files. Things that stuck out were 3 or 4 template files that had different dates than all the others. These template file had obviously been manipulated from the inside because the javascript was inserted in the templates right before the </head> and the spam content was inserted right after the <body> tags.

What was interesting about this spam injection is the javascript turned off the visibility of the spam content so the owner of the site and the users most likely would never see it (unless they are running with javascript off). Only bots who index the page would pick all that spam stuff about drugs, etc. I guess the term for this type of spam is SEO Spam where users don't see it but the search bots do.

I also found the injected code had be placed there almost a year and a half ago (Feb. 2012)! That back door was open a long time. These template files were also easy to spot because they had all been modified shortly after the backdoor tools had be inserted.

So how did I find the back door? That took about 30 seconds with grep. Using SSH:
Syntax: [ Download ] [ Hide ]
grep -r eval\(base64 *
quickly listed any suspicious activity. I found no less than 2 of the 4 domains had backdoors installed.

Other backdoors don't necessarily need base64 encoding either, so another check with grep and a careful sifting of the results revealed nothing malicious:
Syntax: [ Download ] [ Hide ]
grep -r eval\( *

An idea occurred to me that a less obvious way to hide a backdoor would be to avoid exec and base64 junk and leverage include() and php://input to allow the attacker to execute arbitrary PHP code on the infected server. But this is hard to do through a header injection and would require more steps of uploading/deleting.

Let's look at the back door. It was in a file called wp-admin/images/wp-canto-impart.php (Odd to see php scripts in an images directory, no?)

It looks like this:
Syntax: [ Download ] [ Hide ]
<?php eval(base64_decode("JGs9MTQzOyRtPWV4cGxvZGUoIjsiLCIyM...on and on and on...”);
?>

 

I changed this to:
Syntax: [ Download ] [ Hide ]
var_dump(base64_decode("JGs9MTQzOyRtPWV4cGxvZGUoIjsiLCIyM....blah blah”);


I was surprised to get something still cryptic. I guess this is an attempt to avoid automatic detection.

Syntax: [ Download ] [ Hide ]
$k=143;
$m=explode(";","234;253;253;224;253;208; on and on and on for 1,000's of bytes.....;");$z="";
foreach($m as $v) if ($v!="")$z.=chr($v^$k);
eval($z);
I was thinking this is looking interesting, but then I decoded it saw the first two lines:

Syntax: [ Download ] [ Hide ]
error_reporting(E_ERROR | E_WARNING | E_PARSE);
ini_set('display_errors', "0");
 

This doesn't seem so clever. Why enable errors then turn them off? The code continues by looking for a posted value ($_POST[“p”]) and setting this up as a cookie. Then if it checks if the md5 of this value is NOT "8b291cbed412718742b370a46b95ceb4" and presents a form (which posts the “p” value via a 50 char text box and a “check” button) and stops. I made a few guesses at what hashes to this value, but I didn't have any luck. Perhaps a dictionary search might reveal something.

Assuming you get past the “check” form. The script presents a new form and supports the following commands from $_POST[“action”]: upload, sql, runphp. Upload allows anything to be uploaded remotely. SQL is a to hack at the database. What's interesting is the connection info is also pulled remotely so it looks like there is another automated tool out there designed to access these backdoors:
Syntax: [ Download ] [ Hide ]
$lnk = mysql_connect($_POST["server"], $_POST["user"], $_POST["pass"]) or die ('Not connected : ' . mysql_error());
 

I see they aren't using mysqli so this must be a pretty old backdoor right?

And the last action 'runphp' allows an exec() to execute a remote command to php.

So far pretty basic. Then it gets more interesting with the $_POST["cmd"] values if you don't send an “action”. It checks for disabled functions then it works through a variety of options to send a shell commands (via another form that uses javascript to base64 encode/decode messages) (notice all the message suppression):

I've removed most of the code to just show some of the things it tries:
Syntax: [ Download ] [ Hide ]
                @exec($cmd, $result);
                @system($cmd);
                @passthru($cmd);

            elseif(is_resource($fp = @popen($cmd, "r"))) {
                $result = "";
                while (!feof($fp)) {
                    $result .= @fread($fp, 1024);
                }
                @pclose($fp);
 

I've never seen a resource piped through like that.

This backdoor obviously is also designed to interface with some automated tools using POST. This part of the code looks like it is used manually to poke around in the system, probably try to find some of your database access passwords, maybe user information, and then exploit it.

It was interesting that both backdoors that were installed used different filenames, probably pulled from a dictionary, but the code was the same even though they were installed months apart. Whoever did it must not have bothered to explore the system enough to discover the other sub-domains which would have only taken about 3 minutes to locate.

It would have been interesting to make a honey-pot version of this script and replace it. But the site owner wasn't interested and wanted it gone.


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Sun Dec 08, 2013 12:46 am 
Offline
Site Administrator
User avatar

Joined: Wed Aug 25, 2004 7:54 pm
Posts: 13564
Location: New York, NY, US
Interesting read. It is amazing the amount of work that goes into creating backdoors like this. Sort of a shame they aren't putting their talent into creating beneficial software. Thanks for the writeup.

_________________
(#10850)


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Tue Dec 10, 2013 12:06 am 
Offline
DevNet Resident

Joined: Sun Jun 14, 2009 3:13 pm
Posts: 1146
It's sort of telling that they have to password protect their own backdoors to keep out other hackers. I'm about 50% through 7.8 trillion hashs on cmd5 to see if it turns up anything on the backdoor hash. I was going to have a good laugh if was something simple...but I don't think that's the case.


Top
 Profile  
 
 Post subject: Re: PHP Backdoor Example
PostPosted: Tue Dec 10, 2013 8:57 pm 
Offline
DevNet Resident

Joined: Sun Jun 14, 2009 3:13 pm
Posts: 1146
75% into the hash lookup and nothing found. I do have to take back my comments about the opening lines of the shell. I found the
Syntax: [ Download ] [ Hide ]
error_reporting(E_ERROR | E_WARNING | E_PARSE);
turns off the E_NOTICE option which suppresses the reporting of undefined variables. Apparently the
Syntax: [ Download ] [ Hide ]
ini_set('display_errors', "0");
isn't enough. (I'm working on a honey-pot version for the future.)


Top
 Profile  
 
Display posts from previous:  Sort by  
Post new topic Reply to topic  [ 10 posts ] 

All times are UTC - 5 hours


Who is online

Users browsing this forum: No registered users and 2 guests


You cannot post new topics in this forum
You cannot reply to topics in this forum
You cannot edit your posts in this forum
You cannot delete your posts in this forum
You cannot post attachments in this forum

Jump to:  
cron
Powered by phpBB® Forum Software © phpBB Group