[Java反序列化]JDK7U21原生反序列化利用链分析
Posted Y4tacker
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[Java反序列化]JDK7U21原生反序列化利用链分析相关的知识,希望对你有一定的参考价值。
写在前面
这段时间看了也跟踪了CC链,CB链,也跟踪调试了shiro的两个链子,XMLDecoder等,就用JDKK7U21原生反序列化利用链来暂时结束下最近的学习
利用链
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()
JDK7U21原生反序列化利用链分析
JDK7u21的核心点就是sun.reflect.annotation.AnnotationInvocationHandler
,我们来看看AnnotationInvocationHandler
这个方法
再看
可以很清楚的分析到equalsImpl
这个方法
首先是利用反射获取this.type
中的所有方法,之后进行遍历其中的方法并执行,如果我们把this.type
赋为一个类,岂不是能调用里面的所有方法了,还记得那个TemplatesImpl
对象么,我们就可以利用它来进行字节码的加载执行了
接下来我们发现在AnnotationInvocationHandler
下面的invoke
方法
这里我们其实发现,它实现了InvocationHandler
因此我们不难想到一个东西,动态代理,当调用equal
方法时,就能实现完整的利用链,这里前辈们想到的是利用HashSet
,因为HashSet
中储存的对象不允许重复,所以在添加对象的时候,势必会涉及到比较操作。
可以看到在HashSet
的readObject
方法
这里调用了equal
方法,但是从函数当中也能看出前提是他们的hash值
相等
接下来我们就要让proxy对象
的哈希值,等于TemplateImpl
对象的哈希值,我们来看看hash的计算方法
我们来看看这里面的hash
方法
这里我们发现主要是对象的hashCode方法
那我们就来看看这两个方法,首先是TemplatesImpl
的hashcode
方法,无法Debug调试跟踪,最后网上说是一个Native方法,难怪,但是我们不难发现每一次运行都在变,如何处理看后面分析
而看看我们代理的HashCode呢,会通过AnnotationInvocationHandler
的invoke
,进而调用到AnnotationInvocationHandler
的hashCodeImpl
我们看看hashCodeImpl
,它遍历memberValues
中的每个key
和value
,计算 (127 * key.hashCode()) ^ value.hashCode()
并求和
private int hashCodeImpl() {
int var1 = 0;
Entry var3;
for(Iterator var2 = this.memberValues.entrySet().iterator(); var2.hasNext(); var1 += 127 * ((String)var3.getKey()).hashCode() ^ memberValueHashCode(var3.getValue())) {
var3 = (Entry)var2.next();
}
return var1;
}
再来看这个当只有一个key
和value
时,简化成 了(127 * key.hashCode()) ^ value.hashCode()
因此不难想到当key.hashCode()
等于0时,任何数异或0的结果仍是他本身,所以该哈希简化成value.hashCode()
当 value
就是TemplateImpl
对象时,这两个哈希就变成完全相等,因此我们只需要拿到一个hashCode
是0的对象,网上给跑出来的是字符串f5a5a608
我们整理下利用思路
- 构造TemplatesImpl并将执行的字节码赋值
- 实例化一个HashMap,并添加key
f5a5a608
,恶意构造好的TemplatesImpl
加入到map中 - 利用反射实例化
AnnotationInvocationHandler
类 - 为
AnnotationInvocationHandler
对象设置动态代理 - 实例化
HashSet
,并将TemplatesImpl
和设置的代理
这两个对象放进去
流程跟踪
首先通过readObject
调用,之后
跟进去看看,首先第一个对象Hash计算完添加
由于第二个对象hash与第一个相同,调用equal方法
通过动态代理触发equalsImpl
的调用
接下来就是遍历Template
里面的方法并通过反射执行,可以看到这里有执行newTransformer
调用getTransletInstance
方法
继续跟踪调用defineTransletClasses
方法
跟入defineClass
加载字节码
别忘了这里有一个验证加载的字节码的对象必须是class com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet
的子类哦
实例化
成功弹出计算器
参考文章
以上是关于[Java反序列化]JDK7U21原生反序列化利用链分析的主要内容,如果未能解决你的问题,请参考以下文章