作者:阿里安全归零实验室
来源:https://xz.aliyun.com/t/2272
本文分享一下defineClass在反序列化漏洞当中的使用场景,以及在exp构造过程中的一些使用技巧
首先看一下defineClass的官方定义
众所周知,java编译器会将.java文件编译成jvm可以识别的机器代码保存在.class文件当中。正常情况下,java会先调用classLoader去加载.class文件,然后调用loadClass函数去加载对应的类名,返回一个Class对象。而defineClass提供了另外一种方法,从官方定义中可以看出,defineClass可以从byte[]还原出一个Class对象,这种方法,在构造java反序列化利用和漏洞poc时,变得非常有用。下面总结我在实际分析漏洞和编写exp时的一点儿体会,具体有如下几种玩法.
这里以java原生的java.io.ObjectInputStreamread的readObject()作为反序列化函数,以commons-collections-3.1作为payload,注入类文件代码如下
常规的回显思路是用URLClassLoader去加载一个.class或是.java文件,然后调用loadClass函数去加载对应类名,返回对应的Class对象,然后再调用newInstance()实例出一个对象,最后调用对应功能函数,使用例如throw new Exception("genxor");这样抛错的方法,将回显结果带出来。例如
回显结果如下所示:
但是前提是要先写入一个.class或是.jar文件(写入方法这里不描述,使用FileOutputStream类,方法大同小异),这样显得拖泥带水,而且让利用过程变得很复杂。
那可不可以不写文件而直接调用我们的代码呢,使用defineClass很好的解决了这个问题。将我们编译好的.class或是.jar文件转换成byte[]放到内存当中,然后直接用defineClass加载byte[]返回Class对象。那怎么调用defineClass函数呢,因为默认的defineClass是java.lang.ClassLoader的函数,而且是protected属性,无法直接调用(这里暂且不考虑反射),而且java.lang.ClassLoader类也无法被transform函数加载,这里我们使用org.mozilla.classfile.DefiningClassLoader类, 代码如图
他重写了defineClass而且是public属性,正好符合我们要求,这里我写个具体事例,代码如下
回显结果如下所示
根据这个思路,我们构造transformerChain生成map对象,代码如图所示
fastjson早期的一个反序列化命令执行利用poc用到了 com.sun.org.apache.bcel.internal.util.ClassLoader,首先简单说一下漏洞原理,如下是利用poc的格式
fastjson默认开启type属性,可以利用上述格式来设置对象属性(fastjson的type属性使用不属于本文叙述范畴,具体使用请自行查询)。tomcat有一个tomcat-dbcp.jar组件是tomcat用来连接数据库的驱动程序,其中org.apache.tomcat.dbcp.dbcp.BasicDataSource类存在如下代码,如图所示
当com.alibaba.fastjson.JSONObject. parseObject解析上述json的时候,代码会上图中Class.forName的逻辑,同时将driverClassLoader和driverClassName设置为json指定的内容,到这里简单叙述了一下fastjson漏洞的原理,一句话概括就是利用fastjson默认的type属性,操控了相应的类,进而操控Class.forName()的参数,可以使用任意ClassLoader去加载任意代码,达到命令执行的目的。
这里详细说一下利用Class.forName执行代码的方法,有两种方式:
先说第一种,通过控制classname执行代码,这里我写了一个demo,如图所示
这里利用了java的一个特性,利用静态代码块儿static{}来执行,当com.fastjson.pwn.run被Class.forName加载的时候,代码便会执行。
第二种,通过控制classname和classloader执行代码,我写了一个demo,以com.sun.org.apache.bcel.internal.util.ClassLoader这个类为例子,如图所示
这里用到了com.sun.org.apache.bcel.internal.util.ClassLoader这个classloader,而classname是一个经过BCEL编码的evil.class文件,这里我给出evil.java的源码,如图所示
classloader会先把它解码成一个byte[],然后调用defineClass返回Class,也就是evil
具体我们跟一下代码逻辑,如图所示
这里会开始调用com.sun.org.apache.bcel.internal.util.ClassLoader的loadClass加载类,如图所示
这里判断classname如果经过了BCEL编码,则解码获取Class文件,如图
此刻内存中evil.class文件的结构,如图所示
继续跟踪后面的逻辑,如图
这里调用defineClass还原出evil.class中的evil类,因为使用static{},所以在加载过程中代码执行。
OK 回到fastjson漏洞逻辑,因为控制了Class.forName加载的类和ClassLoader,所以可以通过调用特定的ClassLoader去加载精心构造的代码,从而执行我们事先构造好的class文件,从而达到执行任意代码的目的。
jackson的反序列化命令执行跟fastjson类似,也似注入一个精心构造的pwn.class文件,最后通过newInstance实例对象触发代码执行。这里先给出pwn.java的源码,如图所示:
然后写了一个Demo,触发漏洞,代码如下
jackson类似fastjson可以通过type属性,设置变量的值,但是不同时jackson默认不开启type,需要mapper.enableDefaultTyping()设置开启。
当readValue这段json的时候,触发命令执行漏洞,下面调试一下关键步骤,如图
这里defineTransletClasses会解码transletBytecodes成byte[],并执行defineClass得到foo.pwn这个类,然后在后面执行newInstance导致static{}静态代码块儿执行,如图
成功触发,如图所示
利用defineClass在运行时状态下,将我们精心构造的class文件加载进入ClassLoader,通过java的static{}特征,导致代码执行。
以上测试代码全部保存在: https://github.com/genxor/Deserialize.git
阿里安全归零实验室成立于2017年11月,实验室致力于对黑灰产技术的研究,愿景通过技术手段解决当前日益严重的网络违规和网络犯罪问题,为阿里新经济体保驾护航。实验室与寄生在阿里生态经济体的黑灰产直面技术对抗,以打造一流的以情报驱动的黑灰产情报体系能力,看清黑灰产风险、领先黑灰产、演练风险为愿景,重点研究业务安全和数据安全领域中黑灰产风险事件背后的产业链和手法,解决相关风险问题。以情报外部视角切入,在多个安全风险领域内均取得了不错的成绩;以蓝军真实黑灰产视角,模拟黑灰产进行演练攻击,检验防线,为阿里巴巴经济体保驾护航贡献了一份独特的力量。
目前团队也在不断的招聘各种优秀人才,研发专家、数据分析专家、情报分析与体系化专家等,欢迎加盟,联系邮箱 联系:[email protected]