前言
给java反序列化上个引子,顺带把webgoat代码审计结束了
本来要开始学链子了,但是网警和技侦要开始考试了,打算突击一下ctf和代码审计,下个月在正式学习java反序列化
Java 流(Stream)、文件(File)和IO | 菜鸟教程 (runoob.com)
序列化和反序列化
Java 序列化是一种将对象转换为字节流的过程,以便可以将对象保存到磁盘上,将其传输到网络上,或者将其存储在内存中,以后再进行反序列化,将字节流重新转换为对象。
序列化在 Java 中是通过 java.io.Serializable 接口来实现的,该接口没有任何方法,只是一个标记接口,用于标识类可以被序列化。
当你序列化对象时,你把它包装成一个特殊文件,可以保存、传输或存储。反序列化则是打开这个文件,读取序列化的数据,然后将其还原为对象,以便在程序中使用。
序列化是一种用于保存、传输和还原对象的方法,它使得对象可以在不同的计算机之间移动和共享,这对于分布式系统、数据存储和跨平台通信非常有用。
Java 流(Stream)、文件(File)和IO
Java.io 包几乎包含了所有操作输入、输出需要的类。所有这些流类代表了输入源和输出目标。
Java.io 包中的流支持很多种格式,比如:基本类型、对象、本地化字符集等等。
一个流可以理解为一个数据的序列。输入流表示从一个源读取数据,输出流表示向一个目标写数据。
Java 为 I/O 提供了强大的而灵活的支持,使其更广泛地应用到文件传输和网络编程中。
java 反射
在java开发中有一个非常重要的概念就是java反射机制,也是java的重要特征之一。反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问、检测和修改它本身状态或行为的一种能力,通过反射可以调用私有方法和私有属性,大部分框架也都是运用反射原理的。java通常是先有类再有对象,有对象就可以调用方法或者属性,java中的反射其实是通过Class对象来调用类里面的方法。掌握了反射的知识,才能更好的学习java高级课程。
一个类有多个组成部分,例如:成员变量、方法、构造方法等,反射就是加载类,并解剖出类的各个组成部分。
序列化过程简单演示
先创建一个类Person.java
package test;
import java.io.Serializable;
public class Person implements Serializable {
private String username;
public int age;
public Person(String username, int age) {
this.username = username;
this.age = age;
}
@Override
public String toString() {
return "person{" +
"username='" + username + '\'' +
", age=" + age +
'}';
}
}
序列化
序列化文件 SerializationTest.java
package test;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
public class SerializationTest {
public static void serialize(Object object) throws IOException{
ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("ser.bin"));
objectOutputStream.writeObject(object);
}
public static void main(String[] args) throws Exception{
Person person = new Person("water3",23);
serialize(person);
System.out.println("serialize:"+person);
}
}
序列化对象: 使用 ObjectOutputStream 类来将对象序列化为字节流
这里新创建了一个FileOutputStream类来接受序列化对象,该类用来创建一个文件并向文件中写数据。
如果该流在打开文件进行输出前,目标文件不存在,那么该流会创建该文件。
有两个构造方法可以用来创建 FileOutputStream 对象。
使用字符串类型的文件名来创建一个输出流对象:
OutputStream f = new FileOutputStream("C:/java/hello")
也可以使用一个文件对象来创建一个输出流来写文件。我们首先得使用File()方法来创建一个文件对象:
File f = new File("C:/java/hello"); OutputStream fOut = new FileOutputStream(f);
反序列化
package test;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
public class UnserializationTest {
public static Object unserialize(String filename) throws IOException, ClassNotFoundException {
ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("ser.bin"));
Object object = objectInputStream.readObject();
return object;
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Person person = (Person) unserialize("ser.bin");
System.out.println("unserialize"+person);
}
}
这里也可以提前创建个空person对象来接收反序列化后的person对象
Webgoat 反序列化
这道题一直不成功,但还是审计一下:
首先对传入的字符串进行解码,然后进行反序列化,用o接受反序列化之后的对象,最后判断是否为VulnerableTaskHolder的实例
最下面是判断执行时间是否在3到7秒
我们再看一看这个危险类:
这里和例题一样,使用taskAction来rce
从自定义的序列化过程来看,对象必须是十分钟之内创建的,然后rce必须以ping或者sleep开头
payload应该是这样:
但是根据回显在时间判断出了点问题,后来想起来在之前做题的时候发现docker的时间和我的系统时间是对不上的