Java-Deserialization-Chapter-Ⅲ

Java-Deserialization-Chapter-Ⅲ
S0cke3t序
经过一个多月的忙碌,终于是有时间来更一下此系列的文章了,本文中会涉及到java反射和动态代理,如果你对相关不了解,建议先去学习下相关知识
CommonsCollections
Commons Collections包为Java标准的Collections API提供了相当好的补充。在此基础上对其常用的数据结构操作进行了很好的封装、抽象和补充。
Transformer
Transformer是一个接口,提供一个transform方法由实现类决定具体的转换逻辑
在Transformer实现类中,我们主要来看一下InvokeTransformer和ChainedTransformer
InvokeTransformer
首先来看一下构造函数,Invoketransformer共有两个构造函数
其中第一个只需要传入一个String类型的methodName,另一个除需传入methodName外,还需要指定方法的参数类型以及具体的参数值
接下来看一下实现类的transform具体实现
在transform中在拿到传入的object后,利用反射调用自身实例化时传入的方法,并将结果返回
到这里InvokeTransformer的作用我们就大致了解了,当我们实例化一个InvokeTransformer时传入一个要调用的方法名以及它的参数类型的具体的参数值
随后在调用transform时指定一下方法的调用对象,InvokeTransformer会自动利用反射去调用相关方法
如下利用Invoketransformer完成调用Runtime.getRuntime().exec("calc")
1 | /* |
ChainedTransformer
同样ChainedTransformer也是Transformer的一个实现类
它的构造函数需要我们传入一个Transformer类型的数组
接着我们来看下transformer实现
通过实现不难看出在调用 ChainedTransformer 的 transform 方法时,会循环数组,依次调用 Transformer 数
组中每个 Transformer 的 transform 方法,并将执行的结果传递给下一个 Transformer,完成一个链式的调用
TransformedMap
有了上面的ChainedTransformer我们现在可以使用链式调用完成命令执行,接下来就需要找一个在对象操作时触发我们的ChainedTransformer调用的桥梁-TransformedMap
从声明上不难看出,TransformedMap继承自AbstractInputCheckedMapDecorator作为装饰器使用,可以理解为Map提供增强功能
单从代码上可能有点不好理解,看下面的类图就一目了然了
当我们用TransformedMap装饰一个map,并进行put时
TransformedMap将会自动每个元素的transformer方法,这也就和上面ChainedTransformer衔接起来了
同样我们使用TransformedMap并结合ChainedTransformer完成调用Runtime.GetRuntime().exec("calc")
1 | //定义transformer数组并结合invoketransformer完成runtime调用 |
AnnotationInvocationHandler
到目前为止我们找到了完成反序列化漏洞的两个关键步骤执行点和利用链,接下来还需要一个触发点也就是重写了readObject的类来将整个过程串起来
本节内容涉及到java动态代理的一些内容和特性,不了解的朋友可以先去学习一下动态代理基础知识
AnnotationInvocationHandlerJDK原生类,用于注解形式的动态代理
先从readObject看起
首先readObject通过getInstance获取到type对应的注解类型,而要type的条件在构造函数中也有要求
type必须是一个注解,有且只有一个父接口并且是Annotation,只有满足这些条件type和memberValue才会被赋值
回到readObject
在拿到注解类型后调用类型的memberTypes获取到可注解可设置的值
随后使用while循环这个map并设置其中的值,但在设置值之前有一个条件
memberValues中的值和获取到的注解类型中的值存在相同的值,并且这个值不是ExceptionProxy的实例也不能是memberValues的实例
到这里我们整个过程就串起来了
整理一下思路
首先我们需要一个AnnotationInvocationHandler根据构造函数需要传入一个注解类一个Map,并且根据上面赋值要求我们Map中的key要和注解类中有同样的值
根据这个思路可以找到很多可以使用的注解类,比如Target,Resource,Generated等,笔者这里使用Resource的name属性
之后将这个map使用TransformedMap进行封装,使用TransformedMap进行修饰
最后就是上面讲到的利用InvokeTransformer完成链式调用
1 | Map<Object,Object> hashmap = new HashMap<Object,Object>(); |
当然除了使用TransformedMap还可以使用LazyMap做为触发条件,其中涉及到的操作会比TransformedMap稍微复杂一点。这部分内容有时间再补充
That’s all



























