首发先知社区
链接:https://xz.aliyun.com/t/14544
0x01 前言
相信大家在刚开始学习java反序列化漏洞时都会听到过以下的说法:
自定义序列化过程:
在反序列化时重写一个类的
readObject
方法,在反序列化的过程中调用到的就是我们重写的这个readObiect
方法.
今天就这个问题深入的讨论一下!
故事的起因
下午群里有个朋友问了一个问题:java反序列化时重写的readObject()
为什么要写成私有的才会执行,改成public就不行了
说实话我也也不太清楚,赶紧翻翻之前的学习笔记
一看之后有点傻眼,也只是简单的记录了一下重写People类的readObject()方法
并没有在意过权限修饰符为啥必须是private
于是赶紧打开idea跑一下代码瞅瞅:
确实是没有调用到
接下来就记录一下,对这个问题的深入思考,以及分析的过程!
0x02 java中的方法重写
首先去看了一下朋友给发的图,他说原生的readObject权限修饰符是public
去找了一下,发现他给的图是ObjectInputStream的,这块首先就存在两个问题:
- final的方法不能重写,因为方法是 final它无法被子类继承到
- 方法重写应该重写的是父类中的方法,ObjectInputStream也不是我们定义的Person类的父类
那接下来就去看看到底是重写了那个方法,可以看到Person类之继承了一个Serializable接口,所以其父类应该是Object类
验证一下,确实就是Object
但是在Objet也没有发现readObject方法
之后产生了一个疑问?
这里说的重写,是我认为的那个重写(Overriding)吗!
0x03 Serializable接口
通过翻看Serializable接口的注释,我们可以看到这两个方法
众所周知,Serializable
只是一个空接口,那这俩方法到底是在哪里定义的呢?
0x04 ObjectStreamClass
在网上看了看其他师傅的文章,发现了这个类,**ObjectStreamClass
按官方的说法是类的序列化描述符,本质是对 Class 类的包装,提取了类序列化时的一些信息,包括字段的描述信息和 serialVersionUID
和需要序列化的字段 fields
。**
在494行:
从上面这段源码中可以看出,在序列化(反序列化)的时候,ObjectOutputStream(ObjectInputStream)
会寻找目标类中的私有的writeObject(readObject)
方法,赋值给变量writeObjectMethod(readObjectMethod)
。
ObjectStreamClass
类中的一个判断方法
ObjectInputStream
中的最终反序列化对象的方法
0x05 自定义序列化
到这块就解开了开头的疑问
这里所说的重写readObject()
方法,并不是说重写父类中的方法,而是我们自定义个一个private修饰的readObject()
方法,在反序列化的过程中检测到我们程序中存在private修饰的readObject()
方法,就会去调用我们自定义的readObject()
方法,如果没检测到,则将调用默认的defaultReadFields
方法来读取目标类中的属性。
0x06 结语
在学习的过程中,不能轻易接受别人的观点而不加以思考,而是应该多一点自己的思考,注重对知识的深入理解和独立思考。
如果有分析的不到位的,还请各位师傅多多指点!
0x07 参考
https://www.cnblogs.com/binarylei/p/10989372.html
https://www.cnblogs.com/zpchcbd/p/15126154.html
https://blog.csdn.net/Leon_cx/article/details/81517603
1 | 文章首发先知社区,作者Yu |