0x01 回顾
我们先来回顾下之前分析TransformedMap CC1链的过程:
首先我们找到在Transformer接口的实现类InvokerTransformer的transform()中,我们可以控制传入的参数,调用任意对象的任意方法,这是关键点;接着我们找到TransformedMap的checkSetvalue()方法会调用transform(),而checkSetvalue()方法会在我们遍历TransformedMap得到Map.Entry后,再调用setValue()时会被调用;最后我们找到在AnnotationInvocationHandler的readObject()方法中若满足一定条件会调用setValue()方法。从而经过我们的精心构造,得到一条TransformedMap CC1链。对于具体细节,如果不记得了,可以回看。
在第二步中,其实我们当时还找到了在LazyMap.get()方法中也调用到了transform():
今天我们就来学下Ysoserial中是如何使用LazyMap来构造CC1链的。
0x02 LazyMap
我们先来看下LazyMap这个类:
实现了Serializable接口,可序列化;有一个Transformer类型的factory属性,构造器为protected的,但可通过decorate()方法获取到一个LazyMap,这与TransformedMap很类似。
重点看get()方法:LazyMap,“懒”Map,大概就来自get()方法的特点吧。如果要找的key不在map中,就会调用factory.transform(key)去“创造”一个value。而factory是Transformer类型,这就和之前那一系列实现了Transformer接口的类拼接起来了,我们编写如下代码就可弹计算器:
那么什么地方又会调用到get()呢?
当我们兴冲冲地想通过find usages去找什么地方调用get()时:
这可咋玩哦?get这个方法太常见了,以致于出现了这么多,菜鸟的我不知道该怎么挑了。那来看下Ysoserial的作者是怎么玩的吧~
0x03 Ysoserial高端玩法
1.sun.reflect.annotation.AnnotationInvocationHandler再认识
学了动态代理,当我们再来看这个类时,它不仅可以序列化,而且还实现了InvocationHandler接口。(坏笑)
那我们就自然会看到它的invoke()方法:会先得到调用的方法名member,参数类型paramTypes,然后判断是否为equals,toString,hashCode,annotationType 方法,如果不是那就会调用memberValues.get(),而memberValues为一个Map。假如这里的memberValues为LazyMap,那么只要不满足前面的if条件且LazyMap中键名没有和调用方法名一样的,就会进入到我们构造的链子中。
那么怎么才能调用到invoke呢?
2.动态代理的应用
我们只要使用Proxy创建一个代理实例,将我们构造的AnnotationInvocationHandler对象作为调用处理器传入。想一想,这里Proxy应代理哪个类型?我们先来看看AnnotationInvocationHandler的readObject()方法:
然后做出回答:只能是Map类型!
因为AnnotationInvocationHandler.readObject()是我们反序列化的入口,所以我们还得再用AnnotationInvocationHandler对象去包装Proxy创建的代理实例,再序列化;而其反序列化时会调用memberValues的entrySet()方法,我们希望memberValues为我们创建的代理实例,这样反序列化时才会调用到invoke(),从而进入到我们构造的链子当中。而memberValues为Map类型,故此处Proxy只能创建Map类型的代理实例。
0x04 POC 编写
结合上面的分析以及之前的TransformedMap CC1链的POC代码,我们可以写出下面的POC:
这里handler中的第一个参数,只要是继承了Annotation接口的class类型就可以。这个跟TransformedMap CC1中不太一样,因为这里我们不需要进入到AnnotationInvocationHandler.readObject()中for循环的第二个if条件句中。
Gadget chain为:
然后我们再去看下Ysoserial的代码:
主要的区别有两个:
第一:在POC的最后才将执行命令的Transformer数组设置到transformerChain中。
第二:ysoserial中的Transformer数组,最后会增加一个ConstantTransformer(1) 。
我参考了p神在《JAVA安全漫谈》中说的,大概是这样:
第一个是因为在使用Proxy代理了map对象后,在任何地方执行map的方法就会触发Payload弹出计算器,会导致在本地调试代码的时候,不经意间触发了命令,弹出两个计算器(在本菜鸟这里都是只弹了一个~)。所以Ysoserial做了处理,先传一个人畜无害的transformerChain,最后才将执行命令的Transformer数组设置到transformerChain中,以避免本地生成序列化流的程序执行到命令(在调试程序的时候可能会触发一次Proxy#invoke )
第二个可能是为了隐藏异常日志中的一些信息。如果这里没有ConstantTransformer,命令进程对象将会被 LazyMap#get 返回,导致我们在异常信息里能看到这个特征:
如果我们增加一个 ConstantTransformer(1) 在TransformChain的末尾,异常信息将会变成java.lang.Integer cannot be cast to java.util.Set ,隐蔽了启动进程的日志特征:
本菜鸟还是不懂,高端玩家,高端玩家(社会)。
0x05 总结
一、LazyMap CC1链与TransformedMap CC1链对比
1.LazyMap CC1链的构造相比TransformedMap CC1链更精妙,但也更略显复杂。精妙之处在于使用了动态代理将LayMap.get()与AnnotationInvocationHandler.readObject()巧妙地连接起来了,否则我们很难从LayMap.get()逆推找到某个类的readObject()
2.LazyMap CC1链中构造的AnnotationInvocationHandler对象的type属性(所传入注解的class对象)为任意继承Annotation接口的class类型即可,而TransformedMap CC1链要求TransformedMap的键名与所传入注解的方法名相同才能触发利用链。原因在于LazyMap的漏洞触发在get和invoke中,而TransformedMap的漏洞出发点在setValue。
至于Ysoserial的作者为什么选择更复杂的LazyMap,而不选择相对好理解的TransformedMap,大概是为了展示下高端玩法吧(皱眉)
二、动态代理在反序列化链构造中的作用
前面说了,LazyMap CC1链的精妙之处在于使用了动态代理将LayMap.get()与AnnotationInvocationHandler.readObject()巧妙地拼接起来了,而这个巧妙之处又在于AnnotationInvocationHandler.invoke()中的逻辑,意向不到的调用了get()。故我觉得动态代理在反序列化链构造中的作用主要是两个:
1.巧妙地拼接两条链
2.InvocationHandler.invoke()是具体代理的逻辑,有函数调用,可能会有意向不到的收获
三、LazyMap CC1与TransformedMap CC1都只能在jdk<8u71中使用
具体什么原因呢?我们来看下jdk 8u71以后的AnnotationInvocationHandler.readObject():
http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/f8a528d0379d:
黑色部分为没做修改的,红色部分是jdk8u71之前的,绿色部分为jdk8u71之后的,通过绿色部分代码我们可以知道,jdk8u71之后不能用CC1链的原因是:
不再直接使用反序列化出来的Map对象,而是先获取memberValues字段存入streamVals,然后新建了一个LinkedHashMap对象,使用streamVals进行遍历等一系列操作后将得到的键值添加到LinkedHashMap对象。所以,原来我们精心构造的Map已经没了,也就不会触发RCE了。
既然CC1链不能在jdk8u71之后的版本中使用,那么有没有一条通杀的CC链,可以在jdk高版本中使用,没有版本限制呢?(当然在满足Commons-Collections <= 3.2.1的情况下)。
答案是,有!!!
欲知后事如何,且听下回分解~
参考:
p神《JAVA安全漫谈》
Java安全系列文集
第6篇:JAVA安全|基础篇:反射机制之常见ReflectionAPI使用
第8篇:JAVA安全|Gadget篇:TransformedMap CC1链
如果喜欢小编的文章,记得多多转发,点赞+关注支持一下哦~,您的点赞和支持是我最大的动力~
原文始发于微信公众号(沃克学安全):JAVA安全|Gadget篇:LazyMap CC1链
- 左青龙
- 微信扫一扫
-
- 右白虎
- 微信扫一扫
-
评论