Java 反序列化深究

栏目: Java · 发布时间: 4年前

内容简介:关于Java反序列化的文章已经相当的多了,而且大家也对于这个东西说的很清楚了,所以我想换个角度来看看这个东西。我们都知道Java反序列化漏洞的产生原因在于开发者在重写那么我通过下面的代码可以触发反序列化漏洞,弹出计算器。

关于 Java 反序列化的文章已经相当的多了,而且大家也对于这个东西说的很清楚了,所以我想换个角度来看看这个东西。我们都知道Java反序列化漏洞的产生原因在于开发者在重写 readObject 方法的时候,写入了漏洞代码,这个和 PHP 的反序列化漏洞很像,在反序列化的时候出发了在 __destruct 等魔术函数中的漏洞代码。这里就有一个问题了,先看一下我的demo吧, ObjectCalc.java 为重写 readobject 方法文件。

Java 反序列化深究

那么我通过下面的代码可以触发反序列化漏洞,弹出计算器。

Java 反序列化深究

那么问题来了我们通过 第8行 ois.readObject 获取到的输入流过程中调用了 readObject 方法,为什么最后会调用到被反序列化类( ObjectCalc )中的 readObject 方法,这个 readObject 调用过程到底是怎么样的。

0x02 深入分析

为了弄清楚这个问题,我决定在 ObjectCalc.java 文件中的命令执行位置下一个断点,好的相关调用栈已经出来了,这时候我们跟进一下。

Java 反序列化深究

先跟进一下 ObjectInputStream.readObject ,这里我简化了一下代码,关键位置在 第431行 调用了 readObject0 方法,并且传入false。

Java 反序列化深究

继续跟进一下 readObject0 方法,关键在下面这两行,此时的 TC_OBJECT 的值为115,且调用了 readOrdinaryObject 方法。

case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));

跟进 readOrdinaryObject 方法,调用了 readSerialData 方法。

private Object readOrdinaryObject(boolean unshared)
throws IOException
{
...
if (desc.isExternalizable()) {
readExternalData((Externalizable) obj, desc);
} else {
readSerialData(obj, desc);
}

继续跟进一下 readSerialData 方法,该方法的实现如下所示。

Java 反序列化深究 从动态调试结果来看,重写 readObject 会进入第14行的 slotDesc.invokeReadObject 方法中,再跟进一下 slotDesc.invokeReadObject 方法,该方法主要代码如下:

void invokeReadObject(Object obj, ObjectInputStream in)
throws ClassNotFoundException, IOException,
UnsupportedOperationException
{
requireInitialized();
if (readObjectMethod != null) {
try {
readObjectMethod.invoke(obj, new Object[]{ in });

其中 readObjectMethod.invoke 这个方法很熟悉了,java的反射机制,也就说通过重写 readObject 的整个调用流程会进过java的反射机制。

这里再看一个不通过重写 readObject 反序列化的调用过程,我省略了前面的跟踪调试过程,大家看下图。

Java 反序列化深究

不通过重写 readObject 的反序列化过程一样是进入 readSerialData 中,但是是通过 defaultReadFields 进行处理,这里有个关注点是 slotDesc.hasReadObjectMethod() 返回的结果是false,也就是下面这个if判断的结果,我简化了一下流程。

else if (slotDesc.hasReadObjectMethod()) {
slotDesc.invokeReadObject(obj, this);
...
} else {
defaultReadFields(obj, slotDesc);
}

也就是说实际上是否重写了 readObject 影响的是 slotDesc.hasReadObjectMethod() 的结果,那么跟进一下 hasReadObjectMethod 方法,这里我在 return (readObjectMethod != null); 下了一个断点,对比一下重写 readObject 结果和不重写 readObject 结果的差别,第一张图是不重写 readObject ,第二张图是重写 readObject

Java 反序列化深究

Java 反序列化深究

很明显我们发现了返回结果不一样,第一张图的结果自然return为false,第二张图return结果自然为true,也就是说重写 readObject 结果和不重写 readObject 结果的差别本质上在于进入的循环不一样。

0x03 小结

根据上面的动态调试结果,简单做个小结,也就是说如果反序列化的过程中被反序列化类重写了 readObject ,该数据在反序列化的过程中核心流程走到 readSerialData 方法中的 slotDesc.invokeReadObject 方法,通过反射机制触发相关流程,并且调用重写的 readObject 。如果没有重写 readObject ,则调用 ObjectInputStream 类中的 readObject 方法,并且执行反序列化。


以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

零边际成本社会

零边际成本社会

[美]杰里米·里夫金 / 赛迪研究院专家组 / 中信出版社 / 2014-11-1 / 49.00

在这本书中,《第三次工业革命》作者杰里米•里夫金开创性地探讨了极致生产力、协同共享、产消者、生物圈生活方式等全新的概念,详细地描述了数以百万计的人生产和生活模式的转变。他认为,“产消者”正在以近乎零成本的方式制作并分享自己的信息、娱乐、绿色能源和3D打印产品。他们也通过社交媒体、租赁商、合作组织以极低或零成本的模式分享汽车、住房、服装和其他物品;学生更多地参与到基于零成本模式的开放式网络课程…… ......一起来看看 《零边际成本社会》 这本书的介绍吧!

RGB转16进制工具
RGB转16进制工具

RGB HEX 互转工具

随机密码生成器
随机密码生成器

多种字符组合密码

HSV CMYK 转换工具
HSV CMYK 转换工具

HSV CMYK互换工具