Java反序列化漏洞
产生的原因
只要服务端反序列化数据,客户端传递类的readObject中代码会自动执行,给予攻击者在服务器上运行代码的能力。
可能的形式
1.入口类的readObject直接调用危险方法。(在实际情况中这种很难存在,因为已知readObject一定会被执行的情况下再加入危险方法,这样的程序员一般会被拉去枪毙。)
2.入口类参数中包含可控类,该类有危险方法,readObject时调用。
3.入口类参数中包含可控类,该类又调用其他有危险方法的类,readObject时调用。
比如类型定义为Object,调用equals/hashcode/toString
4.构造函数/静态代码块等类加载时隐式执行。
共同条件
继承Serializable(保证可以被序列化与反序列化)
入口类 [重写readObject(需要调用下一步的代码) 参数类型宽泛(可以往里面任意传) 最好jdk自带(可以通用)] 例如:Map对象
调用链
执行类(rce SSRF 写文件)
示例代码
我们以入口类的readObject直接调用危险方法为例来实现一次反序列化攻击的流程。
先自定义一个可以被反序列化的类,并且重写readObject
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| import java.io.IOException; import java.io.ObjectInputStream; import java.io.Serializable;
public class Person implements Serializable { public String name; private int age;
public Person(String name, int age){ this.name = name; this.age = age; } private void readObject(ObjectInputStream ois) throws IOException, ClassNotFoundException{ ois.defaultReadObject(); Runtime.getRuntime().exec("calc"); } }
|
之后实例化并且将这个类序列化,保存在ser.bin文件中
1 2 3 4 5 6 7 8 9
| import java.io.*;
public class SerializePerson { public static void main(String[] args) throws IOException { Person person = new Person("aa", 22); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin")); oos.writeObject(person); } }
|
读取ser.bin,反序列化,执行readObject,弹出计算器
1 2 3 4 5 6 7 8
| import java.io.*;
public class unSerializePerson { public static void main(String[] args) throws IOException, ClassNotFoundException { ObjectInputStream ois = new ObjectInputStream(new FileInputStream("ser.bin")); Object o = ois.readObject(); } }
|
成功执行
