文章归档

置顶文章

Web安全

Web安全基础

PHP相关

Writeups

靶机系列

HackTheBox-Retired

HackTheBox-Active

VulnHub

代码审计

PHP代码审计

大数据安全

机器学习

基础学习

Python

Python基础

Python安全

Java

Java基础

Java安全

算法

Leetcode

随笔

经验

技术

 2021-03-13   999

Java安全学习之反序列化

参考:

P神—代码审计—Java安全漫谈-07.反序列化篇(1)

https://paper.seebug.org/312/

http://www.lmxspace.com/2019/03/11/Java-web学习之路-序列化和反序列化

https://xz.aliyun.com/t/4711

0x01 Java序列化和反序列化

能学到Java序列化和反序列化的同学基本上肯定了解PHP的反序列化漏洞,也能写PHP反序列化的Gadget。其实这两者很相似,但又不尽相同。

Java 序列化是指把 Java 对象转换为字节序列的过程便于保存在内存、文件、数据库中,ObjectOutputStream类的 writeObject() 方法可以实现序列化。
Java 反序列化是指把字节序列恢复为 Java 对象的过程,ObjectInputStream 类的 readObject() 方法用于反序列化。

Java相对PHP序列化更深入的地方在于,其提供了更加高级、灵活地方法 writeObject ,允许开发者在序列化流中插入一些自定义数据,进而在反序列化的时候能够使用 readObject 进行读取。

java中的一个类的对象要想序列化成功,必须满足两个条件:

  1. 该类必须实现 java.io.Serializable 接口,因为 Serializable 接口是启用其序列化功能的接口。
  2. 该类的所有属性必须是可序列化的。

实现序列化与反序列化代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
public class test{
public static void main(String args[])throws Exception{
//定义obj对象
String obj="hello world!";
//创建一个包含对象进行反序列化信息的”object”数据文件
FileOutputStream fos=new FileOutputStream("object");
ObjectOutputStream os=new ObjectOutputStream(fos);
//writeObject()方法将obj对象写入object文件
os.writeObject(obj);
os.close();
//从文件中反序列化obj对象
FileInputStream fis=new FileInputStream("object");
ObjectInputStream ois=new ObjectInputStream(fis);
//恢复对象
String obj2=(String)ois.readObject();
System.out.print(obj2);
ois.close();
}
}

上面代码将 String 对象 obj1 序列化后写入文件 object 文件中,后又从该文件反序列化得到该对象。我们来看一下 object 文件中的内容:

这里需要注意的是,ac ed 00 05是 java 序列化内容的特征,

再来看一段代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
public class test{
public static void main(String args[]) throws Exception{
//定义myObj对象
MyObject myObj = new MyObject();
myObj.name = "hi";
//创建一个包含对象进行反序列化信息的”object”数据文件
FileOutputStream fos = new FileOutputStream("object");
ObjectOutputStream os = new ObjectOutputStream(fos);
//writeObject()方法将myObj对象写入object文件
os.writeObject(myObj);
os.close();
//从文件中反序列化obj对象
FileInputStream fis = new FileInputStream("object");
ObjectInputStream ois = new ObjectInputStream(fis);
//恢复对象
MyObject objectFromDisk = (MyObject)ois.readObject();
System.out.println(objectFromDisk.name);
ois.close();
}
}

class MyObject implements Serializable{
public String name;
//重写readObject()方法
private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
//执行默认的readObject()方法
in.defaultReadObject();
//执行打开计算器程序命令
Runtime.getRuntime().exec("open /System/Applications/Calculator.app/");
}
}

这次我们自己写了一个 class 来进行对象的序列与反序列化。我们看到,MyObject 类有一个公有属性 name ,myObj 实例化后将 myObj.name 赋值为了 “hi” ,然后序列化写入文件 object:

然后读取 object 反序列化时:

我们注意到 MyObject 类实现了Serializable接口,并且重写了readObject()函数。这里的 readObject() 执行了Runtime.getRuntime().exec("open /System/Applications/Calculator.app/"),而 readObject() 方法的作用正是从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回,readObject() 是可以重写的,可以定制反序列化的一些行为。

0x02 反序列化漏洞分析

看完上一章节你可能会说不会有人这么写 readObject() ,当然不会,但是实际也不会太差。

这里就用ysoserial工具给出的各种反序列化漏洞来分析,Step By Step:

ysoserial CommonsCollections1详细分析

ysoserial CommonsCollections2详细分析

ysoserial CommonsCollections3详细分析

ysoserial CommonsCollections4详细分析

ysoserial CommonsCollections5详细分析

ysoserial CommonsCollections6详细分析

ysoserial CommonsCollections7详细分析

Copyright © ca01h 2019-2021 | 本站总访问量