- 使用当前线程的上下文类加载器,或无法控制类加载器时,可能存在同一类名无法加载两次的情况,需要额外处理;
- 在使用例如 BCEL ClassLoader 等特殊的 ClassLoader 时,由于跨类加载加载的问题,需要通过纯反射对一些类和接口进行访问和调用,面临比较大的体力工作。
在漏洞利用的过程中进行动态类加载时,普遍的情况是需要人为的打破双亲委派机制,将恶意类注入到系统中。
与类加载息息相关的就是类的初始化,通常在恶意代码中,会写一些初始化的恶意逻辑,一般可以写在 static 语句块或 public 无参构造方法中:
- static 语句块在类加载的时候执行一次,在其生命周期只执行一次;
- public 无参构造方法在类初始化的时候进行调用,每次新建类实例会调用。
因此,可以根据具体的情况选择类加载器,与将恶意逻辑放置在什么位置。
2. 回显与内存马
在 Goby 反序列化打入内存马的插件上线后,我对漏洞库中反序列化漏洞的利用均进行了增强与修正。
熟悉 Goby 的朋友可能知道,Goby 对于漏洞利用的检测分为 PoC 与 EXP,在面对 Java 原生反序列化时,原本的检测和利用程序为:
- PoC 使用 URLDNS 配合 Goby 自带的 dnslog 平台 GodServer 进行漏洞检测;
- EXP 使用 YSOSERIAL 的字节码,动态替换命令执行部分的 hex 值,进行命令执行的写入。
使用上述逻辑漏洞的检出,是大部分人员面对反序列化漏洞的检测方式,技术上这种检测方式并没有问题,但是实际执行中会遇到如下问题:
- 由于网络或 DNSLOG 平台不稳定,可能导致收不到 DNSLOG 的问题,或者 DNSLOG 有较长的延时;
- 漏洞利用仅仅进行命令执行,时常无法得知漏洞利用是否成功,也无法知道漏洞执行的结果;
- 在不出网的情况下,无法进行反弹 shell,也无法执行更高级的动作,对实战来说,实用性很差。
因此,为了解决实战化的可用性问题,在后续更新的漏洞利用 PoC 均采用了回显的技术,将命令执行的结果返回 response 中;而 EXP 中则是直接打入内存马,节省了中间的很多过程。
在构造回显时,则涉及到关键 request 的定位,搜索内存等技术点,而内存马的打入,则又需要针对漏洞环境准备高可用的内存马,有了这些技术加持,可以解决上面提到的问题,无需第三方 dnslog、OOB 等,直接进行漏洞的高精准检测与利用。
3. 条条大路通内存马
漏洞种类有非常多,能提供任意代码执行的种类也非常多,例如 Java 原生反序列化漏洞、Fastjson/Jackson/XStream 反序列化漏洞、SpEL/Ognl 等表达式注入等。但有很多情况需要额外的利用方式,才能打通漏洞利用的流程,这里以原生反序列化利用为例,列举一些利用链的改造,使其直接可以进行内存马的打入。
Transformer[]
利用链,最经典的利用链,一般是 chain 一个Runtime.getRuntime().exec()
或者new ProcessBuilder().start()
来进行命令执行,如果想执行一些额外的功能,还可以使用new URLClassLoader().loadClass()
来进行远程类加载,在不出网的情况下,可以通过com.sun.org.apache.bcel.internal.util.ClassLoader.loadClass()
、org.mozilla.javascript.DefiningClassLoader().defineClass()
、new ScriptEngineManager().getEngineByName("JavaScript").eval()
的方式写入 JS 进行恶意类的打入,一键利用内存马。