ysoserial中给出了调用链
LinkedHashSet.readObject()
LinkedHashSet.add()
...
TemplatesImpl.hashCode() (X)
LinkedHashSet.add()
...
Proxy(Templates).hashCode() (X)
AnnotationInvocationHandler.invoke() (X)
AnnotationInvocationHandler.hashCodeImpl() (X)
String.hashCode() (0)
AnnotationInvocationHandler.memberValueHashCode() (X)
TemplatesImpl.hashCode() (X)
Proxy(Templates).equals()
AnnotationInvocationHandler.invoke()
AnnotationInvocationHandler.equalsImpl()
Method.invoke()
...
TemplatesImpl.getOutputProperties()
TemplatesImpl.newTransformer()
TemplatesImpl.getTransletInstance()
TemplatesImpl.defineTransletClasses()
ClassLoader.defineClass()
Class.newInstance()
...
MaliciousClass.<clinit>()
...
Runtime.exec()
值的是在JDK版本7u21中的原生反序列化调用链
7u21的核心点在于sun.reflect.annotation.AnnotationInvocationHandler#equalsImpl
方法的else语句存在一处Method.invoke方法可以用于动态执行方法,这里会调用getMemberMethods方法获取Method数组
Method数组来源于this.type.getDeclaredMethods()
而在sun.reflect.annotation.AnnotationInvocationHandler#invoke方法会调用equalsImpl方法
这自然会让我想到动态代理调用equals方法
看看ysoserial的调用链是如何触发equals方法,用到HashSet#readObject
这里可以用到HashMap,在CC7中,HashMap#put方法会触发equals方法
只需要满足HashMap前后的对象HashCode相同
由于我们需要触发调用链,则需要保证这里key为Proxy代码对象,k为TemplatesImpl对象,那么需要Proxy.hashCode等于TemplatesImpl.hashCode
TemplatesImpl.hashCode会调用native方法,这里看Proxy.hashCode,由于动态代理的关系这里会触发AnnotationInvocationHandler#invoke方法,进而触发hashCodeImpl方法
遍历memberValues,对键值对进行处理计算,计算每个127 * ((String)var3.getKey()).hashCode() ^ *memberValueHashCode*(var3.getValue())
并求和。