java反序列化漏洞简单学习

知识点

反序列化并不只存在于php,也存在各种语言中,如java、python等。
在学习java反序列化之前,我们需要知道一个基础知识:重写。

重写

重写,顾名思义就是重新改写该方法,从而达到想要的结果。需要注意的是:

  1. 只有拥有继承关系时才能重写,也就是说,只能重写父类同名方法
  2. 方法重写时, 方法名与形参列表必须一致。
  3. 方法重写时,子类的权限修饰符必须要大于或者等于父类的权限修饰符。
  4. 方法重写时,子类的返回值类型必须要小于或者 等于父类的返回值类型。
  5. 方法重写时, 子类抛出的异常类型要小于或者等于父类抛出的异常类型。 Exception(最坏) RuntimeException(小坏)
    (顺带提一嘴重载,重载就是一个类里的两个或以上同名方法就是方法重载,两个函数的参数类型或者参数数目必须不一样,但函数名一致)

代码准备

正常序列化

package com.sertest;

import java.io.*;
import java.io.Serializable;

class SerObj implements Serializable//实现Serializable接口,使其可以被序列化
{
    public String name;
    public int time;
}
public class  ser{
    public static void main(String args[]) throws Exception{
        // 实例化对象
        SerObj serObj = new SerObj();
        serObj.name = "serobj";
        serObj.time = 10;

        // 以下就是序列化操作
        // 打开object.ser文件
        FileOutputStream fos = new FileOutputStream("object.ser");
        ObjectOutputStream oos = new ObjectOutputStream(fos);
        // 使用writeObject()方法将serObj对象写到object.ser文件
        oos.writeObject(serObj);
        oos.close();
        fos.close();
    }
}

正常反序列化

package com.sertest;

import java.io.*;

public class Unser {
    public static void main(String args[]) throws Exception
    {
        FileInputStream fis = new FileInputStream("object.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        SerObj deSerobj = (SerObj) ois.readObject();
        System.out.println(deSerobj.name);
        ois.close();
        fis.close();
    }
}

此时的结果时正常的。

重写readobject方法后的恶意代码

package com.sertest;

import java.io.*;

class Evil implements Serializable
{
    public String name;
    public int time;
    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException
    {
        in.defaultReadObject();
        Runtime.getRuntime().exec("calc.exe");
    }
}

public class hack_test {
    public static void main(String args[])throws Exception
    {
        Evil h2 = new Evil();
        h2.name = "serobj";
        h2.time = 10;
        FileOutputStream fos = new FileOutputStream("hack.ser");
        ObjectOutputStream os = new ObjectOutputStream(fos);
        os.writeObject(h2);
        os.close();
    }
}

反序列化代码:

package com.sertest;

import java.io.*;

public class Unser {
    public static void main(String args[]) throws Exception
    {
        FileInputStream fis = new FileInputStream("hack.ser");
        ObjectInputStream ois = new ObjectInputStream(fis);
        Evil deSerobj = (Evil) ois.readObject();//这里的类在反序列化的时候需要改变为包含恶意代码的类的名称,这样改是为了看得更明白
        System.out.println(deSerobj.name);
        ois.close();
        fis.close();
    }
}

此时在反序列化时,由于恶意代码重写了readObject,所以在调用时调用的是已经被重写的readObject方法,执行了恶意代码。

本来想试行一下把这两个打包成jar文件包,然后一个用来序列化数据一个用来反序列化数据,奈何java编程水平有限,只能做到这个地步。实际上生成恶意序列化数据的时候肯定要使用同一个类名和变量名,不然会因类名不同而报错,那就不能成功了。
以后有时间的话看能不能写一个简单的链出来,再了解一下JAVA的反射机制,这样能对相关的利用就能有一定程度的理解了。
参考文章:
https://www.cnblogs.com/Fluorescence-tjy/p/11222052.html

你可能感兴趣的:(初窥CTF)