CommonsCollections1反序列化链分析

简介

之前其实分析过一次,但经过一段时间调试,打算再做一次。

测试环境

用ysoserial生成payload然后发送,webserver环境就是之前搭建的

image.png

image.png

测试成功

分析

之前一开始分析的链子也是CC,但是没有调试,为了进一步学习,再分析一遍Ysoserial中的链子构造原理

反序列化链总览

Ysoserial中的利用链,能够发现使用的是LazyMap利用链。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/*
Gadget chain:
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()

Requires:
commons-collections
*/

transformerChain

50行:初始化了一个命令数组,用来获取命令参数

52行:初始化了一条transformerChain,通过下文看应该是用来存放Transformer对象的链子

55行:很熟悉,构建的调用反射方法链子,在上一篇文章里讲的很清楚,不同的是最后65行加入了一个new ConstantTransformer(1);

所以最后返回值是一个1。

image.png

接着开始构建HashMap攻击链

初始化了一个HashMap

通过LazyMapdecorate方法返回了一个LazyMap实例

其中第二个参数传入的是一个目前还是空的transformerChain实例对象

image.png

image.png

Gadgets.createMemoitizedProxy(lazyMap, Map.class)

可以看到接下来Ysoserial调用了Gadgets类的一个方法来初始化代理,Gadgets类是Ysoserial中的核心类,我们跟进代码看这个方法究竟干了啥

image.png

要求传入一个Map类型的对象和任意多个接口类型

这里我们传入了lazyMap实例对象和Map接口类型

image.png

ysoserial.payloads.util.Gadgets.createMemoizedInvocationHandler

image.png

通过反射拿到了sun.reflect.annotation.AnnotationInvocationHandler类的第一个构造器

参数 ANN_INV_HANDLER_CLASS 值为 sun.reflect.annotation.AnnotationInvocationHandler. 该类是 Java 中专门用来处理注解的调用处理器 , 但 Java 中不允许直接获取该类 , 所以必须要通过反射( Reflection ) 才能拿到该类.

image.png

image.png

然后通过反射实例化这个控制器并返回到上面的方法中

image.png

这里传入的var1是Override.class,是java 中自带的 Annotation 的实现类之一,此处只要传一个Annotation的实现类就行,对Override.class没有特别要求image.png

(关于注解的知识会单独写一章学习,这里看别人文章真不如自己看源码。。

继续继续–

ysoserial.payloads.util.Gadgets.createProxy

image.png

通过反射新建了一个Class类型的数组allIfaces存放接口,长度是传入的接口类型数

然后将传入的接口类型都装到数组里

最后返回了一个jdk动态代理

java.lang.reflect.Proxy的newProxyInstance方法来构造一个指定接口的代理类的一个新实例,所有方法会调用给定处理器(也就是AnnotationInvocationHandler)的invoke方法

回到,这里mapProxy很明确了,creatMemoitizedProxy方法也明确了

image.png

他返回了一个动态代理实例,其指定的接口是Map,其处理器是AnnotationInvocationHandler

Gadgets.createMemoizedInvocationHandler(mapProxy)

image.png

这个方法就是上面刚刚分析过的方法,传入我们刚刚创建的动态代理

image.png

把刚刚创建的动态代理赋值到memberValues里

image.png

参考Epicccal师傅的说法:

这一步操作是为了目标服务器在反序列化时会调用 AnnotationInvocationHandler.readObject() 方法 , 从而调用动态代理对象的方法( 被代理的方法 ) , 从而触发拦截与转发 , 从而执行 AnnotationInvocationHandler.invoke() 方法.

稍后看readObject方法

最后

通过反射赋值,把真正的恶意代码数组加入到transformerChain

image.png

这条LazyMap调用链和我上一篇文章看的不大一样,但是最后原理都是相同的,那就是调用LazyMap的get方法从而触发transform

调试

调试是要结合前面的分析看的

我们传入的对象是AnnotationInvocationHandler对象,他会触发AnnotationInvocationHandler.readObject()方法

image.png

而通过ysoserial中的生成的动态代理

AnnotationInvocationHandler.invoke()会被调用

最终完成调用LazyMap.get(),从而完成LazyMap攻击链

image.png

小总结

  • 进一步学习注解和反射

  • 再理解一次JAVA动态代理机制和设计模式

  • 反序列化的原理。。

  • 再看文章,再看文章

  • 明天写一下此文补充点和知识