[CVE-2018-20433]c3p0XXE分析以及复现记录

00×0 前言

越来越懒了,这次复现一下上月爆出的c3p0数据库连接池XXE的漏洞,跟了一下,主要还是对用户自定义的XML文件没进行任何检查。还是有点鸡肋的漏洞,但是怎么使用还是要看各位操作吧。

00×1 复现

受影响版本:<=0.9.5.2

用过c3p0数据库连接池的朋友们都知道,c3p0这个库读的默认配置文件是c3p0-config.xml,由于开发者可以任意编辑c3p0-config.xml,且c3p0源码中直接解析了xml文档导致了这个漏洞的产生。

构造一下环境:

dbUtil.java:

package com.test.util;

import com.mchange.v2.c3p0.ComboPooledDataSource;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.SQLException;

public class dbUtils {
    private static DataSource dataSource = null;

    static {
        dataSource = new ComboPooledDataSource("mysql");
    }

    /**
     * 返回连接
     * @return
     */
    public static Connection getConnection(){
        Connection conn=null;
        try {
            conn = dataSource.getConnection();
        } catch (SQLException e) {
            e.printStackTrace();
        }
        return conn;
    }

    public static void closeConn(Connection conn){
        try {
            if(conn!=null && conn.isClosed()){
                conn.close();
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
}

test.java

package com.test.junit;

import com.test.util.dbUtils;
import org.junit.Test;
import org.junit.runner.RunWith;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import static org.junit.Assert.*;

public class c3p0Test {
    @Test
    public void test(){
        Connection conn = dbUtils.getConnection();
        try {
            PreparedStatement stmt= conn.prepareStatement("select user() ");
            ResultSet rs=stmt.executeQuery();
            while(rs.next()){
                System.out.println(rs.getString(1));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }

}

c3p0-config.xml

在c3p0-config声明之前插入poc.

然后测试test.java

 

00×2 分析

我们根据cve的提示找到漏洞触发点

c3p0 0.9.5.2 allows XXE in extractXmlConfigFromInputStream in com/mchange/v2/c3p0/cfg/C3P0ConfigXmlUtils.java during initialization.

学习过Java的朋友都知道,Java解析xml常用的有四种方法:DOM,SAX,JDOM,DOM4J,而C3P0数据库连接池采用的DOM,而且在源码中也能看到

默认读取的配置文件是c3p0-config.xml

知道了产生的地方,现在我们一步一步来跟进漏洞产生的步骤,在初始化数据库连接池库打下断点。

进入Debug模式。

跟到 AbstractComboPooledDataSource 方法中

再跟进,此处调用了AbstractPoolBackedDataSource类中的构造器

跟进,调用了  PoolBackedDataSourceBase 类中的  PoolBackedDataSourceBase方法

但是值得注意的是,在执行这个方法之前,PoolBackedDataSourceBase类会初始化一些东西

我们需要关注的是dataSourceName这个变量,跟进initializeStringPropertyVar这个方法看下详细内容。

发现并不重要,但是往上看,会发现 C3P0Config这个类,有个静态代码块,初始化的时候加载了一些东西

继续跟进一下findLibraryC3P0Config方法

从代码中可以看到cfgFinder是调用了 C3P0ConfigFinder接口的findConfig方法

搜索一下,我们可以看到C3P0ConfigFinder接口只有一个实现类  DefaultC3P0ConfigFinder

跟进方法,可以看到XML的调用趋势了

调用了开头说的C3P0ConfigXmlUtils类中的另外一个方法中,跟进extractXmlConfigFromDefaultResource方法。

这里们可以看到此处调用了最终存在缺陷的函数,我们可以从代码中看到

is = C3P0ConfigUtils.class.getResourceAsStream(XML_CONFIG_RSRC_PATH);

我们可以在此类的头部看到XML_CONFIG_RSRC_PATH的初始化变量为c3p0-config.xml

代码中将is复制后,将is作为实参传入了  extractXmlConfigFromInputStream 方法中

            is = C3P0ConfigUtils.class.getResourceAsStream(XML_CONFIG_RSRC_PATH);
            if ( is == null )
            {
                warnCommonXmlConfigResourceMisspellings();
                return null;
            }
            else
                return extractXmlConfigFromInputStream( is );
        }

再跟进extractXmlConfigFromInputStream方法,也就是最先说的缺陷函数模块

这样,这个漏洞产生的流程就完整的呈现了出来。

 

00×3 修复方法

修改 extractXmlConfigFromInputStream函数内容,如下

public static C3P0Config extractXmlConfigFromInputStream(InputStream is) throws Exception
    {
        DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
        DocumentBuilder db = fact.newDocumentBuilder();
        fact.setExpandEntityReferences(false);
        Document doc = db.parse( is );

        return extractConfigFromXmlDoc(doc);
    }

 

将setExpandEntityReferences设置为false

即不允许dom扩展出xml中的实体引用节点。

00×4 写在后面的话

    漏洞确实有点鸡肋,但是思路猥琐点会有大用处,怎么操作看各位发挥。

拨开云雾见天日 守得云开见月明~


One thought on “[CVE-2018-20433]c3p0XXE分析以及复现记录

发表评论

电子邮件地址不会被公开。 必填项已用*标注