JAVA 反序列化漏洞入门学习笔记(一)--反序列化简介

java

JAVA 真的令人头大

参考文章

Java反序列化漏洞从入门到深入

JAVA 序列化与反序列化

简介

同 PHP/Python 类似,java 序列化的目的是将程序中对象状态转换成以数据流形式,反序列化是将数据流恢复为对象。

此举可以有效地实现多平台之间的通信、对象持久化存储。

序列化实例

import java.io.*;

//定义一个可序列化的类,该类必须实现 java.io.Serializable 接口

class Giao implements java.io.Serializable

{

public String name;

public String motto;

public void saygiao()

{

System.out.println(this.motto);

}

// 自定义 readObject 方法

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{

//执行默认的readObject()方法

in.defaultReadObject();

//执行命令

Runtime.getRuntime().exec("calc.exe");

}

}

//序列化/反序列化

public class SerializeGiao

{

public static void main(String [] args) throws IOException, ClassNotFoundException{

//实例化一个可序列化对象

Giao testClass = new Giao();

testClass.name = "说唱带师";

testClass.motto = "一给我哩 giao giao!";

//序列化

//将序列化后的对象写入到文件

FileOutputStream fos = new FileOutputStream("test.ser");

ObjectOutputStream os = new ObjectOutputStream(fos);

os.writeObject(testClass);

os.close();

fos.close();

//反序列化

Giao obj = null;

//从文件读取序列化的结果后进行反序列化

FileInputStream fis = new FileInputStream("test.ser");

ObjectInputStream ois = new ObjectInputStream(fis);

obj = (Giao)ois.readObject();

ois.close();

fis.close();

System.out.println(obj.name);

System.out.println(obj.motto);

}

}

//由此可见:人生苦短,我用 Python

序列化结果:

反序列化结果:

序列化条件

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

  • 该类必须实现 java.io.Serializable 或 java.io.Externalizable 接口。

    Externalizable 接口继承自 Serializable 接口,实现Externalizable 接口的类完全由自身来控制序列化的行为,而仅实现 Serializable 接口的类可以采用默认的序列化方式 。
    class Giao implements java.io.Serializable{}

  • 该类的所有属性必须是可序列化的。如果有一个属性不是可序列化的,则该属性必须注明是短暂的。

实现序列化/反序列化的方法

其中实现序列化与反序列化的两个类为:

  • java.io.ObjectOutputStream

    序列化:首先给该类传入一个文件对象(用于写入序列化结果),然后通过调用该类的 writeObject(目标对象) 方法将目标对象写入到文件

  • java.io.ObjectInputStream

    反序列化:首先给该类传入一个文件对象(用于读取文件中的序列化结果),然后通过调用该类的 readObject() 方法将其反序列化为目标对象

看到下面代码的执行结果:

输出了 1ndex,说明反序列化时调用了用户类 Giao 中的 readObject 方法,并且当我注释 in.defaultReadObject(); 代码,实际会输出 null

因此,实际上完成反序列化的操作的具体步骤是用户类 Giao 中的 readObject 方法,也就是继承自 Serializable 接口的 readObject 方法

为什么会出现反序列化漏洞

当被反序列化的数据流用户可控时,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码

关键点在于用户自定义类中的 readObject() 方法形成了不安全的类,导致了反序列化安全问题

简单的 demo

漏洞代码:

class RCE implements java.io.Serializable {

public String cmd;

private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {

in.defaultReadObject();

Runtime.getRuntime().exec(cmd);

}

public class ToRCE{

public static void main(String[] args) throws IOException, ClassNotFoundException {

RCE testClass = new RCE();

testClass.cmd = "calc";

FileOutputStream fileoutputstream = new FileOutputStream("RCE.ser");

ObjectOutputStream outputstream = new ObjectOutputStream(fileoutputstream);

outputstream.writeObject(testClass);

outputstream.close();

FileInputStream fileinputstream = new FileInputStream("RCE.ser");

ObjectInputStream inputstream = new ObjectInputStream(fileinputstream);

RCE obj = (RCE)inputstream.readObject();

inputstream.close();

}

}

看完上面的代码,是不是觉得 JAVA 反序列化漏洞跟 PHP 反序列化漏洞有些相似

但是怎么会有人写这么愚蠢的代码呢?JAVA 反序列化的高端操作还得看 构造反序列化链

JAVA 反序列化漏洞入门学习笔记(二):JAVA 反射

以上是 JAVA 反序列化漏洞入门学习笔记(一)--反序列化简介 的全部内容, 来源链接: utcz.com/z/393207.html

回到顶部