01-JAVA反序列化-入门

发布于:2023-01-01 ⋅ 阅读:(444) ⋅ 点赞:(0)

声明:本公众号文章大部分来源个人日常网安知识学习笔记总结,请勿利用文章内设计技术内容从事非法行为,如因此产生一切不良后果与文章作者与公众号无关。

0x00 Preface 前言

反序列化入门笔记,根据网上学习资料进行的学习总结。本文还不够完善,措辞可能有误,或者个人理解有误,若有大佬发现错误,烦请指出,非常感谢。

0x01 序列化/反序列化原理

一些当初学习的笔记,属于知识概括,简单来说就是:

writeObject()方法序列化

readObject()方法反序列化

一个对象要想被序列化,该对象所属的类必须实现Serializable接口

在这里插入代码片

序列化:对象 -> 字符串
反序列化:字符串 -> 对象

0x02 序列化/反序列化

根据上面所介绍的,这里是一个小案例

静态成员变量是不能被序列化,序列化是针对对象属性,而静态成员变量是属于类的(transient标识的对象成员变量不参与序列化)

1、一个对象要想被序列化,该对象所属的类必须实现Serializable接口。

一个实体类,用于实例化一个Person对象,可以看到这个实体类实现了Serializable接口。

import java.io.Serializable;
public class Person implements  Serializable{
    private String name;
    private int age;
    public Person(){

    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public String toString(){
        return "Person{" +
                "name=" +name +'\''+
                ",age=" +age + '}';
    }
}

2、writeObject()方法序列化

序列化一个对象,其中存放姓名与年龄

import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.HashMap;
import java.util.Map;

public class SerializationTest {
    //将序列化功能封装进了 serialize这个方法里面,在序列化当中
    //通过这个FileOutputStream输出流对象,将序列化的对象输出到ser.bin当中。再调用 oos 的writeObject方法,将对象进行序列化操作。
    public static void serialize(Object obj)throws IOException{
        ObjectOutputStream oos=new ObjectOutputStream(new FileOutputStream("ser.bin"));//文件输出流
        oos.writeObject(obj);//序列化
    }
    public static void main(String[] agrs)throws Exception{
        Person person =new Person("aa",22);
        //System.out.println(person);
        serialize(person);
    }
}

3、readObject()方法反序列化

反序列化一个对象文件,取出其中存放的个人数据

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class UnSerializeTest {
    public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{
        ObjectInputStream ois=new ObjectInputStream(new FileInputStream(Filename));//文件输入流
        Object obj=ois.readObject();//反序列化
        return obj;
    }
    public static void main(String[] args) throws Exception{
        Person person=(Person)unserialize("ser.bin");
        System.out.println(person);
    }
}

反序列化结果:
在这里插入图片描述

0x03 反序列化攻击情况

可能的形式:

1、入口的readObject直接调用危险方法(基本不可能)

2、入口类参数中包含可控类,该类有危险方法,readObject时调用。(也不多见)

3、入口类参数中包含可控类,该类又调用其他危险方法的类,readObject时调用。

比如类型定义为Object,调用equals();hashcode();toString()

(重点 相同类型 同名函数)

4、构造函数/静态代码块等类加载隐式执行。

第一种

最简单,很多时候也意味着几乎遇不到

在实体类里面重写(也许应该叫自定义)readObject()方法

如下,在实体类里面写了一个readObject(),其中写了一个执行系统命令的语句(由以上Person进行小改造),与前面步骤保持一致先序列化,再反序列化,在反序列化过程中弹出计算器。

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.Serializable;
public class Person implements  Serializable{
    private String name;
    private int age;
    public Person(){

    }
    public Person(String name,int age){
        this.name=name;
        this.age=age;
    }
    public String toString(){
        return "Person{" +
                "name=" +name +'\''+
                ",age=" +age + '}';
    }
    //类里面写了一个readObject()其中写了一个执行系统命令的语句,弹计算器
    private void readObject(ObjectInputStream ois)throws IOException,ClassNotFoundException{
        ois.defaultReadObject();
        Runtime.getRuntime().exec("calc");
    }
}

当将其序列化后,再反序列化时,执行了其中的语句
在这里插入图片描述

0x04 实现反序列化攻击路线


首先的攻击前提:继承Serializable

1、入口类 source(重写readObject 调用常见函数 参数类型宽泛 最好jdk自带)

2、调用链gadget chain 相同名称 相同类型

3、执行类 sink (rce/ssrf写文件等等)

以 HashMap 为例说明一下,仅仅只是说明如何找到入口类

以HashMap为例进行说明。

首先,攻击前提,那必然是要继承了Serializable这个接口,要不然谈何序列化与反序列化对吧。

HashMap 确实继承了Serializable这个接口。
在这里插入图片描述

入口类这里比较难懂,还是以HashMap为例吧,这些步骤是要自己动手实操一下。

打开 “Structure”,找到重写的readObject,往下分析。

在这里插入图片描述

我们看到第 1407 行与 1409 行中,Key 与 Value 的值执行了readObject的操作,再将 Key 和 Value 两个变量扔进hash这个方法里,重新计算key的hash值,我们再跟进(ctrl+鼠标左键即可) hash 方法当中。

在这里插入图片描述

若传入的参数 key 不为空,则h = key.hashCode(),于是乎,继续跟进hashCode当中。

hashCode 位置处于 Object 类当中,满足我们 调用常见的函数这一条件。

在这里插入图片描述

重写了hashCode 、equals、toString之类的方法并存在潜在的危险函数,并且这个类还可以反序列化,那么可能就出现在利用链上的类

关注:卡比兽网安笔记 精彩内容 等你发现
在这里插入图片描述