0%

反序列化

定义

反序列化本身是很正常的行为,传递数据要用的,但是当反序列化可控的时候,我们传入的序列化数据被反序列化,自动调用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();//new一个数组输出流
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);//放入Obj对象里边等待反序列化
System.out.println(objectInputStream.readObject().getClass().getName());//调用readObj实现反序列化

}

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 {
//Process exec = Runtime.getRuntime().exec("calc");
qiushan();
}
}

序列化的对象得实现序列化的接口(或者说继承了某一个类,继承的类里边实现了序列化的接口),所以说审计和研究的过程中一定要研究readObject方法,找readObject可控的,然后去调链子,这个方法可控,然后去一步步跟看方法里边调用了哪些方法,然后直到找到sink,这就是漏洞的利用链

当然审漏洞的过程中肯定是不可能有这样的条件,开发直接把漏洞甩你脸上,这样的话开发也该滚蛋了