OXO1 序列化介绍

​ 序列化(Serializable)是将数据对象转换成有序的字节流,便于保存在内存、文件、数据库中。而当需要使用数据时通过反序列化(Deserializable)的操作将字节流对象重建。

​ 在Java中序列化使用 ObjectiOutputStream类的writerObject()方法实现,反序列化使用ObjectInputStream类的readObjetion()方法实现。

  • ObjectiOutputStream 对象序列化流
    • writerObject() 序列化
  • ObjectInputStream 对象反序列化流
    • readObjetion() 反序列化
  • Serializable、Externalizable
    • 标记接口,没有方法或字段,一旦实现该接口,标志该类的对象是可序列化

而序列化的目的是为了让java对象脱离java运行环境的一种手段,可以实现网络传输(RMI RPC)对象持久化存储

0x02 序列化漏洞原理

测试代码:通过下面的小栗子来了解序列化

package com.time.Serializable;

import java.io.*;

public class Test {
public static void main(String[] args) throws Exception {
String obj = "初探Java序列化";

//序列化实现代码
FileOutputStream fos = new FileOutputStream("Object");//创建文件流
ObjectOutputStream os = new ObjectOutputStream(fos);//把对象转成字节数据流输出到文件中保存
os.writeObject(obj); //序列化对象,并写入文件
os.close();

//反序列化实现代码
FileInputStream fis = new FileInputStream("Object");
ObjectInputStream is = new ObjectInputStream(fis);

String obj1 = (String) is.readObject();//读取内容,并反序列化

System.out.println(obj1);

}
}

可以看见测试代码中,通过ObjectOutputStream类中的writeObject方法实现字符串的序列化,并写入了Object文件中。

使用xxd来读取Object文件的序列化内容

image-20220102063710671

文件标识头:aced 0005 是java反序列化内容的特征

又通过ObjectInputStream类中的readObject方法实现字符串的反序列化,恢复对象内容,并输出。

运行结果

image-20220102063615140

0x03 反序列化漏洞之命令执行

在上述小栗子中,我们简单的了解了序列化和反序列化的过程,下面我们通过另外一个小栗子来执行系统命令。

测试代码:

TestDemo.java

package com.time.Serializable;

import java.io.*;

public class TestDemo {
public static void main(String[] args) throws IOException, ClassNotFoundException {
MyObject mobj = new MyObject();
mobj.cmd = "wget http://localhost:8081/time";//执行的命令

FileOutputStream fos = new FileOutputStream("Object1");//创建文件流
ObjectOutputStream os = new ObjectOutputStream(fos);//把对象转成字节数据流输出到文件中保存
os.writeObject(mobj); //序列化对象,并写入文件
os.close();

FileInputStream fis = new FileInputStream("Object1");
ObjectInputStream is = new ObjectInputStream(fis);

MyObject obj1 = (MyObject) is.readObject();//读取内容,并反序列化

System.out.println(obj1.cmd);
is.close();
}
}


TestDemo文件中的代码和之前的没什么区别,只是修改了字符串,而重点在MyOjbect文件中

MyOjbect.java

package com.time.Serializable;

import java.io.IOException;

public class MyObject implements java.io.Serializable {
public String cmd;

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{
//执行默认的readObject()方法
in.defaultReadObject();
//执行命令
Runtime.getRuntime().exec(cmd);
}
}

可以看见MyOjbect类继承了Serializable 接口,标识是可以序列化的,而文件中重写了readObject方法,添加了命令执行代码,在我们调用readObject的的时候,会执行这段代码,执行结果如下。

image-20220102072035861

本地搭建了一个服务器来获取访问信息,可以看见是成功执行了。

通过上述小栗子可以看出反序列化漏洞的危害,后续会更深入的学习反序列的漏洞及,以及反序列化漏洞利用工具-ysoserial中的利用链。

0x04 参考链接

https://mp.weixin.qq.com/s/CbMhYuYafHzglIQ_gogZPg

https://www.freebuf.com/articles/web/266523.html

https://xz.aliyun.com/t/10508#toc-8

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