[备份]浅谈 JSP Webshell 进阶免杀

0x00 简介

前段时间笔者在研究AST相关技术和JS的混淆技巧,无意间想到,能否将一些技术和思路应用在Webshell的免杀呢?

于是尝试编写了一个自动生成免杀Webshell的工具

笔者目前本科在读,才疏学浅,错误和不足之处还请大佬指出,十分感谢!

 

0x01 从一句话开始

首先从一句话角度来做,给出JSP的一句话

这个Webshell是会直接被Windows Defender杀的,百度WEBDIR+也会杀

尝试拆开一句话,再加入回显和消除乱码,得到这样的代码

绕过了Windows Defender和百度WEBDIR+

然而我们不能满足于当前的情况,因为这些平台的查杀力度并不是很强

再这个基础上,可以加入反射调用来做进一步的免杀

以上的情况其实已经做到了足够的免杀,但是否能够进一步做免杀呢

 

0x02 控制流平坦化

在反射调用的基础上结合控制流平坦化的思想后,会达到怎样的效果呢

(对于控制流平坦化的概念笔者其实并不是非常清晰,大致来说就是将代码转为switch块和分发器)

以下是上文反射代码修改后的结果,可以手动也可以写脚本来生成,这并不是本文的重点

注意到在开头定义了0|1|2|3|4|5|6|7|8|9|10|11|12这样的字符串,其中数字的顺序对应了switch块中的执行顺序,当前是从第0条到第12条执行

在进入switch之前,需要实现声明变量,否则在Java的语法下,单一case语句的变量无法被其他case语句获取

当执行完命令后,变量index会超过最大索引,导致报错停止脚本,所以并不会出现占用服务端资源的情况

然而在这种情况下,分发器中的数字顺序是一定的,case块的顺序也是一定的,所以需要打乱这些变量实现混淆和免杀

笔者使用了Java的AST库JavaParser解析代码并实现这样的功能

打乱switch-case块的代码

经过打乱后的效果还是比较满意的

 

0x03 异或加密数字

异或加密很简单:a^b=c那么a^c=b

如果a变量是加密的目标,我们就可以随机一个b,计算得到的c和b异或回到原来的a

对于其中的数字,可以采用异或加密,并可以使用多重

而笔者发现其中的数字变量其实并不够多,那么如何造出来更多的数字变量呢?

把字符串变量都提到全局数组,然后用数组访问的方式使用字符串

这时候的globalArr[1]调用方式就可以用异或加密了

双重异或加密后的效果

 

0x04 加密字符串常量

还剩一部,其中提取的globalArr中的字符串是明文的

加密的算法必须是可逆的,因为在执行的时候需要取出来还原

笔者选择了比较简单的恺撒加密,没有使用复杂的AES等加密

由于恺撒加密无法对特殊字符加密,所以最终选择了Base64加恺撒加密的做法

给出网上找到的算法,在这个基础上做了修改

注意到恺撒密码需要一个偏移量,所以需要保存下这个偏移写入JSP

重点来了,在被加密的字符串调用的时候需要添加上解密函数

效果是:globalArr[1] -> dec(global[1])

处理后的结果,结合异或加密来看效果很不错

 

0x05 标识符随机命名

还差一步,需要对其中所有的标识符进行随机命名

这一步不难,拿到所有的NameExpr对name属性做修改即可

 

0x06 反射马最终处理

最后需要在JSP开头处塞入解密方法,而解密方法也可以进行除了恺撒加密这一步以外的其他手段

反射调用Webshell的例子经过处理后,最终的结果如下

 

0x07 Javac动态编译

三梦师傅提供的Javac动态编译免杀马也可以进一步处理,在工具中已经实现

在JSP中构造命令执行的Java代码动态编译并执行实现Webshell

其中append很多字符串而不直接写,为了更好地恺撒加密和异或加密

处理前的原版Webshell如下:

 

0x08 ScriptEngine免杀

参考天下大木头师傅的ScriptEngine调用JS免杀马,在工具中完成了进一步的免杀

其中append很多字符串而不直接写,一方面为了更好地恺撒加密和异或加密,另外考虑是防止java.lang.Runtime这样的黑名单检测

处理前的原版Webshell如下:

 

0x09 Expression免杀

使用java.beans.Expression类进行免杀,原理较简单,已在工具中实现

处理前的原版Webshell如下:

 

0x0a BCEL字节码免杀

来自Java安全界比较知名的BCELClassLoader,不过对于JDK的版本有一定的限制

在工具中实现了静态BCEL字节码和ASM动态构造的两种免杀Webshell

处理前的静态JSP如下:

处理前的动态构造字节码JSP如下:

 

0x0b defineClass0免杀

思路来自su18师傅的代码,核心思想是加载字节码执行实现Webshell功能,在工具中实现

由于defineClass0native方法,理论上可以绕过一些检测

由于JVM加载了字节码中的某个类,所以该Webshell只有一次执行命令的能力,第二次运行同样的JSP会导致类重复

想要第二次执行必须上传一个字节码的类名不同的Webshell

笔者使用ASM技术实现了随机类名的功能,可以做到每次生成的Webshell的字节码的类名不同

处理前的原版Webshell如下:

其中的字节码是该类,一个普通类,在构造方法中实现简单的回显Webshell

如果该类被实例化就会执行命令,实现Webshell的功能

为何不直接构造字节码,然后加载执行实现Webshell呢

于是笔者用JDK自带的ASM实现了ByteCodeEvil

(注意一定要用自带ASM,因为目标机器一定有JDK但不一定有第三方依赖库)

处理前的原版Webshell如下:

注意该Webshell和上文一样,只能执行一次

如果想多次执行,需要类名不同,而这里实现类名不同非常简单,修改sample/ByteCodeEvil即可

 

0x0c 蚁剑免杀处理

笔者尝试用了以上的方法(0x02-0x05)和花指令等其他小手段,最后实现了蚁剑Webshell的处理,不知道免杀效果如何

处理前的原版Webshell如下:

处理后

 

0x0e 总结

以上的免杀手段是否真正有用,笔者并不是很确定,因为已有的线上webshell查杀平台强度似乎不高

最终总结下,其实在已有的免杀技术上加入混淆技术不一定能够提高免杀能力,因为例如method.invoke等关键类和方法的调用并没有改变,但这也是一种尝试