JDK7u21
JDK7u21
在前面的CommonsCollections这些利用链中,必须依靠第三方jar包 才能反序列化。
JDK7u21的核心是sun.reflect.annotation.AnnotationInvocationHandler
我们查看equalsImpl方法
发现这里有一个反射调用memberMethod.invoke(),而memberMethod
来自于this.type.getDeclaredMethods()
。
也就是说,equalsImpl
这个方法是将this.type
类中的所有方法遍历执行了。那么假设this.type
是Templates类。那么就会执行其中的newTransformer()
或 getOutputProperties()
方法,进而触发任意代码执行。
如何调用equalsImpl
我们看到在invoke方法中调用了equalsImpl。
在之前我们说过。在使用 java.reflect.Proxy
动态绑定一个接口时,如果调用该接口中任意一个方法,会执行到 InvocationHandler#invoke
。执行invoke时,被传入的第一个参数是这个proxy对象,第二个参数是 被执行的方法名,第三个参数是执行时的参数列表。
而 AnnotationInvocationHandler
就是一个 InvocationHandler
接口的实现,我们看看它的invoke 方法:
if (var4.equals("equals") && var5.length == 1 && var5[0] == Object.class)
根据这句来看,方法名等于equals
且只有一个Object类型参数时,会调用equalImpl
方法
找到equals方法调用链
会经常调用equals的场景就是集合set。set中出储存的对象不允许重复。所以在添加对象的时候会涉及到比较操作
我们查看Hashset的readObject方法。
可见,这里使用了HashMap,将对象保存在HashMap的key处来做去重。最后调用了put
这个变量i
就是所谓的哈希。只有两个不通对象的i相等时候。才会执行到key.equals(k)
接下来我们就要让proxy对象
的哈希值,等于TemplateImpl
对象的哈希值
梳理思路
- 首先生成恶意
TemplateImpl
对象 - 实例化
AnnotationInvocationHandler
对象,它的type属性是一个TemplateImpl类,它的memberValues属性是一个Map,Map只有一个key和value,key是字符串f5a5a608
, value是前面生成的恶意TemplateImpl对象 - 对这个
AnnotationInvocationHandler
对象做一层代理,生成proxy对象 - 实例化一个HashSet,这个hashset有两个元素 TempateIpml对象,proxy对象。
- 将HashSet对象序列化
流程跟踪
首先打断点调试,进入Hashset的readObject方法。
然后进入hashMap的put函数,计算第一个hash
设置第一个hash
然后再次进入put
经过计算,第二个hash和第一个相同,调用了equals函数。由于动态代理特性进入invoke方法
所以会调用TemplatesImpl中的所有方法。
然后就是之前分析过的执行字节码的老一套了