freeBuf
主站

分类

云安全 AI安全 开发安全 终端安全 数据安全 Web安全 基础安全 企业安全 关基安全 移动安全 系统安全 其他安全

特色

热点 工具 漏洞 人物志 活动 安全招聘 攻防演练 政策法规

点我创作

试试在FreeBuf发布您的第一篇文章 让安全圈留下您的足迹
我知道了

官方公众号企业安全新浪微博

FreeBuf.COM网络安全行业门户,每日发布专业的安全资讯、技术剖析。

FreeBuf+小程序

FreeBuf+小程序

Z3专栏 | Java代码审计之CommonCollection2分析
2021-12-15 21:29:44
所属地 辽宁省

七、CommonCollection2

本篇文章基础有:
队列
优先队列

分析

代码分析

首先还是先看下代码

这个和1、6两条链有点不一样了,这里没用Map,而是Queue

看下第一行代码

public static Object createTemplatesImpl(String command) throws Exception {
    return Boolean.parseBoolean(System.getProperty("properXalan", "false"))
    ?
    createTemplatesImpl(
        command, 
        Class.forName("org.apache.xalan.xsltc.trax.TemplatesImpl"),
        Class.forName("org.apache.xalan.xsltc.runtime.AbstractTranslet"), 
        Class.forName("org.apache.xalan.xsltc.trax.TransformerFactoryImpl")
    )
    :
    createTemplatesImpl(
        command, 
        TemplatesImpl.class, 
        AbstractTranslet.class, 
        TransformerFactoryImpl.class
    );
}

首先获得系统属性值properXalan
如果返回值为 true 则通过反射创建这三个Class对象
如果返回值为 false或者没有找到 properXalan 属性 , 则直接调用三个类的Class对象(java会自动为每一个类创建Class对象,使用类名.class就能获取到)

properXalan是什么?
不知道,网上搜这个全是关于这条链的分析,但都是互相抄来抄去,没人介绍properXalan,这个问题先跳过

继续看createTemplatesImpl方法

看不懂,反正是将cmd命令写入了templates
继续看下面代码

InvokerTransformer transformer = new InvokerTransformer("toString", new Class[0], new Object[0]);
PriorityQueue<Object> queue = new PriorityQueue(2, new TransformingComparator(transformer));

创建了一个InvokerTransformer,反射调用的方法是toString
创建了一个优先队列,大小为2,第二个参数看起来像是比较的,创建了一个用来比较优先级的Transformer
看下TransformingComparator构造函数


如图,将上面构造的transformer对象保存在了TransformingComparator对象的transformer变量里

然后在队列里连续添加了两个1
然后修改transformer的iMethodName为newTransformer,即transformer反射调用的是newTransformer方法
然后通过反射获取了queue对象的queue数组

将第一个元素设为templates
第二个元素为1

然后,,这,就结束了
好吧,再调试一遍反序列化的过程

调试分析反序列化过程

代码如下,反序列化时虽然报错,但是成功弹出计算器了

之前已经调试过很多次ObjectInputStream的readObject方法了
直接看ObjectInputStream的readSerialData吧,在这个方法内,通过递归反序列化出完整的对象
如图,通过desc可以看见当前正在被反序列化的对象

经过反复调试,最终发现
PriorityQueue对象的readObject方法内调用了heapify(这个函数是用来把数组转堆的,方便排序),导致弹出计算器
看一下代码

代码执行到了siftDownUsingComparator
如图

可以看见,这里的cmp就是之前代码里的TransformingComparator对象,
如图,调用了transform方法
回想一下,这个transformer对象是InvokerTransformer类型,反射方法是newTransformer
也就是这里会调用obj1的newTransformer方法,而obj是通过Gadgets.createTemplatesImpl创建的,包含了命令的对象

如图,就是这句代码,执行后弹出计算器

好,总结下

总结

首先是PriorityQueue在反序列化时
如图,会先把队列内的数据存到数组中,然后调用heapify方法,将数据按堆排列

在构建堆的过程中,会通过TransformingComparator比较两个元素,
而TransformingComparator会对比较的两个数据通过transformer进行处理,而transformer正是前面构造好的,反射调用newTransformer方法的InvokerTransformer对象
而队列中的两个元素分别是TemplatesImpl对象和1
在对他们比较时,InvokerTransformer对象调用了TemplatesImpl的newTransformer方法,导致rce

所以,这条利用链分为几部分
一、构造TemplatesImpl对象,在被调用newTransformer方法时,就会导致rce
二、构造InvokerTransformer对象,通过反射调用对象的newTransformer方法
三、构造PriorityQueue对象,PriorityQueue对象在反序列化时需要构建堆,就需要比较元素,比较元素时通过TransformingComparator对象比较,而TransformingComparator对象比较时会调用Transformer对象,而Transformer对象是第二步构造的InvokerTransformer对象

所以利用链是:
PriorityQueue的readObject->TransformingComparator的cmpare->InvokerTransformer通过反射调用TemplatesImpl的newTransformer方法->导致rce

填坑

上面还有个问题没解决,TemplatesImpl对象是什么?怎么构建的?为什么调用它的newTransformer方法会命令执行
写代码调试一下,,结果,,TemplatesImp对象不能调用newTransformer方法?

代码改写一下,可以运行了,但是不会弹计算器

反复对比刚才反序列化的场景,感觉一毛一样啊
又仔细对比了下
有两个TemplatesImpl包,一个是ysoserial自带的,一个是jdk的
而jdk的包不允许直接import(好像是JDK 9开始的模块封装)

看一下com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl包,,结果里面有newTransformer方法,而且是public,看来是因为模块封装,导致不能调用的

再调试下反序列化过程,发现红框这里弹出了计算器,,看起来是创建了一个对象,,对象名是一串数字

而在执行蓝框之前,_class为null
看一下defineTransletClasses方法,在这里,从_bytecodes中加载了_class

回想一下,之前在Gadgets.createTemplatesImpl方法中设置过_bytecodes
所以是因为TemplateImpl的getTransletInstance方法,实例化了Gadgets.createTemplatesImpl中构造的_bytecodes,导致rce

所以现在看下Gadgets.createTemplatesImpl,如何构造的_bytecodes
之前这里没看懂,调试了下ClassPool对象,,越看越复杂,,网上查了下,原来这个是属于Javassist库
Javassist库是一个Java字节码类库,java程序编译好后都是后缀为.class文件,这就是由字节码组成的
通过Javassist库可以处理字节码
现在再来看下这段代码,它是如何生成字节码

ClassPool pool = ClassPool.getDefault(); // getDefault 方法返回一个单例模式的ClassPool对象
pool.insertClassPath(new ClassClassPath(AbstractTranslet.class)); // 把AbstractTranslet类的路径添加进pool对象(一会下面创建AbstractTranslet对象会用到)
CtClass clazz = pool.makeClass(String.valueOf(System.nanoTime())); // 创建一个空类,类名是系统时间(纳秒)
String cmd = DirectiveProcessor.process(command); // 通过需要执行的命令,构造了一段代码
clazz.makeClassInitializer().insertAfter(cmd); // 通过makeClassInitializer创建了静态代码块,并将上一步构造好的代码,插入到静态代码块
CtClass superC = pool.get(AbstractTranslet.class.getName()); // 通过AbstractTranslet创建了CtClass对象
clazz.setSuperclass(superC); // 设置包含命令执行代码的对象的父类为AbstractTranslet
byte[] classBytes = clazz.toBytecode(); // 包命令执行对象转bytecode即字节码

这个CtClass和Class有点像,都是用来储存类信息的,但是Class对象正常是不能由开发者创建的,是由jvm创建的,开发者只能通过.class属性值或getClass、forName方法去获取到
分析下过程
这里创建了CtClass对象,然后写入静态代码块,设置父类为AbstractTranslet,然后转字节码
静态代码块在讲反射时讲过,当加载类时,会先执行静态代码块里的内容
设置父类为AbstractTranslet是为了在TemplatesImpl中可以执行newTransformer时可以正常创建AbstractTranslet对象

还有个问题就是,怎么构造静态代码块里内容的?
看下DirectiveProcessor.process的代码

构造好了之后是这样的

java.lang.Runtime.getRuntime().exec("calc");

ok,至此,完全明白了CommonsCollections2利用链的利用细节

现在想一下,为什么我刚开始写的代码不能触发rce?

因为这里构造的templates对象,虽然包含了字节码,但是字节码是通过反射,illegal的方式写入的,所以这个templates对象是不完整的
templates对象内_tfactory的值为null,在加载字节码时,会用到它,所以这时就会异常退出
而templates对象反序列化时,不仅读取出了字节码信息,还创建了_tfactory对象(反序列化时创建了完整的templates对象)

再总结下

再总结

  1. 首先通过Javassist库,创建一个字节码类,这个类包含静态代码块,里面是命令执行代码,它的父类是AbstractTranslet

  2. 创建个空的TemplatesImpl对象,把它的_bytecode值改为1中的字节码

  3. 构造InvokeTransformer对象,可以通过反射调用newTransformer方法

  4. 构造优先级队列,添加两个元素,创建TransformingComparator对象,而TransformingComparator对象内部实现是通过InvokeTransformer对象对象

所以在反序列化优先级队列时,,会重新构建堆->调用TransformingComparator的compare方法->InvokeTransformer的transform方法->TemplatesImpl的newTransformer方法->getTransletInstance方法加载了字节码,实例化对象->加载了字节码中的恶意静态代码块,导致rce

ok,至此CommonCollection2学习完毕

# java漏洞 # java # java反序列化 # Java代码审计 # JAVA安全
免责声明
1.一般免责声明:本文所提供的技术信息仅供参考,不构成任何专业建议。读者应根据自身情况谨慎使用且应遵守《中华人民共和国网络安全法》,作者及发布平台不对因使用本文信息而导致的任何直接或间接责任或损失负责。
2. 适用性声明:文中技术内容可能不适用于所有情况或系统,在实际应用前请充分测试和评估。若因使用不当造成的任何问题,相关方不承担责任。
3. 更新声明:技术发展迅速,文章内容可能存在滞后性。读者需自行判断信息的时效性,因依据过时内容产生的后果,作者及发布平台不承担责任。
本文为 独立观点,未经授权禁止转载。
如需授权、对文章有疑问或需删除稿件,请联系 FreeBuf 客服小蜜蜂(微信:freebee1024)
被以下专辑收录,发现更多精彩内容
+ 收入我的专辑
+ 加入我的收藏
相关推荐
  • 0 文章数
  • 0 关注者
文章目录