内容目录
简介Java中的序列化和反序列化API实现靶场详解反序列化原理、修复方法简单小结(面试常问)
简介
简单举个例子:比如上司让你用java设计一个登录页面,且登录账号密码要保存在本地,但是又不能让用户直接看见明文信息。
在这里,我们就会用到java的序列化。
操作流程:我们可以先将用户的账号信息做序列化操作,这样就算用户打开看到的只会是一片乱码,而登录账号再次调用的话只需要对保存信息做反序列化操作即可。
用比较官方语言总结一下就是:序列化将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将其当前状态写入到临时或持久性存储区,而反序列化就是从存储区中读取该数据,并将其还原为对象的过程,称为反序列化。(下面会有代码演示)
Java中的序列化和反序列化API实现
序列化:ObjectputStream类 —> WriteObject()
注意:该方法对参数指定的obj对象进行序列化,把字节序列写到一个目标输出流中,按java的标准约定是给我就一个.ser扩展名。
反序列化:ObjectInputStream类 —>readObject()
注:该方法从源输入流中读取字节序列,再把题目反序列化为一个对象,再将其返回。
这里我们使用代码来进行进行简单演示:
public class SerializeDemo { public static void main(String[] args) throws IOException { Employee e = new Employee(); e.name = “zhangsan”; e.age = 20; e.address = “shenzhen”; // 1.创建序列化流 ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream(“employee.txt”)); // 2.写出对象 outputStream.writeObject(e); // 3.释放资源 outputStream.close();
}}
这个就是一个序列化操作。
这里将将Employee对象写入到了employee.txt文件中。
而反序列化操作呢,我们用以下代码实现:
//如果能找到一个对象的class文件,我们可以进行反序列化操作,调用 ObjectInputStream 读取对象的方法:_public class DeserializeDemo { public static void main(String[] args) throws IOException, ClassNotFoundException { // 1.创建反序列化流 FileInputStream fileInputStream = new FileInputStream(“employee.txt”); ObjectInputStream inputStream = new ObjectInputStream(fileInputStream); // 2.使用ObjectInputStream中的readObject读取一个对象 Object o = inputStream.readObject(); // 3.释放资源_ inputStream.close(); System.out.println(o); }}
运行后打印出的结果就是我们之前序列化前的数据,反序列化操作就是从二进制文件中提取对象。
参考文章:https://www.cnblogs.com/yyhuni/p/14755940.html
看了半天源码是不是还是有点懵,不慌,我们来研究一下下面这个靶场,就懂了。
靶场详解反序列化
如何ide如何查看jar文件源码:(后面有用)https://blog.csdn.net/yang1234567898/article/details/122290512
【复制出来很简单,直接选中复制,粘贴到其他文件夹中就ok。】
将Hibernate的jar包复制到ysoserial工具的目录下,jar包名字中必须是有core的,是插件的核心
这里保存成bin文件是因为我们还需要进行一次bs64编码。
这个就是序列化后的一个结果,此外我们还需要进行一个bs64的编码,这里用脚本或者直接工具进行bs64编码都可以。然后我们将这串字符填入其中,就会直接弹出计算器。命令是可以自己随意修改的,一般是反弹shell。现在应该java反序列化有所了解吧。
webgoat靶场下载(推荐还是用8.1.0版本,因为高版本对jar版本也高)https://github.com/WebGoat/WebGoat/releases/tag/v8.2.2
第一步:使用ide打开webgoat.jar,查看这一关的关键代码(如何打开,方法如上):

读取对象和写入对象操作。

命令执行函数操作。
简单来看关键代码,总结流程就是对你输入的数据进行一个接收,然后对数据进行对象还原,再进行命令执行。
如何判断数据是否为序列化?
一般以rO0AB开头,基本可以认定这串数据就是JAVA序列化base64加密的数据;或者如果以aced开头,那么他就是这一段java序列化的16进制。
现在我们想一想:现在如果我要攻击他,我应该如何构造payload呢?
解:因为这个数据是序列化后再bs64编码的,所以如果我们要重构这串数据的话,我们就直接构造恶意语句,先将语句进行反序列化,再进行bs64加密,即可。
这里如果手工生成的话十分麻烦,不方便,这里我们就使用一个工具来帮助我们,这个也是在java反序列化中常用的。
项目地址:https://github.com/frohoff/ysoserial
[官网貌似没有编译好的,需要自己编译,不过公众号可以回复java反序列化,有成品]
按照ysoserial支持的插件,查找webgoat是否安装了对应的jar包,这里只有两个:
Hibernate和spring-core 但是spring-core的版本不一致,所以就选择Hibernate

命令(弹一个计算器): java -Dhibernate5 -cp hibernate-core-5.4.6.Final.jar;ysoserial.jar ysoserial.GeneratePayload Hibernate1 calc.exe > payload.bin
命令执行简单翻译一下就是这样的: java -Dhibernate5 -cp hibernate-core-5.4.6.Final.jar; //表示hibernate5的插件_ysoserial.jar ysoserial.GeneratePayload Hibernate1 calc.exe > token.bin //生成Hibernate1插件反序列化漏洞的payload,执行calc.exe命令,将payload保存在payload.bin文件中。_
生成的payload
编码后的结果就是这样:

原理、修复方法简单小结(面试常问)
在我们面试中,总有面试官问到Java反序列化,但作为菜鸡的我不知道咋回答,下面我就简单总结一下下。(大家可以按自己的来,我只是简单写一下)。
1.漏洞原理:Java序列化指Java对象转换为字节序列的过程,反序列化指字节序列恢复为Java对象的过程,如果Java应用对用户输入,即不可信数据做了反序列化处理,那么攻击者可以通过构造恶意输入,让反序列化产生非预期的对象,非预期的对象在产生过程中就有可能带来任意代码执行。
2.漏洞举例说明:例如说明shiro的反序列化导致的命令执行,Apache Shiro框架提供了RememberMe的功能,关闭浏览器再次访问时无需再登录即可访问。由于默认使用了cookieremembermanager,服务器处理cookie的流程是,得到rememberMe的cookie值 —> Base64解码 —> AES解密 —> 反序列化,而问题就出在这里,然而AES的密钥是硬编码的,如果没有修改默认的密钥,就导致了攻击者可以构造恶意数据造成反序列化的RCE漏洞,所以我们的攻击流程就是构造恶意命令—>序列化—>AES加密—>base64编码—>发送cookie。(是不是和我们刚刚做的靶场案例流程十分相似)。
3.漏洞修复说明:(1)类的白名单校验机制:对所有传入的反序列化对象,在反序列化过程开始前,对类型名称做一个检查,不符合白名单的类不进行反序列化操作。(2)禁止JVM执行外部命令Runtime.exec,可以通过扩展 SecurityManager 可以实现。
