前言
最近事情比较多,也没心思静下来好好学点新东西。面试的时候被问到反序列化链过程,就回忆起个大概开头结尾的样子真蛮尴尬的,炒个冷饭,回顾一下之前学过的常用反序列化链。 ps:如有错误烦请指正,不胜感激。(画图可能哪错了没注意到)
Commons-Collections
Commons-Collections <= 3.2.1
CC1
通过动态代理类AnnotationInvocationHandler 的invoke方法调用LazyMap#get() 去触发ChainedTransformer 恶意对象反射链。
ObjectInputStream#readObject()
AnnotationInvocationHandler#readObject()
Map(Proxy)#entrySet()
AnnotationInvocationHandler#invoke()
LazyMap#get()
ChainedTransformer#transform()
ConstantTransformer#transform()
InvokerTransformer#transform()
Method#invoke()
Class#getMethod()
InvokerTransformer#transform()
Method#invoke()
Runtime#getRuntime()
InvokerTransformer#transform()
Method#invoke()
Runtime#exec()
CC3
为了绕过一些规则对InvokerTransformer的限制而产生的,使用InstantiateTransformer 类代替InvokerTransformer 类。因为不能通过transform 回调对象的相应方法了,所以将代码执行部分换为了TemplatesImpl动态加载字节码。
ObjectInputStream#readObject()
AnnotationInvocationHandler#readObject()
Map(Proxy)#entrySet()
AnnotationInvocationHandler#invoke()
LazyMap#get()
ChainedTransformer#transform()
InstantiateTransformer#transform()
TrAXFilter#TrAXFilter()
TemplatesImpl#newTransformer()
TemplatesImpl#getTransletInstance()
TemplatesImpl#defineTransletClasses()
TemplatesImpl$TransletClassLoader#defineclass()
CC5
这个链主要是为了解决高版本利用问题,使用BadAttributeValueExpException 替换AnnotationInvocationHandler 配合TiedMapEntry#toString() 去串联LazyMap#get() 调用transform()触发ChainedTransformer 恶意对象反射链。
在8u71以后Java官方修改了sun.reflect.annotation.AnnotationInvocationHandler 的readObject函数:http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/rev/f8a528d0379d
改动后,不再直接使用反序列化得到的Map对象,而是新建了一个LinkedHashMap对象,并将原来的键值添加进去,传进去的恶意Map不再执行set或put操作,便无法触发transform。
ObjectInputStream#readObject()
BadAttributeValueExpException#readObject()
TiedMapEntry#toString()
LazyMap#get()
ChainedTransformer.transform()
ConstantTransformer#transform()
InvokerTransformer#transform()
Method#invoke()
Class#getMethod()
InvokerTransformer#transform()
Method#invoke()
Runtime#getRuntime()
InvokerTransformer#transform()
Method#invoke()
Runtime#exec()
CC6
同样也是高版本适用,用HashXXX设置值的时候计算hashCode来调用LazyMap#get() ,其实和DNSURL那个道理差不多。
ObjectInputStream#readObject()
HashSet#readObject()
HashMap#put()
HashMap#hash()
TiedMapEntry#hashCode()
TiedMapEntry#getValue()
LazyMap#get()
ChainedTransformer.transform()
ConstantTransformer#transform()
InvokerTransformer#transform()
Method#invoke()
Class#getMethod()
InvokerTransformer#transform()
Method#invoke()
Runtime#getRuntime()
InvokerTransformer#transform()
Method#invoke()
Runtime#exec()
CC7
换了Hashtable 类,利用其reconstitutionPut 方法中比较key的值,会调用LazyMap的equals方法。
而其并没有实现该方法就会调用其父类的equals方法最后到AbstractMap#equals() 那有个m.get(key) 操作去串连LazyMap#get() 。
Hashtable#readObject()
Hashtable#reconstitutionPut()
AbstractMapDecorator#equals()
AbstractMap#equals()
LazyMap#get()
ChainedTransformer#transform()
ConstantTransformer#transform()
InvokerTransformer#transform()
Method#invoke()
Class#getMethod()
InvokerTransformer#transform()
Method#invoke()
Runtime#getRuntime()
InvokerTransformer#transform()
Method#invoke()
Runtime#exec()
Commons-Collections == 4.0
使用PriorityQueue 的排序操作需要进行comparator.compare() 操作来比较两个元素大小,从而调用TransformingComparator#compare() 触发下面的命令执行部分。
CC2
用InvokerTransformer#transform() 去触发TemplatesImpl链来加载恶意字节码。
ObjectInputStream#readObject()
PriorityQueue#readObject()
...
PriorityQueue#heapify()
PriorityQueue#siftDown()
PriorityQueue#siftDownUsingComparator()
...
TransformingComparator#compare()
InvokerTransformer#transform()
TemplatesImpl#newTransformer()
TemplatesImpl#getTransletInstance()
TemplatesImpl#defineTransletClasses()
TemplatesImpl$TransletClassLoader#defineclass()
CC4
使用InstantiateTransformer 类代替InvokerTransformer 类和CC3差不多。
ObjectInputStream#readObject()
PriorityQueue#readObject()
...
PriorityQueue#heapify()
PriorityQueue#siftDown()
PriorityQueue#siftDownUsingComparator()
...
TransformingComparator#compare()
ChainedTransformer#transform()
InstantiateTransformer#transform()
TrAXFilter#TrAXFilter()
TemplatesImpl#newTransformer()
TemplatesImpl#getTransletInstance()
TemplatesImpl#defineTransletClasses()
TemplatesImpl$TransletClassLoader#defineclass()
Common-Collections总结
如上图所示基本上起点终点就是那几个点然后相互拼接:
《Shiro RememberMe 漏洞检测的探索之路》中Koalr师傅已经对CommonsCollections 系列 gadget进行了提纯变成以下四条
- CommonsCollectionsK1 (commons-Collections <= 3.2.1 && allowTemplates)
- CommonsCollectionsK2 (commons-Collections == 4.0 && allowTemplates)
- CommonsCollectionsK3 (commons-Collections <= 3.2.1)
- CommonsCollectionsK4 (commons-Collections == 4.0)
起点部分都变成更简洁的HashMap:
HashMap#readObject()
HashMap#hash()
TiedMapEntry#hashCode()
TiedMapEntry#getValue()
LazyMap#get()
对命令执行部分的调用分别为
- InvokerTransformer调用TemplatesImpl
- ChainedTransformer
对 commons-Collections4 的适配则直接用LazyMap.lazyMap 替换LazyMap.decorate
具体代码在:https://github.com/zema1/ysoserial/tree/master/src/main/java/ysoserial/payloads
恶意类总结:
下图截取自文章《玩转Ysoserial-CommonsCollection的七种利用方式分析》
CommonsBeanutils
用了CC 2&4 链的上面部分,使用PriorityQueue 的排序操中比较大小的comparator#compare() 去调用org.apache.commons.beanutils.BeanComparator#compare() 这里面会去调用PropertyUtils.getProperty() 静态方法
该方法会自动找到类属性的getter方法,也就串连起来TemplatesImpl#getOutputProperties() 利用TemplatesImpl进行恶意类加载。
ObjectInputStream#readObject()
PriorityQueue#readObject()
...
PriorityQueue#heapify()
PriorityQueue#siftDown()
PriorityQueue#siftDownUsingComparator()
...
BeanComparator#compare()
PropertyUtils#getProperty()
...
TemplatesImpl#getOutputProperties()
TemplatesImpl#newTransformer()
TemplatesImpl#getTransletInstance()
TemplatesImpl#defineTransletClasses()
TemplatesImpl$TransletClassLoader#defineclass()
参考
https://github.com/frohoff/ysoserial
Java安全漫谈
|