定义
反序列化本身是很正常的行为,传递数据要用的,但是当反序列化可控的时候,我们传入的序列化数据被反序列化,自动调用readObject反序列化方法,完事就是套娃,readObject里边又调了啥类的啥方法,一直跟一路跟,最后到达了sink,其实sink是啥洞就是啥洞了
啥东西
user类
得实现Serializable接口,并且得重写readObject方法
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| package org.example.urldns;
import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable;
public class User implements Serializable { public String name; public int age;
public User(String name, int age) { this.name = name; this.age = age; } private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException { Process exec = Runtime.getRuntime().exec("calc"); } }
|
main类
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| package org.example.urldns;
import java.io.*;
public class Main { public static byte[] Serialize(Object obj) throws IOException { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream); objectOutputStream.writeObject(obj); objectOutputStream.close(); return byteArrayOutputStream.toByteArray(); }
public static void Deserialize(byte[] objstream) throws IOException, ClassNotFoundException { ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(objstream); ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream); System.out.println(objectInputStream.readObject().getClass().getName());
}
public static void main(String[] args) throws IOException, ClassNotFoundException { User user = new User("qiushan",20); byte[] serialize = Serialize(user); System.out.println(serialize);
Deserialize(serialize);
} }
|
该漏洞产生危害的原因:某类重写了readObject方法,比方说下边readObject是调用了别的方法,这样依然套娃导致了反序列化一系列调用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
| package org.example.urldns;
import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable;
public class User implements Serializable { public String name; public int age;
public User(String name, int age) { this.name = name; this.age = age; } public void qiushan() throws IOException { Process exec = Runtime.getRuntime().exec("calc"); } private void readObject(ObjectInputStream objectInputStream) throws IOException, ClassNotFoundException { qiushan(); } }
|
序列化的对象得实现序列化的接口(或者说继承了某一个类,继承的类里边实现了序列化的接口),所以说审计和研究的过程中一定要研究readObject方法,找readObject可控的,然后去调链子,这个方法可控,然后去一步步跟看方法里边调用了哪些方法,然后直到找到sink,这就是漏洞的利用链
当然审漏洞的过程中肯定是不可能有这样的条件,开发直接把漏洞甩你脸上,这样的话开发也该滚蛋了