CommonsCollections1反序列化链分析
简介
之前其实分析过一次,但经过一段时间调试,打算再做一次。
测试环境
用ysoserial生成payload然后发送,webserver环境就是之前搭建的
测试成功
分析
之前一开始分析的链子也是CC,但是没有调试,为了进一步学习,再分析一遍Ysoserial中的链子构造原理
反序列化链总览
Ysoserial中的利用链,能够发现使用的是LazyMap利用链。
1 | /* |
transformerChain
50行:初始化了一个命令数组,用来获取命令参数
52行:初始化了一条transformerChain,通过下文看应该是用来存放Transformer对象的链子
55行:很熟悉,构建的调用反射方法链子,在上一篇文章里讲的很清楚,不同的是最后65行加入了一个new ConstantTransformer(1);
所以最后返回值是一个1。
接着开始构建HashMap攻击链
初始化了一个HashMap
通过LazyMap
的decorate
方法返回了一个LazyMap
实例
其中第二个参数传入的是一个目前还是空的transformerChain实例对象
Gadgets.createMemoitizedProxy(lazyMap, Map.class)
可以看到接下来Ysoserial调用了Gadgets类的一个方法来初始化代理,Gadgets类是Ysoserial中的核心类,我们跟进代码看这个方法究竟干了啥
要求传入一个Map类型的对象和任意多个接口类型
这里我们传入了lazyMap实例对象和Map接口类型
ysoserial.payloads.util.Gadgets.createMemoizedInvocationHandler
通过反射拿到了sun.reflect.annotation.AnnotationInvocationHandler
类的第一个构造器
参数 ANN_INV_HANDLER_CLASS 值为 sun.reflect.annotation.AnnotationInvocationHandler. 该类是 Java 中专门用来处理注解的调用处理器 , 但 Java 中不允许直接获取该类 , 所以必须要通过反射( Reflection ) 才能拿到该类.
然后通过反射实例化这个控制器并返回到上面的方法中
这里传入的var1是Override.class
,是java 中自带的 Annotation 的实现类之一,此处只要传一个Annotation的实现类就行,对Override.class
没有特别要求
(关于注解的知识会单独写一章学习,这里看别人文章真不如自己看源码。。
继续继续–
ysoserial.payloads.util.Gadgets.createProxy
通过反射新建了一个Class类型的数组allIfaces
存放接口,长度是传入的接口类型数
然后将传入的接口类型都装到数组里
最后返回了一个jdk动态代理
java.lang.reflect.Proxy的newProxyInstance方法来构造一个指定接口的代理类的一个新实例,所有方法会调用给定处理器(也就是AnnotationInvocationHandler)的invoke方法
回到,这里mapProxy很明确了,creatMemoitizedProxy方法也明确了
他返回了一个动态代理实例,其指定的接口是Map
,其处理器是AnnotationInvocationHandler
Gadgets.createMemoizedInvocationHandler(mapProxy)
这个方法就是上面刚刚分析过的方法,传入我们刚刚创建的动态代理
把刚刚创建的动态代理赋值到memberValues里
参考Epicccal师傅的说法:
这一步操作是为了目标服务器在反序列化时会调用
AnnotationInvocationHandler.readObject()
方法 , 从而调用动态代理对象的方法( 被代理的方法 ) , 从而触发拦截与转发 , 从而执行AnnotationInvocationHandler.invoke()
方法.
稍后看readObject方法
最后
通过反射赋值,把真正的恶意代码数组加入到transformerChain
中
这条LazyMap调用链和我上一篇文章看的不大一样,但是最后原理都是相同的,那就是调用LazyMap的get方法从而触发transform
调试
调试是要结合前面的分析看的
我们传入的对象是AnnotationInvocationHandler
对象,他会触发AnnotationInvocationHandler.readObject()
方法
而通过ysoserial中的生成的动态代理
AnnotationInvocationHandler.invoke()会被调用
最终完成调用LazyMap.get(),从而完成LazyMap攻击链
小总结
进一步学习注解和反射
再理解一次JAVA动态代理机制和设计模式
反序列化的原理。。
再看文章,再看文章
明天写一下此文补充点和知识