本文分享一下defineClass在反序列化漏洞当中的使用场景,以及在exp构造过程中的一些使用技巧,马上进入正题。

0×00 前言

 首先看一下defineClass的官方定义

 Clipboard Image.png

众所周知,java编译器会将.java文件编译成jvm可以识别的机器代码保存在.class文件当中。正常情况下,java会先调用classLoader去加载.class文件,然后调用loadClass函数去加载对应的类名,返回一个Class对象。而defineClass提供了另外一种方法,从官方定义中可以看出,defineClass可以从byte[]还原出一个Class对象,这种方法,在构造java反序列化利用和漏洞poc时,变得非常有用。下面总结我在实际分析漏洞和编写exp时的一点儿体会,具体有如下几种玩法.

0×01 defineCLass无文件注入构造回显

这里以java原生的java.io.ObjectInputStreamread的readObject()作为反序列化函数,以commons-collections-3.1作为payload,注入类文件代码如下

Clipboard Image.png

常规的回显思路是用URLClassLoader去加载一个.class或是.java文件,然后调用loadClass函数去加载对应类名,返回对应的Class对象,然后再调用newInstance()实例出一个对象,最后调用对应功能函数,使用例如throw new Exception(“genxor”);这样抛错的方法,将回显结果带出来。例如

Clipboard Image.png

回显结果如下所示:

Clipboard Image.png

但是前提是要先写入一个.class或是.jar文件(写入方法这里不描述,使用FileOutputStream类,方法大同小异),这样显得拖泥带水,而且让利用过程变得很复杂。

那可不可以不写文件而直接调用我们的代码呢,使用defineClass很好的解决了这个问题。将我们编译好的.class或是.jar文件转换成byte[]放到内存当中,然后直接用defineClass加载byte[]返回Class对象。那怎么调用defineClass函数呢,因为默认的defineClass是java.lang.ClassLoader的函数,而且是protected属性,无法直接调用(这里暂且不考虑反射),而且java.lang.ClassLoader类也无法被transform函数加载,这里我们使用org.mozilla.classfile.DefiningClassLoader类, 代码如图

Clipboard Image.png

他重写了defineClass而且是public属性,正好符合我们要求,这里我写个具体事例,代码如下

Clipboard Image.png

回显结果如下所示

Clipboard Image.png

根据这个思路,我们构造transformerChain生成map对象,代码如图所示

Clipboard Image.png

0×02 fastjson利用

fastjson早期的一个反序列化命令执行利用poc用到了

com.sun.org.apache.bcel.internal.util.ClassLoader,首先简单说一下漏洞原理,如下是利用poc的格式

 Clipboard Image.png

fastjson默认开启type属性,可以利用上述格式来设置对象属性(fastjson的type属性使用不属于本文叙述范畴,具体使用请自行查询)。tomcat有一个tomcat-dbcp.jar组件是tomcat用来连接数据库的驱动程序,其中org.apache.tomcat.dbcp.dbcp.BasicDataSource类存在如下代码,如图所示

 Clipboard Image.png 

当com.alibaba.fastjson.JSONObject. parseObject解析上述json的时候,代码会上图中Class.forName的逻辑,同时将driverClassLoader和driverClassName设置为json指定的内容,到这里简单叙述了一下fastjson漏洞的原理,一句话概括就是利用fastjson默认的type属性,操控了相应的类,进而操控Class.forName()的参数,可以使用任意ClassLoader去加载任意代码,达到命令执行的目的。

这里详细说一下利用Class.forName执行代码的方法,有两种方式:

1 Class.forName(classname)

2 Class.forName(classname,true, ClassLoaderName)

先说第一种,通过控制classname执行代码,这里我写了一个demo,如图所示

Clipboard Image.png

 Clipboard Image.png

这里利用了java的一个特性,利用静态代码块儿static{}来执行,当com.fastjson.pwn.run被Class.forName加载的时候,代码便会执行。

 Clipboard Image.png

 

这里用到了com.sun.org.apache.bcel.internal.util.ClassLoader这个classloader,而classname是一个经过BCEL编码的evil.class文件,这里我给出evil.java的源码,如图所示

Clipboard Image.png

classloader会先把它解码成一个byte[],然后调用defineClass返回Class,也就是evil 

具体我们跟一下代码逻辑,如图所示

Clipboard Image.png

这里会开始调用com.sun.org.apache.bcel.internal.util.ClassLoader的loadClass加载类,如图所示

Clipboard Image.png

这里判断classname如果经过了BCEL编码,则解码获取Class文件,如图

Clipboard Image.png

此刻内存中evil.class文件的结构,如图所示

Clipboard Image.png

继续跟踪后面的逻辑,如图

Clipboard Image.png 

这里调用defineClass还原出evil.class中的evil类,因为使用static{},所以在加载过程中代码执行。

OK 回到fastjson漏洞逻辑,因为控制了Class.forName加载的类和ClassLoader,所以可以通过调用特定的ClassLoader去加载精心构造的代码,从而执行我们事先构造好的class文件,从而达到执行任意代码的目的。

0×03 jackson利用

jackson的反序列化命令执行跟fastjson类似,也似注入一个精心构造的pwn.class文件,最后通过newInstance实例对象触发代码执行。这里先给出pwn.java的源码,如图所示:

Clipboard Image.png

然后写了一个Demo,触发漏洞,代码如下

Clipboard Image.png

jackson类似fastjson可以通过type属性,设置变量的值,但是不同时jackson默认不开启type,需要mapper.enableDefaultTyping()设置开启。

 Clipboard Image.png

当readValue这段json的时候,触发命令执行漏洞,下面调试一下关键步骤,如图

Clipboard Image.png 

这里defineTransletClasses会解码transletBytecodes成byte[],并执行defineClass得到foo.pwn这个类,然后在后面执行newInstance导致static{}静态代码块儿执行,如图

 Clipboard Image.png

成功触发,如图所示

Clipboard Image.png

作者:阿里安全